还在为 Python 标准库 logging 的复杂配置而头疼吗?Loguru 可能是你一直在寻找的解决方案!
为什么需要 Loguru?
如果你曾经使用过 Python 标准库中的 logging 模块,你可能会记得那些繁琐的配置步骤:创建 logger、设置 handler、定义 formatter… 这一切在 Loguru 面前都将成为过去!
Loguru 是一个旨在让 Python 日志记录变得简单而愉快的库。它提供了一种更加直观和 Pythonic 的方式来处理日志,让我们来看看它的魅力所在。
安装 Loguru
pip install loguru
快速开始:5 秒上手
from loguru import logger
logger.debug("这是一条调试信息")
logger.info("程序正常运行")
logger.warning("出现警告,但程序继续")
logger.error("发生错误!")
logger.critical("严重错误,程序可能终止")
运行上面的代码,你会看到彩色且格式良好的日志输出,无需任何配置!
核心特性详解
1. 开箱即用的精美输出
Loguru 默认提供:
- 彩色输出
- 自动时间戳
- 日志级别标识
- 文件名称和行号
2. 极其简单的文件日志
from loguru import logger
# 添加文件日志,就这么简单!
logger.add("file.log")
logger.info("这条日志会同时输出到控制台和文件")
3. 强大的日志配置
from loguru import logger
import sys
# 移除默认配置
logger.remove()
# 添加控制台输出,自定义格式
logger.add(
sys.stdout,
format="{time:YYYY-MM-DD HH:mm:ss} | <level>{level: <8}</level> | {name}:{function}:{line} - <level>{message}</level>",
level="DEBUG"
)
# 添加文件输出,按时间旋转
logger.add(
"logs/app_{time:YYYY-MM-DD}.log",
rotation="00:00", # 每天午夜旋转
retention="30 days", # 保留30天
compression="zip", # 压缩旧日志
level="INFO"
)
logger.info("这是自定义格式的日志")
4. 异常追踪变得优雅
from loguru import logger
def risky_operation(x, y):
return x / y
def main():
try:
result = risky_operation(10, 0)
except Exception:
logger.exception("计算过程中发生异常")
# 或者使用更简洁的方式:
# logger.opt(exception=True).error("计算失败")
if __name__ == "__main__":
main()
实际应用示例
让我们通过一个完整的例子来看看 Loguru 在实际项目中的应用:
from loguru import logger
import sys
import json
import time
class DataProcessor:
def __init__(self):
self.setup_logging()
def setup_logging(self):
"""配置日志系统"""
logger.remove() # 移除默认配置
# 控制台输出(开发环境)
logger.add(
sys.stdout,
format="<green>{time:YYYY-MM-DD HH:mm:ss}</green> | <level>{level: <8}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>",
level="DEBUG",
colorize=True
)
# 文件输出(生产环境)
logger.add(
"logs/app_{time:YYYY-MM-DD}.log",
rotation="1 day",
retention="30 days",
format="{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {name}:{function}:{line} - {message}",
level="INFO",
compression="zip"
)
# JSON 格式日志(用于日志分析系统)
logger.add(
"logs/structured.json",
format=lambda record: json.dumps({
"time": record["time"].isoformat(),
"level": record["level"].name,
"message": record["message"],
"module": record["name"],
"function": record["function"],
"line": record["line"],
"extra": record["extra"]
}) + "\n",
level="INFO",
rotation="1 day"
)
def process_data(self, data):
"""处理数据的主要方法"""
logger.info("开始处理数据", data_size=len(data))
try:
# 模拟数据处理
processed = []
for i, item in enumerate(data):
logger.debug("处理第 {} 条数据: {}", i, item)
if item < 0:
logger.warning("发现负数数据: {}", item)
result = self.transform_item(item)
processed.append(result)
# 模拟进度日志
if (i + 1) % 100 == 0:
logger.info("处理进度: {}/{}", i + 1, len(data))
logger.success("数据处理完成", processed_count=len(processed))
return processed
except Exception as e:
logger.opt(exception=True).error("数据处理失败")
raise
def transform_item(self, item):
"""转换单个数据项"""
with logger.contextualize(item_id=id(item)):
logger.trace("开始转换数据项")
if item == 0:
logger.error("遇到零值,无法处理")
raise ValueError("零值无效")
result = 100 / item
logger.debug("转换结果: {}", result)
return result
def main():
"""主函数"""
processor = DataProcessor()
# 测试数据
test_data = [1, 2, 3, 0, 5, -1, 7, 8, 9, 10] * 10
# 添加一些元数据到日志
with logger.contextualize(batch_id="batch_001", user="demo_user"):
logger.info("启动数据处理任务")
try:
result = processor.process_data(test_data)
logger.info("任务完成", result_count=len(result))
except Exception:
logger.error("任务执行失败")
logger.info("数据处理任务结束")
if __name__ == "__main__":
main()
高级特性
1. 结构化日志记录
from loguru import logger
import sys
# 配置结构化日志
logger.configure(extra={"user": "unknown", "request_id": "none"})
def process_request(user_id, request_data):
# 为当前请求添加上下文信息
with logger.contextualize(user=user_id, request_id=id(request_data)):
logger.info("开始处理请求", data_size=len(request_data))
# 处理逻辑...
logger.debug("处理步骤1完成")
logger.debug("处理步骤2完成")
logger.success("请求处理完成")
# 使用示例
process_request("user123", {"action": "login", "timestamp": "2024-01-01"})
2. 自定义日志级别
from loguru import logger
# 添加自定义日志级别
logger.level("PERFORMANCE", no=25, color="<magenta>")
def log_performance(func):
def wrapper(*args, **kwargs):
import time
start = time.time()
result = func(*args, **kwargs)
end = time.time()
logger.log("PERFORMANCE", "函数 {} 执行时间: {:.3f}秒", func.__name__, end - start)
return result
return wrapper
@log_performance
def expensive_operation():
time.sleep(0.1)
return "done"
expensive_operation()
3. 条件日志记录
from loguru import logger
# 只在特定条件下记录日志
def conditional_logging(debug_mode=False):
logger.info("这条日志总是会出现")
# 只有 debug_mode 为 True 时才记录调试信息
logger.opt(depth=1).bind(debug=debug_mode).debug("这是调试信息")
# 或者使用条件判断
if debug_mode:
logger.debug("详细的调试信息")
conditional_logging(debug_mode=True)
性能优化技巧
from loguru import logger
# 1. 避免在非调试级别计算昂贵的日志消息
def expensive_debug_data():
# 这个方法很耗时
return "这是需要大量计算的数据"
# 不好的做法:总是计算
# logger.debug(f"数据: {expensive_debug_data()}")
# 好的做法:只在需要时计算
logger.opt(lazy=True).debug("数据: {}", expensive_debug_data)
# 2. 使用过滤减少不必要的日志
def only_important(record):
return "important" in record["message"].lower()
logger.add("important.log", filter=only_important, level="INFO")
与标准 logging 集成
from loguru import logger
import logging
# 将 Loguru 作为标准 logging 的处理器
class InterceptHandler(logging.Handler):
def emit(self, record):
# 获取对应的 Loguru 级别
try:
level = logger.level(record.levelname).name
except ValueError:
level = record.levelno
# 找到调用者
frame, depth = logging.currentframe(), 2
while frame.f_code.co_filename == logging.__file__:
frame = frame.f_back
depth += 1
logger.opt(depth=depth, exception=record.exc_info).log(level, record.getMessage())
# 设置拦截
logging.basicConfig(handlers=[InterceptHandler()], level=0)
# 现在第三方库的日志也会通过 Loguru 输出
import requests
requests.get("https://httpbin.org/get")
926

被折叠的 条评论
为什么被折叠?



