Python 在logging.config.dictConfig()日志配置方式下,使用自定义的Handler处理程序

news2024/12/23 14:10:32

文章目录

    • 一、基于 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.xxxxxx为数字。

接下来将使用自定义处理程序,将生成的备份日志文件的后缀改为rotated.xxx.log

rtfHandler.py 自定义处理程序模块

# -*- coding:utf-8 -*-
import logging
import logging.handlers
import os
import re

def 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 = rotator
    rh.namer = namer

    return rh

def namer(name):
	# 在备份文件后增加 .log 后缀 
    name = name + '.log'
    return name

def rotator(source, dest):
    global dest_file	# 声明全局变量,供 remove_old_log() 方法使用
    dest_file = dest
    sp = 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.StreamHandler
    formatter: simple
    level: DEBUG
    stream: ext://sys.stdout
  rtfhandler:
    # 通过()键,引用一个自定义的处理程序
    # ext:// 用来告诉dicConfig(),它后面的config.rtfHandler.my_rotating_file_handler 是配置以外的对象
    (): ext://config.rtfHandler.my_rotating_file_handler
    level: DEBUG
    formatter: simple
    # 下面的标量都是提供给自定义的处理程序方法的参数
    filename: rotated.log
    mode: a
    maxBytes: 40
    backupCount: 2
    encoding: utf8
    delay: False
loggers:
  mylogger:
    level: DEBUG
    handlers: [console,rtfhandler]
    propagate: no

rtfLogger.py 封装日志模块,使用dictConfig()读取日志配置文件以完成日志配置

# -*- coding:utf-8 -*-
import logging.config
import yaml
import os

class 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 time

mlogger = 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.xxxxxx为格式化的日期时间,如:2023-08-21_23-56-50

接下来将使用自定义处理程序,将生成的备份日志文件的后缀改为rotated.xxx.log

trfHandler.py 自定义处理程序模块

# -*- coding:utf-8 -*-
import logging
import logging.handlers
import os
import re

def my_timed_rotating_file_handler(filename,when='h',interval=1,backupCount=0,encoding=None,delay=False,utc=False,atTime=None):

    global trfh

    trfh = logging.handlers.TimedRotatingFileHandler(
        filename=filename,
        when=when,
        interval=interval,
        backupCount=backupCount,
        encoding=encoding,
        delay=delay,
        utc=utc,
        atTime=atTime
    )

    trfh.rotator = rotator
    trfh.namer = namer

    return trfh

def 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.backupCount

    log_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.StreamHandler
    formatter: simple
    level: DEBUG
    stream: ext://sys.stdout
  trfhandler:
    # 通过()键,引用一个自定义的处理程序
    # ext:// 用来告诉dicConfig(),它后面的config.rtfHandler.my_rotating_file_handler 是配置以外的对象
    (): ext://config.trfHandler.my_timed_rotating_file_handler
    level: DEBUG
    formatter: simple
    # 下面的标量都是提供给自定义的处理程序方法的参数
    filename: timed_rotated.log
    when: S
    interval: 2
    backupCount: 2
    encoding: utf8
    delay: False
    utc: False
    atTime: None
loggers:
  mylogger:
    level: DEBUG
    handlers: [console,trfhandler]
    propagate: no

trfLogger.py 封装日志模块,使用dictConfig()读取日志配置文件以完成日志配置

# -*- coding:utf-8 -*-
import logging.config
import yaml
import os

class Logger():

    def __init__(self,logger_name=''):
        self.logger_name = logger_name
        cur_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 time

mlogger = 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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/910134.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

pandas连接查询

