zapgorm2.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. package zapgorm2
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "github.com/gin-gonic/gin"
  7. "path/filepath"
  8. "runtime"
  9. "strings"
  10. "time"
  11. "go.uber.org/zap"
  12. gormlogger "gorm.io/gorm/logger"
  13. )
  14. const ctxLoggerKey = "zapLogger"
  15. type Logger struct {
  16. ZapLogger *zap.Logger
  17. SlowThreshold time.Duration
  18. Colorful bool
  19. IgnoreRecordNotFoundError bool
  20. ParameterizedQueries bool
  21. LogLevel gormlogger.LogLevel
  22. }
  23. func New(zapLogger *zap.Logger) gormlogger.Interface {
  24. return &Logger{
  25. ZapLogger: zapLogger,
  26. LogLevel: gormlogger.Warn,
  27. SlowThreshold: 100 * time.Millisecond,
  28. Colorful: false,
  29. IgnoreRecordNotFoundError: false,
  30. ParameterizedQueries: false,
  31. }
  32. }
  33. func (l *Logger) LogMode(level gormlogger.LogLevel) gormlogger.Interface {
  34. newlogger := *l
  35. newlogger.LogLevel = level
  36. return &newlogger
  37. }
  38. // Info print info
  39. func (l Logger) Info(ctx context.Context, msg string, data ...interface{}) {
  40. if l.LogLevel >= gormlogger.Info {
  41. l.logger(ctx).Sugar().Infof(msg, data...)
  42. }
  43. }
  44. // Warn print warn messages
  45. func (l Logger) Warn(ctx context.Context, msg string, data ...interface{}) {
  46. if l.LogLevel >= gormlogger.Warn {
  47. l.logger(ctx).Sugar().Warnf(msg, data...)
  48. }
  49. }
  50. // Error print error messages
  51. func (l Logger) Error(ctx context.Context, msg string, data ...interface{}) {
  52. if l.LogLevel >= gormlogger.Error {
  53. l.logger(ctx).Sugar().Errorf(msg, data...)
  54. }
  55. }
  56. func (l Logger) Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) {
  57. if l.LogLevel <= gormlogger.Silent {
  58. return
  59. }
  60. elapsed := time.Since(begin)
  61. elapsedStr := fmt.Sprintf("%.3fms", float64(elapsed.Nanoseconds())/1e6)
  62. logger := l.logger(ctx)
  63. switch {
  64. case err != nil && l.LogLevel >= gormlogger.Error && (!errors.Is(err, gormlogger.ErrRecordNotFound) || !l.IgnoreRecordNotFoundError):
  65. sql, rows := fc()
  66. if rows == -1 {
  67. logger.Error("trace", zap.Error(err), zap.String("elapsed", elapsedStr), zap.Int64("rows", rows), zap.String("sql", sql))
  68. } else {
  69. logger.Error("trace", zap.Error(err), zap.String("elapsed", elapsedStr), zap.Int64("rows", rows), zap.String("sql", sql))
  70. }
  71. case elapsed > l.SlowThreshold && l.SlowThreshold != 0 && l.LogLevel >= gormlogger.Warn:
  72. sql, rows := fc()
  73. slowLog := fmt.Sprintf("SLOW SQL >= %v", l.SlowThreshold)
  74. if rows == -1 {
  75. logger.Warn("trace", zap.String("slow", slowLog), zap.String("elapsed", elapsedStr), zap.Int64("rows", rows), zap.String("sql", sql))
  76. } else {
  77. logger.Warn("trace", zap.String("slow", slowLog), zap.String("elapsed", elapsedStr), zap.Int64("rows", rows), zap.String("sql", sql))
  78. }
  79. case l.LogLevel == gormlogger.Info:
  80. sql, rows := fc()
  81. if rows == -1 {
  82. logger.Info("trace", zap.String("elapsed", elapsedStr), zap.Int64("rows", rows), zap.String("sql", sql))
  83. } else {
  84. logger.Info("trace", zap.String("elapsed", elapsedStr), zap.Int64("rows", rows), zap.String("sql", sql))
  85. }
  86. }
  87. }
  88. var (
  89. gormPackage = filepath.Join("gorm.io", "gorm")
  90. )
  91. func (l Logger) logger(ctx context.Context) *zap.Logger {
  92. logger := l.ZapLogger
  93. if ctx != nil {
  94. if c, ok := ctx.(*gin.Context); ok {
  95. ctx = c.Request.Context()
  96. }
  97. zl := ctx.Value(ctxLoggerKey)
  98. ctxLogger, ok := zl.(*zap.Logger)
  99. if ok {
  100. logger = ctxLogger
  101. }
  102. }
  103. for i := 2; i < 15; i++ {
  104. _, file, _, ok := runtime.Caller(i)
  105. switch {
  106. case !ok:
  107. case strings.HasSuffix(file, "_test.go"):
  108. case strings.Contains(file, gormPackage):
  109. default:
  110. return logger.WithOptions(zap.AddCallerSkip(i - 1))
  111. }
  112. }
  113. return logger
  114. }