// Filename: internal/logging/logging.go package logging import ( "gemini-balancer/internal/config" "io" "os" "path/filepath" "github.com/sirupsen/logrus" "gopkg.in/natefinch/lumberjack.v2" ) // 包级变量,用于存储日志轮转器 var logRotator *lumberjack.Logger // NewLogger 返回标准的 *logrus.Logger(兼容 Fx 依赖注入) func NewLogger(cfg *config.Config) *logrus.Logger { logger := logrus.New() // 设置日志级别 level, err := logrus.ParseLevel(cfg.Log.Level) if err != nil { logger.WithField("configured_level", cfg.Log.Level).Warn("Invalid log level, defaulting to 'info'") level = logrus.InfoLevel } logger.SetLevel(level) // 设置日志格式 if cfg.Log.Format == "json" { logger.SetFormatter(&logrus.JSONFormatter{ TimestampFormat: "2006-01-02T15:04:05.000Z07:00", FieldMap: logrus.FieldMap{ logrus.FieldKeyTime: "timestamp", logrus.FieldKeyLevel: "level", logrus.FieldKeyMsg: "message", }, }) } else { logger.SetFormatter(&logrus.TextFormatter{ FullTimestamp: true, TimestampFormat: "2006-01-02 15:04:05", }) } // 添加全局字段 hostname, _ := os.Hostname() logger = logger.WithFields(logrus.Fields{ "service": "gemini-balancer", "hostname": hostname, }).Logger // 设置日志输出 if cfg.Log.EnableFile { if cfg.Log.FilePath == "" { logger.Warn("Log file enabled but no path specified. Logging to console only") logger.SetOutput(os.Stdout) return logger } logDir := filepath.Dir(cfg.Log.FilePath) if err := os.MkdirAll(logDir, 0750); err != nil { logger.WithError(err).Warn("Failed to create log directory. Logging to console only") logger.SetOutput(os.Stdout) return logger } // 配置日志轮转(保存到包级变量) logRotator = &lumberjack.Logger{ Filename: cfg.Log.FilePath, MaxSize: getOrDefault(cfg.Log.MaxSize, 100), MaxBackups: getOrDefault(cfg.Log.MaxBackups, 7), MaxAge: getOrDefault(cfg.Log.MaxAge, 30), Compress: cfg.Log.Compress, } logger.SetOutput(io.MultiWriter(os.Stdout, logRotator)) logger.WithField("log_file", cfg.Log.FilePath).Info("Logging to both console and file") } else { logger.SetOutput(os.Stdout) } logger.Info("Logger initialized successfully") return logger } // Close 关闭日志轮转器(在 main.go 中调用) func Close() { if logRotator != nil { logRotator.Close() } } func getOrDefault(value, defaultValue int) int { if value <= 0 { return defaultValue } return value }