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