loguru:配置简单的Python日志包

诸神缄默不语-个人技术博文与视频目录

还在为 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")
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

诸神缄默不语

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值