关键词

python将logging模块封装成单独模块并实现动态切换Level方式

一、背景
在Python中,logging模块是非常常用的标准库,用于实现应用的日志记录。logging模块提供了丰富的功能,可以配置logger、handler、formatter等参数,也支持多线程、多进程、日志旋转等高级需求。不过,logging模块也存在一些问题,例如默认日志级别是WARNING,不太方便打印出DEBUG和INFO级别的信息;另外,当需要打印出DEBUG和INFO级别的信息时,需要修改代码中的日志级别参数,重新运行程序才能生效。这些问题可以通过将logging模块进行封装,并实现动态切换Level方式来解决。

二、思路
将logging模块封装成单独模块,需要定义三个类:Logger、Handler、Formatter。Logger类用于定义log输出的方式(如console或file),Handler类用于定义log输出的格式(如log格式和时间格式),Formatter类用于定义log输出的级别(如DEBUG、INFO、WARNING、ERROR、CRITICAL)。通过在Logger中设定level属性,可以对整个Logger对象设置级别。通过设置Handler的级别,可以对指定Handler对象设置级别。通过设置Formatter的级别,可以对log输出的消息内容进行过滤。

三、步骤
1.定义Logger类
Logger类中定义了两个方法:设置日志输出方式和设置日志输出级别。下面是Logger的定义示例:

import logging
import sys

class Logger(object):
    def __init__(self, name):
        self.logger = logging.getLogger(name)
        self.logger.setLevel(logging.DEBUG)

    def addConsoleHandler(self, format):
        handler = logging.StreamHandler(sys.stdout)
        handler.setLevel(logging.DEBUG)
        handler.setFormatter(logging.Formatter(format))
        self.logger.addHandler(handler)

    def addFileHandler(self, file, format):
        handler = logging.FileHandler(filename=file, mode='a', encoding='utf-8')
        handler.setLevel(logging.DEBUG)
        handler.setFormatter(logging.Formatter(format))
        self.logger.addHandler(handler)

    def setLevel(self, level):
        self.logger.setLevel(level)

2.定义Handler类
Handler类中定义了两个方法:设置日志输出格式和设置日志时间格式。下面是Handler的定义示例:

import logging

class Handler(object):
    def __init__(self, format):
        self.format = format

    def setFormat(self, format):
        self.format = format

    def setDateFormat(self, datefmt):
        self.format.datefmt = datefmt

3.定义Formatter类
Formatter类中定义了过滤日志输出级别的方法。下面是Formatter的定义示例:

import logging

class Formatter(logging.Formatter):
    def __init__(self, fmt=None, datefmt=None, level=logging.DEBUG):
        logging.Formatter.__init__(self, fmt, datefmt)
        self.level = level

    def format(self, record):
        if record.levelno >= self.level:
            return logging.Formatter.format(self, record)
        else:
            return ''

4.动态切换Level方式
在主程序中,调用Logger类、Handler类、Formatter类,设置日志输出方式、日志输出格式和日志输出级别,即可实现动态切换Level方式。下面是示例代码:

import logging
import time

from mylogging import Logger, Handler, Formatter

if __name__ == '__main__':
    logger = Logger('mylogger')
    logger.addConsoleHandler('[%(asctime)s] [%(levelname)s] %(message)s')
    logger.addFileHandler('mylog.txt', '[%(asctime)s] [%(levelname)s] %(message)s')

    formatter1 = Formatter('[%(asctime)s] [%(levelname)s] %(message)s', level=logging.INFO)
    formatter2 = Formatter('[%(asctime)s] [%(levelname)s] %(message)s', level=logging.DEBUG)

    print('INFO logging...')
    logger.setLevel(logging.INFO)
    handler = logger.logger.handlers[-1]
    handler.setFormatter(formatter1)
    logger.logger.info('info message')

    time.sleep(1)

    print('DEBUG logging...')
    logger.setLevel(logging.DEBUG)
    handler.setFormatter(formatter2)
    logger.logger.debug('debug message')

运行结果:

INFO logging...
[2021-09-10 19:08:03,759] [INFO] info message

DEBUG logging...
[2021-09-10 19:08:04,765] [DEBUG] debug message

解析:
- Logger类定义了mylogger的Logger,设定日志输出级别为Debug。
- 通过addConsoleHandler()方法,将日志输出到控制台,格式为'[%(asctime)s] [%(levelname)s] %(message)s',级别设为Debug。
- 通过addFileHandler()方法,将日志输出到mylog.txt文件,格式为'[%(asctime)s] [%(levelname)s] %(message)s',级别设为Debug。
- 定义了两个Formatter,格式相同,但级别分别为Info和Debug。
- 通过setLevel()方法,将日志输出级别设为Info,此时只会将大于等于Info级别的日志输出。设置handler的Formatter为formatter1。
- 输出Info级别的日志。
- 通过setLevel()方法,将日志输出级别设为Debug,此时会将所有日志输出。设置handler的Formatter为formatter2。
- 输出Debug级别的日志。

四、总结
日志是编写Python应用程序时必不可少的组成部分。利用logging模块进行日志记录可以帮助我们快速定位问题,并找到解决办法。在实际使用过程中,对logging模块进行封装,以实现动态切换Level方式,可以提高debug的效率,降低调试成本。

本文链接:http://task.lmcjl.com/news/14979.html

展开阅读全文