bigywater.tech
Flask · 181

日志配置

Flask 的日志该怎么配?默认的 app.logger 做了什么、为什么在 gunicorn 下 info 看不到、怎么输出结构化日志?这篇用真实的进程逐项验证(请求 ID 见第 182 篇,多进程日志重复见第 185 篇)。

WARNING
什么都不配时 app.logger 的有效级别(info 与 debug 被丢弃)
0 个
先 logging.basicConfig 之后 app.logger 自己的 handler 数量
JSON
dictConfig 配出的一行一条结构化日志

app.logger 的默认行为

实测 · 本机执行输出
  [什么都不配(debug 关)] 输出的级别:['warning', 'error']
      handlers on app.logger: ['StreamHandler'] | effective level: WARNING
      [2026-10-02 15:51:31,487] WARNING in levels: warning message
      [2026-10-02 15:51:31,487] ERROR in levels: error message
  [app.debug = True] 输出的级别:['debug', 'info', 'warning', 'error']
      handlers on app.logger: ['StreamHandler'] | effective level: DEBUG
      [2026-10-02 15:51:31,591] DEBUG in levels: debug message
      [2026-10-02 15:51:31,591] INFO in levels: info message
      [2026-10-02 15:51:31,591] WARNING in levels: warning message
      [2026-10-02 15:51:31,591] ERROR in levels: error message
  [app.logger.setLevel(INFO)] 输出的级别:['info', 'warning', 'error']
      handlers on app.logger: ['StreamHandler'] | effective level: INFO
      [2026-10-02 15:51:31,694] INFO in levels: info message
      [2026-10-02 15:51:31,694] WARNING in levels: warning message
      [2026-10-02 15:51:31,694] ERROR in levels: error message
  [先 logging.basicConfig(level=INFO)] 输出的级别:['info', 'warning', 'error']
      handlers on app.logger: [] | effective level: INFO
      INFO root-handler: info message
      WARNING root-handler: warning message
      ERROR root-handler: error message

上一篇:优雅关闭;下一篇:请求 ID 链路追踪。

在 gunicorn 下

实测 · 本机执行输出
  [什么都不配]
    [2026-10-02 15:51:31,924] WARNING in gapp: warning from view
    [2026-10-02 15:51:31,925] ERROR in app: Exception on /boom [GET]
        return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)  # type: ignore[no-any-return]
    ZeroDivisionError: division by zero
  [把 gunicorn.error 的 handler 接到 app.logger]
    [2026-10-02 15:51:32 +0800] [73296] [INFO] info from view
    [2026-10-02 15:51:32 +0800] [73296] [WARNING] warning from view
    [2026-10-02 15:51:32 +0800] [73296] [ERROR] Exception on /boom [GET]
        return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)  # type: ignore[no-any-return]
    ZeroDivisionError: division by zero

结构化日志

实测 · 本机执行输出
  {"level": "INFO", "msg": "handling hello", "logger": "japp", "method": "GET", "path": "/hello"}
  {"level": "ERROR", "msg": "Exception on /boom [GET]", "logger": "japp", "method": "GET", "path": "/boom", "exc": "ZeroDivisionError: division by zero"}

访问日志

实测 · 本机执行输出
  [默认] 访问日志行:['127.0.0.1 - - [02/Oct/2026 15:51:33] "GET / HTTP/1.1" 200 -']
  [werkzeug 设为 WARNING] 访问日志行:[]

分步演示

Flask 日志配置
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Python 3.14.7 / Flask 3.1.3 / Werkzeug 3.1.9 / Jinja2 3.1.6 / SQLAlchemy 2.1.1 / gunicorn 26.2.0(都装在自己的虚拟环境里);大多数实验用 Flask 的 test_client(直接调用 WSGI 应用,不经过网络),需要真实 HTTP 时另起 gunicorn 或开发服务器(端口 9600 以上,本机 127.0.0.1);计时用 time.perf_counter,数字每次运行会有小幅抖动。gunicorn、Flask 开发服务器
    • 没有验证:日志写文件与轮转(RotatingFileHandler)、多进程同时写同一个文件、QueueHandler 异步日志、日志采集到 ELK 或云服务、日志性能开销、敏感信息脱敏
    京ICP备2026067502号-1京公网安备11010502063487号