Ведение журнала, StreamHandler и стандартные потоки
Я не могу понять, как регистрировать сообщения на уровне информации в stdout, но все остальное в stderr. Я уже читал это http://docs.python.org/library/logging.html. есть предложения?
3 ответа:
следующий скрипт
log1.py
:import logging, sys class SingleLevelFilter(logging.Filter): def __init__(self, passlevel, reject): self.passlevel = passlevel self.reject = reject def filter(self, record): if self.reject: return (record.levelno != self.passlevel) else: return (record.levelno == self.passlevel) h1 = logging.StreamHandler(sys.stdout) f1 = SingleLevelFilter(logging.INFO, False) h1.addFilter(f1) rootLogger = logging.getLogger() rootLogger.addHandler(h1) h2 = logging.StreamHandler(sys.stderr) f2 = SingleLevelFilter(logging.INFO, True) h2.addFilter(f2) rootLogger.addHandler(h2) logger = logging.getLogger("my.logger") logger.setLevel(logging.DEBUG) logger.debug("A DEBUG message") logger.info("An INFO message") logger.warning("A WARNING message") logger.error("An ERROR message") logger.critical("A CRITICAL message")
при запуске выдает следующие результаты.
C:\temp>log1.py A DEBUG message An INFO message A WARNING message An ERROR message A CRITICAL messageкак и следовало ожидать, так как на терминал
sys.stdout
иsys.stderr
то же самое. Теперь давайте перенаправить стандартный вывод в файл,tmp
:C:\temp>log1.py >tmp A DEBUG message A WARNING message An ERROR message A CRITICAL messageтаким образом, информационное сообщение не было напечатано на терминал - но сообщения, направленные на
sys.stderr
есть были напечатаны. Давайте посмотрим, что вtmp
:C:\temp>type tmp An INFO messageтак что подход, кажется, делать то, что вы хотите.
вообще, я думаю, что есть смысл перенаправление сообщений ниже, чем
WARNING
to stdout, вместоINFO
сообщения.на основе Vinay Sajipотличный ответ, я придумал это:
class MaxLevelFilter(Filter): '''Filters (lets through) all messages with level < LEVEL''' def __init__(self, level): self.level = level def filter(self, record): return record.levelno < self.level # "<" instead of "<=": since logger.setLevel is inclusive, this should be exclusive MIN_LEVEL= DEBUG #... stdout_hdlr = StreamHandler(sys.stdout) stderr_hdlr = StreamHandler(sys.stderr) lower_than_warning= MaxLevelFilter(WARNING) stdout_hdlr.addFilter( lower_than_warning ) #messages lower than WARNING go to stdout stdout_hdlr.setLevel( MIN_LEVEL ) stderr_hdlr.setLevel( max(MIN_LEVEL, WARNING) ) #messages >= WARNING ( and >= STDOUT_LOG_LEVEL ) go to stderr #...
Так как мое редактирование было отклонено, вот мой ответ. ответ @ goncalopp хорош, но не стоит в одиночку или работать из коробки. Вот моя улучшенная версия:
import sys, logging class LogFilter(logging.Filter): """Filters (lets through) all messages with level < LEVEL""" # http://stackoverflow.com/a/24956305/408556 def __init__(self, level): self.level = level def filter(self, record): # "<" instead of "<=": since logger.setLevel is inclusive, this should # be exclusive return record.levelno < self.level MIN_LEVEL = logging.DEBUG stdout_hdlr = logging.StreamHandler(sys.stdout) stderr_hdlr = logging.StreamHandler(sys.stderr) log_filter = LogFilter(logging.WARNING) stdout_hdlr.addFilter(log_filter) stdout_hdlr.setLevel(MIN_LEVEL) stderr_hdlr.setLevel(max(MIN_LEVEL, logging.WARNING)) # messages lower than WARNING go to stdout # messages >= WARNING (and >= STDOUT_LOG_LEVEL) go to stderr rootLogger = logging.getLogger() rootLogger.addHandler(stdout_hdlr) rootLogger.addHandler(stderr_hdlr) logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) # Example Usage >>> logger.debug("A DEBUG message") >>> logger.info("An INFO message") >>> logger.warning("A WARNING message") >>> logger.error("An ERROR message") >>> logger.critical("A CRITICAL message")