应使用 rotatingfilehandler 或 timedrotatingfilehandler 替代 filehandler 实现日志滚动,需先清空 app.logger.handlers,设置 maxbytes=10485760、backupcount=5,并为 handler 显式设 level 和 werkzeug 过滤器。

用 RotatingFileHandler 按大小滚动日志,别直接写 FileHandler
Flask 默认不自带日志滚动能力,直接用 FileHandler 会把所有请求日志堆进一个文件,跑几天就几 GB,查都查不动。必须换 RotatingFileHandler 或 TimedRotatingFileHandler。
关键不是“加日志”,而是“换 handler”。Flask 的 app.logger 是标准 Logger 实例,可以清空原有 handler 后重新挂载:
- 先调用
app.logger.handlers.clear(),否则旧的StreamHandler还在打屏,新 handler 也写,日志重复 -
maxBytes=10485760(即 10MB),别设太小(比如 1MB),否则频繁重命名、IO 毛刺明显 -
backupCount=5表示最多保留 5 个历史文件,.1~.5,超出的自动删,不设就无限涨 - 注意路径权限:确保 Flask 进程对日志目录有写+执行(
mkdir -p /var/log/myapp后chown www-data:www-data /var/log/myapp)
按天滚动必须用 TimedRotatingFileHandler,且 when='midnight' 才真按天
很多人设 when='D',结果发现日志凌晨 3 点切——因为 'D' 是“间隔一天”,从首次启动时间算起,不是按日历日。要严格按 00:00 切,必须用 when='midnight'。
-
interval=1+when='midnight'= 每天 00:00 切一次;设interval=7就是每周一 00:00 切 -
utc=True可避免时区切换导致漏切(比如服务器改了系统时区),但多数场景不用开 - 文件名后缀默认是
2024-05-20这种,如果想带时分秒(比如调试时精确到秒),加suffix='%Y-%m-%d_%H-%M',但日常记录请求没必要 - 同样要清空原 handler,否则
TimedRotatingFileHandler和默认的StreamHandler一起写,日志翻倍
只让请求日志进文件,别把 Flask 启动/SQLAlchemy 日志也塞进去
Flask 的 app.logger 默认级别是 WARNING,但你配的 handler 如果没设 level,会把 INFO 级别的请求日志(来自 Werkzeug)和 DEBUG 级别的 SQL 日志全收进来,根本没法看。
立即学习“Python免费学习笔记(深入)”;
- 给 handler 显式设
setLevel(logging.INFO),再给它加 filter 过滤掉非请求相关日志 - 最简 filter 写法:
lambda record: record.name == 'werkzeug',因为 Flask 请求日志实际由werkzeug发出,不是app.logger - 如果你用了 SQLAlchemy,它的日志名是
sqlalchemy.engine,不加 filter 就会混在一起;同理,urllib3、boto3等第三方库日志也要防着 - 别试图用
app.logger.propagate = False拦全局——这会关掉所有子 logger 透传,可能让异常追踪丢失上下文
生产环境务必关掉 debug=True,否则 RotatingFileHandler 会失效
开发时开 debug=True,Flask 会启用重载器(reloader),每次代码变动就 fork 新进程。而 RotatingFileHandler 的轮转逻辑依赖进程生命周期——老进程还在写,新进程又开新文件,结果出现 app.log、app.log.1、app.log.2 同时被多个进程写,内容错乱甚至损坏。
- 本地调试用
debug=True没问题,但只要部署(哪怕只是gunicorn --bind :5000 app:app),就必须设debug=False - 检查方式:打印
app.debug,或看启动日志里有没有 “* Debugger is active!” 这行 - 如果非要热重载,用
gunicorn --reload或uvicorn --reload,它们自己管理进程,不会干扰 handler 的文件锁机制
真正麻烦的不是配哪个 handler,而是 handler 被多个进程/线程同时写,或者 filter 没拦住非请求日志——这两点不盯住,日志文件看着在滚,其实全是噪音。










