You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为重定向到文件的stderr内容添加日期时间前缀?

问题

我已经用logging模块(logger.info、logger.debug等)实现了规范的日志记录,日志会写入文件。但在一些极端场景(比如外部模块输出、未捕获异常等)下,还是有错误输出到stderr。

我用以下代码把stdout和stderr重定向到文件:

import sys
sys.stdout, sys.stderr = open("stdout.log", "a+", buffering=1), open("stderr.log", "a+", buffering=1)
print("hello")
1/0

这段代码能正常工作,但我想给每条错误内容前加上日期时间前缀。

注:我希望避免使用logging模块,采用更底层的实现方式;同时也不想用下面这个方案:

def exc_handler(ex_cls, ex, tb):
    with open('mylog.log', 'a') as f:
        dt = time.strftime('%Y-%m-%d %H:%M:%S')
        f.write(f"{dt}\n")
        traceback.print_tb(tb, file=f)
        f.write(f"{dt}\n")

sys.excepthook = exc_handler

因为有些外部模块可能会覆盖sys.excepthook。有没有类似重写sys.stderr.print的底层解决方案?

解决方案

可以自定义一个封装类,替代原生的文件对象,重写write方法实现自动添加日期时间前缀,再用这个类的实例替换sys.stderr和sys.stdout。这种底层重定向方式不受sys.excepthook被覆盖的影响。

示例代码如下:

import sys
import time

class TimestampedStream:
    def __init__(self, file_path, mode='a+', buffering=1):
        self.file = open(file_path, mode, buffering=buffering)
        self.buffer = ""  # 缓存未完成的行内容

    def write(self, data):
        self.buffer += data
        # 按换行分割,仅处理完整的行
        lines = self.buffer.split('\n')
        # 剩余未换行的内容放回缓存
        self.buffer = lines.pop() if lines else ""

        timestamp = time.strftime('%Y-%m-%d %H:%M:%S')
        for line in lines:
            if line:
                self.file.write(f"[{timestamp}] {line}\n")
            else:
                self.file.write("\n")

    def flush(self):
        # 处理缓存中剩余的内容
        if self.buffer:
            timestamp = time.strftime('%Y-%m-%d %H:%M:%S')
            self.file.write(f"[{timestamp}] {self.buffer}\n")
            self.buffer = ""
        self.file.flush()

    def close(self):
        self.flush()
        self.file.close()

# 替换标准输出和标准错误
sys.stdout = TimestampedStream("stdout.log", "a+", buffering=1)
sys.stderr = TimestampedStream("stderr.log", "a+", buffering=1)

# 测试代码
print("hello stdout")
1/0  # 触发的异常信息会自动带上时间前缀写入stderr.log

关键说明

  • 缓存机制:避免半行内容就添加前缀,确保只有完整的一行输出才会带上时间戳。
  • 兼容性:所有输出到stdout/stderr的内容(包括外部模块输出、未捕获异常栈)都会被处理,无需依赖sys.excepthook。
  • 资源处理:实现flush和close方法,确保程序退出或刷新时,缓存中的剩余内容能被正确写入。

内容的提问来源于stack exchange,提问作者Basj

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 11:40:22