lxzap.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. package lxzap
  2. import (
  3. "fmt"
  4. "net"
  5. "net/http"
  6. "net/http/httputil"
  7. "os"
  8. "runtime/debug"
  9. "strconv"
  10. "strings"
  11. "time"
  12. "github.com/gin-gonic/gin"
  13. "github.com/natefinch/lumberjack"
  14. "go.uber.org/zap"
  15. "go.uber.org/zap/zapcore"
  16. )
  17. var Lg *zap.Logger
  18. // Level = "info"
  19. // Filename = "./log/a.log"
  20. // MaxSize = 2
  21. // MaxAge = 1000
  22. // MaxBackups = 1000
  23. type ZapLogConfig struct {
  24. Level string `json:"level"`
  25. Filename string `json:"filename"`
  26. MaxSize int `json:"maxsize"`
  27. MaxAge int `json:"max_age"`
  28. MaxBackups int `json:"max_backups"`
  29. }
  30. // InitZapLogger 初始化Logger
  31. func InitZapLogger(cfg ZapLogConfig) (err error) {
  32. writeSyncer := getLogWriter(cfg.Filename, cfg.MaxSize, cfg.MaxBackups, cfg.MaxAge)
  33. encoder := getEncoder()
  34. var l = new(zapcore.Level)
  35. err = l.UnmarshalText([]byte(cfg.Level))
  36. if err != nil {
  37. return
  38. }
  39. core := zapcore.NewCore(encoder, writeSyncer, l)
  40. Lg = zap.New(core, zap.AddCaller())
  41. zap.ReplaceGlobals(Lg) // 替换zap包中全局的logger实例,后续在其他包中只需使用zap.L()调用即可
  42. return
  43. }
  44. func getEncoder() zapcore.Encoder {
  45. encoderConfig := zap.NewProductionEncoderConfig()
  46. encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
  47. encoderConfig.TimeKey = "time"
  48. encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
  49. encoderConfig.EncodeDuration = zapcore.SecondsDurationEncoder
  50. encoderConfig.EncodeCaller = zapcore.ShortCallerEncoder
  51. return zapcore.NewJSONEncoder(encoderConfig)
  52. }
  53. func getLogWriter(filename string, maxSize, maxBackup, maxAge int) zapcore.WriteSyncer {
  54. lumberJackLogger := &lumberjack.Logger{
  55. Filename: filename,
  56. MaxSize: maxSize,
  57. MaxBackups: maxBackup,
  58. MaxAge: maxAge,
  59. LocalTime: true,
  60. }
  61. return zapcore.AddSync(lumberJackLogger)
  62. }
  63. // GinLogger 接收gin框架默认的日志
  64. func GinLogger() gin.HandlerFunc {
  65. return func(c *gin.Context) {
  66. start := time.Now()
  67. path := c.Request.URL.Path
  68. query := c.Request.URL.RawQuery
  69. spanID := NewUUID()
  70. c.Set("X-Span-ID", spanID)
  71. cost := time.Since(start)
  72. Lg.Info(path,
  73. zap.Int("status", c.Writer.Status()),
  74. zap.String("spanId", strconv.Itoa(int(spanID))),
  75. zap.String("method", c.Request.Method),
  76. zap.String("path", path),
  77. zap.String("query", query),
  78. zap.String("ip", c.ClientIP()),
  79. zap.String("user-agent", c.Request.UserAgent()),
  80. zap.String("errors", c.Errors.ByType(gin.ErrorTypePrivate).String()),
  81. zap.Duration("cost", cost),
  82. )
  83. c.Next()
  84. }
  85. }
  86. // GinRecovery recover掉项目可能出现的panic,并使用zap记录相关日志
  87. func GinRecovery(stack bool) gin.HandlerFunc {
  88. return func(c *gin.Context) {
  89. defer func() {
  90. if err := recover(); err != nil {
  91. // Check for a broken connection, as it is not really a
  92. // condition that warrants a panic stack trace.
  93. var brokenPipe bool
  94. if ne, ok := err.(*net.OpError); ok {
  95. if se, ok := ne.Err.(*os.SyscallError); ok {
  96. if strings.Contains(strings.ToLower(se.Error()), "broken pipe") || strings.Contains(strings.ToLower(se.Error()), "connection reset by peer") {
  97. brokenPipe = true
  98. }
  99. }
  100. }
  101. httpRequest, _ := httputil.DumpRequest(c.Request, false)
  102. if brokenPipe {
  103. Lg.Error(c.Request.URL.Path,
  104. zap.Any("error", err),
  105. zap.String("request", string(httpRequest)),
  106. )
  107. // If the connection is dead, we can't write a status to it.
  108. c.Error(err.(error)) // nolint: errcheck
  109. c.Abort()
  110. return
  111. }
  112. if stack {
  113. Lg.Error("[Recovery from panic]",
  114. zap.Any("error", err),
  115. zap.String("request", string(httpRequest)),
  116. zap.String("stack", string(debug.Stack())),
  117. )
  118. } else {
  119. Lg.Error("[Recovery from panic]",
  120. zap.Any("error", err),
  121. zap.String("request", string(httpRequest)),
  122. )
  123. }
  124. c.AbortWithStatus(http.StatusInternalServerError)
  125. }
  126. }()
  127. c.Next()
  128. }
  129. }
  130. func Log(msg string, c *gin.Context) {
  131. v, _ := c.Get("X-Span-ID")
  132. spanId := fmt.Sprintf("%v", v)
  133. zap.L().Info(`spanId:"` + spanId + `"log:` + msg)
  134. }