在gunicorn中运行时,Flask app logger无法正常工作

时间:2015-03-11 08:54:38

标签: python logging flask gunicorn

我试图从日志文件中的一个非常简单的烧瓶应用程序中保存应用程序日志消息。虽然当我使用嵌入式Flask服务器运行应用程序时,这完美无缺,但在gUnicorn中运行时根本无法正常工作,基本上,没有应用程序输出重定向日志文件(我的Flask应用程序中指定的文件)或者在运行gunicorn时的STDOUT。

那就是说,这是我的Flask app:

@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 -

Tailing 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 stdout,除了印刷声明之外什么都没写:

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

Looking around,我试图将所有输出重定向到gunicorn日志,然后像这样开始枪杀:

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

但是现在我甚至不用gunicorn文件中的print语句,这是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? FastCGI的?有什么想法吗?

谢谢! 亚历

编辑:

我已经尝试过与uWGSI相同的设置,而不是枪炮和相同的行为,无论如何都没有获得应用程序记录。

现在基于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]

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

5 个答案:

答案 0 :(得分:21)

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

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

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

第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,请使用以下方法之一: Approach1:

#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

Approach2:

# 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处理程序。

感谢

答案 1 :(得分:9)

Flask使用Werkzeug进行WSGI。 "烧瓶日志"你看到实际上是来自Werkzeug's builtin development服务器,而不是来自Flask本身。

当您使用Gunicorn或uWSGI等替换该开发服务器时,您将看不到其日志。

调试器也是如此。您可以看到熟悉的" Flask调试页面"即使您只使用Werkzeug's Debugger

现在你知道了。 :)

答案 2 :(得分:5)

使用gunicorn 19.6,--capture-output --enable-stdio-inheritance似乎有效。

答案 3 :(得分:1)

@Auguiwan的答案的确说明了起源问题,但没有谈论如何解决。@ indrajeet的答案相当全面,提供了一种解决方案。但是,它们不能解决我的相关问题。

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

独角兽配置部分

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文件。

答案 4 :(得分:0)

有人可以搜索:在将PythonFlask一起使用时,如何查看Gunicorn错误堆栈中的错误。

只需将标志--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