补齐相关日志日志

This commit is contained in:
2026-09-16 00:23:49 +08:00
parent 8c2ea84939
commit b2e5eef3c8
39 changed files with 1576 additions and 176 deletions
@@ -0,0 +1,104 @@
---
name: 日志打点全量评估报告
overview: 全量审计 zt-closet-backend 项目中所有 slog 日志打点,从覆盖度(关键路径遗漏)、级别合理性、字段完整性、敏感信息、规范一致性等维度评估,在 docs/ 下产出一份日志专项评估报告(不改代码)。
todos:
- id: inventory-logging
content: 用 [subagent:code-explorer] 全量盘点所有 slog 打点明细及日志基础设施实现
status: completed
- id: audit-coverage
content: 用 [subagent:code-explorer] 对照业务主线、后台任务与资损路径审计日志覆盖遗漏点
status: completed
dependencies:
- inventory-logging
- id: audit-quality
content: 审计日志级别、字段完整性、敏感信息与规范一致性问题并分级
status: completed
dependencies:
- inventory-logging
- id: write-report
content: 撰写 docs/日志专项评估报告-2026-09-15.md(问题清单+覆盖矩阵+结论)
status: completed
dependencies:
- audit-coverage
- audit-quality
- id: verify-report
content: 抽查报告中文件行号引用与结论准确性,修正偏差并定稿
status: completed
dependencies:
- write-report
---
## User Requirements
对 zt-closet-backend 后端项目**代码中的日志打点**进行一次全量分析评估,核心问题:「是否存在遗漏与不足」。
- **遗漏评估**:关键业务路径(登录、上传、支付、退款、额度、AI 推荐、分享、通知等)、错误分支、后台任务失败分支、中间件异常分支是否存在日志缺失。
- **不足评估**:日志级别是否合理(Error/Warn/Info/Debug 误用)、关键字段是否完整、是否使用 Context 版本 API 以关联 trace_id/span_id、是否泄露敏感信息、字段命名与 msg 风格是否一致。
- **交付物**:在 docs/ 下新增一份日志专项评估报告,列出遗漏点与改进建议。
- **明确约束**:仅输出评估报告,**不修改任何代码**。
## Product Overview
产出一份中文 Markdown《日志专项评估报告》,面向开发/运维人员,作为后续日志优化工作的依据。报告需结论明确、可直接执行:每个问题带精确定位(文件:行号)、问题描述、影响说明与改进建议,并按严重度分级排序,便于后续按优先级逐项处理。
## Core Features
1. **日志基础设施盘点**:输出通道(文件+stdout+OTel 桥接)、滚动策略、级别配置映射、query 脱敏、trace_id/span_id 注入机制现状。
2. **全量打点清单与覆盖度对照矩阵**:覆盖全部 slog 调用点;对照 7 条业务主线、6 个后台任务、资损敏感路径(支付/退款回调、权益发放回收、额度扣减回退、鉴权降级)逐项标注有/无日志。
3. **多维度质量审计**:级别合理性、字段完整性(实体 ID)、敏感信息风险(openid/手机号/token/回调报文)、规范一致性(msg 风格、user_id/userID 命名、ctx 版本使用率)。
4. **结构化问题清单**:编号 + 严重度 + 位置 + 问题 + 影响 + 改进建议,风格对齐 docs/ 既有审查报告。
5. **总体结论**:遗漏与不足的总体判断及改进优先级建议。
## 审计方法(Implementation Approach)
采用**静态代码审计**方式,不运行服务、不依赖运行环境:
1. **盘点阶段**:全量收集所有 slog 调用点(文件、行号、级别、msg、字段、是否 `XxxContext` 版本),同步梳理日志基础设施实现:`main.go`(setupSlogLogger)、`pkg/tracing/fanout.go`、`pkg/tracing/otel.go`、`internal/middleware/logger.go`、配置项 `Log.LogLevel`。
2. **覆盖度审计**:以 README 的 7 条业务主线、6 个后台任务、历史审查报告标注的资损敏感路径为对照基准,逐个关键函数(handler → service → 错误/失败分支)标注日志有无,形成覆盖矩阵并识别遗漏。
3. **质量审计**:对每条打点按 6 个维度逐条检查:级别合理性、字段完整性、敏感信息、trace 关联、命名一致性、基础设施配置。
4. **撰写报告**:对齐 `docs/` 既有审查报告风格(中文、编号+严重度+位置+问题+影响+建议、修复状态可标注)。
5. **校验阶段**:抽查报告中 `文件:行号` 引用与结论准确性,修正偏差后定稿。
## 已知事实基准(用于对照)
- 打点总量约 200 处(非测试约 190+),分布:service 层约 110+、tokenhub/scheduler.go 16、main.go 13、middleware 3 处。
- **0 打点区域**:`internal/routers/`(15 文件)、`internal/mysqldao/`(19 文件)、`internal/redisdao/`(12 文件)、`pkg/` 除 tokenhub/tracing 外全部包;`internal/service/` 中 adreward.go、goods.go、horoscope.go 无打点。
- 基础设施:JSON 日志(lumberjack 滚动压缩 + stdout)+ otelslog 桥接;`OtelContextHandler` 仅在 `slog.XxxContext(ctx)` 调用时才注入 trace_id/span_id;`GinSlogMiddleware` 对 query 中 token/code/secret/password 等脱敏,但请求体不记录。
- 其他输出:main.go:320、pkg/tracing/provider.go:114 用 fmt.Printf(logger 未就绪场景);cmd/migrate 用 fmt.Println(CLI,不纳入问题清单)。
## 评估维度框架(6 项)
1. 覆盖度/遗漏;2. 级别合理性;3. 字段完整性;4. 敏感信息;5. 规范一致性;6. 基础设施配置(如 LogLevel=Info 时 Debug 打点在生产的有效性)。
## 报告结构设计
1. 审计范围与方法说明(含局限:未连接运行环境、以当前工作区代码为准);
2. 日志基础设施现状;
3. 问题清单(按 高/中/低 分级,每条含位置+问题+影响+建议);
4. 关键路径日志覆盖度对照矩阵;
5. 总体结论与改进优先级建议。
## Implementation Notes(执行要点)
- 所有问题必须带 `文件:行号` 引用,行号以**当前工作区**文件为准(工作区存在未提交改动,不得依据历史报告行号)。
- 严重度分级原则:资损/安全相关遗漏(如支付校验失败静默、权益回收无日志)为高;排查困难类(无实体 ID、缺 ctx 关联)为中;规范统一类(命名/风格)为低。
- 报告中描述敏感字段时仅引用字段名,不复制任何真实敏感值;不打印任何配置密钥内容。
- 结论表述为建议(如"建议补充……"),不包含代码修改动作;不再引入与日志无关的审查项(如业务逻辑缺陷),聚焦日志主题。
## Directory Structure
本次仅新增 1 个文件,不修改任何代码:
```
zt-closet-backend/
└── docs/
└── 日志专项评估报告-2026-09-15.md # [NEW] 日志专项评估报告。内容:审计范围与方法说明、日志基础设施现状盘点、按严重度分级的问题清单(编号+位置+问题+影响+改进建议,覆盖遗漏与不足两类)、关键业务路径日志覆盖度对照矩阵、总体结论与改进优先级建议。需对齐 docs/ 既有审查报告的中文风格与"文件:行号"引用规范,所有结论须经代码抽查验证。
```
## Agent Extensions
### SubAgent
- **code-explorer**
- Purpose: 承担跨目录的大规模代码探索:全量收集所有 slog 调用点清单(位置/级别/字段/上下文版本)与日志基础设施实现细节;并对照业务主线逐个关键路径函数核实日志覆盖情况。
- Expected outcome: 产出结构化的打点明细清单与关键路径覆盖情况数据,作为评估报告"问题清单"与"覆盖度对照矩阵"的可靠事实依据,确保报告中所有定位与结论准确可核验。
@@ -0,0 +1,173 @@
---
name: 日志问题全量修复
overview: 依据 docs/日志专项评估报告-2026-09-15.md,以"纯日志改进,零控制流变更"为边界,全量修复 H1-H10 / M1-M8 / L1-L5 共 23 项问题及覆盖矩阵点名的具体静默点:补齐缺失日志、修正级别与字段、修复 trace 断链、增加任务心跳与 Debug 能力、改进日志配置健壮性,并通过构建/测试与逐项 diff 复核保证行为不变。
todos:
- id: fix-trade-logging
content: 补齐交易与回调链路日志:H1-H7/H9 静默点、成功审计与去重,不改控制流
status: completed
- id: fix-auth-user-logging
content: 补齐鉴权与用户链路日志:H8 拒绝分支、登录注册与账号操作静默点
status: completed
- id: fix-clothes-community-logging
content: 补齐衣物与社区链路日志:上传、删除、公开、双写等静默点
status: completed
- id: fix-ai-horoscope-logging
content: 补齐 AI 推荐与运势链路日志:提交、落库、降级静默点
status: completed
- id: fix-quota-scheduler-logging
content: 补齐额度与调度日志:H10、trace 断链与心跳,用 [skill:lsp-code-analysis] 核查签名引用
status: completed
- id: fix-log-infra
content: 改造日志基础设施:访问日志分级、Recovery 结构化、LogLevel 容错与 fanout trace
status: completed
- id: verify-and-annotate
content: 用 [subagent:code-explorer] 复核修复完整性,构建测试通过后标注评估报告状态
status: completed
dependencies:
- fix-trade-logging
- fix-auth-user-logging
- fix-clothes-community-logging
- fix-ai-horoscope-logging
- fix-quota-scheduler-logging
- fix-log-infra
---
## Product Overview
依据《日志专项评估报告(2026-09-15)》对后端服务实施全量日志修复:覆盖报告列出的 23 项编号问题(高 10 项、中 8 项、低 5 项)及评估矩阵点名的全部日志静默点,涉及 20 余个源文件。修复完成后,关键业务失败场景均可在日志中定位、日志可关联同一次请求、级别与字段规范统一,并在评估报告中逐项标注修复状态。全部改动限定为纯日志改进:不改变任何业务行为。
## Core Features
- 交易与回调链路:补齐回调验证、幂等锁、支付信息落库、退款流转、过期补发货、下单失败等静默场景日志,并补成功侧审计日志
- 鉴权与用户链路:补齐各类鉴权拒绝分支、令牌刷新、登录注册、账号操作失败的日志
- 衣物与社区链路:补齐上传校验、删除回退、公开扣额、双写一致性等失败日志
- AI 推荐与运势链路:补齐任务提交、后台生成、落库、降级场景日志
- 额度与后台任务:补齐额度事务失败日志,六个定时任务增加每轮运行记录
- 日志基础设施:访问日志按状态分级、异常恢复输出纳入统一日志、配置容错、链路标识完整注入
- 评估报告逐项标注修复状态(已修复 + 日期)
## Tech Stack
- 语言与框架:Go 1.27 + Gin(沿用现状,不新增任何第三方依赖)
- 日志:标准库 log/slog(JSON 结构化)+ lumberjack 滚动文件(沿用既有输出通道与 OpenTelemetry 桥接)
- 验证工具:gofmt、go vet、go build、go test
## Implementation Approach
### 总体策略
按"文件集互不重叠"的 6 个修复批次顺序执行,加 1 个验证与标注批次(共 7 个任务):
| 批次 | 文件集 | 覆盖问题 |
| --- | --- | --- |
| T1 交易与回调 | order.go、virtualpay.go、virtualpay_compensate.go、benefit_compensation.go、order_expire.go、routers/api/v1/order.go | H1-H7、H9、M1/M2/M3/M4/M5、L3 |
| T2 鉴权与用户 | lzcwyjwt.go、user.go | H8、M1/M2/M3、L4、矩阵缺口 |
| T3 衣物与社区 | clothes.go、outfit.go、like.go、collect.go、closet.go、outfit_share.go、notification.go | H10(clothes 部分)、M2/M3/M4/M5、L4/L5、矩阵缺口 |
| T4 AI 与运势 | airecommend.go、horoscope.go、ai_outfit_cleanup.go | M2/M3/M4/M5、L5、矩阵缺口 |
| T5 额度与调度 | service.go、quota.go、quota_expire.go、tokenhub/scheduler.go、redismodel/keys.go | H10(service 部分)、M3/M4/M5、L4 |
| T6 基础设施 | middleware/logger.go、middleware/recovery.go(新增)、routers/router.go、main.go | M6、L1、L2、M3(fanout) |
| T7 验证与标注 | 全仓复核 + 评估报告状态标注 | 全部 |
### 关键设计决策
1. **唯一落点去重**:每个失败场景只在有完整业务上下文处记录一次。普通支付/退款回调的失败判定(验签/解密/非 SUCCESS/金额等)统一由 service 层记录,handler 只回 FAIL 应答不重复记录;XPay 入口层失败(读体/验签/解密/兼容回显/加密降级)service 不可见,由 handler 层记录;pkg/wechat 等客户端不加日志(错误上抛到 service 记录),避免与 H1 重复。
2. **静默值统一范式**:被 `_ =` 丢弃的返回值改为"接收并记录错误但不阻断后续流程":order.go:461-465、virtualpay.go:426-430、virtualpay.go:370(仅记录,仍 return nil)、outfit.go:277-281、closet.go:131-141 等。
3. **锁错误拆分**:`lerr != nil` 记 Error、`!ok`(正常竞争)记 Debug;分支行为不变(仍 return nil 当作并发处理)。
4. **级别规范**:业务性拒绝 Info;可恢复 / best-effort 失败 Warn;主流程与资损失败 Error;高频与细节路径 Debug(补齐全仓 Debug 能力,L5)。
5. **链路标识**:ctx 可得时一律使用 slog.XxxContext;service.go 事务函数(cosRemainTx、refundCosQuotaTx)透传 ctx;clothes.go:320 清理 context 改用 context.WithoutCancel(ctx) 派生以保留 span 值;user.go:541 异步复位派生独立 span;main.go 将 OtelContextHandler 移至 FanoutHandler 外层,使本地与 OTel 两条分支都注入 trace_id/span_id(本地输出等价、OTel 分支增强)。
6. **后台任务心跳**:每轮有产出记 Info、无产出 / 零值轮次记 Debug(高频任务保持低噪),字段含 scanned / affected / failed 等。
7. **访问日志与 Recovery**:访问日志按状态码分级(5xx 记 Error、4xx(除 401)记 Warn、401 与其余记 Info),user_agent 截断 256 字符;新增 Recovery 中间件:panic 信息与堆栈经 slog.ErrorContext 输出,HTTP 500 与 broken-pipe 处理保持 gin 默认语义。
8. **配置健壮性**:LogLevel 忽略大小写匹配,未匹配值在 logger 就绪后告警并回落 Info;lumberjack 增加 LocalTime: true;AddSource 保留现状(按级别裁剪需自定义 Handler,复杂度与收益不成比例,在报告中注明理由)。
### 性能与可靠性
- 新增日志均为单点 O(1) 调用,无循环内逐条日志;批量任务使用每轮汇总;高频路径(轮询、懒过期、零值轮次)使用 Debug 级,生产默认 Info 下零输出开销;
- 日志调用不进入任何事务 / 锁语义,不改变延迟与并发行为;
- 既有良好实践不回退:资损防线 Error 打点、字段命名(order_no / out_trade_no / _amount)、trace 关联率、敏感信息零泄漏(query 脱敏)。
## Implementation Notes
- 行号基准:以当前工作区文件为准(存在未提交改动),执行时逐文件核对后再修改,不得套用历史报告行号;
- 敏感值红线:不打印 openid 值、session_key、token、回调报文正文(回调报文仅入库);引用字段名不受限;
- 去重检查:同一失败场景唯一落点;同一错误禁止 wrapper 与内层重复记录(virtualpay.go:139/151 需合并为单条);
- msg/字段规范:msg 英文小写、不带标点;字段 snake_case;best-effort 日志不阻断主流程;
- 每批次完成后立即执行 gofmt 与 go build,避免批量错误累积;
- 报告标注:对齐既有 docs 风格(已修复 + 2026-09-15),逐项覆盖 23 项与矩阵缺口。
## Architecture Design
- 无架构变更:不新增分层与模式;唯一新增文件 internal/middleware/recovery.go 属既有 middleware 层;
- 改动分布:service 层 17 个文件(补齐为主);middleware 3 处(鉴权拒绝、访问日志、新增 Recovery);routers 2 处(handler 入口日志、Recovery 替换);main.go 3 处(日志组装、级别容错、LocalTime);pkg 1 处微调(scheduler);
- 数据流不变,仅观测面扩展。
## Directory Structure
```
zt-closet-backend/
├── internal/
│ ├── service/ # 修复主体(17 个文件)
│ │ ├── order.go # [MODIFY] H1(123-129/354-357 回调验签、解密、非 SUCCESS;146/167-170 DB 错误)、H3(134-136/361-363 锁错误拆分)、H4(461-465 记录不阻断)、H5(394-396 settle 失败记录)、H6(196-206 过期补发:成功 Info/DB Error/竞争 Debug)、H7(95-102 落库与 JSAPI 失败)、H9(723-734/786/789 回收静默)、M1(104-115/171-174/341-346/380-389 成功审计)、M2/L3(565/567 补 retry_count/amount/user_id)、M5(438 升 Warn、525 降 Info、741 升 Error)
│ │ ├── virtualpay.go # [MODIFY] H3(244-246/337-339)、H4(426-430)、H5(370 接收返回值记 Error、仍 return nil)、H7(26-63/92-106 业务拒绝 Info、异常 Error)、L3(380 拆分 msg、139/151 去重、345 补 refund_no 与金额)
│ │ ├── virtualpay_compensate.go # [MODIFY] H3(82-85)、M3(142 worker panic 用外层 ctx)、M4(155 每轮汇总补 queried/failed/unpaid)、M5(167 拆分 openid 空/查询失败并修正 error 字段 nil)
│ │ ├── benefit_compensation.go # [MODIFY] H3(43-46)、H9(129-134/61/73/144-146/157 补日志与恢复条数)、L3(154 拆分两种场景)
│ │ ├── order_expire.go # [MODIFY] M4(31-46 每轮汇总:有产出 Info、零值 Debug)
│ │ ├── user.go # [MODIFY] H8(343 吊销失败 Error)、M1(登录成功 Info)、M2/L4(117 补 user_id)、M3(541 独立 span)、矩阵缺口(44-49/70-79/103-105/107-109/111-114/129-131/149-155/222-226/237-294/307-346 各失败点)
│ │ ├── clothes.go # [MODIFY] H10(466-490 删除回退失败)、M2(159 补 user_id、275 retryCall 加业务标识)、M3(320 用 WithoutCancel 派生)、M4(597-620 每轮汇总)、L4(320 补 phase)、L5(143/189/197 状态推进 Debug)、矩阵缺口(55-82 上传校验、84-87 扣额、92-96 落盘、104-109 建记录、609-617 认领与损坏)
│ │ ├── outfit.go # [MODIFY] 矩阵缺口(69-83/136-156/217-224 事务失败 Error、245-248 锁竞争 Debug 与解锁 Warn、256-281 公开失败与扣额回退)、M2(289 补 outfit_uuid)
│ │ ├── like.go / collect.go # [MODIFY] 双写失败(like:60/73、collect:71/78)Warn、写路径 DB 失败 Error、降级 Debug
│ │ ├── closet.go # [MODIFY] 矩阵缺口(72-74/83-94/131-134/139-141/302-304)、M2(102 补 share_uuid)
│ │ ├── outfit_share.go # [MODIFY] 矩阵缺口(63-65/74-80/218-220)
│ │ ├── notification.go # [MODIFY] 矩阵缺口(95-97 Error、124-131 双失败)、M5(170 降 Warn)
│ │ ├── airecommend.go # [MODIFY] 矩阵缺口(68-103 提交三失败点、120-127、153-175、254-260 空衣橱 Info、294-306 落库失败、364-386 运势降级)、M2(270 补 task_id)、M3(417 传 ctx)、M5(213 降 Warn)、L5(轮询 Debug)
│ │ ├── horoscope.go # [MODIFY] 矩阵缺口(51-56/59-67/72-74)
│ │ ├── ai_outfit_cleanup.go # [MODIFY] M4(64-81 每轮汇总)
│ │ ├── service.go # [MODIFY] H10(350-355/103-109/141-144/155-157)、M3(375/434 事务函数透传 ctx)、L4(461 补 related_id/reason)
│ │ └── quota.go / quota_expire.go # [MODIFY] 矩阵缺口(quota:37-40/59-62);M4(quota_expire:80 汇总)
│ ├── middleware/
│ │ ├── lzcwyjwt.go # [MODIFY] H8(30-34/36-41/44-56/59-65 各分支 Warn、71-75 UID 不匹配 Error、84-89/95-99 Warn、91 回填失败 Debug);52 行响应文案不动
│ │ ├── logger.go # [MODIFY] M6(44-53 按状态分级、user_agent 截断)
│ │ └── recovery.go # [NEW] M6:Recovery() 中间件,panic 与堆栈经 slog 输出,500 与 broken-pipe 语义保持 gin 默认
│ ├── routers/
│ │ ├── router.go # [MODIFY] M6:gin.Recovery() 替换为 middleware.Recovery()
│ │ └── api/v1/order.go # [MODIFY] H2(180/187-192/152-173/211-214);普通回调 133-137/142-143 不重复记录(service 唯一落点)
│ └── redismodel/keys.go # [MODIFY] M3(39 启动期无 span,保留并加注释理由)
├── pkg/tokenhub/scheduler.go # [MODIFY] M3/M5(115 用 ctx 并拆分 lerr 记 Error、!ok 记 Info;118 解锁失败 Warn)
├── main.go # [MODIFY] L1(LogLevel 忽略大小写与未匹配告警)、L2(LocalTime: true;AddSource 保留并注理由)、M3(276-291 fanout 重组)
└── docs/日志专项评估报告-2026-09-15.md # [MODIFY] 逐项标注修复状态(已修复 + 2026-09-15)
```
## Key Code Structures
1. main.go 日志组装调整(防误改 fanout.go / otel.go,两者实现均无需改动):
改造前:
```
localHandler := OtelContextHandler{Handler: JSONHandler}
slog.SetDefault(slog.New(NewFanoutHandler(localHandler, otelHandler)))
```
改造后:
```
slog.SetDefault(slog.New(OtelContextHandler{Handler: NewFanoutHandler(JSONHandler, otelHandler)}))
```
本地分支输出等价,OTel 分支获得 trace_id/span_id(FanoutHandler 对子 handler 使用 r.Clone() 分发,外层注入的 attrs 会同时进入两分支)。
2. 新增 Recovery 中间件签名:`internal/middleware/recovery.go` 提供 `func Recovery() gin.HandlerFunc`(基于 gin.CustomRecoveryWithWriter 等价实现,panic 值 + debug.Stack 经 slog.ErrorContext 输出,响应语义与 gin.Recovery 一致)。
## Agent Extensions
### SubAgent
- **code-explorer**
- Purpose: 修复完成后全量复核——重扫全部 slog 打点与静默点,核对 23 项 + 矩阵缺口逐项落地、无重复日志、无敏感输出、ctx 使用正确
- Expected outcome: 输出复核清单与偏差项,支撑评估报告定稿与状态标注
### Skill
- **lsp-code-analysis**
- Purpose: 在签名 / 组装变更点(retryCall 业务标识扩展、service.go 事务函数 ctx 透传、Recovery 替换)执行引用与影响面分析,确保调用点无遗漏、无误改
- Expected outcome: 确认相关符号全部引用点均在预期范围内,签名变更不影响无关调用