TimedRotatingFileHandler 修改 suffix 后 backupCount 设置失效无法自动删除文件

news2024/11/25 22:43:08

本文主要分析 TimedRotatingFileHandler 在实际使用中 backupCount 设置未生效的问题。源码分析显示,文件删除依赖于后缀 suffix 的正则匹配,如果自定义了 suffix 格式,必须同步更新 extMatch 的正则表达式(保证正则表达式可以正常匹配到你新格式的日志文件)。

现象

本文为了测试日志轮转删除,将轮转间隔设为秒(S),设置文件的 backupCount 为 5,同时设置新的日志文件后缀格式为 %Y%m%d%H%M%S.log。

示例如下:

import logging
import os
from logging import handlers

os.makedirs("./logs", exist_ok=True)


def _logging(**kwargs):
    level = kwargs.pop('level', logging.DEBUG)
    filename = kwargs.pop('filename', 'default.log')
    datefmt = kwargs.pop('datefmt', '%Y-%m-%d %H:%M:%S')
    format = kwargs.pop('format', '[%(asctime)s,%(msecs)d][%(module)s][%(levelname)s] %(message)s')

    log = logging.getLogger(filename)
    format_str = logging.Formatter(format, datefmt)

    th = handlers.TimedRotatingFileHandler(filename=filename, when='S', backupCount=5, encoding="utf-8")
    th.suffix = "%Y%m%d%H%M%S.log"
    th.setFormatter(format_str)
    th.setLevel(level)

    log.addHandler(th)
    log.setLevel(level)
    return log


if __name__ == '__main__':
    logger = _logging(filename="./logs/test.log")
    logger.info("Hello world")

然而运行几遍以后,发现产生的日志文件个数已经远远超过了设置的 backupCount 的个数,但旧日期的日志文件却始终没有被删除。

原因

查看源码发现,文件删除依赖于suffix 正则匹配。

而 S 秒默认对应的 extMatch 是下面这个:

extMatch = r"^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}(\.\w+)?$"

 默认的 extMatch 和新的后缀格式匹配不上,导致没有轮滚删除旧的文件。

解决

原因明了以后,解决方案也就明朗了。

设置新的匹配新日志格式的正则表达式就可以了(因为是初始化以后再进行的 extMatch 替换,所以替换时需要先对正则表达式的字符串用 re.compile 进行编译):

extMatch = re.compile(r"^\d{4}\d{2}\d{2}\d{2}\d{2}\d{2}(\.\w+)?$", re.ASCII)

完整示例如下: 

import logging
import os
import re
from logging import handlers

os.makedirs("./logs", exist_ok=True)


def _logging(**kwargs):
    level = kwargs.pop('level', logging.DEBUG)
    filename = kwargs.pop('filename', 'default.log')
    datefmt = kwargs.pop('datefmt', '%Y-%m-%d %H:%M:%S')
    format = kwargs.pop('format', '[%(asctime)s,%(msecs)d][%(module)s][%(levelname)s] %(message)s')

    log = logging.getLogger(filename)
    format_str = logging.Formatter(format, datefmt)

    th = handlers.TimedRotatingFileHandler(filename=filename, when='S', backupCount=5, encoding="utf-8")
    th.suffix = "%Y%m%d%H%M%S.log"
    th.extMatch = re.compile(r"^\d{4}\d{2}\d{2}\d{2}\d{2}\d{2}(\.\w+)?$", re.ASCII)
    th.setFormatter(format_str)
    th.setLevel(level)

    log.addHandler(th)
    log.setLevel(level)
    return log


if __name__ == '__main__':
    logger = _logging(filename="./logs/test.log")
    logger.info("Hello world")

这个时候,产生的日志文件就可以正常轮转删除了。

日志脱敏

哈哈,再顺便来个日志脱敏的小函数,可以指定要脱敏的字段,会将对应字段的 value 替换为等长度的 * 字符串。

logger.py

import copy
import json
import logging
import os
import re
import traceback
from logging import handlers

os.makedirs("./logs", exist_ok=True)


def _logging(**kwargs):
    level = kwargs.pop('level', logging.DEBUG)
    filename = kwargs.pop('filename', 'default.log')
    datefmt = kwargs.pop('datefmt', '%Y-%m-%d %H:%M:%S')
    format = kwargs.pop('format', '[%(asctime)s,%(msecs)d][%(module)s][%(levelname)s] %(message)s')

    log = logging.getLogger(filename)
    format_str = logging.Formatter(format, datefmt)

    th = handlers.TimedRotatingFileHandler(filename=filename, when='S', backupCount=5, encoding="utf-8")
    th.suffix = "%Y%m%d%H%M%S.log"
    th.extMatch = re.compile(r"^\d{4}\d{2}\d{2}\d{2}\d{2}\d{2}(\.\w+)?$", re.ASCII)
    th.setFormatter(format_str)
    th.setLevel(level)

    log.addHandler(th)
    log.setLevel(level)
    return log


