python 如何将 INFO 和 DEBUG 日志消息发送到 stdout 并将更高级别的消息发送到 stderr
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2302315/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can INFO and DEBUG logging message be sent to stdout and higher level message to stderr
提问by Dinoboff
Is there an easy way with python's logging module to send messages with a DEBUG or INFO level and the one with a higher level to different streams?
python 的日志记录模块是否有一种简单的方法可以将具有 DEBUG 或 INFO 级别的消息以及具有更高级别的消息发送到不同的流?
Is it a good idea anyway?
无论如何,这是个好主意吗?
采纳答案by Alex Martelli
Not necessarily a good idea (it could be confusing to see info and debug messages mixed in with normal output!), but feasible, since you can have multiple handler objects and a custom filterfor each of them, in order to pick and choose which log records each handler gets to handle.
不一定是一个好主意(看到信息和调试消息与正常输出混合可能会令人困惑!),但可行,因为您可以为每个处理程序对象和一个自定义过滤器,以便挑选和选择哪个日志记录每个处理程序得到处理。
回答by Zoey Greer
import logging
import sys
class LessThanFilter(logging.Filter):
def __init__(self, exclusive_maximum, name=""):
super(LessThanFilter, self).__init__(name)
self.max_level = exclusive_maximum
def filter(self, record):
#non-zero return means we log this message
return 1 if record.levelno < self.max_level else 0
#Get the root logger
logger = logging.getLogger()
#Have to set the root logger level, it defaults to logging.WARNING
logger.setLevel(logging.NOTSET)
logging_handler_out = logging.StreamHandler(sys.stdout)
logging_handler_out.setLevel(logging.DEBUG)
logging_handler_out.addFilter(LessThanFilter(logging.WARNING))
logger.addHandler(logging_handler_out)
logging_handler_err = logging.StreamHandler(sys.stderr)
logging_handler_err.setLevel(logging.WARNING)
logger.addHandler(logging_handler_err)
#demonstrate the logging levels
logger.debug('DEBUG')
logger.info('INFO')
logger.warning('WARNING')
logger.error('ERROR')
logger.critical('CRITICAL')
Implementation aside, I do think it is a good idea to use the logging facilities in python to output to the terminal, in particular because you can add another handler to additionally log to a file. If you set stdout to be INFO instead of DEBUG, you can even include additional DEBUG information that the user wouldn't standardly see in the log file.
除了实现之外,我确实认为使用 python 中的日志记录工具输出到终端是一个好主意,特别是因为您可以添加另一个处理程序来另外记录到文件。如果您将 stdout 设置为 INFO 而不是 DEBUG,您甚至可以包含用户通常不会在日志文件中看到的其他 DEBUG 信息。
回答by S.Lott
Yes. You must define multiple handlers for your logging.
是的。您必须为日志定义多个处理程序。
http://docs.python.org/library/logging.html#logging-to-multiple-destinations
http://docs.python.org/library/logging.html#logging-to-multiple-destinations
http://docs.python.org/library/logging.handlers.html#module-logging.handlers
http://docs.python.org/library/logging.handlers.html#module-logging.handlers
回答by intgr
I had the same problem and wrote a custom logging handler called SplitStreamHandler:
我遇到了同样的问题并编写了一个名为 SplitStreamHandler 的自定义日志处理程序:
import sys
import logging
class SplitStreamHandler(logging.Handler):
def __init__(self):
logging.Handler.__init__(self)
def emit(self, record):
# mostly copy-paste from logging.StreamHandler
try:
msg = self.format(record)
if record.levelno < logging.WARNING:
stream = sys.stdout
else:
stream = sys.stderr
fs = "%s\n"
try:
if (isinstance(msg, unicode) and
getattr(stream, 'encoding', None)):
ufs = fs.decode(stream.encoding)
try:
stream.write(ufs % msg)
except UnicodeEncodeError:
stream.write((ufs % msg).encode(stream.encoding))
else:
stream.write(fs % msg)
except UnicodeError:
stream.write(fs % msg.encode("UTF-8"))
stream.flush()
except (KeyboardInterrupt, SystemExit):
raise
except:
self.handleError(record)
回答by gcb
right from the updated docs, it cover this case pretty well now.
从更新的文档来看,它现在很好地涵盖了这种情况。
http://docs.python.org/howto/logging.html#logging-advanced-tutorial
http://docs.python.org/howto/logging.html#logging-advanced-tutorial
import sys # Add this.
import logging
# create logger
logger = logging.getLogger('simple_example')
logger.setLevel(logging.DEBUG)
# create console handler and set level to debug
ch = logging.StreamHandler( sys.__stdout__ ) # Add this
ch.setLevel(logging.DEBUG)
# create formatter
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
# add formatter to ch
ch.setFormatter(formatter)
# add ch to logger
logger.addHandler(ch)
# 'application' code
logger.debug('debug message')
logger.info('info message')
logger.warn('warn message')
logger.error('error message')
logger.critical('critical message')
i've mentioned on comments the two changes required from the example to make the output go to stdout. you may also use filters to redirect depending on the level.
我在评论中提到了示例中使输出转到标准输出所需的两个更改。您还可以根据级别使用过滤器进行重定向。
more information to understand the changes is at http://docs.python.org/library/logging.handlers.html#module-logging.handlers
了解更改的更多信息位于 http://docs.python.org/library/logging.handlers.html#module-logging.handlers
回答by y?s??la
Just for your convenience adding everything together with the formatter in one package:
为方便起见,将所有内容与格式化程序一起添加到一个包中:
# shared formatter, but you can use separate ones:
FORMAT = '%(asctime)s - %(name)s - %(levelname)s - %(threadName)s - %(message)s'
formatter = logging.Formatter(FORMAT)
# single app logger:
log = logging.getLogger(__name__)
log.setLevel(logging.INFO)
# 2 handlers for the same logger:
h1 = logging.StreamHandler(sys.stdout)
h1.setLevel(logging.DEBUG)
# filter out everything that is above INFO level (WARN, ERROR, ...)
h1.addFilter(lambda record: record.levelno <= logging.INFO)
h1.setFormatter(formatter)
log.addHandler(h1)
h2 = logging.StreamHandler(sys.stderr)
# take only warnings and error logs
h2.setLevel(logging.WARNING)
h2.setFormatter(formatter)
log.addHandler(h2)
# profit:
log.info(...)
log.debug(...)
My use case was to redirect stdout to a datafile while seeing errors on the screen during processing.
我的用例是将 stdout 重定向到数据文件,同时在处理过程中在屏幕上看到错误。
回答by buhtz
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import logging
import sys
class LessThenFilter(logging.Filter):
def __init__(self, level):
self._level = level
logging.Filter.__init__(self)
def filter(self, rec):
return rec.levelno < self._level
log = logging.getLogger()
log.setLevel(logging.NOTSET)
sh_out = logging.StreamHandler(stream=sys.stdout)
sh_out.setLevel(logging.DEBUG)
sh_out.setFormatter(logging.Formatter('%(levelname)s: %(message)s'))
sh_out.addFilter(LessThenFilter(logging.WARNING))
log.addHandler(sh_out)
sh_err = logging.StreamHandler(stream=sys.stderr)
sh_err.setLevel(logging.WARNING)
sh_err.setFormatter(logging.Formatter('%(levelname)s: %(message)s'))
log.addHandler(sh_err)
logging.critical('x')
logging.error('x')
logging.warning('x')
logging.info('x')
logging.debug('x')