一、背景
在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的效率,降低调试成本。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:python将logging模块封装成单独模块并实现动态切换Level方式 - Python技术站