18

我想在一个函数中实现一个可选的记录器。就像是:

def foo(arg1, arg2, arg3, logger=None):
    logger = logger or (lambda *x: None)

    ...
    self.logger.debug("The connection is lost.")

我希望在存在记录器的情况下进行记录。否则,记录器的调试将无济于事。

基本上实现它的简单方法是将每个调试语句嵌套在一个if logger块中,但是当有许多调试语句时它看起来很混乱。

4

6 回答 6

16

几个选项:

创建一个虚拟记录器(我最喜欢的):

logger = logger or logging.getLogger('dummy') #  without configuring dummy before.

创建一个具有一级null效果的虚拟对象:

class DummyObject(object):
    def __getattr__(self, name):
        return lambda *x: None

logger = logger or DummyObject()

将每个调试语句嵌套在一个块中:

if logger:
    logger.debug("abc")
于 2012-11-23T09:13:08.207 回答
13

自 Python 2.7 起,模块NullHandler中包含了一个无操作:logging

import logging      
logging.getLogger('foo').addHandler(logging.NullHandler())

请参阅为库配置日志记录的文档。

于 2014-10-04T20:48:33.260 回答
3

嗯,这就是logging模块的用途。如何使用食谱

如果你真的想自己动手,我看到了一些选择:

  • self.logger属性。在构造对象或从基类继承时设置。每个对象都有自己的记录器,因此您可以对每个实例进行选择性记录。

  • 具有静态方法或独立模块的记录器类。可以有什么都不做的默认方法,但用户可以在需要时用真正的处理程序替换它们。所有类都访问同一个对象或模块。失去粒度,但设置工作更少。

  • 装饰师。在您想要记录的每个方法上方放置一个@log('message', LEVEL),这将在调用该方法时自动调用日志。相当干净,不太灵活。

于 2012-11-23T01:16:32.120 回答
2

我认为您想要的是日志过滤,所以我的答案是关于如何简单地实现日志过滤。

Python 的日志包已经做到了这一点,你有很多方法来做日志过滤。

两种基本方式是:

  • 日志级别过滤
  • 记录器名称过滤

它们都使用日志记录的配置,因此可以轻松配置。

例如:

import logging

logging.basicConfig()  # easily setup a StreamHandler output

logging.getLogger("realm1").setLevel(logging.WARNING)
logging.getLogger("realm2").setLevel(logging.INFO)

def test():
    r1logger = logging.getLogger("realm1")
    r2logger = logging.getLogger("realm2")
    r1logger.info('r1 info')  # won't print
    r2logger.info('r2 info')  # will print

if __name__ == '__main__':
    test()

因此,除非您需要运行时动态本地更改日志记录策略,否则使用带有仔细日志记录配置的默认记录器就足够了。

于 2012-11-23T03:51:28.323 回答
2

默认情况下,在logging.getLogger调用时用于构造新记录器的类是logging.Logger,默认情况下会将propagate属性设置为True(文档源)。根据文件,

如果此属性 [ propagate] 评估为 true,则记录到此记录器的事件将传递给更高级别(祖先)记录器的处理程序,以及附加到此记录器的任何处理程序。

因此,只要记录器的父级之一具有一些重要的处理程序,@fcs 的答案就不会起作用,这很可能是因为根记录器都是记录器的父级,并且它几乎总是StreamHandlerstderr流一起使用。

以下简单修复将起作用:

import logging
null_logger = logging.getLogger('foo')
null_logger.addHandler(logging.NullHandler())  # read below for reason
null_logger.propagate = False
null_logger.error("error")  # This message will still go nowhere

请注意,添加logging.NullHandler是必要的,因为如果任何处理程序都未处理日志记录,它将由logging.lastResort仍会发出此消息的处理程序处理stderr(自 Python 3.2 以来的行为)。

于 2020-12-31T00:40:59.340 回答
0

你还可以做什么,它比使用 NullHander 设置一个真正的记录器更短:

logger = Mock()
于 2020-07-08T04:26:08.640 回答