【问题标题】:Flask app logger not working when running within gunicorn在 gunicorn 中运行时,Flask 应用程序记录器无法正常工作
【发布时间】:2015-05-12 23:25:48
【问题描述】:

我正在尝试将来自一个非常简单的烧瓶应用程序的应用程序日志消息保存在日志文件中。虽然这在我使用嵌入式 Flask 服务器运行应用程序时完美运行,但在 gUnicorn 中运行时它根本不起作用,基本上,没有应用程序输出被重定向,既不是日志文件(我的 Flask 应用程序中指定的文件)也不是运行 gunicorn 时的 STDOUT。

也就是说,这是我的 Flask 应用:

@app.route('/')
def index():
    app.logger.debug('Into /!!!!')
    print 'Will this print?'
    return 'Flask is running!'


if __name__ == '__main__':
    #Setup the logger
    file_handler = FileHandler('test.log')
    handler = logging.StreamHandler()
    file_handler.setLevel(logging.DEBUG)
    handler.setLevel(logging.DEBUG)
    file_handler.setFormatter(Formatter(
    '%(asctime)s %(levelname)s: %(message)s '
    '[in %(pathname)s:%(lineno)d]'))
    handler.setFormatter(Formatter(
    '%(asctime)s %(levelname)s: %(message)s '
    '[in %(pathname)s:%(lineno)d]'))
    app.logger.addHandler(handler)
    app.logger.addHandler(file_handler)
    app.run(debug=True)

现在,如果我以以下方式启动应用程序:

python app.py

我得到了预期的输出:

 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with stat

--------------------------------------------------------------------------------
DEBUG in app [app.py:23]:
Into /!!!!
--------------------------------------------------------------------------------
2015-03-11 09:36:18,375 DEBUG: Into /!!!! [in app.py:23]
Will this print?
127.0.0.1 - - [11/Mar/2015 09:36:18] "GET / HTTP/1.1" 200 -

拖尾test.log,我明白了:

2015-03-11 09:36:18,375 DEBUG: Into /!!!! [in app.py:23]

到目前为止一切看起来都很棒,然后当我尝试使用 nginx + gunicorn 运行应用程序时,首先我尝试像这样运行 gunicorn:

gunicorn app:app -b localhost:8000 --debug --log-level debug

应用程序正在运行,如果我去http://localhost:

curl http://localhost
Flask is running!

但是查看日志文件,是空的,没有写入任何内容。我添加了 777 权限只是为了检查它是否是权限问题无济于事。然后查看 gunicorn 标准输出,除了 print 语句之外什么都没有写:

2015-03-11 09:42:06 [25641] [DEBUG] GET /
Will this print?

Looking around,我尝试将所有输出重定向到 gunicorn 日志,然后像这样启动 gunicorn:

gunicorn app:app -b localhost:8000 --debug --log-file /tmp/test.log --log-level debug --error-logfile /tmp/error.log

但是现在我什至没有在 gunicorn 文件中获得打印语句,这是 test.log 和 error.log 的输出(它们是相同的):

2015-03-11 09:46:17 [26257] [DEBUG]   tmp_upload_dir: None
2015-03-11 09:46:17 [26257] [DEBUG]   keyfile: None
2015-03-11 09:46:17 [26257] [DEBUG]   backlog: 2048
2015-03-11 09:46:17 [26257] [DEBUG]   logger_class: simple
2015-03-11 09:46:17 [26257] [INFO] Starting gunicorn 17.5
2015-03-11 09:46:17 [26257] [DEBUG] Arbiter booted
2015-03-11 09:46:17 [26257] [INFO] Listening at: http://127.0.0.1:8000 (26257)
2015-03-11 09:46:17 [26257] [INFO] Using worker: sync
2015-03-11 09:46:17 [26262] [INFO] Booting worker with pid: 26262
2015-03-11 09:48:15 [26262] [DEBUG] GET /

