必须在fastapi启动前用logger.add()配置loguru,启用enqueue=true解决多进程写入冲突,结合中间件contextualize注入request_id和path实现请求上下文追踪。

直接用 logger.add() 就行,但必须在 FastAPI 启动前完成配置,且要处理好多进程、异步写入和上下文丢失这三类典型问题。
为什么不能在路由函数里调用 logger.add()
每次请求都执行一次 logger.add() 会不断叠加 handler,导致同一条日志重复写入多次文件,甚至撑爆磁盘。loguru 的 logger 是全局单例,所有模块共享同一个实例,初始化只需一次。
- 正确时机:放在
@app.on_event("startup")或应用工厂函数中 - 错误做法:在
@app.get("/xxx")内部调用logger.add() - 验证方式:启动后检查
logger._core.handlers长度,应为 1~2(控制台 + 文件),不是随请求数增长
logger.add() 必须加 enqueue=True 才能用于 FastAPI
FastAPI 默认用 uvicorn 多 worker 模式运行(--workers 4),每个 worker 是独立进程。不加 enqueue=True 会导致多个进程同时写同一文件,出现内容错乱、覆盖或 OSError。
FastAPI + Flask 混合部署最佳实践,解决路由定义、API 代理等常见问题,适用于同时运行 FastAPI API 与 Flask 前端的场景。
-
enqueue=True启用异步队列,所有日志先发到一个后台线程统一写入,规避多进程竞争 - 搭配
rotation和retention才真正生效,例如:rotation="500 MB"、retention="30 days" - 如果只跑单 worker(
--workers 1)且不关心并发安全,可省略,但不推荐
如何让每条日志自动带上请求 ID 和路径
默认的 logger.info("xxx") 不知道当前是哪个请求,查问题时无法关联。需结合中间件 + logger.contextualize() 注入上下文。
- 先在 startup 时调用
logger.configure(extra={"request_id": "N/A", "path": "N/A"}),避免未 contextualize 时报 KeyError - 在 HTTP 中间件中用
with logger.contextualize(request_id=request_id, path=request.url.path):包裹call_next(request) - 日志格式里用
{extra[request_id]}和{extra[path]}引用,例如:format="{time} | {extra[request_id]} | {message}" - request_id 建议从
request.headers.get("x-request-id")取,或用str(uuid.uuid4())生成
JSON 日志要设 serialize=True,但注意性能和调试成本
结构化日志利于 ELK 收集分析,但 serialize=True 会让每条日志都转成 JSON 字符串,增加 CPU 开销,且控制台输出变成一行难读的 JSON。
- 生产环境建议:文件输出启用
serialize=True,控制台输出禁用(用不同 handler 分开配置) - 调试阶段慎用:JSON 格式丢失颜色、换行和堆栈高亮,排查问题反而更慢
- 如果依赖
extra字段传结构化数据(如用户 ID、订单号),即使不序列化,也能在 format 中用{extra[user_id]}输出
最易被忽略的是:uvicorn 自身的日志(access log、error log)和你的业务日志完全分离,logger.add() 控制不了它。要统一管理,得额外配置 uvicorn 的 --access-log 和 --log-config,或者干脆用中间件把 access 信息也塞进 loguru。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!










