拓冰建站拓冰建站
首页 / 资讯中心 / 正文

FastAPI 筑基 - Day2 彩色日志封装 + Python 装饰器精讲

专栏FastAPI 从零到后端接口实战标签Python、装饰器、日志封装、colorlog、FastAPI 工程化、代码规范前置知识Day1 async/await 异步基础、aiohttp 异步请求前言Day1 我们完成了异步语法与 aiohttp 网络请求编写但代码调试只能依靠原生print打印信息。原生print无法区分日志等级、没有时间戳、不能持久化保存日志文件项目体量变大后排查 BUG 极其麻烦。同时 FastAPI 内部大量使用装饰器做路由注册、参数校验、依赖注入不懂装饰器很难看懂 FastAPI 源码写法。本章两大核心目标基于 colorlog 封装彩色分级日志控制台彩色打印 本地文件落盘由浅入深吃透装饰器基础语法、传参装饰器、wraps 元信息修复、异步函数装饰器产出可复用的日志工具类后续所有 FastAPI 项目直接导入使用。一、Python 原生 logging 模块基础认知1.1 日志 5 个等级由低 → 高等级方法适用场景DEBUGlogging.debug()开发调试、打印变量值、流程节点INFOlogging.info()正常业务运行记录接口调用、请求进入WARNINGlogging.warning()非报错异常配置缺失、请求超时等警告ERRORlogging.error()程序发生异常、接口执行报错CRITICALlogging.critical()致命错误服务无法正常运行日志默认只会输出WARNING 及以上级别日常开发一般配置全局等级为DEBUG。1.2 原生 logging 缺陷控制台文字全部单色不同级别日志肉眼无法快速区分配置代码冗余每个文件都要重复编写 handler、formatter无法同时实现「控制台打印」「文件写入」两种输出。二、colorlog 彩色日志库安装与基础使用colorlog对原生logging进行封装给不同日志等级配置区分颜色大幅提升调试效率。安装依赖pipinstallcolorlog最简彩色日志测试代码importloggingimportcolorlog# 配置日志格式log_formatcolorlog.ColoredFormatter(%(log_color)s%(asctime)s - %(name)s - %(levelname)s - %(message)s,datefmt%Y-%m-%d %H:%M:%S,log_colors{DEBUG:cyan,INFO:green,WARNING:yellow,ERROR:red,CRITICAL:bold_red,})# 创建控制台处理器console_handlercolorlog.StreamHandler()console_handler.setFormatter(log_format)# 初始化 logger 对象loggercolorlog.getLogger(fastapi_project)logger.addHandler(console_handler)logger.setLevel(logging.DEBUG)# 分级打印测试logger.debug(DEBUG接口入参数据打印)logger.info(INFO服务正常启动成功)logger.warning(WARNING请求响应缓慢存在超时风险)logger.error(ERROR数据库查询抛出异常)logger.critical(CRITICALRedis 连接失败服务不可用)运行后在控制台可以看到不同颜色的日志输出一目了然。三、封装通用日志工具类工程化标准写法实现能力✅ 控制台彩色输出✅ 日志自动写入本地logs/文件夹按日期分割日志文件✅ 全局统一配置项目任意文件from ... import即可使用logger_utils.py 完整代码importosimportloggingfromlogging.handlersimportTimedRotatingFileHandlerimportcolorlog# 1、定义日志根目录相对当前脚本所在目录LOG_ROOTos.path.join(os.path.dirname(__file__),logs)ifnotos.path.exists(LOG_ROOT):os.makedirs(LOG_ROOT)# 2、日志文件名称按日期划分LOG_FILEos.path.join(LOG_ROOT,fastapi_run.log)# 3、控制台彩色格式console_formattercolorlog.ColoredFormatter(fmt%(log_color)s%(asctime)s | %(filename)s:%(lineno)d | %(levelname)s | %(message)s,datefmt%Y-%m-%d %H:%M:%S,log_colors{DEBUG:cyan,INFO:green,WARNING:yellow,ERROR:red,CRITICAL:bold_red,bg_white,},)# 4、文件日志普通格式文件不需要颜色代码file_formatterlogging.Formatter(fmt%(asctime)s | %(filename)s:%(lineno)d | %(levelname)s | %(message)s,datefmt%Y-%m-%d %H:%M:%S)# 5、文件处理器按天切割日志保留 30 天日志记录file_handlerTimedRotatingFileHandler(filenameLOG_FILE,whenD,interval1,backupCount30,encodingutf-8)file_handler.setFormatter(file_formatter)# 6、控制台处理器console_handlercolorlog.StreamHandler()console_handler.setFormatter(console_formatter)# 7、组装 loggerdefget_logger(namefastapi_log):loglogging.getLogger(name)log.setLevel(logging.DEBUG)# 避免重复添加 handlerifnotlog.handlers:log.addHandler(file_handler)log.addHandler(console_handler)returnlog# 全局实例化导出loggerget_logger()提示if not log.handlers的判断能避免多次调用get_logger()时重复添加 handler导致日志重复打印。项目中调用示例fromlogger_utilsimportloggerdeftest_log():logger.info(项目日志工具加载完成)logger.debug(测试 debug 日志)try:1/0exceptExceptionase:logger.error(程序运算异常,exc_infoTrue)if__name____main__:test_log()exc_infoTrue会自动打印异常堆栈信息排查报错必备参数。四、Python 装饰器核心知识FastAPI 重中之重4.1 装饰器本质装饰器 接收函数为参数返回新函数的高阶函数作用在不修改原有函数内部代码的前提下对函数执行前后进行功能增强统计耗时、打印日志、权限校验、异常捕获等。4.2 基础无参装饰器模板importtime# 定义装饰器deftimer_decorator(func):defwrapper(*args,**kwargs):starttime.time()# 执行原函数resfunc(*args,**kwargs)costround(time.time()-start,3)print(f函数{func.__name__}执行耗时{cost}s)returnresreturnwrapper# 使用装饰器语法糖 timer_decoratordefdemo_func(sleep_time):time.sleep(sleep_time)return函数执行完毕if__name____main__:print(demo_func(1.2))执行流程拆解demo_func(1.2)→ 实际调用的是wrapper(1.2)→wrapper内部计时 调用原函数 打印耗时 → 返回原函数结果。4.3 带参数的装饰器写法外层再包裹一层函数用来接收装饰器自身参数importtimedeftimer_param(threshold:float):threshold: 超时阈值单位秒defouter(func):defwrapper(*args,**kwargs):stime.time()retfunc(*args,**kwargs)ctime.time()-sifcthreshold:print(f函数{func.__name__}执行超时耗时{c:.3f}s阈值{threshold}s)else:print(f函数{func.__name__}正常执行耗时{c:.3f}s)returnretreturnwrapperreturnouter# 传入阈值参数 0.5 秒timer_param(threshold0.5)deftest_sleep(t):time.sleep(t)test_sleep(0.8)# 输出执行超时test_sleep(0.2)# 输出正常执行三层嵌套结构timer_param(参数)→ 返回outer→outer修饰func→ 返回wrapper。4.4 装饰器修复函数元信息wraps被装饰后的函数会丢失原函数名称、注释文档使用functools.wraps修复fromfunctoolsimportwrapsdeflog_decorator(func):wraps(func)defwrapper(*args,**kwargs):print(f开始执行函数{func.__name__})returnfunc(*args,**kwargs)returnwrapperlog_decoratordefhello():测试函数文档注释passprint(hello.__name__)# 输出hello不加 wraps 会输出 wrapperprint(hello.__doc__)# 输出测试函数文档注释不加 wraps 会输出 None记忆口诀定义装饰器时wraps(func)写在最内层wrapper上面养成习惯。4.5 装饰器修饰异步函数适配 Day1 异步代码异步函数必须在内部await调用原函数普通同步装饰器无法直接修饰async函数importasyncioimporttimefromfunctoolsimportwrapsdefasync_timer(func):wraps(func)asyncdefwrapper(*args,**kwargs):sttime.time()resultawaitfunc(*args,**kwargs)# 注意await 调用原函数costtime.time()-stprint(f异步函数{func.__name__}耗时{cost:.3f}s)returnresultreturnwrapper# 修饰 aiohttp 异步请求函数async_timerasyncdefasync_test():awaitasyncio.sleep(1)print(异步任务执行完成)asyncio.run(async_test())同步装饰器 vs 异步装饰器对比同步装饰器异步装饰器wrapper定义def wrapper(...)async def wrapper(...)调用原函数func(*args, **kwargs)await func(*args, **kwargs)适用场景同步函数async def异步函数五、结合日志 装饰器实战统一接口耗时 异常捕获装饰器日常 FastAPI 开发高频通用装饰器直接放入工具类复用importtimefromfunctoolsimportwrapsfromlogger_utilsimportloggerdefapi_wrapper(func):统一接口日志 耗时统计 异常捕获装饰器wraps(func)asyncdefwrapper(*args,**kwargs):starttime.time()try:respawaitfunc(*args,**kwargs)costround(time.time()-start,4)logger.info(f接口{func.__name__}请求正常耗时{cost}s)returnrespexceptException:costround(time.time()-start,4)logger.error(f接口{func.__name__}执行异常耗时{cost}s,exc_infoTrue)raise# 原样抛出异常保留原始调用栈returnwrapper要点说明exc_infoTrue会自动将异常堆栈写入日志无需手动拼接错误信息。raise不带异常对象会原样抛出保留原始 traceback比raise e更规范。六、Day2 知识点总结序号知识点掌握程度1logging 5 级分级规则理解并会使用2colorlog 控制台彩色日志能独立配置3可复用日志工具类控制台 文件能直接导入使用4基础无参装饰器能手写模板5带参数装饰器三层嵌套理解原理6functools.wraps元信息修复养成习惯7异步函数装饰器编写适配 FastAPI 异步接口8日志 装饰器联合实战产出通用工具下期预告Day3FastAPI 第一个 HelloWorld 接口、路径参数、查询参数、请求体 POST 参数详解正式开始编写后端接口。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门