当前位置: 首页 > news >正文

Uvicorn日志双输出实战:5分钟搞定终端+文件记录(FastAPI项目必备)

Uvicorn日志双输出实战:5分钟搞定终端+文件记录(FastAPI项目必备)

在FastAPI项目的开发过程中,日志记录是调试和监控的关键环节。想象一下这样的场景:你正在本地调试一个API接口,既需要实时查看终端输出的日志以便快速定位问题,又希望这些日志能够持久化保存用于后续分析。这就是Uvicorn日志双输出技术大显身手的地方。

1. 快速搭建基础日志双输出环境

首先,让我们创建一个最简单的双输出配置。在FastAPI项目的入口文件(通常是main.py)中,添加以下代码:

import uvicorn from fastapi import FastAPI import logging app = FastAPI() # 基础路由用于测试 @app.get("/") async def root(): logging.info("访问了根路由") return {"message": "Hello World"} if __name__ == "__main__": # 配置基础日志 logging.basicConfig( level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s", handlers=[ logging.FileHandler("app.log"), logging.StreamHandler() ] ) uvicorn.run(app, host="0.0.0.0", port=8000)

这个配置实现了:

  • 终端输出:通过StreamHandler实现
  • 文件记录:通过FileHandler将日志写入app.log文件
  • 统一格式:包含时间戳、日志级别和消息内容

提示:这种基础配置虽然简单,但已经能满足大多数开发场景的需求。日志文件默认会保存在项目根目录下。

2. 进阶Uvicorn专属日志配置

当我们需要更精细地控制Uvicorn的日志行为时,可以直接修改其LOGGING_CONFIG。以下是更专业的配置方式:

import uvicorn from fastapi import FastAPI app = FastAPI() # 自定义Uvicorn日志配置 LOGGING_CONFIG = { "version": 1, "disable_existing_loggers": False, "formatters": { "default": { "()": "uvicorn.logging.DefaultFormatter", "fmt": "%(asctime)s - %(levelprefix)s %(message)s", "use_colors": True, }, "access": { "()": "uvicorn.logging.AccessFormatter", "fmt": '%(asctime)s - %(levelprefix)s %(client_addr)s - "%(request_line)s" %(status_code)s', }, }, "handlers": { "console": { "formatter": "default", "class": "logging.StreamHandler", "stream": "ext://sys.stdout", }, "file_default": { "formatter": "default", "class": "logging.FileHandler", "filename": "uvicorn.log", }, "file_access": { "formatter": "access", "class": "logging.FileHandler", "filename": "uvicorn_access.log", }, }, "loggers": { "uvicorn": {"handlers": ["console", "file_default"], "level": "INFO"}, "uvicorn.error": {"level": "INFO"}, "uvicorn.access": {"handlers": ["console", "file_access"], "level": "INFO", "propagate": False}, }, } if __name__ == "__main__": uvicorn.run(app, host="0.0.0.0", port=8000, log_config=LOGGING_CONFIG)

这个配置的特点:

  1. 分离日志类型

    • 普通日志输出到uvicorn.log
    • 访问日志单独记录到uvicorn_access.log
  2. 不同格式化

    • 默认日志包含时间、级别和消息
    • 访问日志额外记录客户端地址、请求行和状态码
  3. 保留彩色输出

    • 终端仍然显示彩色日志
    • 文件日志则保持简洁格式

3. 生产环境推荐配置

对于生产环境,我们需要考虑日志轮转、性能优化等问题。以下是经过实战检验的配置方案:

import uvicorn from fastapi import FastAPI from logging.handlers import RotatingFileHandler import logging app = FastAPI() # 生产环境日志配置 def setup_logging(): # 创建日志目录 import os os.makedirs("logs", exist_ok=True) # 应用日志配置 logging.config.dictConfig({ "version": 1, "disable_existing_loggers": False, "formatters": { "default": { "format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s" }, "access": { "format": "%(asctime)s - %(name)s - %(levelname)s - %(client_addr)s - %(request_line)s - %(status_code)s" }, }, "handlers": { "console": { "class": "logging.StreamHandler", "formatter": "default", "stream": "ext://sys.stdout", }, "file_app": { "()": RotatingFileHandler, "formatter": "default", "filename": "logs/app.log", "maxBytes": 1024 * 1024 * 10, # 10MB "backupCount": 5, }, "file_access": { "()": RotatingFileHandler, "formatter": "access", "filename": "logs/access.log", "maxBytes": 1024 * 1024 * 50, # 50MB "backupCount": 10, }, }, "loggers": { "": {"handlers": ["console", "file_app"], "level": "INFO"}, "uvicorn.error": {"level": "INFO"}, "uvicorn.access": {"handlers": ["console", "file_access"], "level": "INFO", "propagate": False}, }, }) if __name__ == "__main__": setup_logging() uvicorn.run( app, host="0.0.0.0", port=8000, log_config=None, # 使用我们自定义的配置 access_log=True )

