无法在 Flask 的子模块中使用 Python 日志记录

Aks*_*ay 0 logging flask python-3.5

我的 Flask 项目布局有两个文件夹 - 前向和后向。Fro 是我的 Flask 应用程序,“back”是包含我的 Flask 应用程序调用的文件/模块的服务层。

我的问题是,虽然用 Fro 编写的函数中的日志语句记录在输出控制台上,但服务层中编写的函数中的日志语句不会显示在日志输出中。

我尝试禁用默认的flask.logger,但这似乎没有帮助。

app.logger.disabled = True
logger = logging.getLogger('werkzeug')
logger.disabled = True
Run Code Online (Sandbox Code Playgroud)

app.py 中的代码如下所示 -

import os
from flask import Flask
import click
import logging
log = logging.getLogger(__name__)

def create_app(test_config=None):
    # create and configure the app
    app = Flask(__name__, instance_relative_config=True)
    app.logger.info("This gets printed")
    configure(app)
    app.logger.info("This also gets printed")
    # bunch of code
    # ...
    return app
Run Code Online (Sandbox Code Playgroud)

路线方法如下所示 -

import logging
from back.services import request_service
log = logging.getLogger(__name__)


@bp.route('/install', methods=('GET', 'POST'))
def install():
    log.info("This gets printed")
    is_valid_request = request_service.check_request_authenticity(request)
    return str(is_hmac_valid)
Run Code Online (Sandbox Code Playgroud)

request_service 中的 check_request_authenticity 函数如下所示 -

import logging
log = logging.getLogger(__name__)
def check_request_authenticity():
        log.info("However this DOES NOT get printed")

Run Code Online (Sandbox Code Playgroud)

我希望能够使用本机 python 日志记录来登录服务层中的函数,而不必将 Flask app.logger 传递给服务层中的函数。

请问有什么指点吗?

Mar*_*icu 6

我得到了你的家人。

为什么它有效

问题出在记录器中,app.py您的日志记录有效是因为:

log = logging.getLogger(__name__)

def create_app(test_config=None):
    # create and configure the app
    app = Flask(__name__, instance_relative_config=True)
    app.logger.info("This gets printed")
    configure(app)
    app.logger.info("This also gets printed")
    # bunch of code
    # ...
    return app
Run Code Online (Sandbox Code Playgroud)

logapp.logger是相同的记录器,因为您将相同的值传递__name__给记录器和Flask对象。

当您这样做时app.loggerFlask将使用__name__它已实例化的来创建该记录器。但是,由于您之前已经创建了该记录器,因此在执行以下操作时,log = logging.getLogger(__name__)Flask看到它存在,并且只会获取现有记录器,并向其添加处理程序,以及带有日期时间文件的良好格式,从而产生log以下形式:

[2019-09-15 12:51:47,534] INFO in app: This gets printed

Flask还将该记录器的级别logging.DEBUG设置为,这就是您的.info()调用起作用的原因。

log.info('Whats poppin cuz')如果您在调用之前执行此操作,app.logger.info()您将看到它不会在控制台上打印任何内容,因为使用的默认日志记录级别将是根级别,即警告(请记住这一点,因为它将在本节中进一步提供有价值的信息)解释)。


问题

继续,当您进入back.services并执行操作时log = logging.getLogger(__name__),您创建了一个名为 的不同记录器,back.services该记录器与上面创建的记录器无关fro.app(因此禁用该记录器不会影响此记录器)。

这意味着,当您这样做时:

log.info("However this DOES NOT get printed")它将将此消息一直传播到根记录器,根记录器的默认级别是(您从上面猜到的)WARNING,并且只有大于或等于WARNING的消息才会被注销。在此处查看所有日志记录级别

如果你要替换log.info()为,log.warning()你会看到它被打印出来。但是,与烧瓶记录器不同,您不会有一个很好的消息格式,您只会得到消息的基本打印。


解决方案

解决方案1

现在我明白你不想app.logger在所有模块中传递该对象,但你不必这样做。要利用该记录器,您所要做的就是获取它,而不传递任何对象,并且您将使用 python 本机日志记录机制和具有良好格式的 Flask 对象,因为这就是 python 日志记录机制的工作原理。创建记录器后,使用该名称的任何其他调用都将仅获取该记录器,而不是再次创建它。

所以而不是做

log = logging.getLogger(__name__)back.services

做就是了

log = logging.getLogger('fro.app')(或者在函数中__name__实例化对象时具有的任何值),您将看到消息的格式化和打印效果如何。Flaskcreate_app

确保您app.logger尽早调用(基本上就像上面所做的那样,在创建 Flask 对象或在 中的某个位置之后app.py),以便 Flask 可以正确设置该记录器。

解决方案2

如果您根本不想app.logger在任何地方使用,只需执行logging.basicConfig(level=DEBUG)尽早拨打电话,您就会在整个应用程序的各个级别中看到所有消息。

您可以继续根据模块名称实例化记录器,就像您现在所做的那样,即log = logging.getLogger(__name__)

你的create_app可以是这样的:

def create_app(test_config=None):
    # create and configure the app
    app = Flask(__name__, instance_relative_config=True)
    logging.basicConfig(level=logging.DEBUG)  # this added here
    app.logger.info("This gets printed")
    app.logger.info("This also gets printed")
    # more code below
    return app
Run Code Online (Sandbox Code Playgroud)

并且您的安装函数和跨应用程序的记录器可以保持原样,并且日志将采用以下形式:

INFO:fro.app:This gets printed
INFO:fro.app:This also gets printed
INFO:back.services:However this DOES get printed
Run Code Online (Sandbox Code Playgroud)

解决方案3

这是更高级的东西,您可以在其中创建日志配置(通过 dictConfig 或 fileConfig),并在应用程序启动时尽早加载它,但这超出了本票的范围。您可以在此处的文档和本论坛的其他答案中找到相关信息。