Files
zt-closet-backend/.codebuddy/plans/按层区分_DAO_span_命名_72d9748c.md
2026-09-11 01:41:52 +08:00

124 lines
6.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: 按层区分 DAO span 命名
overview: 将 mysqldao 的 span 名由 dao.X 改为 mysqldao.X、redisdao 的改为 redisdao.X,共 140 处,解决两层 span 名无法区分的问题。
todos:
- id: rename-mysqldao
content: 批量替换 internal/mysqldao 下 109 处 span 前缀为 mysqldao.
status: completed
- id: rename-redisdao
content: 批量替换 internal/redisdao 下 31 处 span 前缀为 redisdao.
status: completed
- id: verify-rename
content: 用 [subagent:code-explorer] 复核前缀计数与无残留无错改
status: completed
dependencies:
- rename-mysqldao
- rename-redisdao
- id: sync-readme
content: 在 README 目录说明中补充 span 命名约定
status: completed
dependencies:
- verify-rename
- id: build-verify
content: 执行 go build ./... 与 go vet ./... 验证
status: completed
dependencies:
- verify-rename
- sync-readme
---
## 产品概述
统一调整 OTel span 命名前缀:数据访问层的 span 名由通用的 `dao.XXX` 改为可区分来源的 `mysqldao.XXX` 与 `redisdao.XXX`,解决 MySQL 与 Redis 两层调用在链路追踪中无法区分的问题。
## 核心功能
- **MySQL 层改名**:`internal/mysqldao/` 下全部 109 处 span 名前缀 `dao.` 改为 `mysqldao.`
- **Redis 层改名**:`internal/redisdao/` 下全部 31 处 span 名前缀 `dao.` 改为 `redisdao.`
- **命名一致性保持**:仅改前缀,方法名(如 `UserInfoSet`)、业务逻辑、其他 span 属性均不变
- **不影响其他层**:`internal/service`(`service.`)、`pkg/upload`(`upload.`)、`pkg/tokenhub`(`scheduler.`)保持原样
- **可维护性**:README 目录说明补一句 span 命名约定,避免后续新增代码再用回 `dao.`
## 技术栈
- Go 1.27,模块 `git.lzcwy.cn/zhengchiliu/zt-closet-backend`
- OpenTelemetry Trace(`global.Tracer`,OTLP gRPC 上报)
- span 创建统一写法:`ctx, span := global.Tracer.Start(ctx, "<前缀>.<方法名>")`
## 实现方案
采用**目录限定的批量字符串替换**:把 `global.Tracer.Start(ctx, "dao.` 中的前缀分别替换为 `mysqldao.` / `redisdao.`,替换范围严格限定在 `internal/mysqldao/` 与 `internal/redisdao/` 两个目录。
关键决策与取舍:
1. **前缀命名用 `mysqldao.` / `redisdao.` 而非 `mysql.` / `redis.`**:与包名(`package mysqldao` / `package redisdao`)完全一致,Go 项目中 span 名即包名+方法名,排查时可从 span 名直接定位到文件与包,无需映射记忆。
2. **批量 sed 而非逐处手改**:140 处手工改必漏;用 `sed -i 's/Tracer\.Start(ctx, "dao\./Tracer.Start(ctx, "mysqldao./g'` 这类按目录执行的命令可保证一致性与完整性,且模式串锚定了 `Tracer.Start(ctx, "dao.` 全串,不会误伤字符串变量、注释或日志中的 `dao.`。
3. **只改前缀,不改方法名**:方法名与所在函数名一一对应,改名会造成与函数名不一致的二次困惑;同时避免破坏任何按名称检索的既有习惯。
4. **不引入常量**:项目其余前缀(`service.`、`upload.`、`scheduler.`)均为字面量,沿用字面量保持风格统一,不引入新的抽象层(YAGNI)。
5. **不改动 service / upload / tokenhub**:这些层前缀本身已能区分,不属于本次「分不清」的范围,缩小改动面。
性能与可靠性:
- span 名为启动期/调用期构造的字符串常量,改为更长前缀无运行时开销(无额外分配语义变化)。
- 风险点仅为「替换不完整」或「误伤其他目录」,通过目录限定 + 替换后计数校验(mysqldao 109 / redisdao 31 / 残留 `dao.` 为 0)来兜底。
## 实现要点(防回归)
- 替换模式必须锚定完整串 `global.Tracer.Start(ctx, "dao.`,避免误改 `mysqldao.`/`redisdao.` 之外的其它 `dao` 文本(如注释、错误信息)。
- 严格限定目录:`internal/mysqldao/*.go` 与 `internal/redisdao/*.go`,**不要**对仓库根或 `internal/` 整体执行替换(会误伤 `internal/service` 中可能存在的同名串)。
- 替换后必须核验:`internal/mysqldao` 与 `internal/redisdao` 中 `"dao.` 残留为 0;`"mysqldao.` 计数 109、`"redisdao.` 计数 31(与替换前一致)。
- 未发现任何测试或断言依赖 span 名字符串,改名不会破坏断言;仍以 `go build ./...` + `go vet ./...` 作为回归基线。
- 不改动 `configs/config.yaml`(第 2 行 `Domain: *` 为非法 YAML,属用户本地配置,本次不处理)。
## 架构设计
调用链与 span 命名分层(本次改动仅涉及最下两层的命名):
```mermaid
flowchart TD
A["routers/api/v1 handler<br/>Gin 中间件 server span"] --> B["internal/service<br/>span: service.Xxx"]
B --> C["internal/mysqldao<br/>span: mysqldao.Xxx(本次由 dao. 改名)"]
B --> D["internal/redisdao<br/>span: redisdao.Xxx(本次由 dao. 改名)"]
C --> E[("MySQL")]
D --> F[("Redis")]
```
## 目录结构
```
internal/mysqldao/
├── quota.go # [MODIFY] 18 处 span 前缀 dao. → mysqldao.
├── outfit.go # [MODIFY] 13 处
├── order.go # [MODIFY] 12 处
├── clothes.go # [MODIFY] 9 处
├── closet.go # [MODIFY] 8 处
├── user.go # [MODIFY] 7 处
├── horoscope.go # [MODIFY] 7 处
├── benefit_grant_task.go # [MODIFY] 7 处
├── collect.go # [MODIFY] 6 处
├── like.go # [MODIFY] 6 处
├── notification.go # [MODIFY] 6 处
├── auditlog.go # [MODIFY] 4 处
├── goods.go # [MODIFY] 3 处
└── vipflowlog.go # [MODIFY] 3 处
internal/redisdao/
├── quota.go # [MODIFY] 6 处 span 前缀 dao. → redisdao.
├── collect.go # [MODIFY] 4 处
├── like.go # [MODIFY] 4 处
├── auth.go # [MODIFY] 4 处
├── notification.go # [MODIFY] 4 处
├── user.go # [MODIFY] 3 处
├── horoscope.go # [MODIFY] 2 处
├── lock.go # [MODIFY] 2 处
├── outfit.go # [MODIFY] 1 处
└── closet.go # [MODIFY] 1 处
README.md # [MODIFY] 可选:目录树中 mysqldao/redisdao 说明补 span 命名约定(mysqldao.* / redisdao.*)
```
## Agent Extensions
### SubAgent
- **code-explorer**
- Purpose:替换完成后复核两个 DAO 目录的 span 命名:确认 `internal/mysqldao` 全部为 `mysqldao.` 前缀、`internal/redisdao` 全部为 `redisdao.` 前缀、无 `"dao.` 残留,且 `internal/service`、`pkg/upload`、`pkg/tokenhub` 的 span 名未被误改
- Expected outcome:输出各目录前缀计数与残留清单,确保 140 处全部正确改名、零误伤