【问题标题】:Programmatically listen for log message sent to a Python/Django logger以编程方式侦听发送到 Python/Django 记录器的日志消息
【发布时间】:2014-06-30 04:02:59
【问题描述】:

我对 Python 和 Django 都比较陌生,我不确定如何最好地解决我的问题。我最终确实想出了一个解决方案,但它似乎有点权宜之计,或者至少,方法没有被用于目的。无法在网上找到有关该主题的任何内容,我想我会在此处发布 QA 风格,以便至少有一个关于 SO 的答案,并查看其他人是否有改进或更“pythonic”的方法。

我的问题是我正在为我无权修改的代码编写测试,而代码本身只输出对日志的响应——因此该方法需要能够介入并监听日志消息并断言它们符合预期。

import logging

logger = logging.getLogger('shrubbery')

# do stuff
other_code_that_cant_be_altered_that_will_trigger_log_messages()

# assert that the log messages are as we expected
assert_messages_be_good_and_expected()

【问题讨论】:

    标签: python django logging


    【解决方案1】:

    因此,在阅读了许多页面后,我发现有一些日志记录功能可能对我有用。我特别喜欢addHandleraddFilter 的描述。不如其他一些信息丰富,也不比函数本身的命名约定提供更多信息。但是,我不维护任何公共文档,所以不能抱怨。

    1. https://docs.djangoproject.com/en/dev/topics/logging/
    2. https://docs.python.org/2/library/logging.html#logger-objects
    3. https://docs.python.org/2/howto/logging-cookbook.html#filters-contextual
    4. http://www.onlamp.com/pub/a/python/2005/06/02/logging.html

    经过一番反复试验,我将以下内容放在一起。我的第一次尝试是使用addHandler,但这似乎比addFilter 涉及更多,并且缺乏文档。所以基本上代码设置了一个虚假的日志过滤器,它监听每条日志消息,并将它们附加到范围更远的数组中。它总是返回 true,因此日志消息永远不会丢失。我不确定这是否是最优的,或者是否有更好的语义化方式,但它确实有效。

    import logging
    
    messages = []
    logger = logging.getLogger('shrubbery')
    
    # use a filter to listen out for the log
    class ListenFilter(logging.Filter):
        def filter(self, record):
            messages.append(record.getMessage())
            return True
    
    # plug our filter listener in
    f = ListenFilter()
    logger.addFilter(f)
    
    # do stuff
    other_code_that_cant_be_altered_that_will_trigger_log_messages()
    
    # do more stuff, this time reading messages
    assert_messages_be_good_and_expected(messages)
    
    # tidy up
    logger.removeFilter(f)
    

    【讨论】:

      【解决方案2】:

      感谢 Pebbl 的回答!只是想补充一点,使用contextmanager 安装/移除过滤器似乎更干净:

      logger_ = logging.getLogger('some.external.logger')
      
      from contextlib import contextmanager
      
      @contextmanager
      def install_remove_filter(logger_to_filter, filter_to_add_remove):
          logger_to_filter.addFilter(filter_to_add_remove)
          yield
          logger_to_filter.removeFilter(filter_to_add_remove)
      
      # the filter above
      my_filter = ListenFilter()
      
      # installing/removing the filter in the context of the call
      with install_remove_filter(logger_, my_filter):
          call_some_function()
      
      # access the internals of my_filter
      # .... 
      

      【讨论】:

        猜你喜欢
        • 2011-09-26
        • 2011-03-27
        • 2011-10-26
        • 2021-09-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-12-26
        • 1970-01-01
        相关资源
        最近更新 更多