package logger import ( "os" "time" "github.com/gin-gonic/gin" "go.uber.org/zap" "go.uber.org/zap/zapcore" ) // New 创建日志实例 func New(level string) *zap.Logger { var lvl zapcore.Level switch level { case "debug": lvl = zapcore.DebugLevel case "info": lvl = zapcore.InfoLevel case "warn": lvl = zapcore.WarnLevel case "error": lvl = zapcore.ErrorLevel default: lvl = zapcore.InfoLevel } encoderConfig := zapcore.EncoderConfig{ TimeKey: "time", LevelKey: "level", NameKey: "logger", CallerKey: "caller", MessageKey: "msg", StacktraceKey: "stacktrace", LineEnding: zapcore.DefaultLineEnding, EncodeLevel: zapcore.LowercaseLevelEncoder, EncodeTime: zapcore.ISO8601TimeEncoder, EncodeDuration: zapcore.SecondsDurationEncoder, EncodeCaller: zapcore.ShortCallerEncoder, } core := zapcore.NewCore( zapcore.NewJSONEncoder(encoderConfig), zapcore.NewMultiWriteSyncer(zapcore.AddSync(os.Stdout)), lvl, ) return zap.New(core, zap.AddCaller(), zap.AddStacktrace(zapcore.ErrorLevel)) } // GinLogger Gin日志中间件 func GinLogger(log *zap.Logger) gin.HandlerFunc { return func(c *gin.Context) { start := time.Now() path := c.Request.URL.Path query := c.Request.URL.RawQuery c.Next() // 跳过健康检查/探针路径的日志 if path == "/version" || path == "/health" || path == "/healthz" { return } cost := time.Since(start) status := c.Writer.Status() fields := []zap.Field{ zap.Int("status", status), zap.String("method", c.Request.Method), zap.String("path", path), zap.String("query", query), zap.String("ip", c.ClientIP()), zap.String("user-agent", c.Request.UserAgent()), zap.Duration("cost", cost), } if len(c.Errors) > 0 { fields = append(fields, zap.Strings("errors", c.Errors.Errors())) } if status >= 500 { log.Error("Server Error", fields...) } else if status >= 400 { log.Warn("Client Error", fields...) } else { log.Info("Request", fields...) } } }