DeployHelper/pkg/logger/logger.go

171 lines
4.1 KiB
Go
Raw Normal View History

2025-08-01 16:38:08 +08:00
package logger
import (
"fmt"
"log"
"os"
"path/filepath"
"strings"
"sync"
"time"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
rotatelogs "github.com/lestrrat-go/file-rotatelogs"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
const (
TRACKED = "trackID"
)
var (
Logger *zap.Logger
loggerMux sync.Once
CallerSkip = 2
initErr error
)
// BuildLogger 初始化日志系统
func BuildLogger() error {
loggerMux.Do(func() {
initErr = initLogger()
})
return initErr
}
// initLogger 实际的日志初始化逻辑
func initLogger() error {
logLevel := getLogLevel()
logPath := os.Getenv("LOG_PATH")
if logPath == "" {
logPath = "./logs" // 默认日志路径
}
// 尝试创建日志目录
if err := os.MkdirAll(logPath, 0755); err != nil {
// 使用标准库的log记录错误因为zap还没初始化
log.Printf("无法创建日志目录 %s: %v", logPath, err)
return fmt.Errorf("无法创建日志目录 %s: %w", logPath, err)
}
// 配置滚动日志按天滚动保留28天
logFileName := filepath.Join(logPath, "ego.%Y%m%d.log")
logs, err := rotatelogs.New(
logFileName,
rotatelogs.WithMaxAge(28*24*time.Hour),
rotatelogs.WithRotationTime(24*time.Hour),
)
if err != nil {
log.Printf("创建滚动日志失败: %v", err)
return fmt.Errorf("创建滚动日志失败: %w", err)
}
// 配置控制台输出
consoleEncoder := zapcore.NewConsoleEncoder(zap.NewDevelopmentEncoderConfig())
consoleSyncer := zapcore.AddSync(os.Stdout)
// 配置文件输出生产环境JSON格式
prodEncoderConfig := zap.NewProductionEncoderConfig()
prodEncoderConfig.EncodeTime = TimeEncoder
prodEncoderConfig.CallerKey = "caller"
prodEncoderConfig.EncodeCaller = zapcore.ShortCallerEncoder
prodEncoder := zapcore.NewJSONEncoder(prodEncoderConfig)
fileSyncer := zapcore.AddSync(logs)
// 创建日志核心
core := zapcore.NewTee(
zapcore.NewCore(consoleEncoder, consoleSyncer, logLevel),
zapcore.NewCore(prodEncoder, fileSyncer, logLevel),
)
// 初始化 Logger
Logger = zap.New(core, zap.AddCaller(), zap.AddCallerSkip(CallerSkip))
// 记录初始化成功
Logger.Info("日志系统初始化成功",
zap.String("log_path", logPath),
zap.String("log_level", logLevel.String()),
)
return nil
}
// Debug 记录调试日志
func Debug(c *gin.Context, msg string, fields ...zap.Field) {
if Logger != nil {
logWithTrack(c, zap.DebugLevel, msg, fields...)
}
}
// Info 记录信息日志
func Info(c *gin.Context, msg string, fields ...zap.Field) {
if Logger != nil {
logWithTrack(c, zap.InfoLevel, msg, fields...)
}
}
// Warn 记录警告日志
func Warn(c *gin.Context, msg string, fields ...zap.Field) {
if Logger != nil {
logWithTrack(c, zap.WarnLevel, msg, fields...)
}
}
// Error 记录错误日志
func Error(c *gin.Context, msg string, fields ...zap.Field) {
if Logger != nil {
logWithTrack(c, zap.ErrorLevel, msg, fields...)
}
}
// logWithTrack 封装带 trackID 的日志记录
func logWithTrack(c *gin.Context, level zapcore.Level, msg string, fields ...zap.Field) {
if Logger == nil {
return
}
if c == nil {
Logger.Check(level, msg).Write(fields...)
return
}
trackID := GetTrackID(c)
Logger.Check(level, msg).Write(append(fields, zap.String("trackID", trackID))...)
}
// GetTrackID 获取或生成 trackID
func GetTrackID(c *gin.Context) string {
if trackID, exists := c.Get(TRACKED); exists {
return trackID.(string)
}
if random, err := uuid.NewRandom(); err == nil {
// 生成新的 trackID 并存入上下文
newTrackID := strings.ToLower(random.String())
c.Set(TRACKED, newTrackID)
return newTrackID
}
return ""
}
// getLogLevel 根据环境变量获取日志级别
func getLogLevel() zapcore.Level {
switch strings.ToLower(os.Getenv("LOG_LEVEL")) {
case "debug":
return zap.DebugLevel
case "info":
return zap.InfoLevel
case "warn":
return zap.WarnLevel
case "error":
return zap.ErrorLevel
default:
return zap.InfoLevel // 默认使用 Info 级别
}
}
// TimeEncoder 自定义时间格式
func TimeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
enc.AppendString(t.Format("2006-01-02 15:04:05.999"))
}