github.com/goravel/framework@v1.13.9/database/gorm/logger.go (about) 1 package gorm 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "net" 8 "regexp" 9 "runtime" 10 "strconv" 11 "strings" 12 "time" 13 14 "gorm.io/gorm/logger" 15 ) 16 17 func NewLogger(writer logger.Writer, config logger.Config) logger.Interface { 18 var ( 19 infoStr = "%s\n[Orm] " 20 warnStr = "%s\n[Orm] " 21 errStr = "%s\n[Orm] " 22 traceStr = "%s\n[%.3fms] [rows:%v] %s" 23 traceWarnStr = "%s %s\n[%.3fms] [rows:%v] %s" 24 traceErrStr = "%s %s\n[%.3fms] [rows:%v] %s" 25 ) 26 27 if config.Colorful { 28 infoStr = logger.Green + "%s\n" + logger.Reset + logger.Green + "[Orm] " + logger.Reset 29 warnStr = logger.BlueBold + "%s\n" + logger.Reset + logger.Magenta + "[Orm] " + logger.Reset 30 errStr = logger.Magenta + "%s\n" + logger.Reset + logger.Red + "[Orm] " + logger.Reset 31 traceStr = logger.Green + "%s\n" + logger.Reset + logger.Yellow + "[%.3fms] " + logger.BlueBold + "[rows:%v]" + logger.Reset + " %s" 32 traceWarnStr = logger.Green + "%s " + logger.Yellow + "%s\n" + logger.Reset + logger.RedBold + "[%.3fms] " + logger.Yellow + "[rows:%v]" + logger.Magenta + " %s" + logger.Reset 33 traceErrStr = logger.RedBold + "%s " + logger.MagentaBold + "%s\n" + logger.Reset + logger.Yellow + "[%.3fms] " + logger.BlueBold + "[rows:%v]" + logger.Reset + " %s" 34 } 35 36 return &Logger{ 37 Writer: writer, 38 Config: config, 39 infoStr: infoStr, 40 warnStr: warnStr, 41 errStr: errStr, 42 traceStr: traceStr, 43 traceWarnStr: traceWarnStr, 44 traceErrStr: traceErrStr, 45 } 46 } 47 48 type Logger struct { 49 logger.Writer 50 logger.Config 51 infoStr, warnStr, errStr string 52 traceStr, traceErrStr, traceWarnStr string 53 } 54 55 // LogMode log mode 56 func (l *Logger) LogMode(level logger.LogLevel) logger.Interface { 57 newlogger := *l 58 newlogger.LogLevel = level 59 return &newlogger 60 } 61 62 // Info print info 63 func (l Logger) Info(ctx context.Context, msg string, data ...any) { 64 if l.LogLevel >= logger.Info { 65 l.Printf(l.infoStr+msg, append([]any{FileWithLineNum()}, data...)...) 66 } 67 } 68 69 // Warn print warn messages 70 func (l Logger) Warn(ctx context.Context, msg string, data ...any) { 71 if l.LogLevel >= logger.Warn { 72 l.Printf(l.warnStr+msg, append([]any{FileWithLineNum()}, data...)...) 73 } 74 } 75 76 // Error print error messages 77 func (l Logger) Error(ctx context.Context, msg string, data ...any) { 78 // Let upper layer function deals with connection refused error 79 var cancel bool 80 for _, item := range data { 81 if tempItem, ok := item.(*net.OpError); ok { 82 if strings.Contains(tempItem.Error(), "connection refused") { 83 return 84 } 85 86 } 87 if tempItem, ok := item.(error); ok { 88 // Avoid duplicate output 89 if strings.Contains(tempItem.Error(), "Access denied") { 90 cancel = true 91 } 92 } 93 } 94 95 if cancel { 96 return 97 } 98 99 if l.LogLevel >= logger.Error { 100 l.Printf(l.errStr+msg, append([]any{FileWithLineNum()}, data...)...) 101 } 102 } 103 104 // Trace print sql message 105 func (l Logger) Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) { 106 if l.LogLevel <= logger.Silent { 107 return 108 } 109 110 elapsed := time.Since(begin) 111 switch { 112 case err != nil && l.LogLevel >= logger.Error && (!errors.Is(err, logger.ErrRecordNotFound) || !l.IgnoreRecordNotFoundError): 113 sql, rows := fc() 114 if rows == -1 { 115 l.Printf(l.traceErrStr, FileWithLineNum(), err, float64(elapsed.Nanoseconds())/1e6, "-", sql) 116 } else { 117 l.Printf(l.traceErrStr, FileWithLineNum(), err, float64(elapsed.Nanoseconds())/1e6, rows, sql) 118 } 119 case elapsed > l.SlowThreshold && l.SlowThreshold != 0 && l.LogLevel >= logger.Warn: 120 sql, rows := fc() 121 slowLog := fmt.Sprintf("SLOW SQL >= %v", l.SlowThreshold) 122 if rows == -1 { 123 l.Printf(l.traceWarnStr, FileWithLineNum(), slowLog, float64(elapsed.Nanoseconds())/1e6, "-", sql) 124 } else { 125 l.Printf(l.traceWarnStr, FileWithLineNum(), slowLog, float64(elapsed.Nanoseconds())/1e6, rows, sql) 126 } 127 case l.LogLevel == logger.Info: 128 sql, rows := fc() 129 if rows == -1 { 130 l.Printf(l.traceStr, FileWithLineNum(), float64(elapsed.Nanoseconds())/1e6, "-", sql) 131 } else { 132 l.Printf(l.traceStr, FileWithLineNum(), float64(elapsed.Nanoseconds())/1e6, rows, sql) 133 } 134 } 135 } 136 137 // FileWithLineNum return the file name and line number of the current file 138 func FileWithLineNum() string { 139 _, file, _, _ := runtime.Caller(0) 140 gormSourceDir := regexp.MustCompile(`utils.utils\.go`).ReplaceAllString(file, "") 141 goravelSourceDir := "database/gorm.go" 142 143 // the second caller usually from gorm internal, so set i start from 5 144 for i := 5; i < 15; i++ { 145 _, file, line, ok := runtime.Caller(i) 146 if ok && ((!strings.HasPrefix(file, gormSourceDir) && !strings.Contains(file, goravelSourceDir)) || strings.HasSuffix(file, "_test.go")) { 147 return file + ":" + strconv.FormatInt(int64(line), 10) 148 } 149 } 150 151 return "" 152 }