Python中在Web框架里如何正确配置和使用logging模块?
比如
有一个接口,我会记录用户的请求数据 dataA,比如 querystring 再加其他一些数据,
但是我又不想把 dataA 直接用 print
输出到 sys.stdout 里面去,因为这样 dataA 并不好找,所以我就用了 FileRotateHandler,并设置文件最大为 50M,
然而这样会产生一个问题就是,当我用 supervisor 启动多个 web 进程的时候,我发现有许多日志文件大为在 5M
的时候就被切割出来了。如果要解决这种问题是不是只有使用队列这一种方式呢
Python中在Web框架里如何正确配置和使用logging模块?
一般框架都会自带 log 模块吧
在Web框架里配置logging,核心是尽早初始化、统一配置。以Flask为例,最稳妥的做法是在应用工厂函数里配置,确保在任何请求之前logger就绪。
# app/__init__.py
import logging
from logging.config import dictConfig
from flask import Flask
def create_app():
app = Flask(__name__)
# 必须在应用实例化后立即配置logging
dictConfig({
'version': 1,
'formatters': {
'default': {
'format': '[%(asctime)s] %(levelname)s in %(module)s: %(message)s',
}
},
'handlers': {
'wsgi': {
'class': 'logging.StreamHandler',
'stream': 'ext://flask.logging.wsgi_errors_stream',
'formatter': 'default'
},
'file': {
'class': 'logging.handlers.RotatingFileHandler',
'filename': 'app.log',
'maxBytes': 1024 * 1024,
'backupCount': 3,
'formatter': 'default'
}
},
'root': {
'level': 'INFO',
'handlers': ['wsgi', 'file']
}
})
# 移除Flask默认handler,避免重复日志
app.logger.handlers.clear()
# 让app.logger使用我们配置的root logger
app.logger = logging.getLogger()
return app
关键点:
- 用
dictConfig或fileConfig一次性配置所有logger,避免多个模块各自配置 - 配置完成后才导入业务模块,这样模块内的
logging.getLogger(__name__)会自动继承配置 - 生产环境考虑添加邮件handler或集中式日志服务handler
对于Django,在settings.py里配置LOGGING字典;FastAPI则在启动时配置,原理相同。
总结:在应用入口一次性配置,让所有模块共享配置。
log 模块无法处理由于多个 supervisor 进程 导致的多进程问题吧,除非让 supervisor 来处理
不懂 python。你可以 log 到 rsyslog,然后用 logrotate 分割 log 文件
我一般采用下面两种方法:
1. 日志直接输出到 stdout,如直接 print 或者 logging.StreamHandler,然后配置 supervisor 的 stdout_logfile 来将标准输出记录到文件
2. FileRotateHandler 不是进程安全的,多个进程使用会在切文件的时候产生竞争,造成文件切的大小不准确,可以实现一个多进程安全的 RotatingFileHandler
https://gist.github.com/SerhoLiu/a3d7be43df882af80ef98bc375fc6046.js
就是不能输出到 stdout 里面呀,因为这个日志要单独保存。。方便日后查看
FileRotateHandler 不是进程安全的。
用 WatchedFileHandler 来写日志,多个进程可以写同一个日志文件。
有切日志的需求,用 logrotate 来切。

