文章目录
- 一、基于 RotatingFileHandler 的自定义处理程序
- 二、基于 TimedRotatingFileHandler 的自定义处理程序
Python logging模块的基本使用、进阶使用详解
Python logging.handlers模块,RotatingFileHandler、TimedRotatingFileHandler 处理器各参数详细介绍
Python logging.config模块,logging.config.fileConfig()、logging.config.dictConfig() 使用介绍
python logging模块Filters过滤器介绍,如何使用自定义的过滤器
这篇文章将介绍如何在logging.config.dictConfig()
日志配置方式下,使用自定义的Handler
处理程序。
一、基于 RotatingFileHandler 的自定义处理程序
默认情况下,使用logging.handlers.RotatingFileHandler()
生成的备份文件,不是以.log
为后缀,例如:原日志文件为rotated.log
,那么生成的备份日志文件为rotated.log.xxx
,xxx
为数字。
接下来将使用自定义处理程序,将生成的备份日志文件的后缀改为rotated.xxx.log
rtfHandler.py
自定义处理程序模块
# -*- coding:utf-8 -*-
import logging
import logging.handlers
import os
import redef my_rotating_file_handler(filename,mode='a',maxBytes=0,backupCount=0,encoding=None,delay=False):rh = logging.handlers.RotatingFileHandler(filename,mode=mode,maxBytes=maxBytes,backupCount=backupCount,encoding=encoding,delay=delay)global bckCount # 声明全局变量,供 remove_old_log()、rotator() 方法使用bckCount = backupCount# 调用新实现的备份日志文件命名规则rh.rotator = rotatorrh.namer = namerreturn rhdef namer(name):# 在备份文件后增加 .log 后缀 name = name + '.log'return namedef rotator(source, dest):global dest_file # 声明全局变量,供 remove_old_log() 方法使用dest_file = destsp = dest.rsplit(".",3)sp.pop(1) # 删除备份文件中间的那个".log"# 因为改了备份日志文件名称规则,所以原有的备份规则失效了,下面是重写的备份规则for dst in range(bckCount,0,-1):sp[1] = str(dst)dest = ".".join(sp)if os.path.exists(dest):os.remove(dest)sp[1] = str(dst-1)src = ".".join(sp)if os.path.exists(src):os.rename(src,dest)sp[1] = str(1)dest = ".".join(sp)os.rename(source,dest)remove_old_log()# 因为改变了命名规则,所以重新实现了一个删除旧日志文件的方法
def remove_old_log():logdir = os.path.dirname(dest_file)fname = os.path.basename(dest_file)flist = os.listdir(logdir)fsplit = fname.rsplit(".",3)pattern = re.compile(r".".join([fsplit[0],"[0-9]+",fsplit[3]]))for f in flist:if re.match(pattern,f) and int(f.rsplit(".",2)[1]) > bckCount:fpath = os.path.join(logdir,f)os.remove(fpath)
rtfLog.yaml
日志配置文件,handlers.rtfhandler
下配置了一个自定义的处理程序
version: 1
disable_existing_loggers: false
formatters:simple:format: '[%(asctime)s - %(name)s - %(levelname)-8s] %(message)s'
handlers:console:class: logging.StreamHandlerformatter: simplelevel: DEBUGstream: ext://sys.stdoutrtfhandler:# 通过()键,引用一个自定义的处理程序# ext:// 用来告诉dicConfig(),它后面的config.rtfHandler.my_rotating_file_handler 是配置以外的对象(): ext://config.rtfHandler.my_rotating_file_handlerlevel: DEBUGformatter: simple# 下面的标量都是提供给自定义的处理程序方法的参数filename: rotated.logmode: amaxBytes: 40backupCount: 2encoding: utf8delay: False
loggers:mylogger:level: DEBUGhandlers: [console,rtfhandler]propagate: no
rtfLogger.py
封装日志模块,使用dictConfig()
读取日志配置文件以完成日志配置
# -*- coding:utf-8 -*-
import logging.config
import yaml
import osclass Logger():def __init__(self,logger_name=''):self.logger_name = logger_name# 获取当前文件所在目录cur_dir = os.path.dirname(__file__)# 拼接对应的yaml配置文件路径log_conf = os.path.join(cur_dir, 'logconf', 'rtflog.yaml')with open(log_conf, 'r', encoding='utf8') as f:config = yaml.safe_load(f.read())# 加载配置文件logging.config.dictConfig(config)def logger(self):logger = logging.getLogger(self.logger_name)return logger
main.py
主程序,测试日志功能
# -*- coding:utf-8 -*-
from config.rtfLogger import Logger
import timemlogger = Logger('mylogger').logger()for i in range(10):mlogger.info(f'Message no. {i + 1}')time.sleep(1)
运行main.py
程序,输出:
二、基于 TimedRotatingFileHandler 的自定义处理程序
默认情况下,使用logging.handlers.TimedRotatingFileHandler ()
生成的备份文件,不是以.log
为后缀,例如:原日志文件为timed_rotated.log
,那么生成的备份日志文件为timed_rotated.log.xxx
,xxx
为格式化的日期时间,如:2023-08-21_23-56-50
。
接下来将使用自定义处理程序,将生成的备份日志文件的后缀改为rotated.xxx.log
trfHandler.py
自定义处理程序模块
# -*- coding:utf-8 -*-
import logging
import logging.handlers
import os
import redef my_timed_rotating_file_handler(filename,when='h',interval=1,backupCount=0,encoding=None,delay=False,utc=False,atTime=None):global trfhtrfh = logging.handlers.TimedRotatingFileHandler(filename=filename,when=when,interval=interval,backupCount=backupCount,encoding=encoding,delay=delay,utc=utc,atTime=atTime)trfh.rotator = rotatortrfh.namer = namerreturn trfhdef namer(name):name = name + '.log'return name# 重新定义了备份文件命名规则
def rotator(source, dest):fsp = dest.rsplit(".",3)fsp.pop(1)dest = ".".join(fsp)os.rename(source,dest)remove_old_log(trfh)# 重新定义了旧备份文件删除规则
def remove_old_log(trfh):logdir = os.path.dirname(trfh.baseFilename)fname = os.path.basename(trfh.baseFilename)pattern = re.compile(fname.rsplit(".",1)[0] + "\." + trfh.extMatch.pattern[1:],re.ASCII)flist = os.listdir(logdir)loglist = []for f in flist:if re.match(pattern,f):loglist.append(f)loglist.sort(reverse=True)backupCount = trfh.backupCountlog_to_remove = loglist[backupCount:] if len(loglist) > backupCount else []for ltr in log_to_remove:os.remove(os.path.join(logdir,ltr))
trfLog.yaml
日志配置文件,handlers.trfhandler
下配置了一个自定义的处理程序
version: 1
disable_existing_loggers: false
formatters:simple:format: '[%(asctime)s - %(name)s - %(levelname)-8s] %(message)s'
handlers:console:class: logging.StreamHandlerformatter: simplelevel: DEBUGstream: ext://sys.stdouttrfhandler:# 通过()键,引用一个自定义的处理程序# ext:// 用来告诉dicConfig(),它后面的config.rtfHandler.my_rotating_file_handler 是配置以外的对象(): ext://config.trfHandler.my_timed_rotating_file_handlerlevel: DEBUGformatter: simple# 下面的标量都是提供给自定义的处理程序方法的参数filename: timed_rotated.logwhen: Sinterval: 2backupCount: 2encoding: utf8delay: Falseutc: FalseatTime: None
loggers:mylogger:level: DEBUGhandlers: [console,trfhandler]propagate: no
trfLogger.py
封装日志模块,使用dictConfig()
读取日志配置文件以完成日志配置
# -*- coding:utf-8 -*-
import logging.config
import yaml
import osclass Logger():def __init__(self,logger_name=''):self.logger_name = logger_namecur_dir = os.path.dirname(__file__)log_conf = os.path.join(cur_dir, 'logconf', 'trflog.yaml')with open(log_conf, 'r', encoding="utf8") as f:config = yaml.safe_load(f.read())logging.config.dictConfig(config)def logger(self):logger = logging.getLogger(self.logger_name)return logger
main.py
主程序,测试日志功能
# -*- coding:utf-8 -*-
import logging
from config.trfLogger import Logger
import timemlogger = Logger('mylogger').logger()for i in range(10):mlogger.info(f'Message no. {i + 1}')time.sleep(1)
运行main.py
程序,输出:
参考资料:
using-a-rotator-and-namer-to-customize-log-rotation-processing
customizing-handlers-with-dictconfig
logging-config-dict-externalobj