lxzap.go 3.7 KB

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