lxutils/lxzap/lxzap.go
2025-03-24 18:25:15 +08:00

164 lines
4.3 KiB
Go
Raw 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 lxzap
import (
"context"
"fmt"
"net"
"net/http"
"net/http/httputil"
"os"
"runtime/debug"
"strconv"
"strings"
"time"
"github.com/gin-gonic/gin"
"github.com/natefinch/lumberjack"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
var Lg *zap.Logger
// Level = "info"
// Filename = "./log/a.log"
// MaxSize = 2
// MaxAge = 1000
// MaxBackups = 1000
type ZapLogConfig struct {
Level string `json:"level"`
Filename string `json:"filename"`
MaxSize int `json:"maxsize"`
MaxAge int `json:"max_age"`
MaxBackups int `json:"max_backups"`
}
// InitZapLogger 初始化Logger
func InitZapLogger(cfg ZapLogConfig, env string) (err error) {
writeSyncer := getLogWriter(cfg.Filename, cfg.MaxSize, cfg.MaxBackups, cfg.MaxAge)
encoder := getEncoder(env)
var l = new(zapcore.Level)
err = l.UnmarshalText([]byte(cfg.Level))
if err != nil {
return
}
// 创建 zap 核心
core := zapcore.NewCore(
encoder,
zapcore.NewMultiWriteSyncer(zapcore.AddSync(os.Stdout), writeSyncer),
l,
)
if env != "dev" {
core = zapcore.NewCore(encoder, writeSyncer, l)
}
// 创建 zap 日志对象
Lg = zap.New(core, zap.AddCaller())
zap.ReplaceGlobals(Lg) // 替换zap包中全局的logger实例后续在其他包中只需使用zap.L()调用即可
return
}
func getEncoder(env string) zapcore.Encoder {
encoderConfig := zap.NewProductionEncoderConfig()
encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
encoderConfig.TimeKey = "time"
encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
encoderConfig.EncodeDuration = zapcore.SecondsDurationEncoder
encoderConfig.EncodeCaller = zapcore.ShortCallerEncoder
l := zapcore.NewConsoleEncoder(encoderConfig)
if env != "dev" {
l = zapcore.NewJSONEncoder(encoderConfig)
}
return l
}
func getLogWriter(filename string, maxSize, maxBackup, maxAge int) zapcore.WriteSyncer {
lumberJackLogger := &lumberjack.Logger{
Filename: filename,
MaxSize: maxSize,
MaxBackups: maxBackup,
MaxAge: maxAge,
LocalTime: true,
}
return zapcore.AddSync(lumberJackLogger)
}
// GinLogger 接收gin框架默认的日志
func GinLogger() gin.HandlerFunc {
return func(c *gin.Context) {
start := time.Now()
path := c.Request.URL.Path
query := c.Request.URL.RawQuery
spanID := NewUUID()
c.Set("X-Span-ID", spanID)
c.Next()
cost := time.Since(start)
Lg.Info(path,
zap.Int("status", c.Writer.Status()),
zap.String("spanId", strconv.Itoa(int(spanID))),
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.String("errors", c.Errors.ByType(gin.ErrorTypePrivate).String()),
zap.Duration("cost", cost),
)
}
}
// GinRecovery recover掉项目可能出现的panic并使用zap记录相关日志
func GinRecovery(stack bool) gin.HandlerFunc {
return func(c *gin.Context) {
defer func() {
if err := recover(); err != nil {
// Check for a broken connection, as it is not really a
// condition that warrants a panic stack trace.
var brokenPipe bool
if ne, ok := err.(*net.OpError); ok {
if se, ok := ne.Err.(*os.SyscallError); ok {
if strings.Contains(strings.ToLower(se.Error()), "broken pipe") || strings.Contains(strings.ToLower(se.Error()), "connection reset by peer") {
brokenPipe = true
}
}
}
httpRequest, _ := httputil.DumpRequest(c.Request, false)
if brokenPipe {
Lg.Error(c.Request.URL.Path,
zap.Any("error", err),
zap.String("request", string(httpRequest)),
)
// If the connection is dead, we can't write a status to it.
c.Error(err.(error)) // nolint: errcheck
c.Abort()
return
}
if stack {
Lg.Error("[Recovery from panic]",
zap.Any("error", err),
zap.String("request", string(httpRequest)),
zap.String("stack", string(debug.Stack())),
)
} else {
Lg.Error("[Recovery from panic]",
zap.Any("error", err),
zap.String("request", string(httpRequest)),
)
}
c.AbortWithStatus(http.StatusInternalServerError)
}
}()
c.Next()
}
}
func Log(msg any, ctx context.Context) {
v := ctx.Value("X-Span-ID")
spanId := fmt.Sprintf("%v", v)
//zap.L().Info(`spanId:"` + spanId + `"log:` + msg)
zap.L().Info("fmt",
zap.Any("content", msg),
zap.String("spanId", spanId))
}