def do_desensitization(data, flags: list):
    data = copy.copy(data)
    try:
        if not isinstance(data, str):
            data = json.dumps(data, ensure_ascii=False)  # 非字符串类型数据都先统一转 json 字符串处理
        for flag in flags:
            match_pattern = f'([\'|\"]{flag}[\'|\"].*?:.*?[\'|\"](.*?)[\'|\"])'
            res = re.findall(match_pattern, data)
            for item in res:
                full_match = item[0]  # 获取全匹配结果
                value_match = item[1]  # 获取 value 匹配结果
                value_desensitization = '*' * len(value_match)  # 构造等长字符串
                full_match_desensitization = full_match.replace(value_match, value_desensitization)  # 脱敏替换
                data = data.replace(full_match, full_match_desensitization)  # 脱敏替换
        return data
    except Exception as e:
        traceback.print_exc()
        return data


if __name__ == '__main__':
    logger = _logging(filename="./logs/test.log")
    logger.info("Hello world")
    data = {'name': "Looking", "key": "value", 'test': {"name": "test name", "new_key": "new_value"}}
    result = do_desensitization(data, ["name", "key"])
    logger.info(result)

test.log

[2024-09-12 19:06:08,24][logger][INFO] Hello world
[2024-09-12 19:06:08,25][logger][INFO] {"name": "*******", "key": "*****", "test": {"name": "*********", "new_key": "new_value"}}

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

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

相关文章

国庆出游季,南卡Runner Pro5骨传导耳机让旅途更完美!

国庆长假将至,无论是计划一场远行还是近郊的户外活动,一款适合的耳机都能让旅途更加愉快。南卡Runner Pro5骨传导耳机以其独特的设计和功能,成为了国庆出行的理想伴侣。 首先,骨传导耳机通过颅骨传递声音,避免了传统耳…

从理论到实战:人才培养基地如何缩短职场适应期?

在当今竞争激烈的职场环境中,从校园到职场的过渡对于许多新人来说充满挑战。而人才培养基地正以其独特的方式,努力缩短这一职场适应期。 人才培养基地首先注重理论与实践的结合。不再是单纯的知识灌输,而是将理论教学与实际操作紧密相连。 实…

JAVA——方法重载

