【测试开发】Python—logging日志封装

发布于:2023-01-24 ⋅ 阅读:(22) ⋅ 点赞:(0) ⋅ 评论:(0)

python日志模块,可以说在工程项目中应该很广泛,本文简单地介绍Logging封装模块的编写及使用。当前环境:python 3.6.8;编译环境:pycharm。

目录

1、logging简单配置

2、logging原理

2.1、日志事件级别

2.2、日志组件

①Loggers记录器

②Handler 处理器

③Formatter 格式化器

3、logging日志封装

参考文献


1、logging简单配置

我们来看一下最为简朴的日志配置及输出👇

# -*- coding:utf-8 -*-
import logging

#最为简单的配置输出方式与日志级别
logging.basicConfig(filename='logger.log', level="INFO")

#输出不同级别的日志
logging.debug('debug message')
logging.info('info message')
logging.warnning('warn message')
logging.error('error message')
logging.critical('critical message')

输出至同目录下"logger.log 文件",内容如下👇

可以看到,配置语句中的 filenamelevel 各自起到了作用,前者作用是给输出的 .log 文件进行命名,后者则是设置输出内容的等级设置,比如设置日志级别为 INFO ,那么只有日志级别大于等于 INFO 的日志才会输出,可以看出logger.log 文件中 DEBUG 等级内容没有输出,因为其等级是低于 INFO 等级的。

需要注意的是,标准输出(屏幕/控制台)未显示任何信息,因为上边语句只涉及日志文件的输出,关于屏幕输出在后文详述。

2、logging原理

2.1、日志事件级别

级别 日志使用
DEBUG 细节信息,仅当诊断问题时适用。
INFO 确认程序按预期运行
WARNING 表明有已经或即将发生的意外(例如:磁盘空间不足)。程序仍按预期进行
ERROR 由于严重的问题,程序的某些功能已经不能正常执行
CRITICAL 严重的错误,表明程序已不能继续执行

从 logging 简单配置可以得出,日志事件的级别是控制输出内容(日志文件或屏幕)的阀门,默认的级别是 WARNING ,意味着只会追踪该级别及以上的事件,一般情况下我们都会依据项目的情况进行更改。级别排序:DEBUG  INFOWARNING < ERROR < CRITICAL ,个人认为该排序可能取决于各自级别的严重程度,级别错误越严重,那么它级别越大。

2.2、日志组件

日志文件的封装流程大致如下图所示👇

①Loggers记录器

提供应用程序的调用接口,其他py项目或文件可以调用该接口编写日志。Logger 也是一个树形层级结构,在设置等级之前必须创建 Logger 实例,即创建一个记录器,如果没有显式的进行创建,则默认创建一个 root logger ,相关设置均默认。

logger = logging.getLogger(logger_name)
#创建一个logger

创建 Logger 实例后,可以使用以下方法进行日志级别设置,增加处理器 Handler 。👇

logger.setLevel("ERROR") # 设置日志级别为ERROR,即只有日志级别大于等于ERROR的日志才会输出
logger.addHandler(handler_name) # 为Logger实例增加一个处理器
logger.removeHandler(handler_name) # 为Logger实例删除一个处理器

②Handler 处理器

Handler 处理器类型有很多种,本文介绍两个— StreamHandler 和 FileHandler

创建 Handler 之后,可以通过使用以下方法设置日志级别,设置格式化器 Formatter 

xx = logging.xxHandler() #xx为Stream或File
xx.setLevel(logging.WARN) # 指定日志级别,低于WARN级别的日志将被忽略
xx.setFormatter(formatter_name) # 设置一个格式化器formatter

③Formatter 格式化器

使用 Formatter 对象设置日志信息最后的规则、结构和内容,默认的时间格式为:%Y-%m-%d %H:%M:%S

formatter = logging.Formatter(fmt=None, datefmt=None)

其中,fmt 是消息的格式化字符串,datefmt 是日期字符串。如果不指明 fmt ,将使用'%(message)s'。如果不指明 datefmt ,将使用ISO8601日期格式。

注:Logger可以包含一个或多个Handler,即Logger与Handler是一对多的关系;一个Logger实例可以新增多个Handler,一个Handler可以新增多个格式化器,而且日志级别将会继承。

3、logging日志封装

本文采用 Logger.py 文件显示创建记录器Logger、处理器Handler和格式化器Formatter,并进行相关设置,Logger.py 文件👇

import logging
import time
import os

class Logger(object):

    def __init__(self,name=None):
        self.name = name
        #①创建一个记录器
        self.logger = logging.getLogger(self.name)
        self.logger.setLevel("INFO") # 设置日志级别为 'level',即只有日志级别大于等于'level'的日志才会输出
        self.formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") #创建formatter
        #②创建屏幕-输出到控制台,设置输出等级
        self.streamHandler = logging.StreamHandler()
        self.streamHandler.setLevel("DEBUG") 
        #③创建log文件,设置输出等级
        PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))  # 根目录
        time_now = time.strftime('%Y_%m%d_%H', time.localtime()) + '.log'  # log文件命名:2022_0402_21.log
        self.fileHandler = logging.FileHandler(os.path.join(PROJECT_ROOT, "Log", time_now), 'a', encoding='utf-8')
        self.fileHandler.setLevel("DEBUG")
        #④用formatter渲染这两个Handler
        self.streamHandler.setFormatter(self.formatter)
        self.fileHandler.setFormatter(self.formatter)
        #⑤将这两个Handler加入logger内
        self.logger.addHandler(self.streamHandler)
        self.logger.addHandler(self.fileHandler)

    def getLogger(self):
        return self.logger

具体操作在 Logger.py 文件内部有所讲解,简单的封装就是这样,至于更进一步的话可以考虑将方法里边的参数提取出来,放在常量文件或配置文件均可。

既然方法写完了,接下来试用一下~👇

if __name__ == "__main__":#检测日志打印效果
    logger = Logger('baseLogger.py').getLogger() #调用logger接口
    def div_calcul():
        try:
            result = 5 / 0
            print(result)
            logger.info("输出结果成功")
        except Exception as e:
            logger.error("[计算出错原因为:%s]" % e)
    div_calcul() #执行该方法,预期会报错

屏幕输出:

  log文件输出:

完成我们所要达到的目标!


参考文献

1、python日志:logging模块使用 - 知乎 (zhihu.com)

2、python logging模块使用教程 - 简书 (jianshu.com)