-
Notifications
You must be signed in to change notification settings - Fork 3
/
gormlog.go
167 lines (131 loc) · 4.25 KB
/
gormlog.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
package gormv2logrus
import (
"context"
"errors"
"strings"
"time"
"github.com/sirupsen/logrus"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"gorm.io/gorm/utils"
)
// Gormlog must match gorm logger.Interface to be compatible with gorm.
// Gormlog can be assigned in gorm configuration (see example in README.md).
type Gormlog struct {
// SkipErrRecordNotFound if set to true, errors of type gorm.ErrRecordNotFound will be ignored.
SkipErrRecordNotFound bool
// SlowThreshold is used to determine a limit of slow requests, if a request time is above SlowThreshold,
// it will be logged as warning.
SlowThreshold time.Duration
// SourceField if definied, source will appear in log with detailed file context.
SourceField string
LogLevel logger.LogLevel
opts options
}
// NewGormlog create an instance of.
func NewGormlog(opts ...Option) *Gormlog {
gl := &Gormlog{
opts: defaultOptions(),
}
for _, opt := range opts {
opt.apply(&gl.opts)
}
return gl
}
// LogMode implementation log mode.
func (gl *Gormlog) LogMode(ll logger.LogLevel) logger.Interface {
gl.LogLevel = ll
return gl
}
// Info implementation of info log level
func (gl *Gormlog) Info(ctx context.Context, msg string, args ...interface{}) {
if gl.opts.lr != nil {
gl.opts.lr.WithContext(ctx).Infof(msg, args...)
}
if gl.opts.logrusEntry != nil {
gl.opts.logrusEntry.WithContext(ctx).Infof(msg, args...)
}
}
// Warn implementation of warn log level
func (gl *Gormlog) Warn(ctx context.Context, msg string, args ...interface{}) {
if gl.opts.lr != nil {
gl.opts.lr.WithContext(ctx).Warnf(msg, args...)
}
if gl.opts.logrusEntry != nil {
gl.opts.logrusEntry.WithContext(ctx).Warnf(msg, args...)
}
}
// Error Gormlog of error log level
func (gl *Gormlog) Error(ctx context.Context, msg string, args ...interface{}) {
if gl.opts.lr != nil {
gl.opts.lr.WithContext(ctx).Errorf(msg, args...)
}
if gl.opts.logrusEntry != nil {
gl.opts.logrusEntry.WithContext(ctx).Errorf(msg, args...)
}
}
// Trace implementation of trace log level
func (gl *Gormlog) Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) {
// retrieve sql string and affected rows
traceLog, rows := fc()
// use begin to compute performances
stopWatch := time.Since(begin)
// additional logrus fields
logrusFields := logrus.Fields{}
// if logLatency is true, add stopWatch information
if gl.opts.logLatency {
logrusFields["duration"] = stopWatch
}
// add number of affected rows as logrus parameter
logrusFields["rows"] = rows
// if source field is definied, we retrieve line number information
if len(gl.SourceField) > 0 {
logrusFields[gl.SourceField] = utils.FileWithLineNum()
}
// scanning for banned keywords
for idx := 0; idx < len(gl.opts.bannedKeywords); idx++ {
if gl.opts.bannedKeywords[idx].CaseMatters &&
strings.Contains(traceLog, gl.opts.bannedKeywords[idx].Keyword) {
return
} else if !gl.opts.bannedKeywords[idx].CaseMatters &&
strings.Contains(
strings.ToLower(traceLog),
strings.ToLower(gl.opts.bannedKeywords[idx].Keyword),
) {
return
}
}
// check if we have an error
if err != nil {
if !(errors.Is(err, gorm.ErrRecordNotFound) && gl.SkipErrRecordNotFound) {
logrusFields[logrus.ErrorKey] = err
if gl.opts.lr != nil {
gl.opts.lr.WithContext(ctx).WithFields(logrusFields).Errorf("%s", traceLog)
}
if gl.opts.logrusEntry != nil {
gl.opts.logrusEntry.WithContext(ctx).WithFields(logrusFields).Errorf("%s", traceLog)
}
return
}
}
if gl.opts.SlowThreshold != 0 && stopWatch > gl.opts.SlowThreshold && gl.opts.LogLevel >= logger.Warn {
// instead of adding SLOW SQL to the message, add reason field
// this can be parsed easily with logs management tools
logrusFields["reason"] = "SLOW SQL"
if gl.opts.lr != nil {
gl.opts.lr.WithContext(ctx).WithFields(logrusFields).Warnf("%s", traceLog)
}
if gl.opts.logrusEntry != nil {
gl.opts.logrusEntry.WithContext(ctx).WithFields(logrusFields).Warnf("%s", traceLog)
}
return
}
// Use directly with logrus entry
if gl.opts.lr != nil {
gl.opts.lr.WithContext(ctx).WithFields(logrusFields).Debugf("%s", traceLog)
}
// Use with logrusEntry
if gl.opts.logrusEntry != nil {
gl.opts.logrusEntry.WithContext(ctx).WithFields(logrusFields).Debugf("%s", traceLog)
}
}