github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/engine/pkg/orm/log.go (about) 1 // Copyright 2022 PingCAP, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package orm 15 16 import ( 17 "context" 18 "fmt" 19 "time" 20 21 "github.com/pingcap/tiflow/pkg/errors" 22 "go.uber.org/zap" 23 "gorm.io/gorm" 24 "gorm.io/gorm/logger" 25 ) 26 27 type loggerOption struct { 28 slowThreshold time.Duration 29 ignoreTraceRecordNotFoundErr bool 30 } 31 32 type optionFunc func(*loggerOption) 33 34 // WithSlowThreshold sets the slow log threshold for gorm log 35 func WithSlowThreshold(thres time.Duration) optionFunc { 36 return func(op *loggerOption) { 37 op.slowThreshold = thres 38 } 39 } 40 41 // WithIgnoreTraceRecordNotFoundErr sets if ignore 'record not found' error for trace 42 func WithIgnoreTraceRecordNotFoundErr() optionFunc { 43 return func(op *loggerOption) { 44 op.ignoreTraceRecordNotFoundErr = true 45 } 46 } 47 48 // NewOrmLogger returns a logger which implements logger.Interface 49 func NewOrmLogger(lg *zap.Logger, opts ...optionFunc) logger.Interface { 50 var op loggerOption 51 for _, opt := range opts { 52 opt(&op) 53 } 54 55 return &ormLogger{ 56 op: op, 57 lg: lg, 58 } 59 } 60 61 type ormLogger struct { 62 op loggerOption 63 lg *zap.Logger 64 } 65 66 func (l *ormLogger) LogMode(logger.LogLevel) logger.Interface { 67 // TODO implement me 68 return l 69 } 70 71 func (l *ormLogger) Info(ctx context.Context, format string, args ...interface{}) { 72 l.lg.Info(fmt.Sprintf(format, args...)) 73 } 74 75 func (l *ormLogger) Warn(ctx context.Context, format string, args ...interface{}) { 76 l.lg.Warn(fmt.Sprintf(format, args...)) 77 } 78 79 func (l *ormLogger) Error(ctx context.Context, format string, args ...interface{}) { 80 l.lg.Error(fmt.Sprintf(format, args...)) 81 } 82 83 func (l *ormLogger) Trace(ctx context.Context, begin time.Time, resFunc func() (sql string, rowsAffected int64), err error) { 84 elapsed := time.Since(begin) 85 sql, rows := resFunc() 86 var logFunc func(string, ...zap.Field) 87 if err != nil && (!errors.Is(err, gorm.ErrRecordNotFound) || !l.op.ignoreTraceRecordNotFoundErr) { 88 logFunc = l.lg.Error 89 } else { 90 logFunc = l.lg.Debug 91 } 92 var fields []zap.Field 93 fields = append(fields, zap.Duration("elapsed", elapsed), zap.String("sql", sql), zap.Int64("affected-rows", rows)) 94 if err != nil { 95 fields = append(fields, zap.Error(err)) 96 } 97 98 logFunc("trace log", fields...) 99 100 // Split the slow log if we need 101 if elapsed > l.op.slowThreshold && l.op.slowThreshold != 0 { 102 l.lg.Warn("slow log", fields...) 103 } 104 }