• Loguru 源码中如何sink参数是日志路径时,rotation不能精确到天


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

    当日志按天切分的时候,自动生成的文件名太长,包含了时分秒。我们只需要精确到某一天即可;

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

    1. import time
    2. import datetime
    3. from loguru import logger
    4. logger.add('我是日志.log', rotation="14:01")
    5. while True:
    6. logger.info(f'现在时间:{datetime.datetime.now()}')
    7. time.sleep(1)

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

    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()方法:

    1. a = '我是{}, 你是{}'
    2. b = a.format('开发', '产品')
    3. print(b)

     运行效果如下图所示:

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

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

    1. class People:
    2. def __init__(self, name):
    3. self.name = name
    4. def __format__(self, spec):
    5. return '你好世界!'
    6. a = '我是{}, 你是{}'
    7. people = People('测试')
    8. b = a.format(people, 'pm')
    9. print(b)

     

     

     

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

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

    1. class People(object):
    2. def __init__(self, name):
    3. self.name = name
    4. def __format__(self, format_spec):
    5. if 'pm' in format_spec:
    6. return format_spec
    7. else:
    8. return "dev"
    9. if __name__ == '__main__':
    10. a = '我是{:king_name}, 你是{:pm}'
    11. people = People('Developer')
    12. b = a.format(people, people)
    13. 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 的源代码_file_sink.py文件中的generate_rename_path方法即可,例如:

     

  • 相关阅读:
    YOLOv6训练运行教程,鱼苗检测
    Docker默认桥接网络是如何工作的
    Python网络爬虫-re正则匹配数据
    VSCode错误整理
    vs studio 安装opencv 环境
    pyinstaller打包完整python项目
    目前有哪些比较好用的CRM客户关系管理系统?
    【EI会议征稿】 2024年遥感、测绘与图像处理国际学术会议(RSMIP2024)
    备份服务器数据的重要
    java基础之继承[20]
  • 原文地址:https://blog.csdn.net/u010856284/article/details/125425597