FastAPI 整合 Loguru 日志

1. 环境准备

1.1 安装依赖

首先,我们需要安装必要的依赖:

pip install fastapi uvicorn loguru

1.2 项目结构

推荐的项目结构如下:

your_project/
├── app/
│   ├── __init__.py
│   ├── main.py
│   └── core/
│       ├── __init__.py
│       ├── config.py
│       └── logger.py
├── logs/
└── requirements.txt

2. 基础概念

2.1 为什么选择 Loguru?

  1. 相比标准库的优势

    • 更简洁的 API
    • 内置异步支持
    • 强大的文件轮转
    • 丰富的格式化选项
    • 完善的异常诊断
  2. 主要特性

    • 结构化日志记录
    • 自动文件轮转
    • 异步日志写入
    • 异常追踪增强
    • 彩色输出支持

3. 详细实现

3.1 配置文件

首先,在 core/config.py 中定义配置:

from pathlib import Path

class Settings:
    # 项目基础配置
    BASE_DIR = Path(__file__).resolve().parent.parent.parent
    DEBUG = True
    
    # 日志配置
    LOG_ROTATION = "00:00"          # 每天午夜轮转
    LOG_RETENTION = "30 days"       # 保留30天
    LOG_COMPRESSION = "zip"         # 压缩格式

settings = Settings()

3.2 日志拦截器

core/logger.py 中实现日志拦截器:

class InterceptHandler(logging.Handler):
    """
    日志拦截处理器:将所有 Python 标准日志重定向到 Loguru
    
    工作原理:
    1. 继承自 logging.Handler
    2. 重写 emit 方法处理日志记录
    3. 将标准库日志转换为 Loguru 格式
    """
    def emit(self, record: logging.LogRecord) -> None:
        # 尝试获取日志级别名称
        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

        # 使用 Loguru 记录日志
        logger.opt(depth=depth, exception=record.exc_info).log(
            level,
            record.getMessage()
        )

3.3 日志系统配置

详细的日志配置实现:

async def setup_logging():
    """
    配置日志系统
    
    功能:
    1. 控制台彩色输出
    2. 文件日志轮转
    3. 错误日志单独存储
    4. 异步日志记录
    """
    # 步骤1:移除默认处理器
    logger.remove()

    # 步骤2:定义日志格式
    log_format = (
        # 时间信息
        "<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | "
        # 日志级别,居中对齐
        "<level>{level: ^8}</level> | "
        # 进程和线程信息
        "process [<cyan>{process}</cyan>]:<cyan>{thread}</cyan> | "
        # 文件、函数和行号
        "<cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - "
        # 日志消息
        "<level>{message}</level>"
    )

    # 步骤3:配置控制台输出
    logger.add(
        sys.stdout,
        format=log_format,
        level="DEBUG" if settings.DEBUG else "INFO",
        enqueue=True,        # 启用异步写入
        backtrace=True,      # 显示完整的异常回溯
        diagnose=True,       # 显示变量值等诊断信息
        colorize=True        # 启用彩色输出
    )
	
	async def async_makedirs(path: str, exist_ok: bool = True) -> None:
    """
    异步创建目录。

    Args:
        path (str): 要创建的目录路径
        exist_ok (bool): 如果目录已存在,是否忽略错误
    """
    	await asyncio.to_thread(os.makedirs, path, exist_ok=exist_ok)
    
    # 步骤4:创建日志目录
    log_dir = Path(settings.BASE_DIR) / 'logs'
    await async_makedirs(str(log_dir))

    # 步骤5:配置常规日志文件
    logger.add(
        str(log_dir / "{time:YYYY-MM-DD}.log"),
        format=log_format,
        level="INFO",
        rotation=settings.LOG_ROTATION,    # 每天轮转
        retention=settings.LOG_RETENTION,  # 保留30天
        compression=settings.LOG_COMPRESSION,  # 压缩旧日志
        encoding="utf-8",
        enqueue=True                      # 异步写入
    )

    # 步骤6:配置错误日志文件
    logger.add(
        str(log_dir / "error_{time:YYYY-MM-DD}.log"),
        format=log_format,
        level="ERROR",
        rotation=settings.LOG_ROTATION,
        retention=settings.LOG_RETENTION,
        compression=settings.LOG_COMPRESSION,
        encoding="utf-8",
        enqueue=True
    )

    # 步骤7:配置标准库日志
    logging.basicConfig(handlers=[InterceptHandler()], level=0, force=True)

    # 步骤8:配置第三方库日志
    for logger_name in [
        "uvicorn",
        "uvicorn.error",
        "uvicorn.access",
        "uvicorn.asgi",
        "fastapi",
        "fastapi.error",
    ]:
        _logger = logging.getLogger(logger_name)
        _logger.handlers = [InterceptHandler()]
        _logger.propagate = False

    logger.info("日志系统初始化完成")

3.4 FastAPI 集成

main.py 中集成日志系统:

async def run_app():
    """
    应用启动函数
    
    步骤:
    1. 初始化日志系统
    2. 配置 uvicorn
    3. 启动服务器
    """
    # 初始化日志系统
    await setup_logging()
    
    # 配置 uvicorn
    config = uvicorn.Config(
        "main:app",
        host="0.0.0.0",
        port=8000,
        log_config=None  # 禁用默认配置
    )
    
    # 启动服务器
    server = uvicorn.Server(config)
    await server.serve()

if __name__ == '__main__':
    import asyncio
    asyncio.run(run_app())

4. 进阶配置

4.1 自定义日志级别

# 添加自定义日志级别
logger.level("STARTUP", no=15, color="<cyan>")
logger.level("SHUTDOWN", no=25, color="<yellow>")

# 使用自定义级别
logger.log("STARTUP", "应用正在启动...")
logger.log("SHUTDOWN", "应用正在关闭...")

4.2 上下文信息

# 添加上下文信息
logger.configure(extra={"app_name": "your_app"})

# 在日志格式中使用
log_format = "{extra[app_name]} - {message}"

4.3 性能优化

# 批量处理日志配置
logger.add(
    "file.log",           # 日志文件路径
    enqueue=True,         # 启用异步写入,避免阻塞主程序
    batch=True,           # 启用批量写入模式,减少I/O操作
    batch_size=100,       # 设置每批次写入的日志数量,当达到100条时进行写入
    interval=1            # 设置强制写入的时间间隔(秒),即使未达到batch_size也会写入
)

# 批量处理的优势:
# 1. 减少磁盘I/O:通过批量写入减少磁盘操作次数
# 2. 提高性能:异步+批量处理显著提升日志处理性能
# 3. 内存优化:控制内存使用,避免日志队列过大
# 4. 实时性平衡:通过interval参数确保日志及时写入

# 注意事项:
# 1. batch_size不要设置太大,避免内存占用过多
# 2. interval不要设置太长,避免日志丢失风险
# 3. 在应用关闭时,确保日志完全写入

5. 最佳实践

5.1 日志级别使用建议

  • DEBUG: 详细的调试信息

    logger.debug("SQL查询: {}", query)
    
  • INFO: 常规操作信息

    logger.info("用户 {} 登录成功", user_id)
    
  • WARNING: 需要注意的情况

    logger.warning("API速率限制即将达到")
    
  • ERROR: 错误信息

    logger.error("数据库连接失败: {}", err)
    
  • CRITICAL: 严重错误

    logger.critical("系统内存不足")
    

5.2 异常处理

try:
    dangerous_operation()
except Exception as e:
    logger.exception("操作失败")  # 自动包含堆栈跟踪

参考资源

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值