ore*_*nma 30 python logging stdout python-3.x
我有一个记录器,有一个RotatingFileHandler
.我想重定向所有Stdout
与Stderr
该记录器.怎么办?
Cam*_*non 28
没有足够的回复评论,但我想添加这个适用于我的版本,以防其他人处于类似的情况.
class LoggerWriter:
def __init__(self, level):
# self.level is really like using log.debug(message)
# at least in my case
self.level = level
def write(self, message):
# if statement reduces the amount of newlines that are
# printed to the logger
if message != '\n':
self.level(message)
def flush(self):
# create a flush method so things can be flushed when
# the system wants to. Not sure if simply 'printing'
# sys.stderr is the correct way to do it, but it seemed
# to work properly for me.
self.level(sys.stderr)
Run Code Online (Sandbox Code Playgroud)
这看起来像是这样的:
log = logging.getLogger('foobar')
sys.stdout = LoggerWriter(log.debug)
sys.stderr = LoggerWriter(log.warning)
Run Code Online (Sandbox Code Playgroud)
Vin*_*jip 14
如果它是一个全Python系统(即没有C库直接写入fds,正如Ignacio Vazquez-Abrams所说的那样),那么你可以使用这里建议的方法:
class LoggerWriter:
def __init__(self, logger, level):
self.logger = logger
self.level = level
def write(self, message):
if message != '\n':
self.logger.log(self.level, message)
Run Code Online (Sandbox Code Playgroud)
然后设置sys.stdout
并sys.stderr
以LoggerWriter
实例.
she*_*ero 12
所有先前的答案似乎都有问题,在不需要的地方添加额外的换行符.最适合我的解决方案来自http://www.electricmonk.nl/log/2011/08/14/redirect-stdout-and-stderr-to-a-logger-in-python/,在那里他演示了如何将stdout和stderr发送到记录器:
import logging
import sys
class StreamToLogger(object):
"""
Fake file-like stream object that redirects writes to a logger instance.
"""
def __init__(self, logger, log_level=logging.INFO):
self.logger = logger
self.log_level = log_level
self.linebuf = ''
def write(self, buf):
for line in buf.rstrip().splitlines():
self.logger.log(self.log_level, line.rstrip())
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s:%(levelname)s:%(name)s:%(message)s',
filename="out.log",
filemode='a'
)
stdout_logger = logging.getLogger('STDOUT')
sl = StreamToLogger(stdout_logger, logging.INFO)
sys.stdout = sl
stderr_logger = logging.getLogger('STDERR')
sl = StreamToLogger(stderr_logger, logging.ERROR)
sys.stderr = sl
print "Test to standard out"
raise Exception('Test to standard error')
Run Code Online (Sandbox Code Playgroud)
输出如下:
2011-08-14 14:46:20,573:INFO:STDOUT:Test to standard out
2011-08-14 14:46:20,573:ERROR:STDERR:Traceback (most recent call last):
2011-08-14 14:46:20,574:ERROR:STDERR: File "redirect.py", line 33, in
2011-08-14 14:46:20,574:ERROR:STDERR:raise Exception('Test to standard error')
2011-08-14 14:46:20,574:ERROR:STDERR:Exception
2011-08-14 14:46:20,574:ERROR:STDERR::
2011-08-14 14:46:20,574:ERROR:STDERR:Test to standard error
Run Code Online (Sandbox Code Playgroud)
请注意,self.linebuf =''是处理flush的地方,而不是实现flush函数.
Ton*_*aun 10
作为 Cameron Gagnon 回应的演变,我已将LoggerWriter
课程改进为:
class LoggerWriter(object):
def __init__(self, writer):
self._writer = writer
self._msg = ''
def write(self, message):
self._msg = self._msg + message
while '\n' in self._msg:
pos = self._msg.find('\n')
self._writer(self._msg[:pos])
self._msg = self._msg[pos+1:]
def flush(self):
if self._msg != '':
self._writer(self._msg)
self._msg = ''
Run Code Online (Sandbox Code Playgroud)
现在不受控制的异常看起来更好:
2018-07-31 13:20:37,482 - ERROR - Traceback (most recent call last):
2018-07-31 13:20:37,483 - ERROR - File "mf32.py", line 317, in <module>
2018-07-31 13:20:37,485 - ERROR - main()
2018-07-31 13:20:37,486 - ERROR - File "mf32.py", line 289, in main
2018-07-31 13:20:37,488 - ERROR - int('')
2018-07-31 13:20:37,489 - ERROR - ValueError: invalid literal for int() with base 10: ''
Run Code Online (Sandbox Code Playgroud)
sys.stdout.write = logger.info
Run Code Online (Sandbox Code Playgroud)
sys.stderr.write = logger.error
Run Code Online (Sandbox Code Playgroud)
其作用只是将记录器函数分配给 stdout/stderr 调用.write
,这意味着任何写入调用都将调用记录器函数。
这种方法的缺点是,对.write
记录器函数的调用通常都会添加换行符,因此您最终会在日志文件中出现额外的行,这可能会或可能不会成为问题,具体取决于您的用例。
另一个陷阱是,如果您的记录器写入 stderr 本身,我们会得到无限递归(堆栈溢出错误)。所以只能输出到文件。
在 Vinay Sajip 的回答中添加了flush:
class LoggerWriter:
def __init__(self, logger, level):
self.logger = logger
self.level = level
def write(self, message):
if message != '\n':
self.logger.log(self.level, message)
def flush(self):
pass
Run Code Online (Sandbox Code Playgroud)
您可以使用redirect_stdout上下文管理器:
import logging
from contextlib import redirect_stdout
logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
logging.write = lambda msg: logging.info(msg) if msg != '\n' else None
with redirect_stdout(logging):
print('Test')
Run Code Online (Sandbox Code Playgroud)
或者像这样
import logging
from contextlib import redirect_stdout
logger = logging.getLogger('Meow')
logger.setLevel(logging.INFO)
formatter = logging.Formatter(
fmt='[{name}] {asctime} {levelname}: {message}',
datefmt='%m/%d/%Y %H:%M:%S',
style='{'
)
ch = logging.StreamHandler()
ch.setLevel(logging.INFO)
ch.setFormatter(formatter)
logger.addHandler(ch)
logger.write = lambda msg: logger.info(msg) if msg != '\n' else None
with redirect_stdout(logger):
print('Test')
Run Code Online (Sandbox Code Playgroud)
logger.log
和其他函数(.info
/ .error
/etc. )将每个调用输出为单独的行,即隐式添加(格式化和)换行符。
sys.stderr.write
另一方面,只是将其文字输入写入流,包括部分行。例如:输出“ZeroDivisionError:被零除”实际上是对 4(!) 次单独调用sys.stderr.write
:
sys.stderr.write('ZeroDivisionError')
sys.stderr.write(': ')
sys.stderr.write('division by zero')
sys.stderr.write('\n')
Run Code Online (Sandbox Code Playgroud)
4 种最受好评的方法(1、2、3、4)因此会产生额外的换行符——只需将“1/0”放入您的程序中,您将获得以下结果:
2021-02-17 13:10:40,814 - ERROR - ZeroDivisionError
2021-02-17 13:10:40,814 - ERROR - :
2021-02-17 13:10:40,814 - ERROR - division by zero
Run Code Online (Sandbox Code Playgroud)
将中间写入存储在缓冲区中。我使用列表作为缓冲区而不是字符串的原因是为了避免Shlemiel 画家算法。TLDR:它是 O(n) 而不是潜在的 O(n^2)
class LoggerWriter:
def __init__(self, logfct):
self.logfct = logfct
self.buf = []
def write(self, msg):
if msg.endswith('\n'):
self.buf.append(msg.removesuffix('\n'))
self.logfct(''.join(self.buf))
self.buf = []
else:
self.buf.append(msg)
def flush(self):
pass
# To access the original stdout/stderr, use sys.__stdout__/sys.__stderr__
sys.stdout = LoggerWriter(logger.info)
sys.stderr = LoggerWriter(logger.error)
Run Code Online (Sandbox Code Playgroud)
2021-02-17 13:15:22,956 - ERROR - ZeroDivisionError: division by zero
Run Code Online (Sandbox Code Playgroud)
对于Python 3.9以下的版本,您可以将 replace 替换.removesuffix('\n')
为不太准确的.rstrip('\n')
.
归档时间: |
|
查看次数: |
26881 次 |
最近记录: |