logger.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. package logger
  2. import (
  3. "context"
  4. "fmt"
  5. "io/ioutil"
  6. "log"
  7. "os"
  8. "time"
  9. "gorm.io/gorm/utils"
  10. )
  11. // Colors
  12. const (
  13. Reset = "\033[0m"
  14. Red = "\033[31m"
  15. Green = "\033[32m"
  16. Yellow = "\033[33m"
  17. Blue = "\033[34m"
  18. Magenta = "\033[35m"
  19. Cyan = "\033[36m"
  20. White = "\033[37m"
  21. BlueBold = "\033[34;1m"
  22. MagentaBold = "\033[35;1m"
  23. RedBold = "\033[31;1m"
  24. YellowBold = "\033[33;1m"
  25. )
  26. // LogLevel
  27. type LogLevel int
  28. const (
  29. Silent LogLevel = iota + 1
  30. Error
  31. Warn
  32. Info
  33. )
  34. // Writer log writer interface
  35. type Writer interface {
  36. Printf(string, ...interface{})
  37. }
  38. type Config struct {
  39. SlowThreshold time.Duration
  40. Colorful bool
  41. LogLevel LogLevel
  42. }
  43. // Interface logger interface
  44. type Interface interface {
  45. LogMode(LogLevel) Interface
  46. Info(context.Context, string, ...interface{})
  47. Warn(context.Context, string, ...interface{})
  48. Error(context.Context, string, ...interface{})
  49. Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error)
  50. }
  51. var (
  52. Discard = New(log.New(ioutil.Discard, "", log.LstdFlags), Config{})
  53. Default = New(log.New(os.Stdout, "\r\n", log.LstdFlags), Config{
  54. SlowThreshold: 200 * time.Millisecond,
  55. LogLevel: Warn,
  56. Colorful: true,
  57. })
  58. Recorder = traceRecorder{Interface: Default, BeginAt: time.Now()}
  59. )
  60. func New(writer Writer, config Config) Interface {
  61. var (
  62. infoStr = "%s\n[info] "
  63. warnStr = "%s\n[warn] "
  64. errStr = "%s\n[error] "
  65. traceStr = "%s\n[%.3fms] [rows:%v] %s"
  66. traceWarnStr = "%s %s\n[%.3fms] [rows:%v] %s"
  67. traceErrStr = "%s %s\n[%.3fms] [rows:%v] %s"
  68. )
  69. if config.Colorful {
  70. infoStr = Green + "%s\n" + Reset + Green + "[info] " + Reset
  71. warnStr = BlueBold + "%s\n" + Reset + Magenta + "[warn] " + Reset
  72. errStr = Magenta + "%s\n" + Reset + Red + "[error] " + Reset
  73. traceStr = Green + "%s\n" + Reset + Yellow + "[%.3fms] " + BlueBold + "[rows:%v]" + Reset + " %s"
  74. traceWarnStr = Green + "%s " + Yellow + "%s\n" + Reset + RedBold + "[%.3fms] " + Yellow + "[rows:%v]" + Magenta + " %s" + Reset
  75. traceErrStr = RedBold + "%s " + MagentaBold + "%s\n" + Reset + Yellow + "[%.3fms] " + BlueBold + "[rows:%v]" + Reset + " %s"
  76. }
  77. return &logger{
  78. Writer: writer,
  79. Config: config,
  80. infoStr: infoStr,
  81. warnStr: warnStr,
  82. errStr: errStr,
  83. traceStr: traceStr,
  84. traceWarnStr: traceWarnStr,
  85. traceErrStr: traceErrStr,
  86. }
  87. }
  88. type logger struct {
  89. Writer
  90. Config
  91. infoStr, warnStr, errStr string
  92. traceStr, traceErrStr, traceWarnStr string
  93. }
  94. // LogMode log mode
  95. func (l *logger) LogMode(level LogLevel) Interface {
  96. newlogger := *l
  97. newlogger.LogLevel = level
  98. return &newlogger
  99. }
  100. // Info print info
  101. func (l logger) Info(ctx context.Context, msg string, data ...interface{}) {
  102. if l.LogLevel >= Info {
  103. l.Printf(l.infoStr+msg, append([]interface{}{utils.FileWithLineNum()}, data...)...)
  104. }
  105. }
  106. // Warn print warn messages
  107. func (l logger) Warn(ctx context.Context, msg string, data ...interface{}) {
  108. if l.LogLevel >= Warn {
  109. l.Printf(l.warnStr+msg, append([]interface{}{utils.FileWithLineNum()}, data...)...)
  110. }
  111. }
  112. // Error print error messages
  113. func (l logger) Error(ctx context.Context, msg string, data ...interface{}) {
  114. if l.LogLevel >= Error {
  115. l.Printf(l.errStr+msg, append([]interface{}{utils.FileWithLineNum()}, data...)...)
  116. }
  117. }
  118. // Trace print sql message
  119. func (l logger) Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) {
  120. if l.LogLevel > Silent {
  121. elapsed := time.Since(begin)
  122. switch {
  123. case err != nil && l.LogLevel >= Error:
  124. sql, rows := fc()
  125. if rows == -1 {
  126. l.Printf(l.traceErrStr, utils.FileWithLineNum(), err, float64(elapsed.Nanoseconds())/1e6, "-", sql)
  127. } else {
  128. l.Printf(l.traceErrStr, utils.FileWithLineNum(), err, float64(elapsed.Nanoseconds())/1e6, rows, sql)
  129. }
  130. case elapsed > l.SlowThreshold && l.SlowThreshold != 0 && l.LogLevel >= Warn:
  131. sql, rows := fc()
  132. slowLog := fmt.Sprintf("SLOW SQL >= %v", l.SlowThreshold)
  133. if rows == -1 {
  134. l.Printf(l.traceWarnStr, utils.FileWithLineNum(), slowLog, float64(elapsed.Nanoseconds())/1e6, "-", sql)
  135. } else {
  136. l.Printf(l.traceWarnStr, utils.FileWithLineNum(), slowLog, float64(elapsed.Nanoseconds())/1e6, rows, sql)
  137. }
  138. case l.LogLevel == Info:
  139. sql, rows := fc()
  140. if rows == -1 {
  141. l.Printf(l.traceStr, utils.FileWithLineNum(), float64(elapsed.Nanoseconds())/1e6, "-", sql)
  142. } else {
  143. l.Printf(l.traceStr, utils.FileWithLineNum(), float64(elapsed.Nanoseconds())/1e6, rows, sql)
  144. }
  145. }
  146. }
  147. }
  148. type traceRecorder struct {
  149. Interface
  150. BeginAt time.Time
  151. SQL string
  152. RowsAffected int64
  153. Err error
  154. }
  155. func (l traceRecorder) New() *traceRecorder {
  156. return &traceRecorder{Interface: l.Interface, BeginAt: time.Now()}
  157. }
  158. func (l *traceRecorder) Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) {
  159. l.BeginAt = begin
  160. l.SQL, l.RowsAffected = fc()
  161. l.Err = err
  162. }