Python如何将自定义logging日志与未捕获stderr输出写入同一份日志文件
问题解决方法
冲突原因
你同时使用logging内置的文件写入能力和shell层的stderr重定向,相当于同一进程对同一个日志文件持有两个独立的写入句柄,Windows环境下会触发文件独占锁导致权限报错,类Unix环境也会出现日志错位、覆盖的问题,因此不推荐混合使用两种写入逻辑。
推荐实现(代码层统一处理,无冲突)
直接在Python代码中将stderr重定向到logging系统,所有未捕获异常的输出都会走logging的格式化逻辑,统一写入目标日志文件,不会出现句柄冲突。
完整示例代码如下:
import sys import logging # 自定义stderr转发类,将stderr输出转接到logging class StderrToLogger: def __init__(self, logger, log_level=logging.ERROR): self.logger = logger self.log_level = log_level self.line_buf = '' def write(self, buf): for line in buf.rstrip().splitlines(): self.logger.log(self.log_level, line.rstrip()) def flush(self): pass # 配置logging参数,统一日志格式 logging.basicConfig( filename='error.log', filemode='a', level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s' ) # 替换系统默认stderr对象 sys.stderr = StderrToLogger(logging.getLogger()) # 测试场景1:手动捕获异常打日志 try: 1 / 0 except Exception as error: logging.error(f"could not insert error: {error.args[0]}") # 测试场景2:未捕获异常,输出会自动进入日志 raise ValueError("未捕获的测试错误")
替代方案(保留shell重定向逻辑)
如果你必须使用shell层面的重定向命令,就不要在logging配置中指定filename参数,改为让logging默认输出到stderr,所有日志统一从stderr流出后由shell负责写入文件,也不会出现冲突:
代码配置:
import sys import logging logging.basicConfig( level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s', stream=sys.stderr )
执行命令:
python test.py 2>> error.log
注意事项
- 重定向stderr后,所有原本输出到控制台错误流的内容都会写入日志,如果需要同时在控制台查看错误,可给logging额外添加
StreamHandler实现多端输出。 - 多进程场景下写同一个日志文件,需要使用支持多进程写入的logging handler避免写入冲突。
内容的提问来源于stack exchange,提问作者Borut Flis
相关产品推荐
相关产品推荐

