Files
Inbox/Go项目实战/03_基础设施/02_日志/AI 辅助基础设施构建 SOP (v1.0)-全局日志篇.md
2025-12-11 07:24:36 +08:00

234 lines
9.1 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.

---
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 floatELK 处理会麻烦。
4. **容灾:** 如果 `logs/` 目录不可写(权限问题),程序会 Panic 还是降级输出到 Stdout
请给出 1-2 个具体的 `TODO` 优化项。
```