# 符合Go理念的日志系统设计 ## Go语言核心理念遵循 ### 1. 简单性 (Simplicity) - **最小API**: 只提供必要的方法,避免过度设计 - **清晰的职责分离**: 每个组件职责单一 - **直观的接口**: 接口设计符合Go习惯 ### 2. 可组合性 (Composition) - **接口组合**: 使用小接口,支持组合使用 - **选项模式**: 使用函数选项模式进行配置 - **中间件模式**: 支持HTTP中间件组合 ### 3. 并发安全 (Concurrency) - **goroutine安全**: 所有组件都是并发安全的 - **上下文支持**: 集成context.Context - **优雅关闭**: 支持优雅关闭和资源清理 ### 4. 错误处理 (Error Handling) - **显式错误**: 遵循Go的显式错误处理 - **错误包装**: 使用fmt.Errorf进行错误包装 - **错误检查**: 提供便捷的错误检查方法 ### 5. 接口导向 (Interface-oriented) - **小接口**: 设计小而专注的接口 - **依赖注入**: 通过接口进行依赖注入 - **可测试性**: 接口设计便于单元测试 ## 重新设计的架构 ### 核心接口 #### Logger 接口 - 简单而强大 ```go type Logger interface { // 核心日志方法 Debug(msg string, fields ...zap.Field) Info(msg string, fields ...zap.Field) Warn(msg string, fields ...zap.Field) Error(msg string, fields ...zap.Field) Fatal(msg string, fields ...zap.Field) // 便捷方法 With(fields ...zap.Field) Logger Named(name string) Logger // 同步方法 Sync() error } ``` #### AuditLogger 接口 - 审计专用 ```go type AuditLogger interface { // 记录审计事件 Record(entry *AuditEntry) error // 查询审计日志 Query(filter *AuditFilter) ([]*AuditEntry, error) // 清理过期数据 Cleanup(retention time.Duration) error // 同步方法 Sync() error } ``` ### 选项模式配置 #### Logger 配置选项 ```go type LoggerOption func(*loggerConfig) func WithLevel(level zapcore.Level) LoggerOption { return func(c *loggerConfig) { c.level = level } } func WithOutputPaths(paths ...string) LoggerOption { return func(c *loggerConfig) { c.outputPaths = paths } } func WithDevelopment(dev bool) LoggerOption { return func(c *loggerConfig) { c.development = dev } } ``` #### Audit 配置选项 ```go type AuditOption func(*auditConfig) func WithDatabasePath(path string) AuditOption { return func(c *auditConfig) { c.dbPath = path } } func WithRetention(days int) AuditOption { return func(c *auditConfig) { c.retentionDays = days } } ``` ### 构造函数设计 #### Logger 构造函数 ```go func NewLogger(opts ...LoggerOption) (Logger, error) { config := &loggerConfig{ level: zapcore.InfoLevel, development: false, encoding: "json", outputPaths: []string{"stdout"}, } for _, opt := range opts { opt(config) } return newZapLogger(config) } ``` #### AuditLogger 构造函数 ```go func NewAuditLogger(opts ...AuditOption) (AuditLogger, error) { config := &auditConfig{ enabled: true, dbPath: "audit.db", retentionDays: 90, bufferSize: 1000, } for _, opt := range opts { opt(config) } return newSQLiteAuditLogger(config) } ``` ## 数据结构优化 ### AuditEntry - 符合Go习惯 ```go type AuditEntry struct { ID string `json:"id"` Timestamp time.Time `json:"timestamp"` UserID string `json:"user_id,omitempty"` Username string `json:"username,omitempty"` Action string `json:"action"` Resource string `json:"resource,omitempty"` Details string `json:"details,omitempty"` IP string `json:"ip,omitempty"` UserAgent string `json:"user_agent,omitempty"` Success bool `json:"success"` Error string `json:"error,omitempty"` } ``` ### AuditFilter - 查询过滤器 ```go type AuditFilter struct { UserID string Action string Resource string StartTime *time.Time EndTime *time.Time Success *bool Limit int Offset int } ``` ## 符合Go习惯的使用方式 ### 基本使用 ```go // 创建日志器 logger, err := NewLogger( WithLevel(zapcore.DebugLevel), WithDevelopment(true), WithOutputPaths("stdout", "app.log"), ) if err != nil { panic(err) } defer logger.Sync() // 使用日志 logger.Info("用户登录", zap.String("user_id", "123"), zap.String("ip", "192.168.1.1")) ``` ### 审计使用 ```go // 创建审计日志器 audit, err := NewAuditLogger( WithDatabasePath("audit.db"), WithRetention(90), ) if err != nil { panic(err) } defer audit.Sync() // 记录审计事件 err = audit.Record(&AuditEntry{ UserID: "123", Username: "john_doe", Action: "login", IP: "192.168.1.1", Success: true, }) ``` ### 上下文使用 ```go // 创建带上下文的日志器 userLogger := logger.Named("user_service").With( zap.String("user_id", "123"), zap.String("request_id", "req_001"), ) // 在函数中使用 func processUser(ctx context.Context, userID string) error { logger := userLogger.With(zap.String("operation", "process_user")) logger.Info("开始处理用户") defer logger.Info("处理用户完成") // 处理逻辑 if err := doSomething(); err != nil { logger.Error("处理失败", zap.Error(err)) return err } return nil } ``` ### HTTP中间件 ```go func AuditMiddleware(audit AuditLogger) gin.HandlerFunc { return func(c *gin.Context) { start := time.Now() // 处理请求 c.Next() // 记录审计 entry := &AuditEntry{ UserID: getUserID(c), Action: c.Request.Method + " " + c.Request.URL.Path, IP: c.ClientIP(), UserAgent: c.Request.UserAgent(), Success: c.Writer.Status() < 400, } if err := audit.Record(entry); err != nil { // 审计失败不应该影响正常业务 c.Error(err) } // 记录访问日志 duration := time.Since(start) logger.Info("HTTP请求", zap.String("method", c.Request.Method), zap.String("path", c.Request.URL.Path), zap.Int("status", c.Writer.Status()), zap.Duration("duration", duration), ) } } ``` ## 错误处理设计 ### 自定义错误类型 ```go type LoggerError struct { Op string // 操作 Err error // 底层错误 } func (e *LoggerError) Error() string { return fmt.Sprintf("logger %s: %v", e.Op, e.Err) } func (e *LoggerError) Unwrap() error { return e.Err } ``` ### 便捷的错误检查 ```go // 检查是否为日志错误 var loggerErr *LoggerError if errors.As(err, &loggerErr) { // 处理日志相关错误 } // 检查特定操作的错误 if errors.Is(err, ErrAuditDisabled) { // 审计功能被禁用 } ``` ## 测试设计 ### 单元测试 ```go func TestLogger(t *testing.T) { logger, err := NewLogger(WithDevelopment(true)) require.NoError(t, err) defer logger.Sync() // 测试日志输出 logger.Info("测试消息", zap.String("key", "value")) // 验证日志内容(通过钩子或缓冲区) } ``` ### 集成测试 ```go func TestAuditLogger(t *testing.T) { audit, err := NewAuditLogger(WithDatabasePath(":memory:")) require.NoError(t, err) defer audit.Sync() // 插入测试数据 entry := &AuditEntry{ UserID: "test_user", Action: "test_action", Success: true, } err = audit.Record(entry) require.NoError(t, err) // 查询验证 entries, err := audit.Query(&AuditFilter{ UserID: "test_user", Limit: 10, }) require.NoError(t, err) require.Len(t, entries, 1) } ``` ## 性能优化 ### 对象池 ```go var auditEntryPool = sync.Pool{ New: func() interface{} { return &AuditEntry{} }, } func getAuditEntry() *AuditEntry { return auditEntryPool.Get().(*AuditEntry) } func putAuditEntry(entry *AuditEntry) { // 重置对象 *entry = AuditEntry{} auditEntryPool.Put(entry) } ``` ### 异步写入 ```go type asyncAuditLogger struct { AuditLogger entries chan *AuditEntry done chan struct{} } func (a *asyncAuditLogger) Record(entry *AuditEntry) error { select { case a.entries <- entry: return nil case <-a.done: return ErrLoggerClosed default: return ErrBufferFull } } ``` ## 文档和示例 ### 包文档 ```go // Package logger 提供基于Zap的高性能日志和审计功能 // // 设计理念: // - 简单性: 最小化API,专注于核心功能 // - 性能: 利用Zap的高性能特性 // - 可组合性: 支持中间件和选项模式 // - 并发安全: 所有操作都是goroutine安全的 // // 基本使用: // // logger, _ := logger.NewLogger(logger.WithDevelopment(true)) // logger.Info("应用启动") // defer logger.Sync() // // 审计使用: // // audit, _ := logger.NewAuditLogger(logger.WithRetention(90)) // audit.Record(&logger.AuditEntry{Action: "login", Success: true}) package logger ``` 这个重新设计的日志系统完全遵循Go语言的核心理念,提供了简单、高效、可组合的日志和审计解决方案。