使用模拟获取所有日志记录输出 [英] Get all logging output with mock

查看:62
本文介绍了使用模拟获取所有日志记录输出的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用模拟获取所有日志记录输出.我搜索了,但是 只找到了显式模拟logging.info或logging.warn的方法.

I want to get all logging output with mock. I searched, but only found ways to mock explicitly logging.info or logging.warn.

无论设置了什么日志级别,我都需要所有输出.

I need all output, whatever logging level was set.

def test_foo():

   def my_log(...):
      logs.append(...)

   with mock.patch('logging.???', my_log):
        ...

在我们的库中,我们使用以下代码:

In our libraries we use this:

import logging
logger=logging.getLogger(__name__)

def foo():
    logger.info(...)

推荐答案

stdlib

从Python 3.4开始,电池的unittest具有 assertLogs .当不带loggerlevel参数使用时,它将捕获所有日志记录(禁止现有处理程序).您以后可以从上下文管理器的records属性访问记录的条目.文本输出字符串存储在output列表中.

stdlib

Since Python 3.4 the batteries' unittest has assertLogs. When used without logger and level arguments, it catches all logging (suppresses existing handlers). You can later access recorded entries from the context manager's records attribute. Text output strings are stored in output list.

import logging
import unittest


class TestLogging(unittest.TestCase):

    def test(self):
        with self.assertLogs() as ctx:
            logging.getLogger('foo').info('message from foo')
            logging.getLogger('bar').info('message from bar')
        print(ctx.records)

龙卷风

对于Python 2,我通常采用Tornado的 ExpectLog .它是自包含的,适用于普通的Python代码.实际上,它是比stdlib更为优雅的解决方案,因为ExpectLog而不是几个类,只是普通的 logging.Filter (一个类,

Tornado

For Python 2 I usually take Tornado's ExpectLog. It's self-contained and works for normal Python code. It's actually more elegant solution then stdlib's, because instead of several class, ExpectLog is just a normal logging.Filter (a class, source). But it lacks a couple of features, including access to recorded entries, so usually I also extend it a bit, like:

class ExpectLog(logging.Filter):

    def __init__(self, logger, regex, required=True, level=None):
        if isinstance(logger, basestring):
            logger = logging.getLogger(logger)
        self.logger = logger
        self.orig_level = self.logger.level
        self.level = level
        self.regex = re.compile(regex)
        self.formatter = logging.Formatter()
        self.required = required
        self.matched = []
        self.logged_stack = False

    def filter(self, record):
        if record.exc_info:
            self.logged_stack = True
        message = self.formatter.format(record)
        if self.regex.search(message):
            self.matched.append(record)
            return False
        return True

    def __enter__(self):
        self.logger.addFilter(self)
        if self.level:
            self.logger.setLevel(self.level)
        return self

    def __exit__(self, typ, value, tb):
        self.logger.removeFilter(self)
        if self.level:
            self.logger.setLevel(self.orig_level)
        if not typ and self.required and not self.matched:
            raise Exception("did not get expected log message")

然后您可以拥有类似的内容:

Then you can have something like:

class TestLogging(unittest.TestCase):

    def testTornadoself):
        logging.basicConfig(level = logging.INFO)

        with ExpectLog('foo', '.*', required = False) as ctxFoo:
            with ExpectLog('bar', '.*', required = False) as ctxBar:
                logging.getLogger('foo').info('message from foo')
                logging.getLogger('bar').info('message from bar')
        print(ctxFoo.matched)
        print(ctxBar.matched)

但是,请注意,对于过滤器方法,当前的日志记录级别很重要(可以用level参数覆盖),并且每个感兴趣的记录器都需要一个过滤器.您可以按照此方法进行操作,并使其更适合您的情况.

However, note that for the filter approach current logging level is important (can be overridden with level argument), and also you need a filter per logger of interest. You can follow the approach and make something that fits your case better.

或者,对于具有assertLogs的Python 2,存在 unittest2 移植.

Alternatively there's unittest2 backport for Python 2 which has assertLogs.

这篇关于使用模拟获取所有日志记录输出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