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

9.1 KiB
Raw Permalink Blame History

tags, aliases, date created, date modified
tags aliases date created date modified
🏗️ AI 辅助基础设施构建 SOP (v1.0) - [全局日志篇]
星期三, 十二月 10日 2025, 11:50:40 晚上 星期三, 十二月 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 严禁依赖 ginviper (仅接收 Config struct)。

Phase 0: 依赖隔离与任务拆解 (The Dependency-Aware MECE)

目的: 防止 AI 在编写日志核心时引入业务层代码(如 Gin导致循环依赖。

🤖 拆解者 Prompt (复制使用)

你现在是我的 **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: 定义门面接口

在实现具体逻辑前,让我们先锁定 `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

你现在是 **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: 伪代码验证 (复制使用)

配置和接口已锁定。请写一段 **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]:

我们现在执行 **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]:

代码已生成。请进行 **Self-Correction (自我修正)**
1.  检查是否有 `fmt.Print` 残留?
2.  检查 `log.go` 中的静态方法是否使用了 `WithOptions(zap.AddCallerSkip(1))`?如果没用,业务层行号会报错。
3.  检查是否引入了 `gin` 或其他业务包?(Level 0 严禁依赖)。

确认无误后,存入记忆,继续下一步。

Phase 4: 中间件集成 (Middleware Integration)

目的: 只有当核心 Log 库稳定后,才实现 Gin 中间件。

🤖 Prompt 4: 实现链路追踪与访问日志

现在进入 **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: 生成红队测试用例

核心代码已就绪。请为 `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: 运维视角审查

切换角色为 **SRE**。请审查生成的日志模块。

**检查清单:**
1.  **磁盘爆炸风险:** `Lumberjack` 配置是否真的生效了?(检查 WriteSyncer 的封装)。
2.  **性能损耗:** `WithContext` 是否每次都创建了过多的 Zap 对象?(确认是否只是 Shallow Copy)。
3.  **索引友好度:** 时间戳是否为 ISO8601 (`2025-12-10T…`)?如果是 Epoch floatELK 处理会麻烦。
4.  **容灾:** 如果 `logs/` 目录不可写(权限问题),程序会 Panic 还是降级输出到 Stdout

请给出 1-2 个具体的 `TODO` 优化项。