lxzap.go 3.8 KB

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