【问题标题】:Why is Flask application not creating any logs when hosted by Gunicorn?为什么 Flask 应用程序在 Gunicorn 托管时不创建任何日志?
【发布时间】:2014-10-26 22:31:30
【问题描述】:

我正在尝试将日志记录添加到使用 Flask 的 Web 应用程序中。

当使用内置服务器(即python3 server.py)托管时,日志记录有效。使用 Gunicorn 托管时,不会创建日志文件。

重现问题的最简单代码是这个:

#!/usr/bin/env python

import logging
from flask import Flask
flaskApp = Flask(__name__)


@flaskApp.route('/')
def index():
    flaskApp.logger.info('Log message')
    print('Direct output')
    return 'Hello World\n'


if __name__ == "__main__":
    logHandler = logging.FileHandler('/var/log/demo/app.log')
    logHandler.setLevel(logging.INFO)
    flaskApp.logger.addHandler(logHandler)
    flaskApp.logger.setLevel(logging.INFO)
    flaskApp.run()

应用程序被调用:

gunicorn server:flaskApp -b :80 -w 4
    --access-gfile /var/log/demo/access.log
    --error-logfile /var/log/demo/error.log

向网站主页发出请求时,会发生以下情况:

  1. 我收到了预期的 HTTP 200“Hello World\n”作为响应。

  2. /var/log/demo/access.log中有请求的痕迹。

  3. /var/log/demo/error.log 保持不变(只有启动事件)。

  4. 终端中有“直接输出”行。

  5. 没有“/var/log/demo/app.log”。如果我在启动应用程序之前创建文件,则不会修改文件。

请注意:

  • 目录/var/log/demo 可以被所有人访问(读、写、执行),所以这不是权限问题。

  • 如果我将StreamHandler 添加为第二个处理程序,终端和 Gunicorn 日志文件中仍然没有“日志消息”消息的痕迹。

  • Gunicorn 是使用pip3 install gunicorn 安装的,因此不应与 Python 版本不匹配。

发生了什么事?

【问题讨论】:

    标签: python logging flask gunicorn


    【解决方案1】:

    这种方法对我有用:导入 Python 日志记录模块并向其中添加 gunicorn 的错误处理程序。然后您的记录器将登录到 gunicorn 错误日志文件:

    import logging
    
    app = Flask(__name__)
    
    gunicorn_error_logger = logging.getLogger('gunicorn.error')
    app.logger.handlers.extend(gunicorn_error_logger.handlers)
    app.logger.setLevel(logging.DEBUG)
    app.logger.debug('this will show in the log')
    

    我的 Gunicorn 启动脚本配置为将日志条目输出到如下文件:

    gunicorn main:app \
        --workers 4 \
        --bind 0.0.0.0:9000 \
        --log-file /app/logs/gunicorn.log \
        --log-level DEBUG \
        --reload
    

    【讨论】:

    • 我可以在脚本里面添加日志文件的路径而不是在命令行中吗?
    • 这是否会导致为您打印两次日志消息,@pkout? (对我有用。)
    • @pdoherty926 有关双重日志记录问题,请参阅medium.com/@trstringer/…
    • 感谢@IronBishop 的建议。不幸的是,这篇文章最初是引导我走上这条路的,所以它对我没有帮助。我想我已经确定我看到的双重日志记录问题是由我的一个依赖项(Plotly Dash)正在做的事情引起的。它似乎正在创建一个新的日志处理程序,它也在利用我的应用程序日志。
    • 为我工作谢谢! :)
    【解决方案2】:

    当您使用python3 server.py 时,您正在运行 server3.py 脚本。

    当您使用 gunicorn server:flaskApp ... 时,您正在运行 gunicorn 启动脚本,然后该脚本导入模块 server 并在该模块中查找变量 flaskApp

    由于正在导入 server.py__name__ 变量将包含 "server",而不是 "__main__",因此您的日志处理程序设置代码未运行。

    您可以简单地将日志处理程序设置代码移到if __name__ == "__main__": 节之外。但请确保将 flaskApp.run() 保留在其中,因为您确实希望在 gunicorn 导入 server 时运行它。

    更多关于what does if __name__ == “__main__”: do?

    【讨论】:

    • 另外请注意,flask 在 gunicorn 下默认以生产模式运行,其中 app.logger 级别设置为 WARN,因此您不会看到 app.logger.info() 或 app.logger。调试()。如果需要,请设置 app.debug = True。
    【解决方案3】:

    这背后有两个原因:Gunicorn 有自己的记录器,它通过这种机制控制日志级别。对此的解决方法是添加 app.logger.setLevel(logging.DEBUG)。
    但是这种方法有什么问题?好吧,首先,这是硬编码到应用程序本身中的。是的,我们可以将它重构为一个环境变量,但是我们有两个不同的日志级别:一个用于 Flask 应用程序,但一个完全独立的用于 Gunicorn,它是通过 --log-level 参数设置的(例如“调试”、“信息”、“警告”、“错误”和“关键”)。

    解决这个问题的一个很好的解决方案是下面的sn-p:

    import logging
    from flask import Flask, jsonify
    
    app = Flask(__name__)
    
    @app.route('/')
    def default_route():
        """Default route"""
        app.logger.debug('this is a DEBUG message')
        app.logger.info('this is an INFO message')
        app.logger.warning('this is a WARNING message')
        app.logger.error('this is an ERROR message')
        app.logger.critical('this is a CRITICAL message')
        return jsonify('hello world')
    
    if __name__ == '__main__':
        app.run(host=0.0.0.0, port=8000, debug=True)
    
    else:
        gunicorn_logger = logging.getLogger('gunicorn.error')
        app.logger.handlers = gunicorn_logger.handlers
        app.logger.setLevel(gunicorn_logger.level)
    

    参考:Code and Explanation is taken from here

    【讨论】:

      猜你喜欢
      • 2019-02-19
      • 1970-01-01
      • 2017-01-31
      • 2020-02-02
      • 1970-01-01
      • 2010-10-01
      • 1970-01-01
      • 2020-10-20
      • 1970-01-01
      相关资源
      最近更新 更多