首页 文章

除日志文件外,使Python Logger 还将所有消息输出到stdout

提问于
浏览
317

有没有办法让使用 logging 模块的Python日志记录自动输出到stdout以及它们应该去的日志文件?例如,我希望所有调用 logger.warninglogger.criticallogger.error 去往他们想要的地方,但另外总是被复制到 stdout . 这是为了避免重复消息,如:

mylogger.critical("something failed")
print "something failed"

7 回答

  • 458

    所有日志记录输出都由处理程序处理;只需将logging.StreamHandler()添加到根 Logger .

    以下是配置流处理程序(使用 stdout 而不是默认 stderr )并将其添加到根 Logger 的示例:

    import logging
    import sys
    
    root = logging.getLogger()
    root.setLevel(logging.DEBUG)
    
    handler = logging.StreamHandler(sys.stdout)
    handler.setLevel(logging.DEBUG)
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    handler.setFormatter(formatter)
    root.addHandler(handler)
    
  • 29

    最简单的方法:

    import logging
    import sys
    logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
    
  • 48

    可以使用多个处理程序 .

    import logging
    import auxiliary_module
    
    # create logger with 'spam_application'
    log = logging.getLogger('spam_application')
    log.setLevel(logging.DEBUG)
    
    # create formatter and add it to the handlers
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    
    # create file handler which logs even debug messages
    fh = logging.FileHandler('spam.log')
    fh.setLevel(logging.DEBUG)
    fh.setFormatter(formatter)
    log.addHandler(fh)
    
    # create console handler with a higher log level
    ch = logging.StreamHandler()
    ch.setLevel(logging.ERROR)
    ch.setFormatter(formatter)
    log.addHandler(ch)
    
    log.info('creating an instance of auxiliary_module.Auxiliary')
    a = auxiliary_module.Auxiliary()
    log.info('created an instance of auxiliary_module.Auxiliary')
    
    log.info('calling auxiliary_module.Auxiliary.do_something')
    a.do_something()
    log.info('finished auxiliary_module.Auxiliary.do_something')
    
    log.info('calling auxiliary_module.some_function()')
    auxiliary_module.some_function()
    log.info('done with auxiliary_module.some_function()')
    
    # remember to close the handlers
    for handler in log.handlers:
        handler.close()
        log.removeFilter(handler)
    

    请参阅:https://docs.python.org/2/howto/logging-cookbook.html

  • 0

    您可以为file和stdout创建两个处理程序,然后使用 handlers 参数为basicConfig创建一个 Logger . 如果两个处理程序具有相同的log_level和format输出,那么它可能很有用:

    import logging
    import sys
    
    file_handler = logging.FileHandler(filename='tmp.log')
    stdout_handler = logging.StreamHandler(sys.stdout)
    handlers = [file_handler, stdout_handler]
    
    logging.basicConfig(
        level=logging.DEBUG, 
        format='[%(asctime)s] {%(filename)s:%(lineno)d} %(levelname)s - %(message)s',
        handlers=handlers
    )
    
    logger = logging.getLogger('LOGGER_NAME')
    
  • 32

    记录到文件和stderr的最简单方法:

    import logging
      logging.basicConfig(filename="logfile.txt")
      stderrLogger=logging.StreamHandler()
      stderrLogger.setFormatter(logging.Formatter(logging.BASIC_FORMAT))
      logging.getLogger().addHandler(stderrLogger)
    
  • 362

    这是基于dictConfig configuration function的解决方案 . 它不是将每条日志消息发送到stdout,而是将日志级别为ERROR且更高的消息发送到stderr,将其他所有内容发送到stdout . 如果系统的其他部分正在侦听stderr / stdout,这可能很有用 .

    import logging
    import logging.config
    import sys
    
    class _ExcludeErrorsFilter(logging.Filter):
        def filter(self, record):
            """Filters out log messages with log level ERROR (numeric value: 40) or higher."""
            return record.levelno < 40
    
    
    config = {
        'version': 1,
        'filters': {
            'exclude_errors': {
                '()': _ExcludeErrorsFilter
            }
        },
        'formatters': {
            'my_formatter': {
                'format': '(%(process)d) %(asctime)s %(name)s (line %(lineno)s) | %(levelname)s %(message)s'
            }
        },
        'handlers': {
            'console_stderr': {
                # Directs log messages with log level ERROR or higher to stderr
                'class': 'logging.StreamHandler',
                'level': 'ERROR',
                'formatter': 'my_formatter',
                'stream': sys.stderr
            },
            'console_stdout': {
                # Directs log messages with log level lower than ERROR to stdout
                'class': 'logging.StreamHandler',
                'level': 'DEBUG',
                'formatter': 'my_formatter',
                'filters': ['exclude_errors'],
                'stream': sys.stdout
            },
            'file': {
                # Directs all log messages to a file
                'class': 'logging.FileHandler',
                'level': 'DEBUG',
                'formatter': 'my_formatter',
                'filename': 'my.log',
                'encoding': 'utf8'
            }
        },
        'root': {
            'level': 'NOTSET',
            'handlers': ['console_stderr', 'console_stdout', 'file']
        },
    }
    
    logging.config.dictConfig(config)
    
  • 0

    看一下loguru模块 .

    from loguru import logger
    
    logger.debug("That's it, beautiful and simple logging!")
    

相关问题