df1数据如下 df2数据如下 连接查询代码 -1 import pandas as pddf1 pd.DataFrame({id:[1001,1002,1003,1004],name:[Hu,Dotu,Evp,Swe]}) df2 pd.DataFrame({id:[1001,1001,1003,1004, 1003],course:[c1,c2,c3,c2,c1],score:[100, 98, 64, 84, 69]})result pd.merge(df1, df…

【C++初阶】vector容器

👦个人主页:Weraphael ✍🏻作者简介:目前学习C和算法 ✈️专栏:C航路 🐋 希望大家多多支持,咱一起进步!😁 如果文章对你有帮助的话 欢迎 评论💬 点赞&#x1…

0007Java程序设计-jsp问卷调查系统设计与实现

摘 要 随着社会不断进步与发展,生活节奏不断加快,信息已经成为我们生活中不可缺少的一部分,很多企业需要掌握大量的信息来了解特定用户的需求,传统的做法是组织大量的人力物力对用户散发调查表,然后对收集的信息进行统…

python 基础篇 day 1 初识变量和数据类型

文章目录 变量变量作用——用于存储和表示数据。变量命名规则命名法大驼峰小驼峰下划体n j i a x 通常作为临时变量使用 建议 变量种类全局变量(Global Variables)局部变量(Local Variables)静态变量(Static Variables…

linux常用基础命令与文件结构汇总

1 学习目标 说出Linux下的目录结构和常见目录的作用熟练使用Linux下的相对路径和绝对路径熟练使用Linux下常用文件和目录操作相关的命令熟练使用修改用户权限、用户和用户组相关的命令熟练使用文件的查找和检索相关的命令熟练掌握Ubuntu下的软件安装和卸载熟练使用压缩工具完成…

七夕节日表白:七大网页风格与其适用人群

🌷🍁 博主猫头虎 带您 Go to New World.✨🍁 🦄 博客首页——猫头虎的博客🎐 🐳《面试题大全专栏》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺 &a…

YOLOv5源码中的参数超详细解析(5)— 验证部分val(test).py

前言:Hello大家好,我是小哥谈。YOLOv5项目代码中,val.py 是一个代表验证(validation)的 Python 脚本文件名。通常在机器学习或深度学习的任务中,我们会将数据集分为训练集和验证集,使用训练集来…

请说人话!如何理解基本分页存储管理

一、默认设定 (一)按字节编制一个房间可以装8只猪猪 现在的计算机一般都是按字节编址的。这个不理解的话,可以看我的文章为什么20位地址总线决定寻址空间是1MB“http://t.csdn.cn/Eo2nE” (二)内存采用非连续分配方…

法线矩阵推导

法线矩阵推导 https://zhuanlan.zhihu.com/p/72734738 https://juejin.cn/post/7113952418613690382 https://blog.csdn.net/wangjianxin97?typeblog 1、为什么需要法线矩阵 vec3 normalEyeSpace modelViewMatrix * normal;如果模型矩阵执行了非等比缩放, 顶点的改变会导致法…

基于蝴蝶算法优化的BP神经网络(预测应用) - 附代码

基于蝴蝶算法优化的BP神经网络(预测应用) - 附代码 文章目录 基于蝴蝶算法优化的BP神经网络(预测应用) - 附代码1.数据介绍2.蝴蝶优化BP神经网络2.1 BP神经网络参数设置2.2 蝴蝶算法应用 4.测试结果:5.Matlab代码 摘要…

sNMFcross-entropyK

0.简单介绍 稀疏非负矩阵(sNMF)和最小二乘优化来产生祖先比例估计数的祖先推断算法,这个算法呢与admixture来说差别不是很大,但是优点就是快,运算速度可以快到10-30倍左右。 1.安装 这一步不必多说,下载…

tailscale使用教程(远程连接服务器)

tailscale:将多个设备放在同一局域网下,实现异地组网。 首先进入tailscale官网,根据系统需求进行下载 需要远程的设备和被远程的设备都需要下载。 然后两个设备均登录同一账号即可 注:这里重点讲一下linux操作系统上的操作&…

PID输出PWM温度控制(PID输出PWM的各种方法介绍)

这篇博客主要介绍PID的输出如何和PWM输出进行绑定,PID控制算法和源代码大家自行查看PID专栏,这里不再赘述。常用链接如下: 位置式PID(S7-200SMART 单自由度、双自由度梯形图源代码)_RXXW_Dor的博客-CSDN博客有关位置型PID和增量型PID的更多详细介绍请参看PID专栏的相关文章…

读SQL学习指南(第3版)笔记02_数据类型

1. 命令行工具 1.1. mysql -u root -p; 1.2. mysql> show databases; 1.3. mysql> use sakila; 1.4. mysql> SELECT now(); 1.4.1. now()是MySQL的内建函数 1.4.2. 返回当前日期和时间 1.5. mysql> SELECT now() FROM dual…

DFT计算入门新手坑:能带不连续

新手在学习DFT计算时,在熟悉了基本的操作和VASP输入文件后,首先就会学习到结构优化、自洽计算和能带的计算。 而笔者学习DFT计算这些年来看到太多新手学者踩到大大小小的坑,其中能带看起来不连续或者能带不连续则是几乎必踩的坑之一。 这些初…

【HCIP】04.VRRP与BFD

VRRP VRRP基本概念 VRRP路由器 运行VRRP协议的路由器,VRRP是配置在路由器的接口上的,而且也是基于接口来工作的。 VRID 一个VRRP组由多台协同工作的路由器(的接口)组成,使用相同的VRID(Virtual Router…

Spring统一功能处理

1. AOP存在的问题 获取参数复杂AOP的规则相对简单 2. 拦截器 2.1. 应用(以登录为例) 2.1.1. 自定义拦截器 新建interceptor文件夹 import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest; import javax.servlet.http…

Blend for Visual Studio:提升用户界面设计的专业工具

随着软件行业的迅速发展,用户界面设计变得越来越重要。一个好的用户界面能够吸引用户的注意力,提供良好的用户体验,并增加应用程序的成功率。在这个背景下,Blend for Visual Studio作为一款专业的用户界面设计工具,为开…

SpringCloud学习笔记(二)_Eureka注册中心

一、Eureka简介 Eureka是一项基于REST(代表性状态转移)的服务,主要在AWS云中用于定位服务,以实现负载均衡和中间层服务器的故障转移。我们称此服务为Eureka Server。Eureka还带有一个基于Java的客户端组件Eureka Client&#xff…

从电子表格到纸张:Excel转PDF的神奇变身之旅!

当你需要将Excel文件转换为PDF时,可以使用Python编程语言和一些流行的库来实现这个任务。在本篇博客中,我将介绍如何使用wxPython、pandas和PyMuPDF库创建一个简单易用的图形用户界面(GUI)工具来完成这项工作。 C:\pythoncode\new\excelexportpdf.py …