- 新增模块化日志器(pkg/logger/module.go) - 新增 GORM 日志适配器 - 统一日志入口,移除所有 zap.L() 全局 logger 调用 - 字段标准化 - 启动阶段使用结构化日志 - 更新所有相关测试
4.4 KiB
4.4 KiB
Module Logging
Purpose
定义模块化日志器规范,支持模块标识和 Context 传播,实现日志来源快速定位和请求追踪链完整性。
Requirements
Requirement: 模块标识注入
系统 SHALL 支持通过构造函数注入带模块标识的 logger。
Scenario: 构造函数注入模块 logger
- WHEN 创建需要记录日志的组件
- THEN 构造函数 SHALL 接受
*zap.Logger参数 - THEN SHALL 使用
logger.Named("module.name")绑定模块标识 - THEN SHALL 将 logger 存储在结构体字段中
Scenario: 模块标识格式
- WHEN 绑定模块标识
- THEN 单一职责包 SHALL 使用包名(如
database) - THEN 多实体包 SHALL 使用
包名.实体名(如handler.proxy) - THEN 子包 SHALL 使用
包名.子包名(如handler.middleware)
Scenario: 模块标识输出
- WHEN 记录日志
- THEN Console 格式 SHALL 输出为
[module.name] - THEN JSON 格式 SHALL 包含
"logger":"module.name"字段
Requirement: 禁止全局 logger
系统 SHALL 禁止在业务代码中使用全局 logger。
Scenario: 移除 zap.L() 调用
- WHEN 重构现有代码
- THEN SHALL 移除所有
zap.L()调用 - THEN SHALL 通过构造函数注入 logger
- THEN 允许仅在测试代码中使用
zap.L()或zap.NewNop()
Scenario: 移除 zap.L() fallback
- WHEN 构造函数 logger 参数为 nil
- THEN SHALL NOT 使用
zap.L()作为默认值 - THEN 调用方 SHALL 必须传入有效的 logger
Requirement: Request ID 传播
系统 SHALL 通过 Context 传播 request_id。
Scenario: Context 注入 request_id
- WHEN 中间件生成 request_id
- THEN SHALL 存储到
context.Context中 - THEN SHALL 使用类型安全的 context key
Scenario: 从 Context 提取 request_id
- WHEN 业务层需要记录日志
- THEN SHALL 从
gin.Context提取 request_id - THEN SHALL 使用
logger.With(zap.String("request_id", id))创建带 request_id 的 logger - THEN 日志 SHALL 自动包含 request_id 字段
Scenario: Request ID 辅助函数
- WHEN 使用 request_id
- THEN
pkg/loggerSHALL 提供RequestIDFromContext(ctx)辅助函数 - THEN 辅助函数 SHALL 返回
zap.Field类型
Requirement: 单行输出
系统 SHALL 保证所有日志单行输出。
Scenario: Console 单行输出
- WHEN 记录日志到 stdout
- THEN SHALL 单行输出
- THEN 字段之间 SHALL 使用空格分隔
Scenario: JSON 单行输出
- WHEN 记录日志到文件
- THEN SHALL 单行紧凑输出
- THEN SHALL NOT 使用美化缩进
Scenario: 多行数据保留
- WHEN 日志数据本身包含多行(如堆栈跟踪、SQL 换行)
- THEN SHALL 保留原始多行格式
Requirement: 模块命名规范
系统 SHALL 遵循模块命名规范。
Scenario: Handler 层命名
- WHEN 创建 handler 层 logger
- THEN ProxyHandler SHALL 使用
handler.proxy - THEN ProviderHandler SHALL 使用
handler.provider - THEN ModelHandler SHALL 使用
handler.model - THEN StatsHandler SHALL 使用
handler.stats - THEN Middleware SHALL 使用
handler.middleware
Scenario: Provider 层命名
- WHEN 创建 provider 层 logger
- THEN Client SHALL 使用
provider.client
Scenario: Conversion 层命名
- WHEN 创建 conversion 层 logger
- THEN Engine SHALL 使用
conversion.engine - THEN OpenAI Adapter SHALL 使用
conversion.openai - THEN Anthropic Adapter SHALL 使用
conversion.anthropic
Scenario: Service 层命名
- WHEN 创建 service 层 logger
- THEN RoutingCache SHALL 使用
service.routing_cache - THEN StatsBuffer SHALL 使用
service.stats_buffer - THEN ProviderService SHALL 使用
service.provider - THEN ModelService SHALL 使用
service.model - THEN RoutingService SHALL 使用
service.routing - THEN StatsService SHALL 使用
service.stats
Scenario: Repository 层命名
- WHEN 创建 repository 层 logger
- THEN ProviderRepository SHALL 使用
repository.provider - THEN ModelRepository SHALL 使用
repository.model - THEN StatsRepository SHALL 使用
repository.stats
Scenario: Infrastructure 层命名
- WHEN 创建基础设施层 logger
- THEN Database SHALL 使用
database - THEN Config SHALL 使用
config