【问题标题】:logging with filters使用过滤器记录
【发布时间】:2010-10-27 03:44:01
【问题描述】:

我正在使用 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") - 我可以用一行代码以某种方式关闭所有“解析”消息(不管发出消息的模块/函数是什么?)

【问题讨论】:

    标签: python logging


    【解决方案1】:

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

    例子:

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

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

    【讨论】:

    • 我必须将过滤器添加到处理程序。
    • @GringoSuave 这可能是因为处理程序传播,但过滤器没有:saltycrane.com/blog/2014/02/…
    • 如果您添加 filter(),此过滤器将跳过这些消息,我将其与 --verbose 参数结合使用。如果参数不存在,那么我添加过滤器。在标准输出中添加日志记录视觉标记非常有效,您仅在非常特定的情况下才需要。不要再评论日志消息了。
    【解决方案2】:

    不要使用全局。这是一场等待发生的意外。

    您可以为您的记录器指定任何对您有意义的以“.”分隔的名称。

    您可以将它们作为层次结构进行控制。如果您有名为 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 function_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 ...
    

    【讨论】:

    • 感谢 S.Lott 的回复;这会起作用;但是,如果我将我的简单示例扩展到更多模块和每个模块的更多功能,我会担心很多记录器;我可以将每个模块减少到 1 个记录器吗?请注意,日志消息是“结构化的”,即如果记录它的函数正在做一些解析工作,它们都包含前缀 logger.debug("parsing: ...") - 我可以用一行只需关闭所有“解析”消息(不管发出消息的模块/函数如何?)
    【解决方案3】:

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

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

    【讨论】:

    • 文件名是PIL.Image吗?
    • 不是,它是 PIL 记录器的名称,只是我碰巧需要的一个示例。每个库都有不同的名称,可能是它的名字。
    【解决方案4】:

    我发现了一种更简单的方法,如何使用 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.
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-08-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多