一起读源码:为什么 loguru 的时间 rotation 不能只精确到天

简介: 一起读源码:为什么 loguru 的时间 rotation 不能只精确到天

摄影:产品经理猪耳朵与鹌鹑蛋做的皮蛋

今天的问题来自未闻 Code 粉丝交流群:

loguru 每天自动生成的日志名字,可以只精确到日吗?

如下图所示:

这里的每天自动生成日志的名字是什么意思呢?实际上指的就是rotation。我不知道他的中文名叫什么,但rotation 表示一种按特定条件自动切分日志的方式。

如果我们把日志一直不停写入某个文件中,那么这个文件可能会有几十上百 GB,显然这样是没有办法查看和检索的。所以我们需要一些方式来切分日志。例如,每个日志文件只有1GB,超过1GB 后,自动生成新的日志;又或者每天0点自动生成新的日志。

今天的这个问题,实际上就是在日志按天切分的时候,自动生成的文件名太长,包含了时分秒。但是提问的同学只需要精确到天。

我们来做一个测试,安装 loguru 以后,大家编写如下代码:

import time
import datetime
from loguru import logger
logger.add('我是日志.log', rotation="18:16")
while True:
    logger.info(f'现在时间:{datetime.datetime.now()}')
    time.sleep(1)

这段代码每一秒中会写入一条日志。并且日志在18:16分的时候会进行一次切分。运行效果如下图所示:

loguru 每次写入文件的时候,写入的都是我是日志.log。但是当 rotation 的时间到了以后,会先把之前的我是日志.log文件改名为我是日志.%Y-%m-%d_%H-%M-%S_%f.log。然后创建一个新的我是日志.log

提问题的同学想知道,由于他的日志是每天切换一次的,所以实际上时间没有必要精确到毫秒。是否能够只精确到天?

为了回答这个问题,我去看了 loguru 的官方文档,发现确实没有相关的内容提到日志被 rotation 以后,重命名的格式相关的设置。

既然文档没有提到,那么我们就寻求源代码的帮助。日志重命名时,新的文件名是由函数generate_rename_path()生成的。大家可以在 Github 中,loguru 的_file_sink.py文件中找到这个函数:https://github.com/Delgan/loguru/blob/master/loguru/_file_sink.py#L16

决定了文件名的代码如下图所示:

代码第17行,得到一个 datetime 对象creation_datetime。这个对象作为参数传入FileDateFormatter类,得到一个 date 对象。

接下来,在第20行,通过字符串的.format()方法,拼接出一个新的文件名。

这就是全部过程了。是不是讲的太快了,没有 get 到点?那我们从头开始。

这里我们来复习一下字符串的.format()方法:

a = '我是{}, 你是{}'
b = a.format('青南', 'pm')
print(b)

运行效果如下图所示:

这三行代码特别简单,似乎一个不会 Python 的人,看到代码以后就能脱口而出:这不就是把 format 里面的参数,按顺序替换原来字符串中的大括号吗。

是的,要让它运行起来是特别简单。但是,如果 format 的括号里面,有一个参数是一个含有__format__()魔法方法的对象会怎么样?我们再来看一段代码:

class People:
    def __init__(self, name):
        self.name = name
    def __format__(self, spec):
        return '你好世界!'
a = '我是{}, 你是{}'
kingname = People('青南')
b = a.format(kingname, 'pm')
print(b)

可以看到,__format__()方法返回的字符串,可以替换大括号里面的内容。此时,__format__()的能实现的效果,跟__str__()方法没有什么两样。

接下来,不一样的地方来了——在大括号里面,实际上还可以传递参数!只需要在大括号里面先加上一个英文冒号,再加上参数就可以了,我们来看看:

class People:
    def __init__(self, name):
        self.name = name
    def __format__(self, spec):
        if 'pm' in spec:
            return '产品经理到此一游'
        else:
            return '青南'
a = '我是{:kingnma}, 你是{:pm}'
people = People('随便谁')
b = a.format(people, people)
print(b)

运行效果如下图所示:

可以看到,b = a.format(people, people)我们传入的是同一个对象,但是由于大括号里面,冒号后面的参数不同,于是最终生成的字符串也就不一样。

__format__()方法始终会接收一个spec参数,如果我们原字符串的大括号里面没有冒号,那么这个spec是空字符串。如果我们原字符串的大括号里面有冒号,那么冒号后面的内容就会作为 spec 参数传入__format__()方法中。

