亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

如何優(yōu)雅的在flask中記錄log

hsluoyz / 3165人閱讀

摘要:一般的工廠模式結(jié)構(gòu)如下那么我們?cè)谙仍谥卸x,然后再在中定義子,均使用初始化輸出可以發(fā)現(xiàn)輸出的就是所在的文件目錄,之間的繼承關(guān)系與整個(gè)程序包保持一致。在模塊中通過(guò)來(lái)記錄輸出效果注意對(duì)于的引用不能通過(guò)如下方式,會(huì)有的報(bào)錯(cuò)。

背景

記錄日志,在任何項(xiàng)目中,都是很重要的。在Flask項(xiàng)目中,即有Flask提供的logger可以用來(lái)記錄log,也可以通過(guò)直接使用Pythonlogging模塊自定義logger來(lái)記錄。那么這兩者是什么關(guān)系,又該怎么使用呢?

思路

Pythonlogging模塊

先看下對(duì)于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...

上面主要告訴我們?nèi)c(diǎn),

可以通過(guò)logging.getLogger(name)來(lái)獲取一個(gè)logger,相同名字的logger,其實(shí)是同一個(gè)logger

logger是通過(guò)name進(jìn)行繼承的,比如foo.bar就是foo 的子logger。就可以是實(shí)現(xiàn)我們通過(guò)配置一個(gè)rootLogger,然后直接使用rootLogger.sublogger來(lái)記錄一下內(nèi)容,而不需要多帶帶再配置一遍。

當(dāng)使用logging.getLogger(__name__)時(shí),__name__就是這個(gè)模塊所在的python packagenamespace。

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就是一個(gè)標(biāo)準(zhǔn)的Python logging,它的命名是flask。我們既可以使用app.logger,也可以自己定義一個(gè)logger。

那么如何使用app.logger呢?

有兩種方式:

直接調(diào)用

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是一個(gè)單例,可以直接引用到app.logger

通過(guò)修改app.loggername,可以實(shí)現(xiàn)子logger的繼承么?

答案是否定的。

修改app.loggername

# app/__init__.py
app.logger.name = "app"

然后在子模塊中定義一個(gè)app.modulelogger來(lái)記錄:

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")

輸出結(jié)果:

2019-02-01 10:56:01,877 - Thread-2 - app - INFO - logged by current_app.logger

只有current_app.logger的輸出。

修改app.loggername是不是無(wú)效呢?

我們把子模塊中的loggername修改為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")

輸出結(jié)果:

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

兩個(gè)logger均輸出了。

可見(jiàn),通過(guò)修改app.logger.name可以在記錄的時(shí)候顯示為我們?cè)O(shè)置的名稱,但實(shí)際上這個(gè)logger還是flask.app。

__name__的使用

在自定義logger的情況下,為了方便起見(jiàn),我們可以利用__name__這個(gè)參數(shù)。

前面說(shuō)到:當(dāng)使用logging.getLogger(__name__)時(shí),__name__就是這個(gè)模塊所在的python packagenamespace。

一般Flask的工廠模式結(jié)構(gòu)如下:

app
├── __init__.py
├── main
│?? ├── __init__.py
│?? ├── functions.py
│?? └── views.py
└── module
    ├── __init__.py
    ├── functions.py
    └── views.py

那么我們?cè)谙仍?b>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__

可以發(fā)現(xiàn)輸出的logger.name就是所在的文件目錄,logger之間的繼承關(guān)系與整個(gè)程序包保持一致。

總結(jié)

根據(jù)上面分析,那么怎么優(yōu)雅的記錄logger呢?

如果沒(méi)有對(duì)模塊進(jìn)行分logger記錄要求的話。可以直接使用在程序初始化的時(shí)候配置app.logger(可以自行設(shè)置logger.name)。在模塊中通過(guò)import current_app來(lái)記錄:

# 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

__注意__: 對(duì)于current_app.logger的引用不能通過(guò)如下方式,會(huì)有RuntimeError的報(bào)錯(cuò)。

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.

如果希望按自己的實(shí)際需求,對(duì)模塊進(jìn)行分logger記錄要求的話。那么建議自己設(shè)置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

注意

關(guān)于pythonlogging的配置可參考官網(wǎng):

https://docs.python.org/3/lib...

在配置handler時(shí),經(jīng)常會(huì)希望日志可以按時(shí)間分割(TimedRotatingFileHandler)或者按大小分割(RotatingFileHandler).

但是在flask項(xiàng)目中,尤其開(kāi)啟多線程之后,在分割日志(doRollover())時(shí)會(huì)有文件讀寫的異常:

WindowsError: [Error 32]

