为什么Flask应用在Gunicorn托管时不生成日志?
我正在尝试为一个使用Flask的网页应用添加日志记录。
当我使用内置服务器(也就是运行 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
当我访问网站的主页时,会发生以下情况:
我收到了预期的HTTP 200 "Hello World\n" 的响应。
请求的记录在
/var/log/demo/access.log
中有显示。/var/log/demo/error.log
没有变化(里面只有启动事件)。终端中有“直接输出”的信息。
没有找到 '/var/log/demo/app.log' 文件。如果我在启动应用之前手动创建这个文件,启动后文件也不会被修改。
需要注意的是:
目录
/var/log/demo
是所有人都可以访问(读、写、执行),所以这不是权限问题。即使我添加了
StreamHandler
作为第二个处理器,终端和Gunicorn的日志文件中也没有“日志信息”的痕迹。Gunicorn是通过
pip3 install gunicorn
安装的,所以Python版本应该没有不匹配的问题。
这是怎么回事呢?
相关文章:
- 暂无相关问题
3 个回答
这背后有几个原因:Gunicorn有自己的日志记录系统,它通过这个系统来控制日志的级别。解决这个问题的方法是添加app.logger.setLevel(logging.DEBUG)。
但这个方法有什么问题呢?首先,这个设置是写死在应用程序里的。没错,我们可以把它改成一个环境变量,但这样就会出现两个不同的日志级别:一个是Flask应用的日志级别,另一个是Gunicorn的日志级别,后者是通过--log-level参数来设置的(比如“debug”、“info”、“warning”、“error”和“critical”等级别)。
解决这个问题的一个好方法是下面的代码片段:
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)
参考:代码和解释来自这里
这个方法对我有效:导入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
当你使用 python3 server.py
时,你是在运行一个叫做 server.py 的脚本。
而当你使用 gunicorn server:flaskApp ...
时,你是在运行 gunicorn 的启动脚本,这个脚本会导入 server 这个模块,并在里面查找一个叫做 flaskApp 的变量。
因为 server.py 被导入了,所以 __name__
这个变量的值会是 "server"
,而不是 "__main__"
,所以你设置日志处理的代码不会被执行。
你可以简单地把日志处理的代码移到 if __name__ == "__main__":
这个判断语句之外。但要确保 flaskApp.run()
仍然放在里面,因为你不想在 gunicorn 导入 server
时执行它。
想了解更多关于 if __name__ == “__main__”:
的作用。