原理讲完了。我们回到loguru 的源代码中。可以看到,FileDateFormatter类的__format__()方法会做一个判断,如果 spec 参数为空,那么就会强制使用%Y-%m-%d_%H-%M-%S_%f这个格式的时间。

我们再来看generate_rename_path代码第20和25行,renamed_path = "{}.{}{}".format(root, date, ext)renamed_path = "{}.{}.{}{}".format(root, date, counter, ext),其中date对象作为format 的第二个参数传入第二个大括号。但是第二个大括号是空的,里面没有冒号,date对象的__format__()方法的 spec 参数始终为空。所以始终会使用%Y-%m-%d_%H-%M-%S_%f格式。无法人工自定义格式。

综上所述,对这位同学的回答是:无法自定义日志 rotation 时添加的时间格式。如果你想要强行修改的话,那么你只有修改 loguru 的源代码,例如:

相关实践学习
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
目录
相关文章
|
NoSQL Redis 数据库
深入理解redis cluster的failover机制
社区版redis cluster是无中心节点P2P的集群架构,内部采用gossip协议传递维护集群的拓扑结构和集群元数据。社区文档地址:https://redis.io/topics/cluster-tutorial failover是redis cluster提供的容错机制,cluster最核心的功能之一。
15153 0
|
11月前
|
监控 安全 程序员
Python日志模块配置:从print到logging的优雅升级指南
从 `print` 到 `logging` 是 Python 开发的必经之路。`print` 调试简单却难维护,日志混乱、无法分级、缺乏上下文;而 `logging` 支持级别控制、多输出、结构化记录,助力项目可维护性升级。本文详解痛点、优势、迁移方案与最佳实践,助你构建专业日志系统,让程序“有记忆”。
956 0
|
10月前
|
存储 人工智能 自然语言处理
构建AI智能体:二十三、RAG超越语义搜索:如何用Rerank模型实现检索精度的大幅提升
本文介绍了重排序(Rerank)技术在检索增强生成(RAG)系统中的应用。Rerank作为初始检索和最终生成之间的关键环节,通过交叉编码器对初步检索结果进行精细化排序,筛选出最相关的少量文档提供给大语言模型。相比Embedding模型,Rerank能更精准理解查询-文档的语义关系,显著提高答案质量,降低Token消耗。文章详细比较了BGE-Rerank和CohereRerank等主流模型,并通过代码示例展示了Rerank在解决歧义查询(如区分苹果公司和水果)上的优势。
2418 5
|
存储 分布式计算 数据可视化
Hadoop生态圈深度解读:从数据到可视化的全景视图
数据处理后可通过多种方式输出,计算后的数据输出可通过传统数据库或文件形式,并通过Tomcat服务器可视化展示结果。ZooKeeper为分布式系统提供可靠的协调服务。最后,计算分析结果将通过传统Tomcat服务器进行可视化展示。同时,ZooKeeper作为Google Chubby的开源实现,为大型分布式系统提供可靠协调服务,封装了复杂且易出错的关键服务,为用户提供简单易用、性能高效且功能稳定的系统。 至此,我们对整个大数据Hadoop生态体系的层次划分、技术支持和运行流程有了初步了解。接下来,我们将着手搭建Hadoop生态体系集群,深入解析各个框架的实现过程与执行原理,以完成项目数据分析。
|
消息中间件 安全 Python
Python日志管理之Loguru
Python日志管理之Loguru
1004 6
|
存储 消息中间件 NoSQL
【Redis】常用数据结构之List篇:从常用命令到典型使用场景
本文将系统探讨 Redis List 的核心特性、完整命令体系、底层存储实现以及典型实践场景,为读者构建从理论到应用的完整认知框架,助力开发者在实际业务中高效运用这一数据结构解决问题。
|
监控 虚拟化 Docker
Sentinel监测到了服务,但是实时监控不显示曲线图,应该怎么解决这个问题?
在虚拟机(VMware,IP:192.168.175.100)中部署了Sentinel,使用Docker运行,端口映射为8858。服务的`application.properties`配置指向Sentinel仪表盘(192.168.175.100:8858),客户端IP为物理机IP(192.168.2.2)。然而,cart-service在Sentinel中显示失联且无曲线图,而sentinel-dashboard自身监控正常。
|
存储 数据库 Python
Loguru:Python中强大的日志库
Loguru:Python中强大的日志库
1360 2
|
存储 定位技术 数据库
探索GeoHash:滴滴打车定位技术揭秘
【10月更文挑战第28天】
1903 5