Python日志监控系统的核心是理解logging模块的层级传播机制、处理器生命周期和格式化链路;传播导致日志重复,RotatingFileHandler阻塞主线程因同步rollover,JSON日志需结构化而非字符串拼接。
Python 日志监控系统不是靠堆砌配置项跑起来的,核心在于理解 logging 模块的层级传播机制、处理器生命周期和日志格式化链路。没理清这三点,加再多 RotatingFileHandler 或接再 fancy 的 Loguru 都会漏日志、卡主线程、甚至吃光磁盘。
这是最常被忽略的传播(propagate)行为。默认所有 logger 的 propagate 属性为 True,日志会逐级向父 logger 传递,直到根 logger(root)。所以:
getLogger('a.b.c') 的父是 getLogger('a.b'),再往上是 getLogger('a'),最终到 root
propagate=False,日志就会被重复处理'a.b.c' 加了 FileHandler,又没关 propagate,结果日志同时写进文件 + 控制台(因为 root 默认有 StreamHandler)实战建议:
logger = logging.getLogger('myapp.db')
logger.propagate = False # 关闭向上透传
logger.addHandler(file_handler)
RotatingFileHandler 在触发 rollover(如文件超限)时,默认同步执行 rename + copy 操作,I/O 阻塞不可忽视。尤其在高并发写日志场景下,可能拖慢整个请求响应。
maxBytes 别设太小(比如 1MB),推荐 10–100MB;backupCount 别过大(5–10 足够)Queu
eHandler + QueueListener 把 I/O 移出主线程queue = Queue() queue_handler = QueueHandler(queue) logger.addHandler(queue_handler) listener = QueueListener(queue, file_handler) listener.start()
直接用 json.dumps() 拼字符串进 Formatter.format(),看似输出 JSON,实则只是「字符串长得像 JSON」。Kibana 依赖字段结构化,需要真正按 key/value 提取,而非把整条日志当一个 message 字段塞进去。
formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s') + 手动 json.dumps(dict(...)) 作为 msg
python-json-logger 库的 JsonFormatter,或自定义 formatter 覆盖 format() 方法,返回纯 dict(由 handler 序列化)extra 参数传入的字段名与 Kibana 索引模板中定义的字段一致,比如 extra={'trace_id': 'xxx', 'user_id': 123},对应索引里要有 trace_id.keyword 字段真正的难点不在怎么打日志,而在于每条日志是否能被准确定位、关联、过滤。比如 request_id 要贯穿一次请求的所有日志行,这要求你在中间件注入、在子线程里显式传递、在异步任务中用 contextvars 绑定——这些细节比选哪个日志库重要得多。