使用过滤器记录

jd.*_*jd. 33 python logging

我正在使用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()
Run Code Online (Sandbox Code Playgroud)

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

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

Dav*_*d Z 50

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

例:

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

logger.addFilter(NoParsingFilter())
Run Code Online (Sandbox Code Playgroud)

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

  • 我不得不将过滤器添加到处理程序中. (9认同)
  • @GringoSuave原因可能是因为处理程序传播,但过滤器不传播:https://www.saltycrane.com/blog/2014/02/python-logging-filters-do-not-propagate-like-handlers-和级别-do/ (2认同)

S.L*_*ott 18

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

您可以为记录器提供任何"." - 对您有意义的分隔名称.

您可以将它们控制为层次结构.如果您有一个名为记录器a.b.ca.b.d,你可以检查日志记录级别a.b,并同时改变记录仪.

你可以拥有任意数量的记录器 - 它们价格便宜.

最常见的设计模式是每个模块一个记录器.请参阅命名Python记录器

做这个.

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 ...
Run Code Online (Sandbox Code Playgroud)

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

Gri*_*ave 6

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

# 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)
Run Code Online (Sandbox Code Playgroud)

  • 不,这是 PIL 记录器的名称,只是我碰巧需要的一个示例。每个图书馆都会有一个不同的名字,可能就是它的名字。 (2认同)