我在使用Python 3.6(Flask==0.11.1
)和gunicorn==19.9.0
时遇到轻微的日志记录问题。我在Flask应用程序中使用structlog==18.1.0
(用于JSON记录)和python-json-logger==0.1.9
来注销各种本身可以正常工作的内容,即在不使用gunicorn的情况下运行Flask应用程序。但是当在gunicorn中运行Flask应用程序时,随机会出现一些日志记录问题,即,从gunicorn和Flask应用程序内部访问日志都丢失了。
一个记录事件的例子是
import structlog
def some_flask_endpoint():
logger = structlog.getLogger(__name__)
logger.info('This is an info event', additional_data='some additional data')
应该向与此类似的日志输出JSON消息
{"message": "This is an info event", "additional_data": "some additional data"}
目前,这一切都是通过记录FileConfig(gunicorn和flask应用程序都在使用)完成的,如下所示:
[loggers]
keys = root,gunicorn.error,gunicorn.access
[handlers]
keys=console,logfile
[formatters]
keys=json
[logger_root]
level=INFO
handlers=console,logfile
[logger_gunicorn.error]
level = INFO
handlers = logfile
propagate = 1
qualname = gunicorn.error
[logger_gunicorn.access]
level = INFO
handlers = logfile
propagate = 0
qualname = gunicorn.access
[handler_console]
class=logging.StreamHandler
formatter=json
args=(sys.stdout, )
[handler_logfile]
class=logging.handlers.TimedRotatingFileHandler
formatter=json
args=('logs.log', 'midnight', )
[formatter_json]
format=%(message)s
class=pythonjsonlogger.jsonlogger.JsonFormatter
即gunicorn正在将此文件与参数--logconfig logconfig.ini
一起使用,而flask已与logging.config.fileConfig('logconfig.ini')
软件包中的logging
一起使用。
我意识到将根记录器输出到日志文件可能会导致其他记录器的某些事件被再次记录,但是我主要担心的是,由于gunicorn旋转了多个工作程序(在这种情况下为4个),因此每个工作程序内部可能发生冲突使用structlog
的位置(即多个进程试图访问一个文件),这可能是某些日志丢失的原因。
所以我想到的另一种选择是简单地将根记录器更改为仅使用console
处理程序,或者仅创建structlog
使用的新记录器,即
import structlog
logger = structlog.getLogger('my_app')
logger.info('some info')
[logger_my_app]
level=INFO
handlers=console
然后使gunicorn主服务器从stdout中获取所有日志,并处理将其写入日志文件,并解决多进程单文件问题。但是,在为gunicorn提供此日志记录配置文件时(这样它就可以在json中输出其日志,因此我不必为配置gunicorn提供无数的参数),它似乎完全忽略了参数--capture-output
,因此我的{ {1}}日志仅显示在控制台中,但不会写出到任何配置文件。
因此,在这篇冗长但希望说明性的文章之后,没有人知道有关将日志从structlog
/ logging
储存到Gunicorn内部的正确方法的信息,因为我找不到任何具体信息在线和Gunicorn文档在这个话题上赚了不少钱?
Tl; dr:如何将stdout发送到gunicorn中的日志文件,同时还向gunicorn提供日志配置文件。