Python自身具有默认的日志组件-loggin,功能强大且专业度强,正因如此,要真正的用好logging组件的复杂度可不低。你是否曾因懒配置logging组件而只是对其简单配置一下或直接使用 print()
?……我曾有过,但日志记录是每个应用的基础,能极大简化调试过程。然而,可以通过 Loguru组件来极度轻松的使用日志,你没有任何理由不从项目伊始就使用它——只需 from loguru import logger
即可开始,简单至极。
此外,该库通过添加一系列实用功能解决标准日志模块的痛点,力求让 Python 日志记录不再痛苦。日志记录应成为开发的本能,而 Loguru 试图使其既愉悦又强大。
安装
pip install loguru
核心特性
-
开箱即用,无需样板代码
无需配置Handler
、Formatter
、Filter
,一个函数搞定一切。 -
更便捷的文件日志管理
支持日志轮转(rotation)、保留(retention)和压缩(compression)。 -
现代大括号风格字符串格式化
类似str.format()
,更优雅强大。 -
自动捕获主线程或子线程异常
确保所有错误都能记录。 -
美观的彩色日志输出
终端兼容时自动着色。 -
异步、线程安全、多进程安全
默认线程安全,支持消息入队确保多进程安全。 -
完整的异常描述
显示变量值和完整堆栈跟踪(生产环境需谨慎启用)。 -
按需结构化日志
支持序列化为 JSON。 -
惰性求值优化性能
避免生产环境中不必要的计算开销。 -
自定义日志级别
灵活添加新级别并设置颜色和图标。 -
更友好的时间处理
直观的时间格式配置,支持时区。 -
适用于脚本和库
轻松配置或禁用日志,避免污染依赖项目。 -
完全兼容标准
logging
模块
可与现有日志处理程序无缝集成。 -
通过环境变量自定义默认值
修改默认格式或颜色。 -
便捷的日志解析工具
支持正则提取和类型转换。 -
全面的通知集成
结合apprise
库发送邮件、Discord 等通知。 -
10 倍于标准日志模块的速度
关键函数即将通过 C 实现进一步优化性能。
快速入门
开箱即用
from loguru import logger
logger.debug("简洁、美观且易用的日志记录!")
默认预配置为输出到 stderr
,但可完全自定义。
添加处理器(Handler)
通过 add()
函数配置日志输出目标(控制台、文件等):
logger.add(sys.stderr, format="{time} {level} {message}", filter="my_module", level="INFO")
-
移除处理器:使用
logger.remove()
。 -
覆盖默认配置:先调用
logger.remove()
再添加新处理器。
文件日志与轮转
# 按时间自动生成日志文件
logger.add("file_{time}.log")
# 按大小轮转(500MB 轮转,保留旧文件)
logger.add("file_1.log", rotation="500 MB")
# 按时间轮转(每天中午或每周)
logger.add("file_2.log", rotation="12:00")
logger.add("file_3.log", rotation="1 week")
# 保留策略(10 天后清理)
logger.add("file_X.log", retention="10 days")
# 压缩日志(节省空间)
logger.add("file_Y.log", compression="zip")
字符串格式化
logger.info("如果你在用 Python {},当然要选择 {feature}!", 3.6, feature="f-strings")
异常自动捕获
使用装饰器或上下文管理器自动记录异常:
@logger.catch
def risky_function():
return 1 / 0
彩色日志
logger.add(sys.stdout, colorize=True, format="<green>{time}</green> <level>{message}</level>")
线程与多进程安全
logger.add("somefile.log", enqueue=True) # 启用入队确保多进程安全
完整异常堆栈
logger.add("out.log", backtrace=True, diagnose=True) # 生产环境慎用 diagnose=True
def func(a, b):
return a / b
def nested(c):
try:
func(5, c)
except ZeroDivisionError:
logger.exception("出错了!")
nested(0)
输出示例:
2024-01-31 14:34:56 | ERROR | __main__:nested:10 - 出错了!
Traceback (most recent call last):
File "test.py", line 12, in <module>
nested(0)
File "test.py", line 8, in nested
func(5, c)
File "test.py", line 4, in func
return a / b
ZeroDivisionError: division by zero
结构化日志
# 序列化为 JSON
logger.add(custom_sink, serialize=True)
# 添加上下文信息
context_logger = logger.bind(ip="192.168.0.1", user="someone")
context_logger.info("轻松添加上下文")
# 临时上下文
with logger.contextualize(task=task_id):
logger.info("任务结束")
惰性求值
logger.opt(lazy=True).debug("生产环境不执行此计算: {x}", x=lambda: expensive(2**64))
自定义级别
new_level = logger.level("SNAKY", no=38, color="<yellow>", icon="🐍")
logger.log("SNAKY", "自定义级别日志")
时间格式
logger.add("file.log", format="{time:YYYY-MM-DD at HH:mm:ss} | {level} | {message}")
库与脚本配置
# 脚本配置
config = {
"handlers": [
{"sink": sys.stdout, "format": "{time} - {message}"},
{"sink": "file.log", "serialize": True},
],
"extra": {"user": "someone"}
}
logger.configure(**config)
# 库中禁用日志
logger.disable("my_library")
与标准日志兼容
# 使用标准 Handler
handler = logging.handlers.SysLogHandler(address=('localhost', 514))
logger.add(handler)
# 将 Loguru 日志传递到标准 logging
class PropagateHandler(logging.Handler):
def emit(self, record):
logging.getLogger(record.name).handle(record)
logger.add(PropagateHandler(), format="{message}")
# 拦截标准 logging 消息到 Loguru
class InterceptHandler(logging.Handler):
def emit(self, record):
level = logger.level(record.levelname).name
logger.opt(depth=6, exception=record.exc_info).log(level, record.getMessage())
logging.basicConfig(handlers=[InterceptHandler()], level=0, force=True)
环境变量配置
bash
# Linux/OSX
export LOGURU_FORMAT="{time} | <lvl>{message}</lvl>"
# Windows
setx LOGURU_DEBUG_COLOR "<green>"
日志解析
pattern = r"(?P<time>.*) - (?P<level>[0-9]+) - (?P<message>.*)"
caster_dict = {"time": dateutil.parser.parse, "level": int}
for groups in logger.parse("file.log", pattern, cast=caster_dict):
print("解析结果:", groups) # 输出字典:{"time": datetime, "level": int, "message": str}
通知集成
import apprise
notifier = apprise.Apprise()
notifier.add(f"discord://WEBHOOK_ID/WEBHOOK_TOKEN")
logger.add(notifier.notify, level="ERROR", filter={"apprise": False})
性能优势
Loguru 的关键函数设计高效,未来将通过 C 实现进一步提速,使其在密集日志场景下表现卓越。
总结
Loguru 以极简的 API 和强大的功能,重新定义了 Python 日志记录的体验。无论是小型脚本还是大型应用,它都能让日志记录变得直观、高效且愉悦。完整使用说明可访问 Loguru GitHub 主页。