将所有 stdout/stderr 全局重定向到记录器
Redirect all stdout/stderr globally to logger
背景
我有一个非常大的 python 应用程序,它启动命令行实用程序来获取它需要的数据片段。我目前只是将 python 启动程序脚本重定向到一个日志文件,它为我提供了所有 print()
输出,加上命令行实用程序的输出,即:
python -m launcher.py &> /root/out.log
问题
I've since implemented a proper logger via logging
, which lets me format the logging statements more precisely, lets me limit log file size, etc. 我已经用对记录器的调用替换了大部分 print()
语句。但是,我遇到了一个问题:none 的命令行应用程序输出出现在我的日志中。它反而被转储到控制台。此外,这些程序的启动方式也不尽相同:有些是通过 popen()
启动的,有些是通过 exec()
启动的,有些是通过 os.system()
启动的,等等
问题
有没有办法将所有 stdout
/stderr
文本全局重定向到我的日志记录功能,而不必 re-write/modify 启动这些命令行工具的代码?我尝试设置我在另一个问题中发现的以下内容:
sys.stderr.write = lambda s: logger.error(s)
但是失败并显示“sys.stderr.write
是只读的”。
虽然这不是完整的答案,但它可能会向您显示重定向以适应您的特定情况。不久前我就是这样做的。虽然我不记得我为什么这样做,或者我试图规避的限制是什么,但以下是将 stdout
和 stderr
重定向到 class for print()
声明。 class 随后写入屏幕和文件:
import os
import sys
import datetime
class DebugLogger():
def __init__(self, filename):
timestamp = datetime.datetime.strftime(datetime.datetime.utcnow(),
'%Y-%m-%d-%H-%M-%S-%f')
#build up full path to filename
logfile = os.path.join(os.path.dirname(sys.executable),
filename + timestamp)
self.terminal = sys.stdout
self.log = open(logfile, 'a')
def write(self, message):
timestamp = datetime.datetime.strftime(datetime.datetime.utcnow(),
' %Y-%m-%d-%H:%M:%S.%f')
#write to screen
self.terminal.write(message)
#write to file
self.log.write(timestamp + ' - ' + message)
self.flush()
def flush(self):
self.terminal.flush()
self.log.flush()
os.fsync(self.log.fileno())
def close(self):
self.log.close()
def main(debug = False):
if debug:
filename = 'blabla'
sys.stdout = DebugLogger(filename)
sys.stderr = sys.stdout
print('test')
if __name__ == '__main__':
main(debug = True)
import sys
import io
class MyStream(io.IOBase):
def write(self, s):
logger.error(s)
sys.stderr = MyStream()
print('This is an error', stream=sys.stderr)
这会使对 sys.stderr
的所有调用都转到记录器。
原来的一直在sys.__stderr__
背景
我有一个非常大的 python 应用程序,它启动命令行实用程序来获取它需要的数据片段。我目前只是将 python 启动程序脚本重定向到一个日志文件,它为我提供了所有 print()
输出,加上命令行实用程序的输出,即:
python -m launcher.py &> /root/out.log
问题
I've since implemented a proper logger via logging
, which lets me format the logging statements more precisely, lets me limit log file size, etc. 我已经用对记录器的调用替换了大部分 print()
语句。但是,我遇到了一个问题:none 的命令行应用程序输出出现在我的日志中。它反而被转储到控制台。此外,这些程序的启动方式也不尽相同:有些是通过 popen()
启动的,有些是通过 exec()
启动的,有些是通过 os.system()
启动的,等等
问题
有没有办法将所有 stdout
/stderr
文本全局重定向到我的日志记录功能,而不必 re-write/modify 启动这些命令行工具的代码?我尝试设置我在另一个问题中发现的以下内容:
sys.stderr.write = lambda s: logger.error(s)
但是失败并显示“sys.stderr.write
是只读的”。
虽然这不是完整的答案,但它可能会向您显示重定向以适应您的特定情况。不久前我就是这样做的。虽然我不记得我为什么这样做,或者我试图规避的限制是什么,但以下是将 stdout
和 stderr
重定向到 class for print()
声明。 class 随后写入屏幕和文件:
import os
import sys
import datetime
class DebugLogger():
def __init__(self, filename):
timestamp = datetime.datetime.strftime(datetime.datetime.utcnow(),
'%Y-%m-%d-%H-%M-%S-%f')
#build up full path to filename
logfile = os.path.join(os.path.dirname(sys.executable),
filename + timestamp)
self.terminal = sys.stdout
self.log = open(logfile, 'a')
def write(self, message):
timestamp = datetime.datetime.strftime(datetime.datetime.utcnow(),
' %Y-%m-%d-%H:%M:%S.%f')
#write to screen
self.terminal.write(message)
#write to file
self.log.write(timestamp + ' - ' + message)
self.flush()
def flush(self):
self.terminal.flush()
self.log.flush()
os.fsync(self.log.fileno())
def close(self):
self.log.close()
def main(debug = False):
if debug:
filename = 'blabla'
sys.stdout = DebugLogger(filename)
sys.stderr = sys.stdout
print('test')
if __name__ == '__main__':
main(debug = True)
import sys
import io
class MyStream(io.IOBase):
def write(self, s):
logger.error(s)
sys.stderr = MyStream()
print('This is an error', stream=sys.stderr)
这会使对 sys.stderr
的所有调用都转到记录器。
原来的一直在sys.__stderr__