Python:将 sys.stdout 和 sys.stderr 都捕获为日志文件

Python: capturing both of sys.stdout and sys.stderr as a log file

粗略地说,我想将其移植到纯 Python:

#!/bin/bash

{
    python test.py
} &> /tmp/test.log

由于某些未知原因,这不起作用:

import os.path, sys
import tempfile

with open(os.path.join(tempfile.gettempdir(), "test.log"), "a") as fp:
    sys.stdout = sys.stderr = fp
    raise Exception("I'm dying")

当我使用 Python 2.6.6、Python 2.7.8 和Python CentOS 上的 3.4.2 x86_64.

但理想情况下,我想要 Python 2.6.

的解决方案

(目前,可以容忍将 stdoutstderr 或多线程的混合输出弄乱日志文件,只要任何数据不会简单地消失在黑洞中即可。)

显示一个简洁且可移植的解决方案,该解决方案已确认可与 sys.stderr. 上的异常堆栈跟踪一起使用(最好是 os.dup2 以外的东西)

你可以使用这样的方法:

import traceback
import sys
from contextlib import contextmanager


@contextmanager
def output_to_file(filepath, write_mode='w'):
    stdout_orig = None
    stderr_orig = None

    stdout_orig = sys.stdout
    stderr_orig = sys.stderr

    f = open(filepath, write_mode)

    sys.stdout = f
    sys.stderr = f

    try:
        yield
    except:
        info = sys.exc_info()
        f.write('\n'.join(traceback.format_exception(*info)))

    f.close()

    sys.stdout = stdout_orig
    sys.stderr = stderr_orig

用法是:

with output_to_file('test.log'):
    print('hello')
    raise Exception('I am dying')

并且 cat test.log 产生:

hello
Traceback (most recent call last):

  File "<ipython-input-3-a3b702c7b741>", line 20, in outputi_to_file
    yield

  File "<ipython-input-4-f879d82580b2>", line 3, in <module>
    raise Exception('I am dying')

Exception: I am dying

这对我有用:

#!/usr/bin/env python
from __future__ import print_function
import os, os.path, sys, tempfile

old_out = os.dup(sys.stdout.fileno())
old_err = os.dup(sys.stderr.fileno())
with open(os.path.join(tempfile.gettempdir(), "test.log"), "a") as fp:
    fd = fp.fileno()
    os.dup2(fd, sys.stdout.fileno())
    os.dup2(fd, sys.stderr.fileno())
    print("Testing")
    print('testing errs', file=sys.stderr)
    raise Exception("I'm dying")

future 只是为了更清晰地处理具有相同示例的 Python2 或 Python3。 (我还更改了 raise 语句以实例化异常,作为异常的字符串已被弃用很长时间并且它们在 Python3 下未得到适当支持)。 =11=]

如果我们想在使用重定向文件后恢复原始标准输出 and/or 标准错误,那么旧的_* 值就可以了。

记住文件对象在 with 块后关闭 :)

简单地使用这个:

sys.stdout = sys.stderr = open("test.log","w")
raise Exception("Dead")

退出后test.log的内容:

Traceback (most recent call last):
  File "test.py", line 5, in <module>
    raise Exception("Dead")
Exception: Dead