Python技术迷

Python日志捕获与断言那些你不知道的实用技巧。。。

作为一名程序员,日志对我来说就像一个黑匣子。调试难搞的问题?翻翻日志准没错。出bug了不想背锅?日志也能帮你洗清冤屈。

不过,光有日志还不够,有时候我们需要更高级的操作,比如动态捕获日志内容、在测试中对日志断言,甚至把日志记录到文件里方便后续分析。今天我就带大家全面了解一下Python的logging模块,以及它在实际场景中的高效用法。

Python的logging模块是一个强大的内置工具,支持灵活的日志级别和处理方式。每当提到日志,绕不开一个概念:日志级别。

DEBUG是最基础的调试信息,INFO记录正常的运行状态,WARNING提示可能出现的问题,ERROR说明程序出错了,而CRITICAL表示严重问题,程序可能直接“嗝屁”。这些级别从低到高,重要性逐步递增。

我们来看一个简单的例子:

import logging

# 配置日志格式和级别
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')

# 生成不同级别的日志信息
logging.debug('调试信息:变量x的值为42')
logging.info('程序启动成功')
logging.warning('警告:磁盘空间不足')
logging.error('错误:文件未找到')
logging.critical('严重错误:系统崩溃!')

运行后,日志会直接打印到控制台,包括时间、日志级别和具体的消息。比如:

2024-11-18 14:30:00,000 - DEBUG - 调试信息:变量x的值为42
2024-11-18 14:30:00,001 - INFO - 程序启动成功
2024-11-18 14:30:00,002 - WARNING - 警告:磁盘空间不足
2024-11-18 14:30:00,003 - ERROR - 错误:文件未找到
2024-11-18 14:30:00,004 - CRITICAL - 严重错误:系统崩溃!

这时候你可能会问:“日志打印的内容如果太多,我能不能只看重要的?”当然可以!只需修改日志级别,比如设置为WARNING,这样就只会显示WARNING及以上级别的日志,清爽多了。

不过,有时候日志内容不仅要打印出来,还得捕获下来进行后续操作,比如在测试中验证日志是否符合预期。这里有个小技巧:使用StringIO捕获日志内容。

import logging
from io import StringIO

# 使用 StringIO 作为日志捕获容器
log_capture_string = StringIO()
ch = logging.StreamHandler(log_capture_string)
ch.setLevel(logging.DEBUG)

# 配置日志格式
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
ch.setFormatter(formatter)

# 设置 logger
logger = logging.getLogger()
logger.addHandler(ch)
logger.setLevel(logging.DEBUG)

# 写入一些日志
logger.info('这是一个普通日志')
logger.error('出现了一个错误')

# 获取日志内容
log_contents = log_capture_string.getvalue()
print("捕获的日志内容:")
print(log_contents)

# 清理处理器
logger.removeHandler(ch)
log_capture_string.close()

运行后,你会发现日志内容被存储到了StringIO对象中,想怎么处理就怎么处理。这种方式特别适合在测试场景下使用,比如断言日志内容是否正确。

在自动化测试中,日志捕获和断言是标配。用unittest结合logging,就能轻松验证日志输出是否符合预期。看下面的例子:

import logging
from io import StringIO
import unittest

class TestLogging(unittest.TestCase):

    def test_logging_output(self):
        log_capture_string = StringIO()
        ch = logging.StreamHandler(log_capture_string)
        ch.setLevel(logging.DEBUG)

        formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
        ch.setFormatter(formatter)

        logger = logging.getLogger()
        logger.addHandler(ch)
        logger.setLevel(logging.DEBUG)

        # 写入日志
        logger.info('测试日志内容')
        logger.error('模拟错误日志')

        # 获取日志内容
        log_contents = log_capture_string.getvalue()

        # 验证日志内容是否包含特定消息
        self.assertIn('测试日志内容', log_contents)
        self.assertIn('模拟错误日志', log_contents)

        logger.removeHandler(ch)
        log_capture_string.close()

if __name__ == '__main__':
    unittest.main()

这个例子中,assertIn用来检查日志内容是否包含特定的字符串。如果日志内容匹配,测试通过;如果不匹配,测试直接失败,方便排查问题。

当然,日志不仅要实时捕获,往往还需要写入文件以便日后分析。Python的FileHandler可以轻松实现这一点:

import logging

# 配置日志文件
logging.basicConfig(
    filename='app.log',
    level=logging.DEBUG,
    format='%(asctime)s - %(levelname)s - %(message)s'
)

# 写入日志
logging.debug('这是调试日志')
logging.info('启动成功')
logging.warning('磁盘空间不足')
logging.error('文件未找到')
logging.critical('系统崩溃')

运行代码后,你会发现所有日志都被写入了app.log文件中。通过这种方式,你可以轻松实现日志的长期保存。

结合捕获、断言和文件记录,我们可以设计一个综合的测试框架。以下是一个综合实例,展示如何在测试中同时捕获日志内容并写入文件:

import logging
from io import StringIO
import unittest

class TestLoggingWithFile(unittest.TestCase):

    def setUp(self):
        self.log_capture_string = StringIO()
        ch = logging.StreamHandler(self.log_capture_string)
        ch.setLevel(logging.DEBUG)

        fh = logging.FileHandler('test_log.log')
        fh.setLevel(logging.DEBUG)

        formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
        ch.setFormatter(formatter)
        fh.setFormatter(formatter)

        self.logger = logging.getLogger()
        self.logger.addHandler(ch)
        self.logger.addHandler(fh)
        self.logger.setLevel(logging.DEBUG)

    def tearDown(self):
        self.logger.handlers.clear()

    def test_logging_capture_and_file(self):
        self.logger.info('测试日志写入')
        self.logger.error('这是一个错误日志')

        log_contents = self.log_capture_string.getvalue()
        self.assertIn('测试日志写入', log_contents)
        self.assertIn('这是一个错误日志', log_contents)

if __name__ == '__main__':
    unittest.main()

这个实例演示了如何捕获日志内容进行断言,并同时将日志写入到文件中。这种方法非常适合用于复杂的测试场景。

日志记录不仅是调试和监控的利器,还能通过捕获和断言的方式进一步提升测试质量。Python的logging模块功能强大且灵活,无论是开发还是测试,都值得深入掌握。

对编程、职场感兴趣的同学,大家可以联系我微信:golang404,拉你进入“程序员交流群”。
🔥虎哥私藏精品 热门推荐🔥

虎哥作为一名老码农,整理了全网最全《python高级架构师资料合集》。

资料包含了《IDEA视频教程》、《最全python面试题库》、《最全项目实战源码及视频》及《毕业设计系统源码》,总量高达650GB,全部免费领取。