1.loguru
1.1 loguru 介绍
loguru
是一个功能强大且非常容易使用的第三方开源Python日志管理库。它建立在Python标准库中的logging模块之上,并提供了更加简洁直观、功能丰富的接口。github仓库地址:https://github.com/Delgan/loguru
1.2 安装
想要快速体验其功能,首先需要安装该库,安装命令如下所示:
$ pip install loguru
1.3 基本用法
在安装完成,我们就可以来快速体验其功能了,如下所示:
1.3.1 快速使用
from loguru import loggerlogger.info("这是一条INFO信息")
logger.debug("这是一条DEBUG信息")
logger.warning("这是一条WARNING信息")
logger.error("这是一条ERROR信息")
logger.critical("这是一条CRITICAL信息")
输出结果如下所示:
loguru 日志输出默认格式如下:
- 时间戳:日志记录的具体时间,格式通常为
年-月-日 时:分:秒.毫秒
- 日志级别:当前这条日志的严重性级别
- 模块名称:表示日志来自哪个模块
- 函数或作用域范围:表示日志来自哪个函数或作用域范围
- 行号:触发日志所在的行号
- 日志消息:实际的日志内容
每条日志被特定的分隔符分隔并显示,默认分隔符为 |
。同时loguru 也支持 使用颜色
来区分不同的日志级别,使得日志输出更加直观。如果默认功能不能满足需求,也可以进行自定义。
loguru 默认会将日志输出到 standard error stream (stderr),loguru这样做是为了把日志输出与你的应用程序日志分开。如果需要更复杂的日志配置,你也可以自定义配置,例如将日志存储到文件、发送到网络服务中等。
1.3.2 日志级别
1.3.2.1 日志级别介绍
通过前面的快速使用,相信你已经对loguru有了一个基本的了解。为了更好的根据日志级别进行分类,loguru 根据其日志的重要性,定义了日志级别分类。如下所示:
级别 | 方法 | 数值 | 目的 |
---|---|---|---|
TRACE | logger.trace() | 5 | 最详细的日志记录,常用于追踪代码执行过程 |
DEBUG | logger.debug() | 10 | 用于记录详细的程序调试信息,一般用于开发阶段 |
INFO | logger.info() | 20 | 用于记录常规消息记录 |
SUCCESS | logger.success() | 25 | 用于记录一些操作成功的消息记录 |
WARNING | logger.warning() | 30 | 用于记录一些可能不是错误,但需要关注的消息记录 |
ERROR | logger.error() | 40 | 用于记录错误信息,这些错误可能会影响程序某些功能,但不会导致出现崩溃或停止运行 |
CRITICAL | logger.critical() | 50 | 用于记录非常严重的错误信息,这些错误通常会导致程序出现崩溃或停止运行 |
1.3.2.2 调整日志级别
默认情况下,loguru的日志级别为DEBUG(10)
因此loguru会记录并显示日志级别为DEBUG及以上级别的消息记录。这也就意味着,在你第一次使用loguru打印日志时,会显示除TRACE级别以外的所有日志信息。
如果想要开启TRACE级别的日志记录,可以自行调整最小日志级别,可以使用logger.add()
方法,如下所示:
import sys
from loguru import logger# 修改日志最小级别
logger.add(sys.stderr,level="TRACE")logger.info("这是一条INFO信息")
logger.debug("这是一条DEBUG信息")
logger.warning("这是一条WARNING信息")
logger.error("这是一条ERROR信息")
logger.critical("这是一条CRITICAL信息")
logger.trace("这是一条TRACE信息")
输出结果如下所示:
通过上述代码,我们导入了sys
模块并且将输出重定向于sys.stderr
。通过logger.add()
方法添加了一个新的handler
,这样我们就成功修改了loguru默认的日志级别,并将日志输出到sys.stderr中。
通过调用loggeer.add()
方法之后,会返回一个唯一值(handler_id)
,用于标识handler
。后面我们可以调用方法logger.remove(handler_id)
来移除handler。示例如下所示:
import sys
from loguru import loggerdef print_log():logger.info("~~"*30)logger.info("这是一条INFO信息")logger.debug("这是一条DEBUG信息")logger.warning("这是一条WARNING信息")logger.error("这是一条ERROR信息")logger.critical("这是一条CRITICAL信息")logger.trace("这是一条TRACE信息")if __name__ == '__main__':# 修改日志最小级别handler_id=logger.add(sys.stderr,level="TRACE")logger.info(f"handler id:{handler_id}")print_log()logger.remove(handler_id)print_log()
输出结果如下所示:
调用logger.remove()
方法时,如果不传入参数值,则默认删除所有已经存在的handler,并且包含默认的handler。通过这个方法,我们就可以实现在创建新的handler之前,删除所有已经存在的handler。
loguru中默认的handler_id为0,如果需要删除默认的handler,在调用logger.remove()中传入0即可。如果需要删除其他新增的handler,为避免出现不是期望的结果,建议传入明确的handler_id值。
在理解了loguru的日志级别之后,我们就可以根据需要选择合适的日志级别策略。例如在开发环境中,可以使用DEBUG
级别,在生产环境中,可以使用WARNING
或以上的日志级别。
1.3.3 自定义日志
1.3.3.1 日志参数
在loguru中,add函数用于添加日志处理器。这个函数用于指定日志消息应该被发送到何处,例如控制台、文件或其他自定义的目的地。其定义如下所示:
def add(self,sink: Union[TextIO, Writable, Callable[[Message], None], Handler],*,level: Union[str, int] = ...,format: Union[str, FormatFunction] = ...,filter: Optional[Union[str, FilterFunction, FilterDict]] = ...,colorize: Optional[bool] = ...,serialize: bool = ...,backtrace: bool = ...,diagnose: bool = ...,enqueue: bool = ...,context: Optional[Union[str, BaseContext]] = ...,catch: bool = ...
) -> int: ...
add函数主要参数介绍如下:
- sink: 定义日志消息的输出位置,可以是文件路径、标准输出(stdout)、标准错误(stderr,默认)或其他自定义的输出位置。
- format: 指定日志消息的格式,可以是简单的字符串,也可以是格式化字符串,支持各种字段插值。
- level: 设置处理程序处理的日志消息的最低级别。比如设置为DEBUG,则处理程序将处理DEBUG以上所有级别的日志消息。
- filter: 可选参数,用于添加过滤器,根据特定的条件过滤掉不需要的日志消息。
- colorize: 布尔值,指定是否对日志消息进行着色处理,使日志在控制台中更易于区分。
- serialize: 布尔值,指定是否对日志消息进行序列化处理,通常与enqueue=True一起使用,以确保多线程安全。
- enqueue: 布尔值,指定是否将日志消息放入队列中处理,用于多线程应用中避免阻塞。
- backtrace: 布尔值或字符串,指定是否记录回溯信息,默认为False。
- diagnose: 布尔值,启用后,会在处理程序内部出现错误时记录诊断信息。
- rotation: 日志文件轮换的配置,支持按大小或时间进行日志文件的轮换。
- retention: 用于设置日志文件的保留时间。
- compression: 布尔值,指定是否对轮换后的日志文件进行压缩处理。
1.3.3.2 开发实践
loguru 默认的配置已经适用于大部分场景了,但也会有一些场景需要自定义日志的场景,我们可能过logger.add()
方法来实现。
1.3.3.2.1 自定义format
通过format可以自定义想要输出的内容,而不必输出其他额外的信息,示例如下所示:
import sys
from loguru import loggerdef print_log():logger.info("~~"*30)logger.info("这是一条INFO信息")logger.debug("这是一条DEBUG信息")logger.warning("这是一条WARNING信息")logger.error("这是一条ERROR信息")logger.critical("这是一条CRITICAL信息")logger.trace("这是一条TRACE信息")if __name__ == '__main__':logger.remove()# 修改日志最小级别handler_id=logger.add(sys.stderr,level="INFO",format="{message}")logger.info(f"handler id:{handler_id}")print_log()logger.remove(handler_id)
输出结果如下所示:
handler id:1
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
这是一条INFO信息
这是一条WARNING信息
这是一条ERROR信息
这是一条CRITICAL信息
在上述代码中,使用{message}
占位符来表示要输出的日志消息。这样我们就得到了一个最小日志输出记录,而无其他额外日志记录,例如时间戳、日志级别、来源等信息。format
还支持以下占位符:
{time}
: 时间戳{level}
: 日志级别{message}
: 实际的日志消息{name}
: Module 名称{line}
: 行号
更多占位符的文档可查看官网文档:https://loguru.readthedocs.io/en/stable/api/logger.html#record
在日常使用,为了更好的进行问题定位和分析日志,在日志记录中,至少包含时间戳、日志级别、日志内容这三项。示例如下所示:
import sys
from loguru import loggerdef print_log():logger.info("~~"*30)logger.info("这是一条INFO信息")logger.debug("这是一条DEBUG信息")logger.warning("这是一条WARNING信息")logger.error("这是一条ERROR信息")logger.critical("这是一条CRITICAL信息")logger.trace("这是一条TRACE信息")if __name__ == '__main__':logger.remove()# 修改日志最小级别handler_id=logger.add(sys.stderr,level="INFO",format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {message}")logger.info(f"handler id:{handler_id}")print_log()
输出结果如下所示:
2025-09-27 18:29:40 | INFO | handler id:1
2025-09-27 18:29:40 | INFO | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2025-09-27 18:29:40 | INFO | 这是一条INFO信息
2025-09-27 18:29:40 | WARNING | 这是一条WARNING信息
2025-09-27 18:29:40 | ERROR | 这是一条ERROR信息
2025-09-27 18:29:40 | CRITICAL | 这是一条CRITICAL信息
其中时间格式自定义可参考文档: https://loguru.readthedocs.io/en/stable/api/logger.html
loguru 也支持在format中使用颜色标记符来自定义输出的字符串颜色,例如<red>
、<blue>
等。这样在终端中显示日志消息,会自动转换对应的颜色进行显示。示例如下所示:
import sys
from loguru import loggerdef print_log():logger.info("~~"*30)logger.info("这是一条INFO信息")logger.debug("这是一条DEBUG信息")logger.warning("这是一条WARNING信息")logger.error("这是一条ERROR信息")logger.critical("这是一条CRITICAL信息")logger.trace("这是一条TRACE信息")if __name__ == '__main__':logger.remove()# 修改日志最小级别handler_id=logger.add(sys.stderr,level="INFO",format="<red><b>{time:YYYY-MM-DD HH:mm:ss}</b></red> | <blue>{name}:{line}</blue> | <green>{level}</green> | <yellow><b> {message} </b></yellow>")logger.info(f"handler id:{handler_id}")print_log()
输出结果如下所示:
1.3.3.2.2 添加日志上下文
在一部分场景中,我们可以添加一些额外的上下文信息,来帮助更好理解在记录日志时发生了什么事情。loguru也提供几种方式来添加上下文信息。其中最简单常见的方式,就是通过关键字参数来传值。示例如下所示:
import sys
from loguru import loggerif __name__ == '__main__':logger.remove()# 修改日志最小级别handler_id=logger.add(sys.stderr,level="INFO",format="{time:YYYY-MM-DD HH:mm:ss}| {level} | {message} | {extra}")logger.warning(f"日志级别为警告级别", log_level="WARNING")logger.info(f"handler id:",handler_id=handler_id)
输出结果如下所示:
2025-09-27 18:55:58| WARNING | 日志级别为警告级别 | {'log_level': 'WARNING'}
2025-09-27 18:55:58| INFO | handler id: | {'handler_id': 1}
上述通过占位符{extra}
为日志添加了一个上下文信息,适合于一次性添加的场景
,loguru 还提供了以下两个方法,来适用更多的场景:
bind()
: 可以在所有handler实例上面添加额外的上下文信息,属于永久性添加contextualize()
: 添加临时性的上下文信息
bind()
方法非常适合于在所有的logger实例中添加额外的上下文信息。例如,在所有logger实例上添加诸如userId、sessionIdt。这种操作将大量节省在所有logger上手动添加额外上下文信息。示例代码如下所示:
import sys
from loguru import loggerif __name__ == '__main__':logger.remove()# 修改日志最小级别handler_id=logger.add(sys.stderr,level="INFO",format="{time:YYYY-MM-DD HH:mm:ss}| {level} | {message} | {extra}")user_logger=logger.bind(username="Surpass",user_id=999,session_id=8888)user_logger.info("I am Supass")user_logger.warning("loguru user logger.bind()")
输出结果如下所示:
2025-09-27 19:09:50| INFO | I am Supass | {'username': 'Surpass', 'user_id': 999, 'session_id': 8888}
2025-09-27 19:09:50| WARNING | loguru user logger.bind() | {'username': 'Surpass', 'user_id': 999, 'session_id': 8888}
contextualize()
提供了一种非常干净的方式来添加一个临时的上下文信息,而且在操作完成后还会自动清理,示例代码如下所示:
import sys
from loguru import loggerif __name__ == '__main__':logger.remove()# 修改日志最小级别handler_id=logger.add(sys.stderr,level="INFO",format="{time:YYYY-MM-DD HH:mm:ss}| {level} | {message} | {extra}")with logger.contextualize(username="Surpass",user_id=999,session_id=8888):logger.info("Add temporarily context with contextualize")logger.warning("Hello Surpass",without_contextualize=True)
在上述示例中,contextualize()
事实上使用了Python的上下文管理器来临时添加额外的上下文信息,在with
块里面,所有日志消息都会被添加额外的上下文信息,而一旦退出with
块,则额外的上下文信息则会移除。
输出结果如下所示:
2025-09-27 19:16:55| INFO | Add temporarily context with contextualize | {'username': 'Surpass', 'user_id': 999, 'session_id': 8888}
2025-09-27 19:16:55| WARNING | Hello Surpass | {'without_contextualize': True}
1.3.3.2.3 保存日志到文件
将日志输出到终端在开发阶段非常有用,而在生产环境中,日志需要保存到文件中,供日后的问题定位和日志分析。loguru 允许将日志保存至文件,并设置日志切割和日志保留期限策略。
-
Log rotation: 即日志切割,它通常决定在什么时候开启一个新的文件用于记录日志,可以由日志文件大小、时间间隔、其他条件等决定。支持以下几种方式的定义:
文件大小: 当文件大小达到设定的大小后,创建新的日志文件,可以取的值有:100 MB、2 GB
时间: 即达到指定的时间就创建新的日志文件,可以取的值有:12:00
时间间隔:即达到指定的时间间隔之后,就创建新的日志文件,可以取的值有: 12 hours、3 days -
Log retention: 即日志保留期限,它通常决定何时删除旧的日志文件,可以由基于数量和基于时间来决定。支持以下几种方式的定义:
基于数量: 即仅保留最近n个文件,如果设置为3,则表示仅保留最近3个日志文件,其他日志文件则删除
基于时间:即仅保留最近设定时间的文件,如果设置为"1 week",则表示仅保留最近1雕的日志文件,其他日志文件则删除
from loguru import loggerif __name__ == '__main__':logger.remove()# 修改日志最小级别handler_id=logger.add("app.log",level="INFO",format="{time:YYYY-MM-DD HH:mm:ss}| {level} | {message} | {extra}",rotation="1 KB", # 即日志文件达到1KB,就创建一个新日志文件retention="1d" # 即日志文件仅保留当天,其他则要删除)with logger.contextualize(username="Surpass",user_id=999,session_id=8888):logger.info("Add temporarily context with contextualize")logger.warning("Hello Surpass",without_contextualize=True)
1.3.3.2.4 错误处理和使用Loguru调试
当我们在调试程序时,仅仅从日志中得知程序运行出现错误信息是不够的。我们需要知道错误是什么时候产生和为什么会产生错误等。loguru 提供了一个非常强大的功能来辅助查看详细的日志信息,例如错误信息、变量信息、上下文信息等。
- 使用装饰器@logger.catch
最简单抓取错误日志信息的方式就是使用装饰器@logger.catch。示例如下所示:
import sys
from loguru import logger@logger.catch
def divide(a:int,b:int)->int:return a/bif __name__ == '__main__':divide(10,0)
上述代码在运行会出现报错,loguru产生的日志如下所示:
2025-09-27 20:06:45.140 | ERROR | __main__:<module>:10 - An error has been caught in function '<module>', process 'MainProcess' (4288), thread 'MainThread' (24912):
Traceback (most recent call last):> File "C:\Users\Surpass\Documents\PyCharmProjects\TestNote\test-note\loguru-demo\main.py", line 10, in <module>divide(10,0)└ <function divide at 0x000001EE6B0C8860>File "C:\Users\Surpass\Documents\PyCharmProjects\TestNote\test-note\loguru-demo\main.py", line 6, in dividereturn a/b│ └ 0└ 10ZeroDivisionError: division by zero
- 使用装饰器@logger.catch并添加其他额外信息
使用基本装饰器@logger.catch
可以做到不需要任何配置就能自动捕捉错误信息,但在一些大型工程中,我们通常需要自行处理和控制输出的错误信息,这个时候就需要能够自定义一些错误信息、日志级别、处理特定类型的错误。这个时候我们依然可以使用装饰器@logger.catch,并传递额外的参数即可。示例如下所示:
import sys
from loguru import logger@logger.catch(message="database connection failed",level="ERROR")
def connect_to_db(addr:str,port:int):if port < 1000:raise ValueError("Port must be greater than 1000")# 模拟连接数据库错误raise Exception("Connection to database failed")if __name__ == '__main__':connect_to_db("127.0.0.1",123)
输出结果如下所示:
2025-09-27 20:18:06.998 | ERROR | __main__:<module>:12 - database connection failed
Traceback (most recent call last):> File "C:\Users\Surpass\Documents\PyCharmProjects\TestNote\test-note\loguru-demo\main.py", line 12, in <module>connect_to_db("127.0.0.1",123)└ <function connect_to_db at 0x00000249B8400400>File "C:\Users\Surpass\Documents\PyCharmProjects\TestNote\test-note\loguru-demo\main.py", line 7, in connect_to_dbraise ValueError("Port must be greater than 1000")ValueError: Port must be greater than 1000
1.3.3.2.5 文件和控制台同时输出日志
在前面的示例中,日志要么输出到文件,要么输出到控制台,现在想同时输出到文件和控制中,该如何操作了,示例代码如下所示:
import sys
from loguru import loggerformat="<green>{time:YYYY-MM-DD HH:mm:ss ZZ}</green> | <red><b>{level}</b></red> | <blue>{message}</blue> | {extra}"
level="DEBUG"config={"handlers": [{"sink":sys.stdout,"format":format,"level":level},{"sink":"app.log", "format":format,"level":level}],"extra": {"name":"Surpass"}
}logger.configure(**config)logger.info(logger.level(level))
logger.info("I am Surpass",level="INFO",age=28)
logger.warning("Test Warning",level="WARNING")
logger.debug("Test Debug",level="DEBUG")
logger.error("Test Error",level="ERROR")
输出结果如下所示:
2025-09-27 21:28:22 +0800 | INFO | Level(name='DEBUG', no=10, color='<blue><bold>', icon='🐞') | {'name': 'Surpass'}
2025-09-27 21:28:22 +0800 | INFO | I am Surpass | {'name': 'Surpass', 'level': 'INFO', 'age': 28}
2025-09-27 21:28:22 +0800 | WARNING | Test Warning | {'name': 'Surpass', 'level': 'WARNING'}
2025-09-27 21:28:22 +0800 | DEBUG | Test Debug | {'name': 'Surpass', 'level': 'DEBUG'}
2025-09-27 21:28:22 +0800 | ERROR | Test Error | {'name': 'Surpass', 'level': 'ERROR'}
2.参考资料
- https://github.com/Delgan/loguru
- https://loguru.readthedocs.io/en/stable/index.html
- https://realpython.com/python-loguru/
本文同步在微信订阅号上发布,如各位小伙伴们喜欢我的文章,也可以关注我的微信订阅号:woaitest,或扫描下面的二维码添加关注: