使Python记录器将除日志文件外的所有消息输出到stdout


450

除了应该将日志文件放到哪里,是否有一种方法可以使用该logging模块使Python日志自动输出到stdout ?例如,我想所有呼叫,,去他们预期的地方,但除了总是被复制到。这是为了避免重复消息,例如:logger.warninglogger.criticallogger.errorstdout

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

Answers:


635

所有日志记录输出均由处理程序处理;只需添加一个logging.StreamHandler()在根记录器中即可。

这是配置流处理程序(使用stdout而不是默认值stderr)并将其添加到根记录器的示例:

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)

4
很好,但是如果已经将其重定向到文件,我又如何将其打印到文件stdout

54
@ user248237:通过添加新的处理程序,如图所示。新的处理程序不会替换现有的处理程序,它们还会处理日志条目。
马丁·彼得斯

@MartijnPieters是否可以在每个打印出的日志语句中添加一个字符串?
Prakhar Mohan Srivastava

7
@PrakharMohanSrivastava我想您可以将其添加到传入的字符串中logging.Formatter
A.Wan

3
@ himanshu219:用例是,一旦您开始添加多个处理程序,通常就希望与众不同。DEBUG到控制台,警告和多达文件等
的Martijn Pieters的

505

登录到stdout的最简单方法:

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

57
嗯,但这没有记录到文件中,对吧?问题是如何记录到文件控制台。
魏登林德2015年


至少在Python 3中,似乎省略stream=sys.stdout了对我来说仍然可以登录到控制台。
泰勒·埃德米斯顿

3
@TaylorEdmiston是的,但这是stderr流AFAIK。尝试从外壳重定向输出。
索林

1
好。这不能同时回答两个问题:登录文件和控制台,但是很高兴在3行以内找到我需要的内容。
Steve3p0

67

可以使用多个处理程序。

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


4
很好的答案,尽管有点混乱。喜欢如何展示如何对流和文件使用不同级别和格式。+1,但精神+2。
Unfun Cat

对我来说,没有sys.stdout参数,这是行不通的ch = logging.StreamHandler()
veuncent

64

您可以为file和stdout创建两个处理程序,然后创建一个handlers参数为的记录器basicConfig。如果两个处理程序具有相同的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)

在控制台中的日志消息之前,这不会显示标签INFO,DEBUG和ERROR。它的确在文件中显示了这些标签。有什么想法还可以在控制台中显示标签吗?
JahMyst '16

1
谢谢@JahMyst,我添加了格式化程序。不幸的是,它不再那么短,而是最简单的方法。:-)
Weidenrinde

12

这是基于强大的,但记录不完整的解决方案logging.config.dictConfig的方法。而不是将所有日志消息发送到stdout,而是将日志级别ERROR和更高级别的消息发送stderrstdout。如果系统的其他部分正在收听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': {
        # Modify log message format here or replace with your custom formatter class
        'my_formatter': {
            'format': '(%(process)d) %(asctime)s %(name)s (line %(lineno)s) | %(levelname)s %(message)s'
        }
    },
    'handlers': {
        'console_stderr': {
            # Sends log messages with log level ERROR or higher to stderr
            'class': 'logging.StreamHandler',
            'level': 'ERROR',
            'formatter': 'my_formatter',
            'stream': sys.stderr
        },
        'console_stdout': {
            # Sends 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': {
            # Sends all log messages to a file
            'class': 'logging.FileHandler',
            'level': 'DEBUG',
            'formatter': 'my_formatter',
            'filename': 'my.log',
            'encoding': 'utf8'
        }
    },
    'root': {
        # In general, this should be kept at 'NOTSET'.
        # Otherwise it would interfere with the log levels set for each handler.
        'level': 'NOTSET',
        'handlers': ['console_stderr', 'console_stdout', 'file']
    },
}

logging.config.dictConfig(config)

必须将记录器重命名为空字符串才能真正获得根记录器。否则非常有帮助,谢谢!
Newtopian '19

8

由于没有人共享两个整齐的班轮,我将分享我自己的:

logging.basicConfig(filename='logs.log', level=logging.DEBUG, format="%(asctime)s:%(levelname)s: %(message)s")
logging.getLogger().addHandler(logging.StreamHandler())

2

这是一个非常简单的示例:

import logging
l = logging.getLogger("test")

# Add a file logger
f = logging.FileHandler("test.log")
l.addHandler(f)

# Add a stream logger
s = logging.StreamHandler()
l.addHandler(s)

# Send a test message to both -- critical will always log
l.critical("test msg")

输出将在标准输出和文件中显示“ test msg”。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.