有一个非常相似的问题here,其中一个答案似乎表明在gunicorn 中运行时没有可用的应用程序记录器???这听起来,至少,很奇怪......那我应该如何登录?

另一个proposed solution 似乎建议不要使用 Flask 记录器,但与 gunicorn 无关(我认为)...

我错过了什么?我应该放弃 gunicorn 并选择 Apache-mod wsgi 吗? Nginx-uWSGI?快速CGI?有什么想法吗?

谢谢! 亚历杭德罗

编辑:

我已经尝试过使用 uWGSI 而不是 gunicorn 和相同行为的相同设置,但没有获得任何应用程序日志记录。

现在基于 this responseother one,我想出了这个(在 gUnicorn 和 uWSGI 上,两者都有效)

from flask import Flask
import logging
from logging import Formatter, FileHandler

app = Flask(__name__)

LOGGER = logging.getLogger('whatever')
file_handler = FileHandler('test.log')
handler = logging.StreamHandler()
file_handler.setFormatter(Formatter(
    '%(asctime)s %(levelname)s: %(message)s '
    '[in %(pathname)s:%(lineno)d]'
))
handler.setFormatter(Formatter(
    '%(asctime)s %(levelname)s: %(message)s '
    '[in %(pathname)s:%(lineno)d]'
))
LOGGER.addHandler(file_handler)
LOGGER.addHandler(handler)
LOGGER.setLevel(logging.INFO)

@app.route('/')
def hello():
    LOGGER.info('info log')
    LOGGER.debug('debug log')
    return 'Hello!'

if __name__ == '__main__':
    app.run()

gunicorn 的输出:

2015-03-11 12:25:01 [11540] [INFO] Starting gunicorn 17.5
2015-03-11 12:25:01 [11540] [INFO] Listening at: http://127.0.0.1:8000 (11540)
2015-03-11 12:25:01 [11540] [INFO] Using worker: sync
2015-03-11 12:25:01 [11545] [INFO] Booting worker with pid: 11545
2015-03-11 12:26:20,765 INFO: info log [in /home/mosquito/www/flask-project/flask-project/app.py:24]

然后查看我的 test.log 文件:

2015-03-11 12:26:20,765 INFO: info log [in /home/mosquito/www/flask-project/flask-project/app.py:24]

所以是的,它有点工作,但最初的问题仍然存在......为什么 Flask 记录器在 wsgi 容器中运行时似乎不起作用 - gunicorn,uWSGI?

【问题讨论】:

  • 这对我也有用。

标签: python logging flask gunicorn


【解决方案1】:

您自己在这里回答了您的问题。虽然我会添加我的答案,希望它可以帮助其他有类似问题的人。

由于您的问题有 2 个部分,其中第一部分已解决,因此请标记我对每个部分的回答:

第 1 部分:如果不是直接通过 python 运行应用程序,而是在 gunicorn 下运行它,则不会发生日志记录 这是因为,当直接运行时,name == 'ma​​in' 为 True,并且您的代码同时初始化了 FileHandler 和 StreamHandler,并且日志记录工作。 但是当通过 gunicorn 运行时,name == 'ma​​in' 会失败,因为 name 将包含您的模块的名称。这意味着不会初始化任何有效处理程序。因此看不到任何日志记录。

第 2 部分:为什么 Flask 记录器在 gunicorn/uWSGI 下默认不工作 最新的烧瓶版本从头开始初始化 app.logger,并在默认情况下附加一些处理程序,如 DebugHandler、StreamHandler,具体取决于 app.debug==True。记录器仍然不够,只会记录到 STDERR。 在过去的几个版本中,gunicorn 发生了多次变化。 版本 19.4.1 不会将 STDOUT 和 STDERR 捕获到 gunicorn error.log。 但它确实提供了名称为“gunicorn”、“gunicorn.access”和“gunicorn.error”的记录器。最后一个有一个 FileHandler 写入配置的 error.log。 如果您希望烧瓶应用程序中的日志转到 error.log,请使用以下方法之一: 方法1:

