first commit

This commit is contained in:
2026-09-11 01:41:52 +08:00
commit 9f22e6ccae
263 changed files with 28935 additions and 0 deletions
@@ -0,0 +1,133 @@
---
name: dao-tracing-refactor
overview: 按 UserCreate 的链路追踪模式,为 mysqldao(13 文件) 与 redisdao(10 文件) 中所有 DAO 方法/函数统一补全 tracing span(Start/defer End/RecordError),并保持增删改查list 顺序。
todos:
- id: mysqldao-batch-a
content: 按样板改造 mysqldao 的 user.go 剩余方法、auditlog.go、closet.go、clothes.go、collect.go、goods.go,补充 Span 追踪与错误记录
status: completed
- id: mysqldao-batch-b
content: 改造 mysqldao 的 horoscope.go、like.go、notification.go、order.go、outfit.go、quota.go、vipflowlog.go,处理 RowsAffected 分支并加追踪
status: in_progress
dependencies:
- mysqldao-batch-a
- id: redisdao-batch-a
content: 改造 redisdao 的 auth.go、closet.go、collect.go、horoscope.go、like.go,处理管道 Exec 与 redis.Nil 豁免并加追踪
status: pending
- id: redisdao-batch-b
content: 改造 redisdao 的 lock.go、notification.go、outfit.go、quota.go、user.go,处理 Lua 脚本与 redis.Nil 豁免(user.go 补充 go-redis 导入)
status: pending
dependencies:
- redisdao-batch-a
- id: verify-build
content: 执行 go build ./... 与 go vet ./... 验证编译通过、无新增告警且语义不变
status: pending
dependencies:
- mysqldao-batch-b
- redisdao-batch-b
---
## 产品概述
为 `zt-closet-backend` 的数据访问层(DAO)统一接入 OpenTelemetry 链路追踪能力,使 MySQL 与 Redis 的每个数据操作方法都具备可观测的 Span 追踪和错误记录,便于分布式追踪与线上问题定位。
## 核心功能
- 以 `UserCreate` 方法为改造样板,为 `internal/mysqldao` 下全部 DAO 方法(13 个文件)补充统一的 Span 追踪与错误记录逻辑。
- 为 `internal/redisdao` 下全部包级函数/方法(10 个文件)补充相同风格的 Span 追踪与错误记录逻辑。
- 统一改造模式:方法开头启动 Span(命名 `dao.<方法名>`)→ `defer span.End()` → 执行原有 DB/缓存调用 → 出错时先 `span.RecordError(err)` 再返回。
- 保持各方法原有业务逻辑、入参与返回值语义完全不变,仅新增追踪与错误记录。
- 对 Redis 查询"未命中"(`redis.Nil`)等属于正常业务分支的场景不记录为错误,避免污染追踪链路。
- 维持既有 "增-删-改-查-list" 的方法排列顺序。
## 技术栈
- 语言:Go
- ORM:GORM(`gorm.io/gorm`),已通过 `d.db.WithContext(ctx)` 传递上下文
- 缓存:go-redis v9(`github.com/redis/go-redis/v9`)
- 追踪:OpenTelemetry,全局追踪器 `global.Tracer`(定义于 `global/otel.go` 的 `var Tracer trace.Tracer`)
## 实现方式
基于用户提供的 `UserCreate` 样板,对每个 DAO 方法套用统一的追踪装饰模式。这是纯增量式改造,不改变任何业务语义与函数签名,风险可控、易于批量执行。
### 改造模板(mysqldao,结构体方法)
```
func (d *XxxDao) XxxCreate(ctx context.Context, ...) (...) {
ctx, span := global.Tracer.Start(ctx, "dao.XxxCreate")
defer span.End()
if err := d.db.WithContext(ctx).Create(x).Error; err != nil {
span.RecordError(err)
return err
}
return nil
}
```
- 单行 `return ...Error` 需改写为 `if err := ...; err != nil { span.RecordError(err); return err }` 形式。
- 带 `RowsAffected` 返回值的方法(如 `QuotaIncreaseUsed`、`OrderUpdateStatusByOrderNo`):先判断 `res.Error`,记录后再返回,保留 `RowsAffected > 0` 判断逻辑。
- 查询类方法(`First`/`Find`)出错统一 `span.RecordError(err)` 后返回。
- `ctx` 必须重新赋值(`ctx, span := ...`),确保新 Span 的上下文继续向下游 `WithContext(ctx)` 传递。
### 改造模板(redisdao,多为包级函数)
```
func XxxSet(ctx context.Context, ...) error {
ctx, span := global.Tracer.Start(ctx, "dao.XxxSet")
defer span.End()
if err := global.RedisEngine.Set(ctx, key, val, ttl).Err(); err != nil {
span.RecordError(err)
return err
}
return nil
}
```
- redisdao 方法原多为 `return xxx.Err()` / `return xxx.Result()`,需先捕获 error/result 再记录并返回。
- 事务管道(`TxPipeline` + `Exec`,见 `auth.go`):对 `pipe.Exec(ctx)` 返回的 err 做记录后返回。
- Lua 脚本调用(`lock.go`、`quota.go`):对 `script.Run(...)` 返回结果的 error 做记录后返回。
- **`redis.Nil` 处理策略**:对 Get 类"未命中属正常"的方法(如 `UserInfoGet`、`AuthUserIDByAccess`、`QuotaRemainGet`),仅当 `err != nil && err != redis.Nil` 时才调用 `span.RecordError(err)`,其余错误正常记录;`redis.Nil` 仍原样返回给调用方,语义不变。`quotaDailyValue` 已内部吞掉 `redis.Nil`,无需特殊处理。
### 实现要点
- **保持顺序**:延续既有 "增删改查list" 排列,不调整方法位置。
- **import**:mysqldao 各文件已含 `global`;redisdao 各文件已含 `global`,对需判断 `redis.Nil` 的文件确认已导入 `github.com/redis/go-redis/v9`(`user.go` 当前未导入,需新增)。
- **零行为变更**:不改动 SQL/Redis 命令、条件、返回值与错误传播路径,仅叠加追踪。
- **性能**:Span 创建为轻量操作,DAO 均为单次 I/O,无额外热点开销;不引入 N+1 或重复遍历。
- **安全**:仅记录 error 对象,不写入用户敏感数据(避免 PII 进入追踪属性)。
## 目录结构
```
zt-closet-backend/
├── internal/
│ ├── mysqldao/
│ │ ├── user.go # [MODIFY] UserCreate 已完成;改造 UserUpdateByID/UserGetByID/UserGetByUUID/UserGetByOpenID
│ │ ├── auditlog.go # [MODIFY] ClosetAuditLog* 与 OutfitAuditLog* 全部方法加追踪
│ │ ├── closet.go # [MODIFY] ClosetShare* 与 ClosetShareItem* 全部方法加追踪
│ │ ├── clothes.go # [MODIFY] Clothes* 全部方法加追踪
│ │ ├── collect.go # [MODIFY] 收藏相关 DAO 方法加追踪
│ │ ├── goods.go # [MODIFY] 商品相关 DAO 方法加追踪
│ │ ├── horoscope.go # [MODIFY] 星座相关 DAO 方法加追踪
│ │ ├── like.go # [MODIFY] 点赞相关 DAO 方法加追踪
│ │ ├── notification.go # [MODIFY] 通知相关 DAO 方法加追踪
│ │ ├── order.go # [MODIFY] Order* 与 RefundFlowLog* 方法加追踪(含 RowsAffected 分支)
│ │ ├── outfit.go # [MODIFY] 穿搭相关 DAO 方法加追踪
│ │ ├── quota.go # [MODIFY] Quota*/UserDailyUsage*/QuotaFlowLog* 方法加追踪(含 RowsAffected 分支)
│ │ └── vipflowlog.go # [MODIFY] VIP 流水相关 DAO 方法加追踪
│ └── redisdao/
│ ├── auth.go # [MODIFY] AuthTokenSet/Del(管道 Exec)、AuthUserIDBy*(redis.Nil 豁免)
│ ├── closet.go # [MODIFY] 衣柜缓存相关函数加追踪
│ ├── collect.go # [MODIFY] 收藏缓存相关函数加追踪
│ ├── horoscope.go # [MODIFY] 星座缓存相关函数加追踪
│ ├── like.go # [MODIFY] LikeAdd/Remove/IsMember/Count 加追踪
│ ├── lock.go # [MODIFY] TryLock/Unlock(Lua 脚本)加追踪
│ ├── notification.go # [MODIFY] 通知缓存相关函数加追踪
│ ├── outfit.go # [MODIFY] 穿搭缓存相关函数加追踪
│ ├── quota.go # [MODIFY] Quota 缓存/Lua 脚本相关函数加追踪
│ └── user.go # [MODIFY] UserInfoSet/Del/Get(Get 需 redis.Nil 豁免,新增 go-redis 导入)
├── global/
│ └── otel.go # [无需修改] 提供 global.Tracer
```