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

时间:2012-12-27 17:11:21

标签: python logging error-logging

有没有办法使用logging模块自动将事物输出到stdout 以及到他们应该去的日志文件?例如,我希望所有拨打logger.warninglogger.criticallogger.error的电话都可以转到预定的位置,但另外要始终复制到stdout。这是为了避免重复消息,如:

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

11 个答案:

答案 0 :(得分:501)

所有日志输出都由处理程序处理;只需在根记录器中添加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)

答案 1 :(得分:404)

最简单的方法:

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

答案 2 :(得分:52)

可以使用多个处理程序。

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

答案 3 :(得分:46)

您可以为file和stdout创建两个处理程序,然后创建一个composer.lock参数basicConfig的记录器。如果两个处理程序具有相同的log_level和格式输出,那么它可能很有用:

handlers

答案 4 :(得分:30)

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

<xcad:DockingManager Grid.Row="1"
                       AllowMixedOrientation="True"
                       BorderBrush="Black"
                       BorderThickness="1">
        <xcad:LayoutRoot x:Name="LayoutRoot">
            <xcad:LayoutPanel Orientation="Horizontal">

                <xcad:LayoutAnchorablePane DockWidth="200">
                    <xcad:LayoutAnchorable Title="Toolbox" CanClose="False" CanFloat="False" CanHide="False" ContentId="toolbox" x:Name="CtrlToolbox">
                    </xcad:LayoutAnchorable>

                    <xcad:LayoutAnchorable Title="Outline" CanClose="False" CanFloat="False" CanHide="False" ContentId="outline" x:Name="CtrlOutline">
                    </xcad:LayoutAnchorable>
                </xcad:LayoutAnchorablePane>

答案 5 :(得分:8)

有关详细说明,请参见link上的出色文档。 例如:很简单,您只需要设置两个记录器即可。

import sys
import logging

logger = logging.getLogger('')
logger.setLevel(logging.DEBUG)
fh = logging.FileHandler('my_log_info.log')
sh = logging.StreamHandler(sys.stdout)
formatter = logging.Formatter('[%(asctime)s] %(levelname)s [%(filename)s.%(funcName)s:%(lineno)d] %(message)s', datefmt='%a, %d %b %Y %H:%M:%S')
fh.setFormatter(formatter)
sh.setFormatter(formatter)
logger.addHandler(fh)
logger.addHandler(sh)

def hello_logger():
    logger.info("Hello info")
    logger.critical("Hello critical")
    logger.warning("Hello warning")
    logger.debug("Hello debug")

if __name__ == "__main__":
    print(hello_logger())

输出-终端:

[Mon, 10 Aug 2020 12:44:25] INFO [TestLoger.py.hello_logger:15] Hello info
[Mon, 10 Aug 2020 12:44:25] CRITICAL [TestLoger.py.hello_logger:16] Hello critical
[Mon, 10 Aug 2020 12:44:25] WARNING [TestLoger.py.hello_logger:17] Hello warning
[Mon, 10 Aug 2020 12:44:25] DEBUG [TestLoger.py.hello_logger:18] Hello debug
None

输出-文件中:

log in file


更新:彩色端子

包装:

pip install colorlog

代码:

import sys
import logging
import colorlog

logger = logging.getLogger('')
logger.setLevel(logging.DEBUG)
fh = logging.FileHandler('my_log_info.log')
sh = logging.StreamHandler(sys.stdout)
formatter = logging.Formatter('[%(asctime)s] %(levelname)s [%(filename)s.%(funcName)s:%(lineno)d] %(message)s', datefmt='%a, %d %b %Y %H:%M:%S')
fh.setFormatter(formatter)
sh.setFormatter(colorlog.ColoredFormatter('%(log_color)s [%(asctime)s] %(levelname)s [%(filename)s.%(funcName)s:%(lineno)d] %(message)s', datefmt='%a, %d %b %Y %H:%M:%S'))
logger.addHandler(fh)
logger.addHandler(sh)

def hello_logger():
    logger.info("Hello info")
    logger.critical("Hello critical")
    logger.warning("Hello warning")
    logger.debug("Hello debug")
    logger.error("Error message")

if __name__ == "__main__":
    hello_logger()

输出: enter image description here

答案 6 :(得分:3)

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

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

答案 7 :(得分:1)

这是基于dictConfig configuration function的解决方案。 它没有将所有日志消息发送到stdout,而是将日志级别为ERROR和更高级别的消息发送到stderr,并将其他所有消息发送到stdout。 如果系统的其他部分正在侦听stderr / stdout,这将很有用。

git branch

答案 8 :(得分:1)

看看loguru模块。

from loguru import logger

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

答案 9 :(得分:1)

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

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")

输出将在stdout以及文件中显示“ test msg”。

答案 10 :(得分:0)

我简化了源代码(其原始版本为OOP并使用配置文件),从而为您提供了@EliasStrehle的替代解决方案,而无需使用dictConfig(因此最容易与现有源代码集成):

import logging
import sys


def create_stream_handler(stream, formatter, level, message_filter=None):
    handler = logging.StreamHandler(stream=stream)
    handler.setLevel(level)
    handler.setFormatter(formatter)
    if message_filter:
        handler.addFilter(message_filter)
    return handler


def configure_logger(logger: logging.Logger, enable_console: bool = True, enable_file: bool = True):
    if not logger.handlers:
        if enable_console:
            message_format: str = '{asctime:20} {name:16} {levelname:8} {message}'
            date_format: str = '%Y/%m/%d %H:%M:%S'
            level: int = logging.DEBUG
            formatter = logging.Formatter(message_format, date_format, '{')

            # Configures error output (from Warning levels).
            error_output_handler = create_stream_handler(sys.stderr, formatter,
                                                         max(level, logging.WARNING))
            logger.addHandler(error_output_handler)

            # Configures standard output (from configured Level, if lower than Warning,
            #  and excluding everything from Warning and higher).
            if level < logging.WARNING:
                standard_output_filter = lambda record: record.levelno < logging.WARNING
                standard_output_handler = create_stream_handler(sys.stdout, formatter, level,
                                                                standard_output_filter)
                logger.addHandler(standard_output_handler)

        if enable_file:
            message_format: str = '{asctime:20} {name:16} {levelname:8} {message}'
            date_format: str = '%Y/%m/%d %H:%M:%S'
            level: int = logging.DEBUG
            output_file: str = '/tmp/so_test.log'

            handler = logging.FileHandler(output_file)
            formatter = logging.Formatter(message_format, date_format, '{')
            handler.setLevel(level)
            handler.setFormatter(formatter)
            logger.addHandler(handler)

这是一种非常简单的测试方法:

logger: logging.Logger = logging.getLogger('MyLogger')
logger.setLevel(logging.DEBUG)
configure_logger(logger, True, True)
logger.debug('Debug message ...')
logger.info('Info message ...')
logger.warning('Warning ...')
logger.error('Error ...')
logger.fatal('Fatal message ...')