摘要:一般的工廠模式結構如下那么我們在先在中定義,然后再在中定義子,均使用初始化輸出可以發現輸出的就是所在的文件目錄,之間的繼承關系與整個程序包保持一致。在模塊中通過來記錄輸出效果注意對于的引用不能通過如下方式,會有的報錯。
背景
記錄日志,在任何項目中,都是很重要的。在Flask項目中,即有Flask提供的logger可以用來記錄log,也可以通過直接使用Python的logging模塊自定義logger來記錄。那么這兩者是什么關系,又該怎么使用呢?
思路
Python的logging模塊
先看下對于logging模塊的官方介紹
Loggers have the following attributes and methods. Note that Loggers are never instantiated directly, but always through the module-level function logging.getLogger(name). Multiple calls to getLogger() with the same name will always return a reference to the same Logger object.The name is potentially a period-separated hierarchical value, like foo.bar.baz (though it could also be just plain foo, for example). Loggers that are further down in the hierarchical list are children of loggers higher up in the list. For example, given a logger with a name of foo, loggers with names of foo.bar, foo.bar.baz, and foo.bam are all descendants of foo. The logger name hierarchy is analogous to the Python package hierarchy, and identical to it if you organise your loggers on a per-module basis using the recommended construction logging.getLogger(__name__). That’s because in a module, __name__ is the module’s name in the Python package namespace.
https://docs.python.org/3/lib...
上面主要告訴我們三點,
可以通過logging.getLogger(name)來獲取一個logger,相同名字的logger,其實是同一個logger。
logger是通過name進行繼承的,比如foo.bar就是foo 的子logger。就可以是實現我們通過配置一個rootLogger,然后直接使用rootLogger.sublogger來記錄一下內容,而不需要多帶帶再配置一遍。
當使用logging.getLogger(__name__)時,__name__就是這個模塊所在的python package的namespace。
flask提供的logger
再看下flask中的logging模塊:
Flask uses standard Python logging. All Flask-related messages are logged under the "flask" logger namespace.Flask.logger returns the logger named "flask.app", and can be used to log messages for your application.Depending on the situation, an extension may choose to log to app.logger or its own named logger. Consult each extension’s documentation for details.
http://flask.pocoo.org/docs/1...
我們可以知道flask的logger就是一個標準的Python logging,它的命名是flask。我們既可以使用app.logger,也可以自己定義一個logger。
那么如何使用app.logger呢?
有兩種方式:
直接調用
logger = logging.getLogger("flask.app") logger.info("flask.app")
使用Flask提供的接口
from flask import current_app current_app.logger.info("logged by current_app from main")
這里推薦還是使用第二種,current_app是一個單例,可以直接引用到app.logger。
通過修改app.logger的name,可以實現子logger的繼承么?
答案是否定的。
修改app.logger的name:
# app/__init__.py app.logger.name = "app"
然后在子模塊中定義一個app.module的logger來記錄:
from flask import current_app import logging logger = logging.getLogger("app.module") @module.route("/test", methods=["GET"]) def test(): logger.info("logged by app.module") current_app.logger.info("logged by current_app.logger")
輸出結果:
2019-02-01 10:56:01,877 - Thread-2 - app - INFO - logged by current_app.logger
只有current_app.logger的輸出。
修改app.logger的name是不是無效呢?
我們把子模塊中的logger的name修改為flask.app.module:
from flask import current_app import logging logger = logging.getLogger("flask.app.module") @module.route("/test", methods=["GET"]) def test(): logger.info("logged by flask.app.module") current_app.logger.info("logged by current_app.logger")
輸出結果:
2019-02-01 11:00:10,944 - Thread-2 - flask.app.module - INFO - logged by flask.app.module 2019-02-01 11:00:10,946 - Thread-2 - app - INFO - logged by current_app.logger
兩個logger均輸出了。
可見,通過修改app.logger.name可以在記錄的時候顯示為我們設置的名稱,但實際上這個logger還是flask.app。
__name__的使用
在自定義logger的情況下,為了方便起見,我們可以利用__name__這個參數。
前面說到:當使用logging.getLogger(__name__)時,__name__就是這個模塊所在的python package的namespace。
一般Flask的工廠模式結構如下:
app ├── __init__.py ├── main │?? ├── __init__.py │?? ├── functions.py │?? └── views.py └── module ├── __init__.py ├── functions.py └── views.py
那么我們在先在app.__init__中定義rootLogger,然后再在app.module.functions.py中定義子Logger,均使用logging.getLogger(__name__):
# app.__init__.py 初始化rootlogger rootLogger = logging.getLogger(__name__) rootLogger.setLevel(logging.DEBUG) socketHandler = logging.handlers.SocketHandler("localhost",logging.handlers.DEFAULT_TCP_LOGGING_PORT) rootLogger.addHandler(socketHandler) rootLogger.setLevel(logging.DEBUG) # app.module.functions.py import logging logger = logging.getLogger(__name__) def record_from_logging(): logger.info("logged by logging from __name__")
輸出:
2019-02-01 12:18:34,743 - MainThread - app - INFO - register root logger by __name__ 2019-02-01 12:19:24,954 - Thread-4 - app.module.functions - INFO - logged by logging from __name__
可以發現輸出的logger.name就是所在的文件目錄,logger之間的繼承關系與整個程序包保持一致。
總結根據上面分析,那么怎么優雅的記錄logger呢?
如果沒有對模塊進行分logger記錄要求的話。可以直接使用在程序初始化的時候配置app.logger(可以自行設置logger.name)。在模塊中通過import current_app來記錄:
# app.__init__.py def register_logging(app): app.logger.name = "app" # logstash_handler stashHandler = logstash.LogstashHandler("app.config.get("ELK_HOST")", "app.config.get("ELK_PORT")") app.logger.addHandler(stashHandler) # socket_handler socketHandler = logging.handlers.SocketHandler("localhost", logging.handlers.DEFAULT_TCP_LOGGING_PORT) app.logger.addHandler(socketHandler) # app.module.function.py from flask import current_app @module.route("/test", methods=["GET"]) def test(): current_app.logger.info("logging someting") return "logged by current_app.logger"
輸出效果:
2019-02-01 13:49:28,998 - Thread-2 - app - INFO - logged by current_app from main 2019-02-01 13:49:38,346 - Thread-3 - app - INFO - logged by current_app of functions
__注意__: 對于current_app.logger的引用不能通過如下方式,會有RuntimeError的報錯。
from flask import current_app logger = current_app.logger ## 異常 raise RuntimeError(_app_ctx_err_msg) RuntimeError: Working outside of application context. This typically means that you attempted to use functionality that needed to interface with the current application object in some way. To solve this, set up an application context with app.app_context(). See the documentation for more information.
如果希望按自己的實際需求,對模塊進行分logger記錄要求的話。那么建議自己設置logger。
# app.__init__.py def register_logging(): # set own root logger rootLogger = logging.getLogger(__name__) rootLogger.setLevel(logging.DEBUG) # socketHandler socketHandler = logging.handlers.SocketHandler("localhost",logging.handlers.DEFAULT_TCP_LOGGING_PORT) rootLogger.addHandler(socketHandler) # logstash_handler stashHandler = logstash.LogstashHandler("app.config.get("ELK_HOST")", "app.config.get("ELK_PORT")") rootLogger.addHandler(stashHandler) rootLogger.setLevel(logging.DEBUG) # app.module.function.py import logging logger = logging.getLogger(__name__) @module.route("/test", methods=["GET"]) def test(): logger.info("logging someting") return "logged by logging module"
輸出效果:
2019-02-01 13:49:49,297 - Thread-5 - app.module.views - INFO - logged by flask.app.module 2019-02-01 13:50:01,013 - Thread-7 - app.module.functions - INFO - logged by logging module of functions
完整代碼可參考:https://github.com/keejo125/flask_logging_demo
注意關于python中logging的配置可參考官網:
https://docs.python.org/3/lib...
在配置handler時,經常會希望日志可以按時間分割(TimedRotatingFileHandler)或者按大小分割(RotatingFileHandler).
但是在flask項目中,尤其開啟多線程之后,在分割日志(doRollover())時會有文件讀寫的異常:
WindowsError: [Error 32]
建議使用SocketHandler,將日志發送給多帶帶的LogServer來進行二次處理。
簡易的接收socketlog的LogServer可參考:https://github.com/keejo125/f...
或者現在流行的stashHandler,將日志發送給ELK來進行二次處理。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/43142.html
摘要:示例如下靜態路由使用動態變量的路由未指定變量類型使用動態變量的路由指定變量類型指定的路由變量,可以作為被裝飾的函數參數傳入進來。 開始決定認真的在網上寫一些東西,主要原因還是在于希望能提升學習效果。雖說python寫了有幾年,但是web后端框架的確沒怎么接觸過,買了本狗書寥寥草草的過了一遍,發現很多東西還是理解不深,真的是好記性不如爛筆頭,知識也要從基礎開始,退回來好好看看官方文檔,再...
摘要:前端一種新一代高性能全棧開發實踐背景本項目將使用配合最簡單的邏輯來展示一個基于的全新一代高性能全棧開發實踐的為什么是對于為何不是等著名框架,或許可能很多人會產生疑惑,本身和非常的相似,而它的出現,不僅是大大改進過去時代性能低下通病,外加配 SanicCRUD-vue Sanic + 前端MVVM 一種新一代Python高性能全棧開發實踐showImg(https://segmentfa...
摘要:前端一種新一代高性能全棧開發實踐背景本項目將使用配合最簡單的邏輯來展示一個基于的全新一代高性能全棧開發實踐的為什么是對于為何不是等著名框架,或許可能很多人會產生疑惑,本身和非常的相似,而它的出現,不僅是大大改進過去時代性能低下通病,外加配 SanicCRUD-vue Sanic + 前端MVVM 一種新一代Python高性能全棧開發實踐showImg(https://segmentfa...
摘要:側邊欄選用提到的。將改成來訪問的形式組織代碼出現循環的問題往往意味著代碼的布局有問題,可以合并或者分離競爭資源。分離的話就是把需要的資源提取到一個第三方文件去。總之就是將循環變成單向。對于周期性任務缺一不可。其他任務可僅運行。 1、bootstrap代碼片段: 如果你沒有藝術細胞,偷懶的方法就是到這上面去找,比如登錄框界面等。側邊欄選用:http://www.designerslib....
摘要:側邊欄選用提到的。將改成來訪問的形式組織代碼出現循環的問題往往意味著代碼的布局有問題,可以合并或者分離競爭資源。分離的話就是把需要的資源提取到一個第三方文件去。總之就是將循環變成單向。對于周期性任務缺一不可。其他任務可僅運行。 1、bootstrap代碼片段: 如果你沒有藝術細胞,偷懶的方法就是到這上面去找,比如登錄框界面等。側邊欄選用:http://www.designerslib....
閱讀 3868·2021-07-28 18:10
閱讀 2577·2019-08-30 15:44
閱讀 1082·2019-08-30 14:07
閱讀 3455·2019-08-29 17:20
閱讀 1577·2019-08-26 18:35
閱讀 3533·2019-08-26 13:42
閱讀 1816·2019-08-26 11:58
閱讀 1585·2019-08-23 18:33