feat: add the single summarizer for HTTP error bodies
Issue #10 Task 2: head-and-tail rather than a head-only cut, because the code and request_id that let you chase the provider sit at the very end of a JSON error body. Cap 2048 follows k8s client-go for the same job.
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
"""HTTP 错误响应体的取用与摘要(issue #10 设计 §3.2)。
|
||||
|
||||
两个 transport 各有自己的状态码分类逻辑(OCR 有意不做 429 细分),但**摘要口径
|
||||
必须是同一份**——issue #10 的教训正是"只有一个分支用了响应体",一处例外就是
|
||||
下一次事后查不到原因。故本模块是全库唯一的摘要实现,不得在别处复制。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import httpx
|
||||
|
||||
_ERROR_BODY_CAP = 2048
|
||||
"""摘要总长上限(**字符**,含省略标记在内)。
|
||||
|
||||
取值对齐 Kubernetes client-go `rest/request.go` 的 `maxUnstructuredResponseTextBytes
|
||||
= 2048`——它是唯一与本设计同场景(读 HTTP 错误体做诊断)的成熟先例。按字符而非
|
||||
字节切,多字节字符不会被切成半个;`error` 列是 TEXT,无定长约束,不需要字节口径。
|
||||
"""
|
||||
|
||||
_HEAD_CHARS = 1400
|
||||
_TAIL_CHARS = 600
|
||||
|
||||
|
||||
def summarize_body(text: str) -> str:
|
||||
"""折叠空白后按头尾策略摘要;空/空白入参返回空串。
|
||||
|
||||
**折叠空白**不是洁癖: 错误体常是缩进 JSON,原样拼进 message 会把一行日志
|
||||
炸成多行、把遥测列变得不可读。
|
||||
|
||||
**保头保尾**而非头部硬切: 截断的对象是结构化 JSON,信息分布头重尾也重——
|
||||
人话(`message`)在前,机器可判的 `type`/`code`/`param`/`request_id` 在后。
|
||||
k8s/Sentry 用头部硬切是因为它们截的是任意文本;本函数截的是错误 JSON,
|
||||
头部硬切正好切掉向网关方追查时唯一有用的那部分。策略取自标准库 `reprlib`
|
||||
对"给人读的长字符串"的处置。
|
||||
|
||||
**标记记下省略字数**,读的人才知道自己丢了多少,不会误以为网关只说了这么多。
|
||||
"""
|
||||
collapsed = " ".join(text.split())
|
||||
if len(collapsed) <= _ERROR_BODY_CAP:
|
||||
return collapsed
|
||||
omitted = len(collapsed) - _HEAD_CHARS - _TAIL_CHARS
|
||||
return f"{collapsed[:_HEAD_CHARS]}…(略 {omitted} 字)…{collapsed[-_TAIL_CHARS:]}"
|
||||
|
||||
|
||||
def compose_message(message: str, summary: str) -> str:
|
||||
"""摘要非空才拼后缀,避免留下悬空的分隔符。
|
||||
|
||||
分隔符取 ` | ` 而非既有的 `: `,让"库说的话"与"网关说的话"一眼可分。
|
||||
"""
|
||||
return f"{message} | {summary}" if summary else message
|
||||
|
||||
|
||||
def response_body(response: httpx.Response) -> str:
|
||||
"""取**已缓冲**的响应文本;未读缓冲一律降级空串。
|
||||
|
||||
绝不在此触发网络读: 那会在错误路径上凭空插入一次可能挂住的 IO。降级方向
|
||||
与缓存/遥测同档(库铁律)——诊断信息缺失不得把一次本可正确分类的失败变成
|
||||
不可分类的崩溃,那正是 `ResponseNotRead` 泄漏出四分类之外的后果。
|
||||
"""
|
||||
try:
|
||||
return response.text
|
||||
except httpx.ResponseNotRead:
|
||||
return ""
|
||||
Reference in New Issue
Block a user