第一部分别把日志当“事后烟”——它该是你的黑匣子刚写FastAPI那会儿我也觉得日志嘛不就是print(“Here!)的高级版直到线上出了个诡异的偶发性400错误翻遍代码一无所获才彻底醒悟。日志系统的核心价值是在你无法“现场调试”的生产环境里还原事故现场。它得告诉你谁IP/用户、在什么时候、请求了什么、内部经过了哪些步骤、最终为什么失败。FastAPI本身不造轮子它完美集成Python标准的logging模块。你的任务就是用好这个强大的原生工具而不是东一榔头西一棒子地乱打print。 第二部分核心四步走配置一个“会思考”的日志系统好咱们先来捋清思路。一个健壮的日志配置通常围绕这四个问题展开1. 日志记到哪里(Handlers)- 控制台开发调试看一眼。- 文件长期保存便于追溯。这里千万别学我当初偷懒只用单个文件否则文件体积爆炸打开都费劲。- 网络/第三方服务如Logstash, Sentry用于集中式日志管理。2. 记录什么级别(Levels)DEBUG INFO WARNING ERROR CRITICAL。简单说INFO记录常规流程ERROR记录错误异常。生产环境通常从INFO起记。3. 记录成什么格式(Formatters)时间、级别、模块、行号、消息……一个都不能少。格式清晰查起来才快。4. 各个模块怎么控制(Loggers)你可以给FastAPI核心、SQLAlchemy、你自己的业务模块设置不同的记录级别和输出目的地非常灵活。 第三部分实战给你一份能直接“抄作业”的配置接下来重点来了上代码。我将一个项目中的精华配置拆解给你看。把它放在你的配置文件如log_config.py里。import logging import logging.handlers from pathlib import Path # 1. 创建logs目录 LOG_DIR Path(__file__).parent.parent / logs LOG_DIR.mkdir(exist_okTrue) # 2. 定义格式 DETAIL_FORMAT %(asctime)s - %(name)s - %(levelname)s - %(filename)s:%(lineno)d - %(message)s SIMPLE_FORMAT %(asctime)s - %(levelname)s - %(message)s # 3. 配置Logger def setup_logging(): # 根日志记录器 logger logging.getLogger() logger.setLevel(logging.INFO) # 全局最低级别 # 清除可能已有的处理器防止重复Jupyter等环境需要 if logger.handlers: logger.handlers.clear() # ---- 控制台处理器 (开发时看) ---- console_handler logging.StreamHandler() console_handler.setLevel(logging.DEBUG) # 控制台可以看更细 console_formatter logging.Formatter(SIMPLE_FORMAT) console_handler.setFormatter(console_formatter) logger.addHandler(console_handler) # ---- 文件处理器 (按天轮转避免单个文件过大) ---- # 这是关键用RotatingFileHandler或TimedRotatingFileHandler file_handler logging.handlers.TimedRotatingFileHandler( filenameLOG_DIR / app.log, whenmidnight, # 每天午夜轮转 interval1, backupCount30, # 保留最近30天 encodingutf-8 ) file_handler.setLevel(logging.INFO) file_formatter logging.Formatter(DETAIL_FORMAT) # 文件里记详细点 file_handler.setFormatter(file_formatter) logger.addHandler(file_handler) # ---- 错误日志单独文件 ---- error_file_handler logging.handlers.RotatingFileHandler( filenameLOG_DIR / error.log, maxBytes10 * 1024 * 1024, # 10MB backupCount5, encodingutf-8 ) error_file_handler.setLevel(logging.ERROR) # 只记录ERROR及以上 error_file_handler.setFormatter(logging.Formatter(DETAIL_FORMAT)) logger.addHandler(error_file_handler) # 4. 控制第三方库的日志噪音比如uvicorn访问日志太吵 # 官方文档虽然没强调但根据线上经验适当调整更清净 logging.getLogger(uvicorn.access).setLevel(logging.WARNING) # 如果你用了SQLAlchemy也可以这样控制SQL日志 # logging.getLogger(sqlalchemy.engine).setLevel(logging.WARNING) # 最后记录一条日志表示配置完成 logger.info(日志系统初始化完成) if __name__ __main__: setup_logging()然后在你的FastAPI应用主文件如main.py开头导入并调用from fastapi import FastAPI import log_config import logging log_config.setup_logging() # 最先初始化 app FastAPI() app.get(/) async def root(): # 在视图里愉快地记录日志吧 log logging.getLogger(__name__) # 推荐用__name__获取logger log.info(有人访问了根路径) return {message: Hello World} if __name__ __main__: import uvicorn uvicorn.run(appapp)⚠️ 第四部分容易翻车的点 进阶思考坑1异步代码中的日志阻塞。标准logging是同步的如果在大量异步任务中疯狂写日志可能会拖慢整体性能。对于超高并发场景考虑使用像structlog异步处理器或者将日志先放入内存队列异步写入。坑2日志格式包含敏感信息。千万注意不要在日志里记录密码、完整Token、身份证号。可以在Formatter里做过滤或者覆写LogRecord来清洗数据。坑3过度日志导致磁盘爆炸。一定要用RotatingFileHandler或TimedRotatingFileHandler并设置合理的maxBytes和backupCount。 进阶一下结构化日志别再只输出纯文本了。输出JSON格式方便后续用ELKElasticsearch, Logstash, Kibana或Loki等工具进行检索和分析。一条好的日志应该是一个结构化的数据对象。请求ID贯穿为每个 incoming request 生成一个唯一ID并让它出现在这个请求链路的所有相关日志里。这是分布式系统排查问题的“黄金线索”。可以通过中间件实现。与监控告警联动当出现ERROR或更高级别日志时自动触发告警通知发短信、发钉钉/企微。让日志系统从“记录仪”变成“预警机”。