package logger import ( "fmt" "io" "log" "os" "path/filepath" "git.toowon.com/jimmy/go-common/config" ) // Logger 日志记录器 type Logger struct { infoLog *log.Logger errorLog *log.Logger warnLog *log.Logger debugLog *log.Logger config *config.LoggerConfig } // NewLogger 创建日志记录器 func NewLogger(cfg *config.LoggerConfig) (*Logger, error) { if cfg == nil { // 使用默认配置 cfg = &config.LoggerConfig{ Level: "info", Output: "stdout", FilePath: "", } } // 设置默认值 if cfg.Level == "" { cfg.Level = "info" } if cfg.Output == "" { cfg.Output = "stdout" } // 创建输出目标 var writers []io.Writer switch cfg.Output { case "stdout": writers = append(writers, os.Stdout) case "stderr": writers = append(writers, os.Stderr) case "file": if cfg.FilePath == "" { return nil, fmt.Errorf("file path is required when output is file") } // 确保目录存在 dir := filepath.Dir(cfg.FilePath) if err := os.MkdirAll(dir, 0755); err != nil { return nil, fmt.Errorf("failed to create log directory: %w", err) } file, err := os.OpenFile(cfg.FilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) if err != nil { return nil, fmt.Errorf("failed to open log file: %w", err) } writers = append(writers, file) case "both": writers = append(writers, os.Stdout) if cfg.FilePath == "" { return nil, fmt.Errorf("file path is required when output is both") } dir := filepath.Dir(cfg.FilePath) if err := os.MkdirAll(dir, 0755); err != nil { return nil, fmt.Errorf("failed to create log directory: %w", err) } file, err := os.OpenFile(cfg.FilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) if err != nil { return nil, fmt.Errorf("failed to open log file: %w", err) } writers = append(writers, file) default: return nil, fmt.Errorf("invalid output type: %s", cfg.Output) } // 创建多写入器 multiWriter := io.MultiWriter(writers...) // 创建日志前缀 prefix := "" if cfg.Prefix != "" { prefix = cfg.Prefix + " " } // 创建日志记录器 logger := &Logger{ config: cfg, } // 根据日志级别创建不同的logger flags := log.LstdFlags if cfg.DisableTimestamp { flags = 0 } if cfg.Level == "debug" || cfg.Level == "info" || cfg.Level == "warn" || cfg.Level == "error" { logger.infoLog = log.New(multiWriter, prefix+"[INFO] ", flags) logger.warnLog = log.New(multiWriter, prefix+"[WARN] ", flags) logger.errorLog = log.New(multiWriter, prefix+"[ERROR] ", flags) if cfg.Level == "debug" { logger.debugLog = log.New(multiWriter, prefix+"[DEBUG] ", flags) } } return logger, nil } // Debug 记录调试日志 func (l *Logger) Debug(format string, v ...interface{}) { if l.debugLog != nil { l.debugLog.Printf(format, v...) } } // Info 记录信息日志 func (l *Logger) Info(format string, v ...interface{}) { if l.infoLog != nil { l.infoLog.Printf(format, v...) } } // Warn 记录警告日志 func (l *Logger) Warn(format string, v ...interface{}) { if l.warnLog != nil { l.warnLog.Printf(format, v...) } } // Error 记录错误日志 func (l *Logger) Error(format string, v ...interface{}) { if l.errorLog != nil { l.errorLog.Printf(format, v...) } } // Fatal 记录致命错误日志并退出程序 func (l *Logger) Fatal(format string, v ...interface{}) { if l.errorLog != nil { l.errorLog.Fatalf(format, v...) } else { log.Fatalf(format, v...) } } // Panic 记录恐慌日志并触发panic func (l *Logger) Panic(format string, v ...interface{}) { if l.errorLog != nil { l.errorLog.Panicf(format, v...) } else { log.Panicf(format, v...) } } // WithFields 创建带字段的日志记录器(简化版,返回格式化字符串) func (l *Logger) WithFields(fields map[string]interface{}) *Logger { // 返回自身,实际使用时可以在format中包含fields return l } // formatFields 格式化字段 func formatFields(fields map[string]interface{}) string { if len(fields) == 0 { return "" } result := "" for k, v := range fields { result += fmt.Sprintf("%s=%v ", k, v) } return result } // Debugf 记录调试日志(带字段) func (l *Logger) Debugf(fields map[string]interface{}, format string, v ...interface{}) { if l.debugLog != nil { fieldStr := formatFields(fields) l.debugLog.Printf(fieldStr+format, v...) } } // Infof 记录信息日志(带字段) func (l *Logger) Infof(fields map[string]interface{}, format string, v ...interface{}) { if l.infoLog != nil { fieldStr := formatFields(fields) l.infoLog.Printf(fieldStr+format, v...) } } // Warnf 记录警告日志(带字段) func (l *Logger) Warnf(fields map[string]interface{}, format string, v ...interface{}) { if l.warnLog != nil { fieldStr := formatFields(fields) l.warnLog.Printf(fieldStr+format, v...) } } // Errorf 记录错误日志(带字段) func (l *Logger) Errorf(fields map[string]interface{}, format string, v ...interface{}) { if l.errorLog != nil { fieldStr := formatFields(fields) l.errorLog.Printf(fieldStr+format, v...) } }