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?
-
相比标准库的优势
- 更简洁的 API
- 内置异步支持
- 强大的文件轮转
- 丰富的格式化选项
- 完善的异常诊断
-
主要特性
- 结构化日志记录
- 自动文件轮转
- 异步日志写入
- 异常追踪增强
- 彩色输出支持
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("操作失败") # 自动包含堆栈跟踪