建議使用SocketHandler,將日志發(fā)送給多帶帶的LogServer來(lái)進(jìn)行二次處理。

簡(jiǎn)易的接收socketlogLogServer可參考:https://github.com/keejo125/f...

或者現(xiàn)在流行的stashHandler,將日志發(fā)送給ELK來(lái)進(jìn)行二次處理。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/43142.html

相關(guān)文章

  • flask文檔學(xué)習(xí)筆記1-快速入門

    摘要:示例如下靜態(tài)路由使用動(dòng)態(tài)變量的路由未指定變量類型使用動(dòng)態(tài)變量的路由指定變量類型指定的路由變量,可以作為被裝飾的函數(shù)參數(shù)傳入進(jìn)來(lái)。 開(kāi)始決定認(rèn)真的在網(wǎng)上寫一些東西,主要原因還是在于希望能提升學(xué)習(xí)效果。雖說(shuō)python寫了有幾年,但是web后端框架的確沒(méi)怎么接觸過(guò),買了本狗書寥寥草草的過(guò)了一遍,發(fā)現(xiàn)很多東西還是理解不深,真的是好記性不如爛筆頭,知識(shí)也要從基礎(chǔ)開(kāi)始,退回來(lái)好好看看官方文檔,再...

    lingdududu 評(píng)論0 收藏0
  • Sanic + 前端MVVM 一種新一代Python高性能全棧開(kāi)發(fā)實(shí)踐

    摘要:前端一種新一代高性能全棧開(kāi)發(fā)實(shí)踐背景本項(xiàng)目將使用配合最簡(jiǎn)單的邏輯來(lái)展示一個(gè)基于的全新一代高性能全棧開(kāi)發(fā)實(shí)踐的為什么是對(duì)于為何不是等著名框架,或許可能很多人會(huì)產(chǎn)生疑惑,本身和非常的相似,而它的出現(xiàn),不僅是大大改進(jìn)過(guò)去時(shí)代性能低下通病,外加配 SanicCRUD-vue Sanic + 前端MVVM 一種新一代Python高性能全棧開(kāi)發(fā)實(shí)踐showImg(https://segmentfa...

    Profeel 評(píng)論0 收藏0
  • Sanic + 前端MVVM 一種新一代Python高性能全棧開(kāi)發(fā)實(shí)踐

    摘要:前端一種新一代高性能全棧開(kāi)發(fā)實(shí)踐背景本項(xiàng)目將使用配合最簡(jiǎn)單的邏輯來(lái)展示一個(gè)基于的全新一代高性能全棧開(kāi)發(fā)實(shí)踐的為什么是對(duì)于為何不是等著名框架,或許可能很多人會(huì)產(chǎn)生疑惑,本身和非常的相似,而它的出現(xiàn),不僅是大大改進(jìn)過(guò)去時(shí)代性能低下通病,外加配 SanicCRUD-vue Sanic + 前端MVVM 一種新一代Python高性能全棧開(kāi)發(fā)實(shí)踐showImg(https://segmentfa...

    NusterCache 評(píng)論0 收藏0
  • mdwiki開(kāi)發(fā)之路二資源與踩坑記錄

    摘要:側(cè)邊欄選用提到的。將改成來(lái)訪問(wèn)的形式組織代碼出現(xiàn)循環(huán)的問(wèn)題往往意味著代碼的布局有問(wèn)題,可以合并或者分離競(jìng)爭(zhēng)資源。分離的話就是把需要的資源提取到一個(gè)第三方文件去??傊褪菍⒀h(huán)變成單向。對(duì)于周期性任務(wù)缺一不可。其他任務(wù)可僅運(yùn)行。 1、bootstrap代碼片段: 如果你沒(méi)有藝術(shù)細(xì)胞,偷懶的方法就是到這上面去找,比如登錄框界面等。側(cè)邊欄選用:http://www.designerslib....

    molyzzx 評(píng)論0 收藏0
  • mdwiki開(kāi)發(fā)之路二資源與踩坑記錄

    摘要:側(cè)邊欄選用提到的。將改成來(lái)訪問(wèn)的形式組織代碼出現(xiàn)循環(huán)的問(wèn)題往往意味著代碼的布局有問(wèn)題,可以合并或者分離競(jìng)爭(zhēng)資源。分離的話就是把需要的資源提取到一個(gè)第三方文件去??傊褪菍⒀h(huán)變成單向。對(duì)于周期性任務(wù)缺一不可。其他任務(wù)可僅運(yùn)行。 1、bootstrap代碼片段: 如果你沒(méi)有藝術(shù)細(xì)胞,偷懶的方法就是到這上面去找,比如登錄框界面等。側(cè)邊欄選用:http://www.designerslib....

    linkFly 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<