Python日志仅记录来自脚本的信息

31 投票
2 回答
16494 浏览
提问于 2025-04-17 07:03

我在我的一个简单脚本中使用了Python的日志模块,当前的设置如下。

logging.basicConfig(format='%(asctime)s %(message)s', level=logging.INFO, datefmt='%Y-%m-%d %H:%M:%S')
logger = logging.getLogger(__name__)

我的问题是,这个设置也会捕捉到第三方模块,比如requests,输出它们的info()日志信息。我想知道有没有办法屏蔽这些信息,或者让日志模块只记录我自己脚本中的信息?

2 个回答

28

在你的模块中使用命名日志记录器:

import logging
logger = logging.getLogger(__name__)
logger.info("my info")
logger.error("my error")

你可以把其他所有日志记录器的日志级别设置为错误,而把你自己的日志记录器设置为调试:

import logging
logging.basicConfig(level=logging.ERROR)
logging.getLogger(my_module.__name__).setLevel(logging.DEBUG)
41

上面的回答其实不太正确——它只是提高了其他模块消息显示的门槛。

一个非常简单的方法是使用这段代码:

import logging.config
logging.config.dictConfig({
    'version': 1,
    'disable_existing_loggers': True,
})

你需要在导入所有模块之后设置这个——它会禁用到目前为止创建的所有日志记录器。这种方法大多数情况下都能奏效,但有些模块在你创建类实例时会生成它们的日志记录器(这通常发生在你代码的后面)。


当你按照基础的Python教程设置日志记录器时,他们会告诉你使用 logging.basicConfig(...)。这就有问题了,因为这会把日志处理器(也就是日志要发送到哪里)设置为 logging.lastResort,在Python 3.2及之后的版本中,这个处理器是标准错误输出(stderr),而且是对进程中所有日志记录器全局生效。这意味着你现在为所有模块启用了完整的日志记录。

所以更好的方法是为你的模块创建一个不同的日志记录器,并给它一些自己的处理器,而不是使用 basicConfig()

有两种方法可以做到这一点:

1) 使用函数:

import logging

log = logging.getLogger(__name__)
log.setLevel(logging.DEBUG)
formatter = logging.Formatter(fmt="%(asctime)s %(levelname)s: %(message)s", 
                          datefmt="%Y-%m-%d - %H:%M:%S")
ch = logging.StreamHandler(sys.stdout)
ch.setLevel(logging.DEBUG)
ch.setFormatter(formatter)
fh = logging.FileHandler("mylog.log", "w")
fh.setLevel(logging.DEBUG)
fh.setFormatter(formatter)
log.addHandler(ch)
log.addHandler(fh)

这样你就会得到一个名为 log 的日志记录器,你可以像这样使用它 log.error("发现错误")。它会写入一个名为 mylog.log 的新文件,并且也会记录到 sys.stdout。你当然可以根据需要进行更改。

2) 使用字典:

import logging
import logging.config

DEFAULT_LOGGING = {
    'version': 1,
    'formatters': { 
        'standard': {
            'format': '%(asctime)s %(levelname)s: %(message)s',
            'datefmt': '%Y-%m-%d - %H:%M:%S' },
    },
    'handlers': {
        'console':  {'class': 'logging.StreamHandler', 
                     'formatter': "standard", 
                     'level': 'DEBUG', 
                     'stream': sys.stdout},
        'file':     {'class': 'logging.FileHandler', 
                     'formatter': "standard", 
                     'level': 'DEBUG', 
                     'filename': 'live_detector.log','mode': 'w'} 
    },
    'loggers': { 
        __name__:   {'level': 'INFO', 
                     'handlers': ['console', 'file'], 
                     'propagate': False },
    }
}

logging.config.dictConfig(DEFAULT_LOGGING)
log = logging.getLogger(__name__)

这将得到与上面相同的结果,虽然稍微长一点,但可能更容易阅读。这个方法会自动设置 'disable_existing_loggers': True。如果你不想这样,你需要手动添加并将其设置为 False。

撰写回答