日志模块python loguru
下载
pip install loguru
开箱即用
Loguru 的主要概念是只有一个:logger
from loguru import logger
logger.info("This is log info!")
logger.warning("This is log warn!")
logger.error("This is log error!")
logger.debug("This is log debug!")
可以看到不需要手动设置,Loguru 会提前配置一些基础信息,自动输出时间、日志级别、模块名、行号等信息,而且根据等级的不同,还自动设置了不同的颜色,方便观察,真正做到了开箱即用!
如果想自定义日志级别,自定义日志格式,保存日志到文件该怎么办?
与 logging 模块不同,不需要 Handler,不需要 Formatter,只需要一个 add()
函数就可以了,
from loguru import logger
logger.add('test.log')
logger.debug('this is a debug')
我们不需要像 logging 模块一样再声明一个 FileHandler 了,就一行 add()
语句搞定,运行之后会发现目录下 test.log 里面同样出现了刚刚控制台输出的 debug 信息。
与 add()
语句相反,remove()
语句可以删除我们添加的配置:
from loguru import logger
log_file = logger.add('test.log')
logger.debug('This is log debug!')
logger.remove(log_file)
logger.debug('This is another log debug!')
完整参数
Loguru 对输出到文件的配置有非常强大的支持,比如支持输出到多个文件,分级别分别输出,过大创建新文件,过久自动删除等等。 下面我们来详细看一下 add()
语句的详细参数:
基本语法:
add(sink, *, level='DEBUG', format='<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | <level>{level: <8}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>', filter=None, colorize=None, serialize=False, backtrace=True, diagnose=True, enqueue=False, catch=True, **kwargs)
基本参数
sink:可以是一个 file 对象,例如 sys.stderr 或 open('file.log', 'w'),也可以是 str 字符串或者 pathlib.Path 对象,即文件路径,也可以是一个方法,可以自行定义输出实现,也可以是一个 logging 模块的 Handler,比如 FileHandler、StreamHandler 等,还可以是 coroutine function,即一个返回协程对象的函数等。
level:日志输出和保存级别。
format:日志格式模板。
filter:一个可选的指令,用于决定每个记录的消息是否应该发送到 sink。
colorize:格式化消息中包含的颜色标记是否应转换为用于终端着色的 ansi 代码,或以其他方式剥离。 如果没有,则根据 sink 是否为 tty(电传打字机缩写) 自动做出选择。
serialize:在发送到 sink 之前,是否应首先将记录的消息转换为 JSON 字符串。
backtrace:格式化的异常跟踪是否应该向上扩展,超出捕获点,以显示生成错误的完整堆栈跟踪。
diagnose:异常跟踪是否应显示变量值以简化调试。建议在生产环境中设置 False,避免泄露敏感数据。
enqueue:要记录的消息是否应在到达 sink 之前首先通过多进程安全队列,这在通过多个进程记录到文件时很有用,这样做的好处还在于使日志记录调用是非阻塞的。
catch:是否应自动捕获 sink 处理日志消息时发生的错误,如果为 True,则会在 sys.stderr 上显示异常消息,但该异常不会传播到 sink,从而防止应用程序崩溃。
\kwargs:仅对配置协程或文件接收器有效的附加参数(见下文)。
当且仅当 sink 是协程函数时,以下参数适用:
loop:将在其中调度和执行异步日志记录任务的事件循环。如果为 None,将使用 asyncio.get_event_loop() 返回的循环。
当且仅当 sink 是文件路径时,以下参数适用:
rotation:一种条件,指示何时应关闭当前记录的文件并开始新的文件。
*retention *:过滤旧文件的指令,在循环或程序结束期间会删除旧文件。
compression:日志文件在关闭时应转换为的压缩或存档格式。
delay:是在配置 sink 后立即创建文件,还是延迟到第一条记录的消息时再创建。默认为 False。
mode:内置 open() 函数的打开模式,默认为 a(以追加模式打开文件)。
buffering:内置 open() 函数的缓冲策略,默认为1(行缓冲文件)。
encoding:内置 open() 函数的文件编码,如果 None,则默认为 locale.getpreferredencoding()。
\kwargs:其他传递给内置 open() 函数的参数。
这么多参数可以见识到 add() 函数的强大之处,仅仅一个函数就能实
当且仅当 sink 是文件路径时,以下参数适用:
rotation:一种条件,指示何时应关闭当前记录的文件并开始新的文件。
*retention *:过滤旧文件的指令,在循环或程序结束期间会删除旧文件。
compression:日志文件在关闭时应转换为的压缩或存档格式。
delay:是在配置 sink 后立即创建文件,还是延迟到第一条记录的消息时再创建。默认为 False。
mode:内置 open() 函数的打开模式,默认为 a(以追加模式打开文件)。
buffering:内置 open() 函数的缓冲策略,默认为1(行缓冲文件)。
encoding:内置 open() 函数的文件编码,如果 None,则默认为 locale.getpreferredencoding()。
rotation 日志文件分隔
add()
函数的 rotation 参数,可以实现按照固定时间创建新的日志文件,比如设置每天 0 点新创建一个 log 文件:
logger.add('runtime_{time}.log', rotation='00:00')
设置超过 500 MB 新创建一个 log 文件:
logger.add('runtime_{time}.log', rotation="500 MB")
设置每隔一个周新创建一个 log 文件:
logger.add('runtime_{time}.log', rotation='1 week')
retention 日志保留时间
dd()
函数的 retention 参数,可以设置日志的最长保留时间,比如设置日志文件最长保留 15 天:
logger.add('runtime_{time}.log', retention='15 days')
设置日志文件最多保留 10 个:
logger.add('runtime_{time}.log', retention=10)
也可以是一个 datetime.timedelta
对象,比如设置日志文件最多保留 5 个小时:
import datetime
from loguru import logger
logger.add('runtime_{time}.log', retention=datetime.timedelta(hours=5))
compression 日志压缩格式
add()
函数的 compression 参数,可以配置日志文件的压缩格式,这样可以更加节省存储空间,比如设置使用 zip 文件格式保存:
logger.add('runtime_{time}.log', compression='zip')
其格式支持:gz
、bz2
、xz
、lzma
、tar
、tar.gz
、tar.bz2
、tar.xz
字符串格式化
Loguru 在输出 log 的时候还提供了非常友好的字符串格式化功能,相当于 str.format()
:
logger.info('If you are using Python {}, prefer {feature} of course!', 3.6, feature='f-strings')
输出:
2021-10-19 14:59:06.412 | INFO | __main__:<module>:3 - If you are using Python 3.6, prefer
异常追溯
在 Loguru 里可以直接使用它提供的装饰器就可以直接进行异常捕获,而且得到的日志是无比详细的:
from loguru import logger
@logger.catch
def my_function(x, y, z):
# An error? It's caught anyway!
return 1 / (x + y + z)
my_function(0, 0, 0)
日志输出:
Traceback (most recent call last):
> File "D:\python27\djku\sanbanfu\app01\tests.py", line 40, in <module>
my_function(0, 0, 0)
└ <function my_function at 0x000001CCC54F89D0>
File "D:\python27\djku\sanbanfu\app01\tests.py", line 37, in my_function
return 1 / (x + y + z)
│ │ └ 0
│ └ 0
└ 0
ZeroDivisionError: division by zero
在控制台的输出是这样的:
相关文献
https://loguru.readthedocs.io/en/stable/