使用过滤器记录

时间:2009-05-18 20:43:49

标签: python logging

我正在使用记录(import logging)来记录消息。

在1个单独的模块中,我在调试级别my_logger.debug('msg')记录消息;

其中一些调试消息来自function_a(),其他来自function_b();我希望能够根据它们来自a还是来自b来启用/禁用日志记录;

我猜我必须使用Logging的过滤机制。

有人可以告诉我下面的代码是如何进行检测以做我想要的吗?

import logging
logger= logging.getLogger( "module_name" )

def function_a( ... ):
    logger.debug( "a message" )

def function_b( ... ):
    logger.debug( "another message" )

if __name__ == "__main__":
    logging.basicConfig( stream=sys.stderr, level=logging.DEBUG )

    #don't want function_a()'s noise -> ....
    #somehow filter-out function_a's logging
    function_a()

    #don't want function_b()'s noise -> ....
    #somehow filter-out function_b's logging
    function_b()

如果我将这个简单的例子扩展到每个模块的更多模块和更多功能,我会关注很多记录器;

我可以将每个模块保持在1个记录器吗?请注意,日志消息是“结构化的”,即如果记录它的函数正在进行一些解析工作,它们都包含前缀logger.debug("parsing: xxx") - 我可以以某种方式使用单行关闭所有“解析“消息(无论发出消息的模块/功能如何?)

4 个答案:

答案 0 :(得分:48)

只需实现logging.Filterhttp://docs.python.org/library/logging.html#filter-objects的子类。它将有一个方法filter(record),它检查日志记录并返回True以记录它或False以丢弃它。然后,您可以通过调用Logger方法在HandleraddFilter(filter)上安装过滤器。

示例:

class NoParsingFilter(logging.Filter):
    def filter(self, record):
        return not record.getMessage().startswith('parsing')

logger.addFilter(NoParsingFilter())

或类似的东西,无论如何。

答案 1 :(得分:17)

不要使用全球。这是一个等待发生的事故。

您可以为记录器添加任何“。” - 对您有意义的分隔名称。

您可以将它们控制为层次结构。如果您有名为a.b.c的记录器和 a.b.d,您可以检查a.b的日志记录级别并更改两个记录器。

你可以拥有任意数量的记录器 - 它们很便宜。

最常见的设计模式是每个模块一个记录器。见Naming Python loggers

这样做。

import logging

logger= logging.getLogger( "module_name" )
logger_a = logger.getLogger( "module_name.function_a" )
logger_b = logger.getLogger( "module_name.function_b" )

def function_a( ... ):
    logger_a.debug( "a message" )

def functio_b( ... ):
    logger_b.debug( "another message" )

if __name__ == "__main__":
    logging.basicConfig( stream=sys.stderr, level=logging.DEBUG )
    logger_a.setLevel( logging.DEBUG )
    logger_b.setLevel( logging.WARN )

    ... etc ...

答案 2 :(得分:1)

我发现了一种更简单的方法,该方法可以使用 sshtunel 模块过滤掉以下问题的默认日志记录配置,以取代INFO级消息。

带有前2个不需要的记录的默认报告如下:

2020-11-10 21:53:28,114  INFO       paramiko.transport: Connected (version 2.0, client OpenSSH_7.9p1)
2020-11-10 21:53:28,307  INFO       paramiko.transport: Authentication (password) successful!
2020-11-10 21:53:28,441  INFO       |-->QuerySSH: Query execution successful.

记录器配置更新:

logging.basicConfig(
            level=logging.INFO,
            format='%(asctime)s  %(levelname)-10s %(name)s: %(message)s',
            handlers=[
                logging.StreamHandler(),
                logging.FileHandler(self.logging_handler)
            ]
        )

# Filter paramiko.transport debug and info from basic logging configuration
logger_descope = logging.getLogger('paramiko.transport')
logger_descope.setLevel(logging.WARN)

结果令我满意的是:

2020-11-10 22:00:48,755  INFO       |-->QuerySSH: Query execution successful.

答案 3 :(得分:0)

我在您的主脚本中找到了一种使用函数的简单方法:

# rm 2to3 messages
def filter_grammar_messages(record):
    if record.funcName == 'load_grammar':
        return False
    return True

def filter_import_messages(record):
    if record.funcName == 'init' and record.msg.startswith('Importing '):
        return False
    return True

logging.getLogger().addFilter(filter_grammar_messages)  # root
logging.getLogger('PIL.Image').addFilter(filter_import_messages)