python3实现整时刻日志文件分离的Handler

文章目录

  • 整时刻日志文件分离的Handler

整时刻日志文件分离的Handler

logging 自带的 handlers

  • RotatingFileHandler:日志文件到达设置的大小阈值后分离
  • TimedRotatingFileHandler:日志文件到达指定的间隔时分离

这些都不满足到达某个整点时刻时进行分离(TimedRotatingFileHandler 是从启动开始计算间隔,唯一支持的整点也只是 midnightW{0-6}这两个配置项,不能自己设置固定的时间点)

logging.handlers 中有 BaseRotatingHandler,是 RotatingFileHandlerTimedRotatingFileHandler 的父类

基本逻辑是:

  • emit 函数会调用 shouldRollover 来判断当前 record(日志消息对象) 是否应该切换日志文件,如果需要切换那么调用 doRollover 进行切换

  • rotation_filename:调用 namer 来修改所给的文件名(namer 用来加上前缀后缀的部分

  • rotate:将所给的文件和当前的文件进行交换

只需要对 TimedRotatingFileHandler 进行部分修改就能实现功能:

  • 支持秒、分、时、天的间隔设置(需要在每个时间间隔内有日志信息输出才能分离)
    • 如果设置 10秒间隔,那么就是一分钟内的第10s、20s、30s…时分离日志
    • 如果设置 5 分钟间隔,那么就是一小时内的第5min、10min、15min…时分离日志
    • 如果设置为 1 天间隔,那么就是一天的24点进行分离
import datetime
import logging.handlers
import os
import re
import time
from stat import ST_MTIME


class HourRotationFileHandler(logging.handlers.BaseRotatingHandler):

    def __init__(
        self,
        filename: str,
        interval=1,
        unit: str = "H",
        backupCount=0,
        utc=False,
        encoding=None,
        delay=False,
        errors=None,
    ):
        """

        :param filename: 日志文件名
        :param interval: 两次输出日志的间隔
        :param unit: 单位
        :param backupCount: 最多保留日志文件数量
        :param utc: 日志名称的时间部分是否使用 utc 时区格式
        :param encoding: 日志文件的编码
        :param delay:
        :param errors:
        """
        logging.FileHandler.__init__(self, filename, "a", encoding, delay, errors)
        self.backupCount = backupCount
        self.unit = unit.lower()
        # second
        if self.unit == "second":
            self.interval = 1
            self.suffix = "%Y-%m-%d_%H-%M-%S"
            self.extMatch = r"^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}(\.\w+)?$"
        # minute
        elif self.unit == "minute":
            self.interval = 60
            self.suffix = "%Y-%m-%d_%H-%M"
            self.extMatch = r"^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}(\.\w+)?$"
        # hour
        elif self.unit == "hour":
            self.interval = 60 * 60
            self.suffix = "%Y-%m-%d_%H"
            self.extMatch = r"^\d{4}-\d{2}-\d{2}_\d{2}(\.\w+)?$"
        # day
        elif self.unit == "day":
            self.interval = 60 * 60 * 24
            self.suffix = "%Y-%m-%d"
            self.extMatch = r"^\d{4}-\d{2}-\d{2}(\.\w+)?$"
        else:
            raise ValueError("Invalid rollover interval specified: %s" % self.unit)

        self.extMatch = re.compile(self.extMatch, re.ASCII)
        self.interval = self.interval * interval
        self.utc = utc

        # 获取当前时区的本地时间
        local_now = datetime.datetime.now(datetime.timezone.utc).astimezone()
        # 获取本地时间相对于UTC的偏移量
        self.tz_offset = local_now.utcoffset().total_seconds()

        filename = self.baseFilename
        if os.path.exists(filename):
            t = os.stat(filename)[ST_MTIME]
        else:
            t = int(time.time())

        self.rolloverAt = self.computeRollover(t)

    def computeRollover(self, currentTime):
        """
        计算下次需要分离的时间
        """
        # 计算当前所在的间隔区间 [startTime, endTime)
        if self.unit == 'day':
            # 一天的开始应该是0点
            startTime = currentTime - (currentTime % self.interval) - self.tz_offset
        else:
            startTime = currentTime - (currentTime % self.interval)
        endTime = startTime + self.interval
        return endTime

    def shouldRollover(self, record):
        """
        判断是否需要分离
        """
        t = int(time.time())
        if t >= self.rolloverAt:
            # 目标日志文件不是一个文件,选择不写入
            if os.path.exists(self.baseFilename) and not os.path.isfile(
                self.baseFilename
            ):
                self.rolloverAt = self.computeRollover(t)
                return False

            return True
        return False

    def getFilesToDelete(self):
        """
        当文件分离时,需要删除的日志文件
        """
        dirName, baseName = os.path.split(self.baseFilename)
        fileNames = os.listdir(dirName)
        result = []
        n, e = os.path.splitext(baseName)
        prefix = n + "."
        plen = len(prefix)
        for fileName in fileNames:
            if self.namer is None:
                # Our files will always start with baseName
                if not fileName.startswith(baseName):
                    continue
            else:
                # Our files could be just about anything after custom naming, but
                # likely candidates are of the form
                # foo.log.DATETIME_SUFFIX or foo.DATETIME_SUFFIX.log
                if (
                    not fileName.startswith(baseName)
                    and fileName.endswith(e)
                    and len(fileName) > (plen + 1)
                    and not fileName[plen + 1].isdigit()
                ):
                    continue

            if fileName[:plen] == prefix:
                suffix = fileName[plen:]
                # See bpo-45628: The date/time suffix could be anywhere in the
                # filename
                parts = suffix.split(".")
                for part in parts:
                    if self.extMatch.match(part):
                        result.append(os.path.join(dirName, fileName))
                        break
        if len(result) < self.backupCount:
            result = []
        else:
            result.sort()
            result = result[: len(result) - self.backupCount]
        return result

    def doRollover(self):
        # 关闭当前流
        if self.stream:
            self.stream.close()
            self.stream = None

        # 时间
        currentTime = int(time.time())
        dstNow = time.localtime(currentTime)[-1]

        # 左区间的端点
        t = self.rolloverAt - self.interval
        if self.utc:
            timeTuple = time.gmtime(t)
        else:
            timeTuple = time.localtime(t)
            dstThen = timeTuple[-1]
            if dstNow != dstThen:
                if dstNow:
                    addend = 3600
                else:
                    addend = -3600
                timeTuple = time.localtime(t + addend)

        # 创建替换的文件,替换当前的文件
        dfn = self.rotation_filename(
            self.baseFilename + "." + time.strftime(self.suffix, timeTuple)
        )
        if os.path.exists(dfn):
            os.remove(dfn)
        self.rotate(self.baseFilename, dfn)

        # 删除多的日志文件
        if self.backupCount > 0:
            for s in self.getFilesToDelete():
                os.remove(s)

        if not self.delay:
            self.stream = self._open()

        # 计算新的切换时间
        newRolloverAt = self.computeRollover(currentTime)

        while newRolloverAt <= currentTime:
            newRolloverAt = newRolloverAt + self.interval

        # If DST changes and midnight or weekly rollover, adjust for this.
        if not self.utc:
            dstAtRollover = time.localtime(newRolloverAt)[-1]
            if dstNow != dstAtRollover:
                if (
                    not dstNow
                ):  # DST kicks in before next rollover, so we need to deduct an hour
                    addend = -3600
                else:  # DST bows out before next rollover, so we need to add an hour
                    addend = 3600
                newRolloverAt += addend

        self.rolloverAt = newRolloverAt

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ICCV 2021 | FcaNet: Frequency Channel Attention Networks 中的频率分析

ICCV 2021 | FcaNet: Frequency Channel Attention Networks 中的频率分析 论文&#xff1a;https://arxiv.org/abs/2012.11879代码&#xff1a;https://github.com/cfzd/FcaNet 文章是围绕 2D 的 DCT 进行展开的&#xff0c;本文针对具体的计算逻辑进行梳理和解析。 f ( u ,…

【MySQL精炼宝库】数据库的约束 | 表的设计 | 聚合查询 | 联合查询

目录 一、数据库约束 1.1 约束类型&#xff1a; 1.2 案例演示&#xff1a; 二、表的设计 2.1 一对一: 2.2 一对多: 2.3 多对多: 2.4 内容小结&#xff1a; 三、新增 四、查询 4.1 聚合查询&#xff1a; 4.1.1 聚合函数&#xff1a; 4.1.2 GROUP BY子句&#xff1a…

linux使用docker 安装mysql redis

linux安装docker https://hub-stage.docker.com/ 前往这里搜索容器来部署。每个容器都有独立的运行环境。 具体安装教程 https://docs.docker.com/engine/install/centos/#install-using-the-repository 检查是否安装成功&#xff1a; sudo docker --version 配置国内镜像加速…

人脸识别概念解析

目录 1. 概述 2. 人脸检测 3. 人脸跟踪 4. 质量评价 5. 活体检测 6. 特征提取 7. 人脸验证 8. 人脸辨识 1. 概述 人脸识别在我们的生活中随处可见&#xff0c;例如在大楼门禁系统中&#xff0c;它取代了传统的门禁卡或密码&#xff0c;提高了进出的便捷性和安全性。在商…

Adfind的使用

Adfind是一个使用C语言写的活动目录查询工具&#xff0c;它允许用户轻松地搜索各种活动目录信息。它不需要安装&#xff0c;因为它是基于命令行的。它提供了许多选项&#xff0c;可以细化搜索并返回相关细节。下面讲解Adfind的参数以及其使用。 参数 执行如下命令即可查看Adf…

ruoyi-nbcio-plus基于vue3的flowable为了适配文件上传改造VForm3的代码记录

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 http://218.75.87.38:9666/ 更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码&#xff1a; h…

Flutter笔记:DefaultTextStyle和DefaultTextHeightBehavior解读

Flutter笔记 DefaultTextStyle和DefaultTextHeightBehavior解读 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this article:htt…

PriorityQueue—优先级队列FollowUp

FollowUp大纲&#xff1a; 思维导图&#xff1a; FollowUp PriorityQueue: Q1&#xff1a;但不知道是大根堆化石小根堆 A&#xff1a;Q1 只需要放进去几个元素peek&#xff08;&#xff09;出元素是大的还是小的 下面如果是5就是小根堆10就是大根堆 A&#xff1a;默认是小根…

Github创建远程仓库(项目)

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

OPPO Reno10Pro/Reno11/K10手机强解BL刷root权限KSU内核抓包刷机救砖

OPPO Reno10Pro/Reno11/K10手机虽然发布时间并不久&#xff0c;但由于天玑处理器的体质&#xff0c;已经支持强制解锁BL了&#xff0c;该漏洞来自第三方工具适配&#xff0c;支持OPPO天机8100/8200刷机救砖解锁BL不需要等待官方深度测试直接实现。解锁BL后的OPPO Reno10Pro/Ren…

华为ensp中BGP(边界网关协议)基础原理及配置命令

作者主页&#xff1a;点击&#xff01; ENSP专栏&#xff1a;点击&#xff01; 创作时间&#xff1a;2024年4月27日10点04分 BGP&#xff08;边界网关协议&#xff09;是一种路由协议&#xff0c;用于在互联网中的不同自治系统&#xff08;AS&#xff09;之间交换路由信息。它…

Edge浏览器新特性深度解析,写作ai免费软件

首先&#xff0c;这篇文章是基于笔尖AI写作进行文章创作的&#xff0c;喜欢的宝子&#xff0c;也可以去体验下&#xff0c;解放双手&#xff0c;上班直接摸鱼~ 按照惯例&#xff0c;先介绍下这款笔尖AI写作&#xff0c;宝子也可以直接下滑跳过看正文~ 笔尖Ai写作&#xff1a;…

运算符重载(2)

1.赋值运算符重载 #include<iostream> using namespace std;class Person { friend void test01(); public:Person(int age){m_Age new int(age);}/*堆区的数据由程序员手动开辟并手动释放*/~Person(){if (m_Age ! NULL){delete m_Age;}}Person& operator(Person &a…

如此建立网络根文件系统 Mount NFS RootFS

安静NFS系统服务 sudo apt-get install nfs-kernel-server 创建目录 sudo mkdir /rootfsLee 将buildroot编译的根文件系统解压缩到 sudo tar xvf rootfs.tar -C /rootfsLee/ 添加文件NFS访问路径 sudo vi /etc/exports sudo /etc/exports文件&#xff0c;添加如下一行 …

比 PSD.js 更强的下一代 PSD 解析器,支持 WebAssembly

比 PSD.js 更强的下一代 PSD 解析器&#xff0c;支持 WebAssembly 1.什么是 webtoon/ps webtoon/ps 是 Typescript 中轻量级 Adobe Photoshop .psd/.psb 文件解析器&#xff0c;对 Web 浏览器和 NodeJS 环境提供支持&#xff0c;且做到零依赖。 Fast zero-dependency PSD par…

创建SpringBoot和RabbitMQ的整合项目

文章目录 创建SpringBoot和RabbitMQ的整合项目首先快速创建一个maven项目引入SpringBoot整合rabbitMQ的依赖在src/main目录下创建resources目录并引入配置文件写消息发送者MessageSender写消息接收者MessageReceiver写RabbitMQConfig配置类写SpringBoot启动主类CommandLineRunn…

决策树模型示例

通过5个条件判定一件事情是否会发生&#xff0c;5个条件对这件事情是否发生的影响力不同&#xff0c;计算每个条件对这件事情发生的影响力多大&#xff0c;写一个决策树模型pytorch程序,最后打印5个条件分别的影响力。 一 决策树模型是一种非参数监督学习方法&#xff0c;主要…

Java高阶私房菜:JVM垃圾回收机制及算法原理探究

目录 垃圾回收机制 什么是垃圾回收机制 JVM的自动垃圾回收机制 垃圾回收机制的关键知识点 初步了解判断方法-引用计数法 GCRoot和可达性分析算法 什么是可达性分析算法 什么是GC Root 对象回收的关键知识点 标记对象可回收就一定会被回收吗&#xff1f; 可达性分析算…

使用R语言进行简单的因子分析

在本文中&#xff0c;将介绍如何使用R语言进行因子分析&#xff0c;并通过一个示例演示整个过程。因子分析是一种多元统计分析方法&#xff0c;用于探索变量之间的潜在结构和关系。R语言提供了丰富的统计工具和包&#xff0c;使因子分析的实现变得简单而高效。 准备工作 首先…

c++中的链表list的模拟实现

拖更了半个月&#xff0c;我终于来填c的坑啦。上次我们说的vetcor不知道小伙伴还记得多少呢&#xff1f;今天我们要讲list的模拟实现。 目录 架构结点list表的结构 构造函数尾插push_back()尾删pop_back()计算个数&#xff1a;size()判断空empty()※迭代器问题普通迭代器迭代器…