--- 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
Gin 中间件 server span"] --> B["internal/service
span: service.Xxx"] B --> C["internal/mysqldao
span: mysqldao.Xxx(本次由 dao. 改名)"] B --> D["internal/redisdao
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 处全部正确改名、零误伤