I
Member
Python 多进程程序的日志最容易出的问题是:多个进程同时写同一个文件,日志行互相交错,甚至互相覆盖。multiprocessing 自带的日志方案在实际项目里不太够用,我现在固定用 QueueHandler + 独立监听进程的模式。
1. 为什么不能直接让每个进程写文件
多个进程同时 open 同一个文件追加写入,操作系统层面不保证“一次写调用对应一行日志”,长日志行会被切成两段,和其他进程的日志拼在一起。加文件锁能解决交错,但锁竞争会让高频日志场景性能掉一大截。
2. QueueHandler + QueueListener 的标准结构
每个工作进程只把 LogRecord 发进 multiprocessing.Queue,不碰文件;一个独立的监听进程(或主进程里的监听线程)从队列取记录,统一写文件。这样写文件的只有一个人,交错问题从根上消失。
3. 进程退出前要 flush 队列
工作进程退出时,队列里可能还有没取走的记录。正确做法是进程退出前调用 handler 的 close,或者用 atexit 注册清理,否则最后几行日志悄悄丢了,查故障时最关键的几行正好不在。
4. 日志级别和格式统一在监听端定
工作进程只管发,格式、级别过滤、滚动策略全部放在监听进程里。这样改日志格式不用重启所有工作进程,也避免了各进程格式不一致。
5. 队列满了怎么办
日志突发量大时,无界队列会吃内存。我的做法是给队列设上限,满了之后工作进程侧丢弃 DEBUG 级别记录并计数,定期输出“丢弃 N 条”的统计,至少让丢日志这件事本身可见。
你们多进程日志一般怎么处理?有没有遇到过日志交错导致查故障走弯路的情况?
1. 为什么不能直接让每个进程写文件
多个进程同时 open 同一个文件追加写入,操作系统层面不保证“一次写调用对应一行日志”,长日志行会被切成两段,和其他进程的日志拼在一起。加文件锁能解决交错,但锁竞争会让高频日志场景性能掉一大截。
2. QueueHandler + QueueListener 的标准结构
每个工作进程只把 LogRecord 发进 multiprocessing.Queue,不碰文件;一个独立的监听进程(或主进程里的监听线程)从队列取记录,统一写文件。这样写文件的只有一个人,交错问题从根上消失。
3. 进程退出前要 flush 队列
工作进程退出时,队列里可能还有没取走的记录。正确做法是进程退出前调用 handler 的 close,或者用 atexit 注册清理,否则最后几行日志悄悄丢了,查故障时最关键的几行正好不在。
4. 日志级别和格式统一在监听端定
工作进程只管发,格式、级别过滤、滚动策略全部放在监听进程里。这样改日志格式不用重启所有工作进程,也避免了各进程格式不一致。
5. 队列满了怎么办
日志突发量大时,无界队列会吃内存。我的做法是给队列设上限,满了之后工作进程侧丢弃 DEBUG 级别记录并计数,定期输出“丢弃 N 条”的统计,至少让丢日志这件事本身可见。
你们多进程日志一般怎么处理?有没有遇到过日志交错导致查故障走弯路的情况?