logging.getlogger() 返回的实例在多进程里不共享,因子进程会重新初始化日志系统,导致父进程配置的处理器失效或冲突;需在子进程单独配置或使用 queuehandler + queuelistener。

为什么 logging.getLogger() 返回的实例在多进程里不共享
Python 的 logging 模块本身不是进程安全的,getLogger() 拿到的是当前进程内的对象,子进程会重新初始化日志系统,导致父进程配置的日志处理器(比如文件写入、网络发送)在子进程中失效或重复触发。
常见错误现象:INFO 级别日志在主进程能写入文件,fork 出的子进程却完全没输出,或者多个子进程同时往同一个文件写导致内容错乱。
- 使用
multiprocessing时,应在每个子进程启动后单独调用logging.basicConfig()或重建Handler,不要复用父进程的 logger 实例 - 若需集中收集日志,推荐改用
QueueHandler+QueueListener:子进程只往队列发日志,由单独监听线程统一处理 - 避免在子进程中调用
logging.basicConfig()多次——它默认有“仅首次生效”逻辑,但不同进程间互不影响,容易误以为配置成功
如何让日志自动带上 trace_id 支持监控链路追踪
标准 Formatter 不知道当前请求上下文,必须靠 LogRecord 动态注入字段。Django/Flask 等框架有中间件支持,但纯 logging 需手动绑定。
使用场景:排查线上某个请求耗时高,需要从 Prometheus/Grafana 查到对应日志;或 ELK 中按 trace_id 聚合全部相关日志行。
立即学习“Python免费学习笔记(深入)”;
- 用
LoggerAdapter包裹 logger,通过extra参数传入trace_id,再在Formatter的format()中读取record.trace_id - 别直接修改
record.__dict__—— 某些 handler(如SocketHandler)序列化时会丢掉自定义字段 - 如果用
structlog,优先走它的绑定机制(bind()),比原生 logging 更稳
adapter = logging.LoggerAdapter(logger, {"trace_id": "abc123"})
adapter.info("user login") # 输出含 trace_id 的日志行logging + Prometheus 的典型集成方式有哪些
日志本身不是指标,但日志量、错误率、响应延迟分布这些可以从日志里提取出来喂给 Prometheus。关键不是“把日志塞进 Prometheus”,而是选对采集层和聚合逻辑。
性能影响:每条日志都实时解析并上报 Counter 是灾难性的,应避免在业务线程中做正则匹配+HTTP 上报。
- 用
filebeat或fluent-bit做日志采集,在采集端用 grok 过滤出status_code、duration_ms等字段,再通过prometheus_exporter插件暴露指标 - 如果必须代码内埋点,用
prometheus_client.Counter统计错误次数,但只在关键路径上.inc(),别在每条 info 日志后加一句 - 注意时间窗口:日志打点时间和指标采集时间不同步,Prometheus 抓取间隔设为 15s 时,
rate(http_errors_total[1m])可能漏掉短突发
为什么日志文件没滚动、磁盘爆满却没报错
RotatingFileHandler 默认不检查磁盘空间,只按大小或数量轮转;TimedRotatingFileHandler 在 Windows 下可能因文件锁无法删除旧文件;更隐蔽的是,backupCount=0 或 maxBytes=0 会让轮转彻底失效。
常见错误现象:日志目录占满 100GB,ls -l 显示只有单个 app.log 文件持续增长,app.log.1 等备份文件一个没有。
- 确认
maxBytes > 0且backupCount > 0,例如RotatingFileHandler(..., maxBytes=10485760, backupCount=5) - Linux 下检查是否有残留的 deleted 文件句柄:
lsof | grep deleted | grep app.log,有就说明进程还在写已删文件,得重启服务 - 别依赖
delay=True来“延迟创建文件”——它只是推迟 open() 调用,不解决轮转逻辑问题
最麻烦的情况是日志路径权限不对,handler 静默失败,连 ERROR 都打不出来。上线前务必用 touch /path/to/log/app.log && chmod 644 $_ 手动验证可写性。










