ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Litestar 请求日志完全指南:LoggingMiddleware 从配置到源码实现

Litestar 请求日志完全指南:LoggingMiddleware 从配置到源码实现 Litestar 请求日志完全指南LoggingMiddleware 从配置到源码实现【免费下载链接】litestarLight, flexible and extensible ASGI framework | Built to scale项目地址: https://gitcode.com/GitHub_Trending/li/litestarLitestar 通过LoggingMiddleware中间件为每个 HTTP 请求/响应自动记录日志且对底层日志库完全解耦——标准库logging、structlog或任何符合logging.Logger接口的对象都可以直接传入。读完本篇你将掌握如何在Litestar应用中接入请求日志、可配置的请求/响应日志字段全集、敏感数据Headers/Cookies脱敏机制、与CompressionConfig共存时响应体日志的行为、结构化日志模式以及异常路径401/403/500下状态码为何也能被正确记录并可对照仓库源码与测试用例逐条验证。一、基本用法把 LoggingMiddleware 加入应用Litestar 将日志能力封装为独立的 ASGI 中间件通过应用的middleware参数注册即可。日志器可以是一个logging.Logger实例或任何符合Logger协议的第三方 logger一个返回 logger 的可调用对象一个字符串Litestar 内部会调用logging.getLogger(name)将其转换为标准库 logger见 litestar/middleware/logging.py 的 logger 解析逻辑。官方示例来自 docs/examples/middleware/logging_middleware.pyimport logging from litestar import Litestar, get from litestar.middleware.logging import LoggingMiddleware get(/) async def my_handler() - dict[str, str]: return {hello: world} app Litestar( route_handlers[my_handler], middleware[ LoggingMiddleware( logging.getLogger(my.app), request_log_fields(query, body), # only log query and body fields ) ], )每个 HTTP 请求会产出两条日志一条HTTP Request请求进入时记录一条HTTP Response响应发出后记录。完整参数参考以下参数来自LoggingMiddleware.__init__签名litestar/middleware/logging.py参数类型默认值说明loggerlogging.Logger \| Logger \| str \| Callable[[], Logger]必填日志器实例、字符串名称或返回 logger 的工厂函数excludestr \| list[str] \| NoneNone正则路径模式列表匹配的请求跳过日志exclude_opt_keystr \| NoneNone当 scope 中该 key 对应值为真时跳过日志可按路由 opt-outinclude_compressed_bodyboolFalse压缩响应体是否仍记录到body字段request_cookies_to_obfuscateIterable[str](session,)请求中需脱敏的 Cookie 名request_headers_to_obfuscateIterable[str](Authorization, X-API-KEY)请求中需脱敏的 Header 名response_cookies_to_obfuscateIterable[str](session,)响应中需脱敏的 Cookie 名response_headers_to_obfuscateIterable[str](Authorization, X-API-KEY)响应中需脱敏的 Header 名request_log_messagestrHTTP Request请求日志消息前缀response_log_messagestrHTTP Response响应日志消息前缀request_log_fieldsSequence[RequestExtractorField](path, method, content_type, query, path_params)要记录的请求字段response_log_fieldsSequence[ResponseExtractorField](status_code,)要记录的响应字段parse_bodyboolFalsebody字段按 Content-Type 解析为结构化数据否则记录原始字节parse_queryboolTruequery字段解析为 dict否则记录原始字节串log_structuredboolFalse结构化日志模式字段以关键字参数传给 logger二、默认记录哪些字段原文档明确了默认日志属性这里结合 litestar/data_extractors.py 中的RequestExtractorField/ResponseExtractorField类型定义给出完整的可选项清单。默认请求日志属性request_log_fields默认值path—— 请求路径method—— HTTP 方法Request.methodcontent_type—— 解析后的 Content-Type 及选项query—— 查询参数parse_queryTrue时为 dictpath_params—— 路径参数默认响应日志属性status_code—— 响应状态码全部可选项按需追加到request_log_fields/response_log_fields请求侧path、method、content_type、headers、cookies、query、path_params、body、scheme、client响应侧status_code、headers、body、cookies从测试用例tests/unit/test_middleware/test_logging_middleware.py可以看到字段裁剪的效果LoggingMiddleware(litestar.test, response_log_fields[status_code], request_log_fields[path]) # 日志输出 # HTTP Request: path/ # HTTP Response: status_code200排除特定路径exclude传入正则字符串或列表匹配的路径不记录日志LoggingMiddleware(litestar.test, exclude[^/exclude])exclude_opt_key指定一个 scope 键适合按路由精细控制。从源码结构看路由处理器可在 handler 上通过opts携带该键例如get(/exclude, skip_loggingTrue)配合exclude_opt_keyskip_logging实现“某个路由不记录日志”的声明式写法。两种用法均有测试覆盖tests/unit/test_middleware/test_logging_middleware.py。三、脱敏避免敏感数据进入日志请求/响应中的 Header 与 Cookie 往往携带凭证Litestar 内置脱敏机制被脱敏的键值会替换为*****实现见 litestar/data_extractors.py 的_obfuscate匹配不区分大小写。默认脱敏项即使你不配置任何脱敏参数也会生效请求/响应 HeaderAuthorization、X-API-KEY请求/响应 Cookiesession扩展脱敏范围的官方写法与 docs/usage/logging.rst 中示例一致from litestar.middleware.logging import LoggingMiddleware logging_middleware_config LoggingMiddleware( request_cookies_to_obfuscate{my-custom-session-key}, response_cookies_to_obfuscate{my-custom-session-key}, request_headers_to_obfuscate{my-custom-header}, response_headers_to_obfuscate{my-custom-header}, )一个实战相关的佐证使用内置 session 中间件时sessionCookie 本身不会被日志中间件改写——测试test_logging_middleware_with_session_middlewaretests/unit/test_middleware/test_logging_middleware.py断言客户端 Cookie 中的session值原样保留只有日志输出中的值会被脱敏保证“日志脱敏”与“运行时行为”互不干扰。四、压缩与响应体日志的交互当应用同时配置了 CompressionConfig如compression_configCompressionConfig(backendgzip, minimum_size1)与LoggingMiddleware时即使response_log_fields包含body被压缩的响应体默认也不会被记录日志中间件能拿到的 body 是压缩后的字节原文无法直接还原如需强制记录压缩响应体将include_compressed_bodyTrue与response_log_fields中的body一起设置。源码中该逻辑位于 litestar/middleware/logging.py 的extract_response_data通过ScopeState读取response_compressed标志当字段为body且响应已压缩时仅当include_compressed_body为真才写入数据。参数化测试test_logging_middleware_compressed_response_bodytests/unit/test_middleware/test_logging_middleware.py验证了includeTrue/False两种分支includeTrue时日志包含bodyincludeFalse时不包含。五、结构化日志Structured Logging设置log_structuredTrue后中间件不再把字段拼接成keyvalue字符串而是期望一个接受任意关键字参数的 logger即以self.logger.info(message, **values)的方式调用见 litestar/middleware/logging.py 的log_message。这与 structlog 等结构化日志库天然契合。官方示例docs/examples/middleware/logging_middleware_structlog.pyimport structlog from litestar import Litestar, get from litestar.middleware.logging import LoggingMiddleware get(/) async def my_handler() - dict[str, str]: return {hello: world} app Litestar( route_handlers[my_handler], middleware[ LoggingMiddleware( structlog.get_logger(my.app), request_log_fields(query, body), # only log query and body fields ) ], )测试用例test_logging_middleware_struct_loggertests/unit/test_middleware/test_logging_middleware.py展示了 structlog JSONRenderer 下的实际输出形态每条日志是一个结构化事件字段平铺为字典键{ event: HTTP Request, path: /, method: GET, content_type: (, {}), headers: {host: testserver.local, ...}, cookies: {request-cookie: abc}, query: {}, path_params: {}, log_level: info, }非结构化模式下的输出则是单行字符串例如HTTP Request: path/, methodGET, content_type[,{}], query{}, path_params{}。仓库中还提供了一个可运行的 structlog 集成示例应用 test_apps/structlog_app/main.py演示了StructLoggingConfigLoggingMiddleware在 handler 内使用request.logger的组合方式可作为接入参考注意其中引用了litestar.logging.config与当前litestar.middleware.logging的模块路径对照阅读。六、响应日志的底层机制send 包装器从源码结构看LoggingMiddleware是ASGIMiddleware子类scopes (ScopeType.HTTP,)只处理 HTTP 连接其响应日志依赖对 ASGIsend函数的包装litestar/middleware/logging.pycreate_send_wrapper拦截http.response.start与http.response.body两类消息缓存到ScopeState.log_context每当收到 body 消息即调用log_response用ResponseDataExtractor从 start/body 消息中提取status_code、headers自动剥离set-cookie头、cookies从set-cookie解析等字段当more_body为假时清空日志上下文完成一次请求的日志闭环。请求日志则在handle入口先行执行构造Request实例后经ConnectionDataExtractor.extract按request_log_fields逐字段提取body提取器还会根据parse_body与 Content-Type 决定解析为 JSON/form 结构还是返回原始字节litestar/data_extractors.py并且内置了skip_parse_malformed_bodyTrue保护——畸形请求体如尾部多逗号的 JSON不会导致日志崩溃而是回退为原始字节。异常路径也能记录响应状态一个容易被忽略的能力HTTP 异常与未处理异常也会触发响应日志。handle中捕获HTTPException时将异常携带的status_code写入log_context再记录响应日志401/403 等捕获其他Exception时则按 500 记录随后原样抛出litestar/middleware/logging.py。对应测试test_logging_middleware_records_correct_status_for_exceptions验证了 401/403 状态码出现在日志中test_logging_middleware_records_generic_exception_as_500验证了通用异常场景tests/unit/test_middleware/test_logging_middleware.py。这意味着即使请求以错误结束你依然能在日志里看到真实的响应状态码而不是只有一条孤立的请求记录。七、接入第三方日志库文档给出的原则是直接传入第三方 logger 即可Litestar 不绑定任何具体日志框架structlogLoggingMiddleware(structlog.get_logger(my.app), log_structuredTrue)配合JSONRenderer等 processor 输出 JSON 日志标准库 logging传logging.getLogger(my.app)或字符串名称均可输出为拼接字符串仓库中的 test_apps/structlog_app/main.py 提供了带StructLoggingConfig的完整应用模板可用uvicorn直接运行验证。相关文档与代码入口使用指南docs/usage/logging.rstAPI 参考docs/reference/middleware/logging.rst中间件实现litestar/middleware/logging.py数据提取器litestar/data_extractors.py单元测试tests/unit/test_middleware/test_logging_middleware.py【免费下载链接】litestarLight, flexible and extensible ASGI framework | Built to scale项目地址: https://gitcode.com/GitHub_Trending/li/litestar创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表