234 lines
9.1 KiB
Markdown
234 lines
9.1 KiB
Markdown
---
|
||
tags: []
|
||
aliases:
|
||
- 🏗️ AI 辅助基础设施构建 SOP (v1.0) - [全局日志篇]
|
||
date created: 星期三, 十二月 10日 2025, 11:50:40 晚上
|
||
date modified: 星期三, 十二月 10日 2025, 11:52:08 晚上
|
||
---
|
||
|
||
# 🏗️ AI 辅助基础设施构建 SOP (v1.0) - [全局日志篇]
|
||
|
||
**核心理念:**
|
||
|
||
1. **Configuration Driven (配置驱动):** 先定义配置结构与 Viper 映射,再实现逻辑。
|
||
2. **Zero Allocation Constraint (零分配约束):** 在 Prompt 层面封杀 `zap.Any`,强制使用强类型字段。
|
||
3. **Layered Delivery (分层交付):** 先交付 `pkg/log` (Level 0),再交付 `middleware` (Level 1)。
|
||
|
||
---
|
||
|
||
## 📋 准备工作:上下文注入
|
||
|
||
在使用以下 Prompt 前,请确保 AI 已理解《全局日志模块详细设计说明书》的全部内容。
|
||
|
||
- `{语言/框架}`: Go 1.24+ / Uber Zap / Lumberjack v2
|
||
- `{模块路径}`: `internal/pkg/log` (核心) & `internal/middleware` (集成)
|
||
- `{关键约束}`: `pkg/log` **严禁依赖** `gin` 或 `viper` (仅接收 Config struct)。
|
||
|
||
---
|
||
|
||
## Phase 0: 依赖隔离与任务拆解 (The Dependency-Aware MECE)
|
||
|
||
**目的:** 防止 AI 在编写日志核心时引入业务层代码(如 Gin),导致循环依赖。
|
||
|
||
### 🤖 拆解者 Prompt (复制使用)
|
||
|
||
```Markdown
|
||
你现在是我的 **System Architect (系统架构师)**。
|
||
我们要实现 `Global Logging Infrastructure`。基于《详细设计说明书》,请执行 **“依赖隔离任务拆解”**。
|
||
|
||
**1. 架构红线 (Architecture Rules):**
|
||
- **Level 0 (Core):** `internal/pkg/log`。只依赖 `zap`, `lumberjack`, standard `context`。**严禁依赖 `gin`**。
|
||
- **Level 1 (Integration):** `internal/middleware`。依赖 `internal/pkg/log` 和 `gin`。
|
||
|
||
**2. 原子化切分:**
|
||
请将工作拆解为两个独立的 Batch,每个 Batch 包含若干 Step。
|
||
- **Batch A (Core)**: 必须按 `options.go` (配置) -> `zap.go` (构造) -> `context.go` (桥接) -> `log.go` (门面) 的顺序。
|
||
- **Batch B (Middleware)**: 包含 `trace.go`, `access_log.go`, `recovery.go`。
|
||
|
||
**3. 输出格式:**
|
||
请输出一个 **Markdown Checklist**。
|
||
格式示例:
|
||
- [ ] **Batch A - Step 1: {文件名}** - {核心职责} (关键设计点: …)
|
||
…
|
||
```
|
||
|
||
---
|
||
|
||
## Phase 0.5: API 签名锁定 (API Surface Lock)
|
||
|
||
**目的:** 在实现 `zap` 复杂构建逻辑前,先锁死对外暴露的“门面”方法,确保调用体验。
|
||
|
||
### 🤖 Prompt 0.5: 定义门面接口
|
||
|
||
```Markdown
|
||
在实现具体逻辑前,让我们先锁定 `internal/pkg/log` 的 **Public API**。
|
||
请只输出 `log.go` 和 `context.go` 中 **Exported Functions** 的签名(无需函数体)。
|
||
|
||
**关键要求:**
|
||
1. **初始化:** `Init(opts …Option)` 设计为 Functional Options 模式还是直接传 Struct?(依据设计文档应为 Struct 传入,但保留 Option 扩展性)。
|
||
2. **上下文注入:** `WithContext(ctx context.Context) *zap.Logger` 的签名确认。
|
||
3. **静态代理:** `Info`, `Error` 等静态方法如何处理 `CallerSkip`?请在注释中说明。
|
||
4. **后台任务:** 必须包含 `StartBackgroundTrace(ctx)` 的定义。
|
||
|
||
请输出带有完整 Go Doc 的接口定义代码块。
|
||
```
|
||
|
||
---
|
||
|
||
## Phase 1: 配置契约定义 (Configuration Contract)
|
||
|
||
**目的:** 只有确定了“怎么配”,才能决定“怎么写”。
|
||
|
||
### 🤖 Prompt 1: 定义配置结构与 Schema
|
||
|
||
```Markdown
|
||
你现在是 **DevOps 专家**。
|
||
请定义日志模块的配置结构 (`options.go`) 以及对应的 YAML 写法。
|
||
|
||
**任务:**
|
||
1. **Go Struct:** 定义 `Options` 结构体。
|
||
- 包含 `Level`, `Format` (json/console), `Filename`, `MaxSize`, `MaxBackups`, `MaxAge`, `Compress`。
|
||
- Tag 必须适配 `mapstructure` (Viper 使用)。
|
||
2. **Default Value:** 提供一个 `NewOptions()` 函数返回生产环境推荐的默认值 (100MB, 30个文件, JSON 格式)。
|
||
3. **YAML Example:** 给出一个 `config.yaml` 的片段示例。
|
||
|
||
**约束:**
|
||
- 字段类型必须明确(如 `MaxSize` 是 int 还是 string? 建议 int 单位 MB)。
|
||
```
|
||
|
||
---
|
||
|
||
## Phase 2: 体验验证 (DX Verification)
|
||
|
||
**目的:** 验证开发者在业务代码中打印日志是否顺手,防止过度封装导致 API 臃肿。
|
||
|
||
### 🤖 Prompt 2: 伪代码验证 (复制使用)
|
||
|
||
```Markdown
|
||
配置和接口已锁定。请写一段 **Service 层** 的伪代码,展示如何使用该日志库。
|
||
|
||
**场景验证:**
|
||
1. **标准调用:** 在 `UserRegister` 方法中,如何打日志并自动带上 TraceID?
|
||
2. **强类型约束:** 展示使用 `zap.String`, `zap.Int` 的写法。**严禁出现 `zap.Any`**。
|
||
3. **子 Context:** 在 `go func()` 中如何使用 `StartBackgroundTrace` 保证链路不断?
|
||
4. **Error 处理:** 遇到 DB 错误时,如何记录 log 并返回 error?
|
||
|
||
请展示代码,并自我评价是否符合“低心智负担”原则。
|
||
```
|
||
|
||
---
|
||
|
||
## Phase 3: 核心防御式实现 (Core Defensive Implementation)
|
||
|
||
**核心机制:** 这是一个**循环步骤**。针对 `internal/pkg/log` 的每个文件执行。
|
||
|
||
### 🔄 循环动作 A: 生成代码
|
||
|
||
**[发送 Prompt]:**
|
||
|
||
```Markdown
|
||
我们现在执行 **Batch A - Step {N}**。
|
||
|
||
**任务目标:**
|
||
生成 `{文件名}` (例如 `zap.go`)。
|
||
|
||
**设计文档引用:**
|
||
- 引用《设计说明书》中关于 `{章节名}` 的要求。
|
||
|
||
**代码质量硬性约束 (Hard Constraints):**
|
||
1. **Snake Case:** 所有的 JSON Key (包括 TraceID) 必须手动指定为 snake_case (如 `zap.String("trace_id", v)`)。
|
||
2. **No Zap Any:** 严禁在核心逻辑中使用 `zap.Any`。如果是 map/struct,必须手动拆解或实现 `zapcore.ObjectMarshaler`。
|
||
3. **Safety:**
|
||
- `writer.go`: Lumberjack 的 `Compress` 必须默认为 true。
|
||
- `log.go`: `globalLogger` 必须有 `sync.Once` 保护,且默认初始化为 Console (避免 nil pointer)。
|
||
4. **Caller Skip:** 确保静态方法 (log.Info) 和实例方法 (logger.Info) 的 Caller 层级正确,都能定位到业务代码行号。
|
||
|
||
请生成完整代码。
|
||
```
|
||
|
||
### 🔄 循环动作 B: 质量检查锚点
|
||
|
||
**[发送 Prompt]:**
|
||
|
||
```Markdown
|
||
代码已生成。请进行 **Self-Correction (自我修正)**:
|
||
1. 检查是否有 `fmt.Print` 残留?
|
||
2. 检查 `log.go` 中的静态方法是否使用了 `WithOptions(zap.AddCallerSkip(1))`?如果没用,业务层行号会报错。
|
||
3. 检查是否引入了 `gin` 或其他业务包?(Level 0 严禁依赖)。
|
||
|
||
确认无误后,存入记忆,继续下一步。
|
||
```
|
||
|
||
---
|
||
|
||
## Phase 4: 中间件集成 (Middleware Integration)
|
||
|
||
**目的:** 只有当核心 Log 库稳定后,才实现 Gin 中间件。
|
||
|
||
### 🤖 Prompt 4: 实现链路追踪与访问日志
|
||
|
||
```Markdown
|
||
现在进入 **Batch B**。我们需要实现 `internal/middleware/trace.go` 和 `access_log.go`。
|
||
|
||
**任务要求:**
|
||
1. **Trace Middleware:**
|
||
- 从 Request Header (`X-Trace-ID`) 读取,若无则生成 UUID。
|
||
- **关键点:** 必须调用 `log.WithTraceID(ctx, id)` 将 ID 注入 Standard Context,再回写到 `c.Request`。
|
||
2. **Access Log Middleware:**
|
||
- 记录 Start Time, End Time, Latency。
|
||
- 使用 `log.WithContext(c.Request.Context()).Info(…)` 打印。
|
||
- **字段映射:** `method`, `path`, `ip`, `status`, `latency` (ms)。
|
||
3. **Recovery Middleware:**
|
||
- 捕获 Panic。
|
||
- 打印包含 Stack Trace 的 JSON Error 日志 (非 Console 文本)。
|
||
- 返回 500 响应。
|
||
|
||
请一次性生成这三个文件的核心逻辑。
|
||
```
|
||
|
||
---
|
||
|
||
## Phase 5: 极限防御测试 (Extreme Defensive Testing)
|
||
|
||
**目的:** 验证并发安全、文件轮转和敏感数据脱敏。
|
||
|
||
### 🤖 Prompt 5: 生成红队测试用例
|
||
|
||
```Markdown
|
||
核心代码已就绪。请为 `pkg/log` 编写单元测试 `log_test.go`。
|
||
|
||
**请覆盖以下 3 个高危场景 (Test Cases):**
|
||
|
||
1. **并发竞争 (Race Detection):**
|
||
- 启动 100 个 Goroutine,同时调用 `log.WithContext(ctx).Info(…)`。
|
||
- 断言:`go test -race` 不报错,且 TraceID 不串号。
|
||
|
||
2. **Caller 准确性验证:**
|
||
- 编写一个测试辅助函数,解析输出的 JSON,断言 `caller` 字段指向的是测试代码行号,而不是 `log.go` 内部。
|
||
|
||
3. **敏感数据脱敏 (Mock):**
|
||
- 模拟打印 `zap.String("password", "123456")`。
|
||
- (注意:如果我们在 Zap Core 层没做拦截,这里需要验证是否通过 AI 辅助代码生成时的规范来避免。此处请测试:如果定义了 Masking Hook,密码是否被替换为 `******`)。
|
||
- *注:根据设计文档,我们采用“编码规范+AI辅助”策略,故此处测试应侧重于“TraceID 是否在 Log 中正确出现”。*
|
||
|
||
请输出 Test 代码。
|
||
```
|
||
|
||
---
|
||
|
||
## Phase 6: SRE 验收 (SRE Review)
|
||
|
||
### 🤖 Prompt 6: 运维视角审查
|
||
|
||
```Markdown
|
||
切换角色为 **SRE**。请审查生成的日志模块。
|
||
|
||
**检查清单:**
|
||
1. **磁盘爆炸风险:** `Lumberjack` 配置是否真的生效了?(检查 WriteSyncer 的封装)。
|
||
2. **性能损耗:** `WithContext` 是否每次都创建了过多的 Zap 对象?(确认是否只是 Shallow Copy)。
|
||
3. **索引友好度:** 时间戳是否为 ISO8601 (`2025-12-10T…`)?如果是 Epoch float,ELK 处理会麻烦。
|
||
4. **容灾:** 如果 `logs/` 目录不可写(权限问题),程序会 Panic 还是降级输出到 Stdout?
|
||
|
||
请给出 1-2 个具体的 `TODO` 优化项。
|
||
```
|