关键优化点:

  • 日志轮转:使用RotatingFileHandler防止单个日志文件过大

    • 应用日志限制为10MB,保留5个备份
    • 访问日志限制为50MB,保留10个备份
  • 目录组织:所有日志文件存放在logs子目录中

  • 性能考虑

    • 访问日志单独处理,避免影响主日志性能
    • 合理设置日志级别,避免过度记录

4. 常见问题与调试技巧

在实际使用中,你可能会遇到以下典型问题:

4.1 日志不显示或记录不全

检查清单

  1. 确认日志级别设置正确(DEBUG/INFO/WARNING等)
  2. 检查handler是否正确添加到logger
  3. 确保没有在其他地方覆盖了日志配置

4.2 日志文件权限问题

当遇到无法写入日志文件时:

# 检查文件权限 ls -la /path/to/logfile # 更改文件所有者(假设使用www-data用户) sudo chown www-data:www-data /path/to/logfile

4.3 性能优化建议

对于高流量应用:

  • 考虑使用异步日志处理器(如concurrent-log-handler
  • 将访问日志与应用日志分离到不同磁盘
  • 定期归档和清理旧日志

4.4 集成第三方日志服务

如果需要将日志发送到ELK等系统,可以添加如下handler:

"handlers": { "logstash": { "class": "logstash.LogstashHandler", "host": "logstash.example.com", "port": 5959, "version": 1, "tags": ["python"], }, }

记得在loggers配置中添加这个handler。

5. 实际项目中的最佳实践

经过多个FastAPI项目的实践,我总结了以下经验:

  1. 开发环境:使用简单的双输出配置,方便调试

  2. 测试环境:增加日志详细程度,可以考虑添加文件行号

    "format": "%(asctime)s - %(name)s - %(levelname)s - %(pathname)s:%(lineno)d - %(message)s"
  3. 生产环境

    • 使用RotatingFileHandler确保日志不会无限增长
    • 访问日志和应用日志分离
    • 设置合理的日志级别(通常INFO足够)
  4. 容器化部署:将日志输出到stdout,由容器平台收集

    "handlers": { "console": { "class": "logging.StreamHandler", "formatter": "default", "stream": "ext://sys.stdout", }, }
  5. 调试技巧:临时提升日志级别

    logging.getLogger("uvicorn.error").setLevel(logging.DEBUG)
http://www.cnnetsun.cn/news/1403931.html

相关文章:

  • GTE-Pro语义相似度计算优化:Faiss向量检索实战
  • Privoxy+SOCKS5实战:如何打造更安全的匿名上网环境
  • 新手必看!Miniconda-Python3.11镜像快速上手全攻略
  • UC3842反激式开关电源设计与选型资料:开关变压器、RCD电容、X电容计算及自动联系、开关电...
  • 微信小店低成本涨单,就靠推客系统
  • 告别“黑盒封禁”:你的TikTok账号资产,真的安全吗?
  • 2026 年万能粉碎机与制粒机行业发展白皮书:趋势洞察、品牌优选与标杆企业解析
  • 并查集(图论)
  • 最小生成树
  • 玩转综合能源系统与冷热电三联供的 Simulink 仿真
  • 如何在ESP32上运行TinyML模型
  • Kafka(二):从Lambda到Kappa,流批一体计算的起源
  • OAuth 2026正式启用倒计时:MCP认证体系重构实录——2026年Q1前不升级将丧失联邦访问权限
  • 自然语言处理:第一百零三章 如何优化DeepSeek R1的推理输出效率
  • 关于Agent的一些名词解释
  • 人工智能时代算力基建哪家强?
  • 吐血整理,性能测试总结分析,快速上手打通(一)
  • Frida Hook实战:用JavaScript脚本拦截Android App的HttpURLConnection网络请求
  • 【文献阅读】MINT:让AI“学会”蛋白质对话的语言,开启相互作用预测新时代
  • 医用设备带:从基础生命支持终端到智慧医疗核心枢纽的演进之路
  • Modbus RTU 51单片机从机:轻松对接多种组态软件
  • EIT电阻抗断层成像下位机逻辑及二次开发
  • 路试不跟车,数据秒上云:CANFDLog-1000系列重新定义车载数据采集
  • 军工保密系统如何实现网页端安全截屏转存?
  • 2026年AI Agent发展趋势与挑战:从理论到实践的跨越
  • Dify自定义节点异步调度实战:从阻塞到毫秒级响应的7步性能跃迁指南
  • 手把手教你用MaxMind GeoIP数据库分析fail2ban攻击日志(附Python代码)
  • 北大数字普惠金融指数省市县2011-2024面板数据
  • C++ string 类常用接口解析(附代码介绍)
  • LA04-Abaqus嵌合体退火仿真案例教程:完全热力耦合分析的实践与解析