DeployHelper/pkg/logger/logger.go

171 lines
4.1 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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"))
}