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  }