feat(log): 前后端共用 request_id 与四时间点时钟校准

- X-Request-Id 请求头带合法 UUID 则沿用为 request_id(严格格式白名单防注入),否则自生成 12 位 hex
- 响应头新增 X-Server-Received-Ms / X-Server-Sent-Ms 供前端时钟校准
- CORS Allow-Headers 增加 X-Request-Id,Expose-Headers 显式列出(credentials 下不认 *)

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-27 07:46:38 +08:00
parent e22df36d3f
commit d3e71decf4
4 changed files with 157 additions and 9 deletions
+21 -3
View File
@@ -23,13 +23,31 @@ HoTime 框架内置 Seq 日志推送支持。通过在 `config.json` 填写 `seq
激活后每个 HTTP 请求会自动:
- 生成 `request_id`12 位 hex),回写响应头 `X-Request-Id`
- 确定 `request_id`前端带合法 UUID 则沿用,否则自生成 12 位 hex),回写响应头 `X-Request-Id`
-`sessionId` 前 12 位作为 `sid` 写入请求级日志(脱敏,避免把登录凭据写进 Seq)
- 业务日志、SQL 日志、访问日志均携带 `sid` / `request_id`
- **控制台自动降噪**(零额外配置):业务日志(`that.Log`)控制台放宽到 **Info+**(Debug/SQL 不上控制台),访问日志(`that.WebConnectLog`)控制台保持 **Warn+**(量大不上控制台);Debug/SQL/访问日志(Info 级)仍全量进 Seq 与文件
---
## 请求追踪与前端串联(共用 request_id
前后端**共用一个 `request_id`**:前端为每次请求生成 UUID 并经 `X-Request-Id` 请求头带上,服务端严格校验(36 位 8-4-4-4-12 hex+连字符,统一小写)通过则直接沿用为本请求 `request_id`;非法或缺失(含浏览器直接访问、老前端)则服务端自生成 12 位 hex。最终值回写响应头 `X-Request-Id`,业务/SQL/访问日志统一携带——Seq 里一条 `request_id = '<uuid>'` 即可同时串出前端事件与后端全链路日志。
- 严格格式白名单杜绝日志注入(换行/引号/超长一律丢弃走自生成分支)
- 前端伪造/重复 UUID 只污染其自身请求的串联,不影响其他请求;接受该风险换取单字段简洁
同时每个请求回写**服务端收发时间**响应头,供前端做四时间点时钟校准(前端日志的 `@t` 对齐服务器时间轴):
- `X-Server-Received-Ms`handler 入口时间(ms
- `X-Server-Sent-Ms`:响应体写出前时间(ms`context.View()` 设置;静态文件不带)
CORS 已相应放行/暴露:`Access-Control-Allow-Headers` 增加 `X-Request-Id``Access-Control-Expose-Headers``*` 改为显式 `X-Request-Id,X-Server-Received-Ms,X-Server-Sent-Ms`credentials 模式下浏览器不认 `*`)。
**怎么测**`request_trace_test.go``go test . -count=1 -run 'TestNormalizeRequestId|TestRequestIdSharing|TestViewSetsServerSentMsHeader'`
---
## 会话追踪与 LogBind
框架在 `handler` 入口派生请求级 Logger,并浅拷贝 `Db` 将其 `Log` 指向同一 Logger,因此 **SQL 日志自动带会话字段**。字段会出现在同条日志的控制台/文件/Seq 出口上。
@@ -122,7 +140,7 @@ multiWriterhotimev1.5/log/logger.go
| `message` / `msg` | `@m` | 消息正文(不用 `@mt`,避免 `{xxx}` 被当模板) |
| `caller` | `caller` | 调用位置 |
| `sid` | `sid` | sessionId 前 12 位 |
| `request_id` | `request_id` | 单次请求 id |
| `request_id` | `request_id` | 单次请求 id(前端合法 UUID 沿用,否则服务端 12 位 hex) |
| `ip` | `ip` | 客户端最佳 IP |
| `ip_chain` | `ip_chain` | 多源去重链路(与 `ip` 不同时才有) |
| `ip_country` | `ip_country` | 有 `EO-Client-IPCountry` 时 |
@@ -138,7 +156,7 @@ multiWriterhotimev1.5/log/logger.go
| 目标 | 查询语句 |
|---|---|
| 按会话追踪 | `sid = 'abc123def456'` |
| 按单次请求 | `request_id = 'fedcba987654'` |
| 按单次请求(前后端同 id 串联) | `request_id = '6f0a1b2c-3d4e-4f5a-8b6c-7d8e9f0a1b2c'`(服务端自生成时为 12 位 hex |
| 关键词 | 直接输入,如 `支付失败` |
| 日志级别 | `@l = 'Error'` |
| 特定实例 | `instance = '192.168.1.10:8085'` |