#only use gunicorn.error logger for all logging
LOGGER = logging.getLogger('gunicorn.error')
LOGGER.info('my info')
LOGGER.debug('debug message')
# this would write the log messages to error.log

方法2:

# Only use the FileHandler from gunicorn.error logger
gunicorn_error_handlers = logging.getLogger('gunicorn.error').handlers
app.logger.handlers.extend(gunicorn_error_handlers )
app.logger.addHandler(myhandler1)
app.logger.addHandler(myhandler2)
app.logger.info('my info')
app.logger.debug('debug message')

将推荐方法 2,因为除了 gunicorn.error 之外,您还可以保留任何您想要的处理程序。此外,您可以根据条件选择不添加 gunicorn.error 处理程序。

谢谢

【讨论】:

  • 我喜欢这种方法,将对其进行测试,谢谢@indrajeet
  • 方法 2 适用于我,但它在 stdout [2020-02-26 14:28:53 +0000] [21] [INFO] checking db \n checking db 上打印两次
  • 这对我有帮助。我想添加一个格式化的,它可以将我的烧瓶日志以指定的格式移动到 gunicorn。
【解决方案2】:

Flask 将Werkzeug 用于 WSGI。您看到的“Flask 日志”实际上来自 Werkzeug's builtin development 服务器,而不是来自 Flask 本身。

当您用 Gunicorn 或 uWSGI 之类的东西替换该开发服务器时,您看不到它的日志。

调试器也是如此。即使只使用Werkzeug's Debugger,也能看到熟悉的“Flask debug page”。

现在你知道了。 :)

【讨论】:

    【解决方案3】:

    使用 gunicorn 19.6,--capture-output --enable-stdio-inheritance 似乎可以工作。

    【讨论】:

    • 不,不走运
    • 唯一对我有用的解决方案。谢谢你。使用它你不需要任何这些处理程序:) 只需导入 logging 和 logging.basicConfig(level='DEBUG') 并使用 logging.info('something to log') ,适用于 gunicorn 和 wsgi
    • 一旦我设置了PYTHONUNBUFFERED=TRUE 环境变量(如docs 中所述),就为我工作
    • 这个答案适用于 FastAPI 和 gunicorn。谢谢。
    【解决方案4】:

    有人可以搜索:在使用FlaskGunicorn 时如何查看带有Python 错误堆栈的错误。

    只需将标志 --error-logfile 设置为您想要查看错误堆栈的文件路径。特别是(在Docker 中使用时),您可以在GUNICORN_CMD_ARGS 环境变量中将其设置为下一个值(示例):

    --bind=0.0.0.0:8000 --access-logfile=/logs/rest.app/access.log --error-logfile=/logs/rest.app/error.log --capture-output --enable-stdio-inheritance

    【讨论】:

      【解决方案5】:

      @Auguiwan 的回答确实解释了起源问题,但没有谈到如何解决它。@indrajeet 的回答相当全面,并提供了一种解决方案。但是,它们并没有解决我的相关问题。

      我的回答主要是帮助那些像我一样通过搜索类似关键字“flask gunicorn log”到达这里的人。 我发现此链接在相关搜索结果中非常有用 https://medium.com/@yoanis_gil/logging-with-docker-part-1-1-965cb5e17165

      部分Gunicorn配置

      exec gunicorn ${WSGI_MODULE}:${WSGI_APP} \
        --name $NAME \
        --workers $NUM_WORKERS \
        --user=$USER --group=$GROUP \
        --bind=unix:$SOCKFILE \
        --log-level=info \
        --log-file=/dev/stdout
      

      真的帮助我。核心配置为--log-level--log-file部分。
      如果您像我一样使用supervisoredgunicorn.conf,只需更改相关的gunicorn.conf 文件即可。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-03-28
        • 1970-01-01
        • 2022-01-15
        • 2014-09-18
        • 2020-02-20
        • 2023-02-16
        • 1970-01-01
        • 2012-02-15
        相关资源
        最近更新 更多