方法的重载:多个方法在同一个类,方法名相同,参数/参数类型/参数数量不同 返回值不能作为重载条件 public class demo9_12_2 {public static void main(String[] args) {//调用,方法的签名getMax();getMax(10);getMax(10.9F);}//…

如何在Word中复制整页内容并保持原有格式不变?

在日常处理工作时,我们经常需要在Word文档中复制和粘贴内容,特别是在处理报告方案等文档时,保持复制内容的格式不变显得尤为重要。本文将详细介绍如何在Word中复制整页内容并保持原有格式不变,确保文档的整洁性和一致性。 方法一&…

修改jupyter notebook 默认浏览器(不动配置文件,改系统默认浏览器)

最开始把联想浏览器切到EDGE就是用的修改系统的默认浏览器。不知怎么的现在搜到的方法都是在说修改配置文件😓。 不想动配置文件,平时对默认浏览器没有特殊要求的,可以用这个方法。 这里是把默认浏览器改成联想浏览器,电脑也是联…

【学习笔记】SSL密码套件的选择

往期介绍了TLS/SSL中4种密码套件,分别是Key Exchang、Authentication、Encryption和Hashing,每种密码套件下又包含多种协议。 当我们部署SSL证书时,我们需要选择自己支持哪种密码套件。我们可能想要用最安全的,但我们的潜在客户可…

一文弄懂FLink状态及checkpoint源码

一文弄懂Flink重要源码 1. Flink 状态源码1.1 valueState源码1.1.1 Update方法1.1.2 Value 方法 2. checkPoint 源码分析2.1 SourceStreamTask的checkpoint实现2.1.1 JobManager端checkpoint调度2.1.2 ScheduledTrigger定时触发checkpoint2.1.3 SourceStreamTask的Checkpoint执…

搭建 WordPress 及常见问题与解决办法

浪浪云活动链接 :https://langlangy.cn/?i8afa52 文章目录 环境准备安装 LAMP 堆栈 (Linux, Apache, MySQL, PHP)配置 MySQL 数据库 安装 WordPress配置 WordPress常见问题及解决办法数据库连接错误白屏问题插件或主题冲突内存限制错误 本文旨在介绍如何在服务器上…

推荐一款非常强大的表单校验库:React Hooks Form

React Hooks Form react-hook-form 是一个专注于管理 React 表单状态的库。它的核心理念是利用 React Hooks 来简化表单的处理过程。与其他表单管理库相比,它的优势在于性能和简洁性。它不需要在每次输入更改时重新渲染整个表单组件,从而提高了性能。 …

茶百道三天市值抹去三分之一:新茶饮脱下“皇帝的新装”

近日,随着港股通标的调整生效,茶百道获纳入的消息传出后,股价不升反降,单日跌幅之大引发热议。 9月10日至12日,茶百道在三个交易日内累计下跌36%,股价屡创上市以来新低。其中,9月11日单日跌幅更…

【强化学习系列】Gym库使用——创建自己的强化学习环境1:单一环境创建测试

目录 一、Gym类创建单一环境 1.gym类初始化 __init__() 2.gym类初始状态 reset() 3.gym类渲染可视化 render() 4.gym类运行核心 step() 5.gym类运行 在强化学习中实操中,有两个非常重要的设计模块,一个是模型网络和算法的设计,另一个则是用于…

计算机毕业设计选题推荐-学生在线投票系统-Java/Python项目实战(亮点:数据可视化分析、找回密码)

✨作者主页:IT研究室✨ 个人简介:曾从事计算机专业培训教学,擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Python…

UML-统一建模语言学习笔记20240912

UML入门 一、软件开发基础知识: 1.软件开发的生命周期,包括需求分析,设计,实现,测试和维护等阶段。 2.面向对象的编程(OOP):UML 是一种用于描述面向对象系统的语言,需要…

这么好用的电脑桌面美化工具 你怎么能错过她?

芝麻时钟是一个功能强大的桌面时钟软件,它具有多种实用功能,包括桌面时钟、时钟屏保、任务栏时钟和桌面日历等。这个软件不仅提供了丰富的主题和美观的界面,更重要的是它的实用性和特色功能。(下载地址:https://clock.zhimasoft.c…

计算机网络 ---- OSI参考模型TCP/IP模型

目录 一、OSI参考模型 1.1 学习路线 1.2 OSI参考模型和TCP/IP模型 1.3 具体设备与具体层次对应关系 1.3.1 物理层 1.3.2 数据链路层 1.3.3 网络层 1.3.4 传输层 1.3.5 会话层、表示层、应用层 1.4 各层次数据传输单位 二、TCP/IP模型 2.1 学习路线 2.2 TCP/I…

源代码防泄密软件的五大特点

在数据防泄密领域,深信达的SDC沙盒软件以其独特的技术和创新应用,为源代码安全提供了强有力的保护。特别是在源代码防泄密方面,SDC沙盒表现出色,其实现方式主要包括以下几个方面: 1. **内核级虚拟沙盒技术**&#xff1…

QT学习参考书籍

6.2 Qt参考书籍资料 6.2.1 《Qt C编程从入门到实战》 主编:彭源 6.2.2 《Qt 5编程入门 第2版》编著:程梁 霍亚飞 6.2.3 《嵌入式Qt开发项目教程》编著:王浩 著 王浩 6.2.4 《Qt Quick核心编程》编著:安晓辉 6.2.5《零基础学Qt 4编程》 作者:吴迪著 6.2.6 《C并发编程实战(第2版…

【Python机器学习】循环神经网络(RNN)——超参数

几乎所有模型都可以根据数据和样本进行调整,它们都有各自的优势和相应的利弊权衡方式。寻找最优超参数集通常是一个棘手的问题,但是人类的直觉和经验可以为我们提供解决问题的方法。比如之前的例子: #设置任意输入序列的最大长度 maxlen100 …

论文笔记:基于LLM和多轮学习的漫画零样本角色识别与说话人预测

整理了ACM MM2024 Zero-Shot Character Identification and Speaker Prediction in Comics via Iterative Multimodal Fusion)论文的阅读笔记 背景模型框架实现细节 模型数据集实验可视化消融实验 背景 最近读到一篇新文章,主要是做漫画中的零样本角色识…

Linux中限制服务如mysql的最大cpu使用率

1、cpu占用测试&#xff1a; DELIMITER // DROP PROCEDURE IF EXISTS intensive_calculations; CREATE PROCEDURE intensive_calculations() BEGINDECLARE v INT DEFAULT 0;DECLARE i INT DEFAULT 0;WHILE i < 1000000 DOSET v SQRT(i * i (RAND() * 10000));SET i i 1…