一、前言
Python logging 模块定义了为应用程序和库实现灵活的事件日志记录的函数和类。
程序开发过程中,很多程序都有记录日志的需求,并且日志包含的信息有正常的程序访问日志还可能有错误、警告等信息输出,Python 的 logging 模块提供了标准的日志接口,可以通过它存储各种格式的日志,日志记录提供了一组便利功能,用于简单的日志记录用法。
使用 Python Logging 模块的主要好处是所有 Python 模块都可以参与日志记录Logging 模块提供了大量具有灵活性的功能。
为什么要使用loguru?
简单且方便的帮助我们输出需要的日志信息:
使用 Python 来写程序或者脚本的话,常常遇到的问题就是需要对日志进行删除。一方面可以帮助我们在程序出问题的时候排除问题,二来可以帮助我们记录需要关注的信息。
但是,使用自带自带的 logging 模块的话,则需要我们进行不同的初始化等相关工作。对应不熟悉该模块的同学来说,还是有些费劲的,比如需要配置 Handler/Formatter 等。 随着业务的复杂度提升, 对日志收集有着更高的要求, 例如: 日志分类, 文件存储, 异步写入, 自定义类型等等
loguru 是一个 Python 简易且强大的第三方日志记录库,该库旨在通过添加一系列有用的功能来解决标准记录器的注意事项,从而减少 Python 日志记录的痛苦。
二、优雅的使用loguru
1. 安装loguru
1
|
pip install loguru |
2.功能特性介绍
有很多优点,以下列举了其中比较重要的几点:
- 开箱即用,无需准备
- 无需初始化,导入函数即可使用
- 更容易的文件日志记录与转存/保留/压缩方式
- 更优雅的字符串格式化输出
- 可以在线程或主线程中捕获异常
- 可以设置不同级别的日志记录样式
- 支持异步,且线程和多进程安全
- 支持惰性计算
- 适用于脚本和库
- 完全兼容标准日志记录
- 更好的日期时间处理
3. 开箱即用,无需准备
1
2
|
from loguru import logger logger.debug( "That's it, beautiful and simple logging!" ) |
无需初始化,导入函数即可使用, 那么你肯定要问, 如何解决一下问题?
- 如何添加处理程序(handler)呢?
- 如何设置日志格式(logs formatting)呢?
- 如何过滤消息(filter messages)呢?
- 如何如何设置级别(log level)呢?
1
2
3
4
5
|
# add logger.add(sys.stderr, \ format = "{time} {level} {message}" ,\ filter = "my_module" ,\ level = "INFO" ) |
是不是很easy~
4. 更容易的文件日志记录与转存/保留/压缩方式
1
2
3
4
5
6
7
8
9
10
|
# 日志文件记录 logger.add( "file_{time}.log" ) # 日志文件转存 logger.add( "file_{time}.log" , rotation = "500 MB" ) logger.add( "file_{time}.log" , rotation = "12:00" ) logger.add( "file_{time}.log" , rotation = "1 week" ) # 多次时间之后清理 logger.add( "file_X.log" , retention = "10 days" ) # 使用zip文件格式保存 logger.add( "file_Y.log" , compression = "zip" ) |
5. 更优雅的字符串格式化输出
1
2
3
|
logger.info( "If you're using Python {}, prefer {feature} of course!" , 3.10 , feature = "f-strings" ) |
6. 在子线程或主线程中捕获异常
1
2
3
4
5
|
@logger .catch def my_function(x, y, z): # An error? It's caught anyway! return 1 / (x + y + z) my_function( 0 , 0 , 0 ) |
7. 可以设置不同级别的日志记录样式
Loguru 会自动为不同的日志级别,添加不同的颜色进行区分, 也支持自定义颜色哦~
1
2
3
4
5
6
7
|
logger.add(sys.stdout, colorize = True , format = "<green>{time}</green> <level>{message}</level>" ) logger.add( 'logs/z_{time}.log' , level = 'DEBUG' , format = '{time:YYYY-MM-DD :mm:ss} - {level} - {file} - {line} - {message}' , rotation = "10 MB" ) |
8.支持异步且线程和多进程安全
- 默认情况下,添加到 logger 中的日志信息都是线程安全的。但这并不是多进程安全的,我们可以通过添加 enqueue 参数来确保日志完整性。
- 如果我们想要在异步任务中使用日志记录的话,也是可以使用同样的参数来保证的。并且通过 complete() 来等待执行完成。
1
2
|
# 异步写入 logger.add( "some_file.log" , enqueue = True ) |
你没有看错, 只需要enqueue=True
即可异步执行
9. 异常的完整性描述
用于记录代码中发生的异常的 bug 跟踪,Loguru 通过允许显示整个堆栈跟踪(包括变量值)来帮助您识别问题
1
2
3
4
5
6
7
8
9
|
logger.add( "out.log" , backtrace = True , diagnose = True ) def func(a, b): return a / b def nested(c): try : func( 5 , c) except ZeroDivisionError: logger.exception( "What?!" ) nested( 0 ) |
10. 结构化日志记录
- 对日志进行序列化以便更容易地解析或传递数据结构,使用序列化参数,在将每个日志消息发送到配置的接收器之前,将其转换为 JSON 字符串。
- 同时,使用 bind() 方法,可以通过修改额外的 record 属性来将日志记录器消息置于上下文中。还可以通过组合 bind() 和 filter 对日志进行更细粒度的控制。
- 最后 patch() 方法允许将动态值附加到每个新消息的记录 dict 上。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
# 序列化为json格式 logger.add(custom_sink_function, serialize = True ) # bind方法的用处 logger.add( "file.log" , format = "{extra[ip]} {extra[user]} {message}" ) context_logger = logger.bind(ip = "192.168.2.174" , user = "someone" ) context_logger.info( "Contextualize your logger easily" ) context_logger.bind(user = "someone_else" ).info( "Inline binding of extra attribute" ) context_logger.info( "Use kwargs to add context during formatting: {user}" , user = "anybody" ) # 粒度控制 logger.add( "special.log" , filter = lambda record: "special" in record[ "extra" ]) logger.debug( "This message is not logged to the file" ) logger.bind(special = True ).info( "This message, though, is logged to the file!" ) # patch()方法的用处 logger.add(sys.stderr, format = "{extra[utc]} {message}" ) loggerlogger = logger.patch( lambda record: record[ "extra" ].update(utc = datetime.utcnow())) |
11. 惰性计算
有时希望在生产环境中记录详细信息而不会影响性能,可以使用 opt() 方法来实现这一点。
1
2
3
4
5
6
7
8
|
logger.opt(lazy = True ).debug( "If sink level <= DEBUG: {x}" , x = lambda : expensive_function( 2 * * 64 )) # By the way, "opt()" serves many usages logger.opt(exception = True ).info( "Error stacktrace added to the log message (tuple accepted too)" ) logger.opt(colors = True ).info( "Per message <blue>colors</blue>" ) logger.opt(record = True ).info( "Display values from the record (eg. {record[thread]})" ) logger.opt(raw = True ).info( "Bypass sink formatting\n" ) logger.opt(depth = 1 ).info( "Use parent stack context (useful within wrapped functions)" ) logger.opt(capture = False ).info( "Keyword arguments not added to {dest} dict" , dest = "extra" ) |
12. 可定制的级别
1
2
|
new_level = logger.level( "SNAKY" , no = 38 , color = "<yellow>" , icon = "
延伸 · 阅读
精彩推荐
|