forked from thomas-tacquet/gormv2-logrus
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgormlog.go
222 lines (170 loc) · 5.71 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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
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
}
// 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 {
if gl.opts.Colorful {
gl.opts.lr.WithContext(ctx).WithFields(logrusFields).Errorf(
Magenta+"%s\n"+Reset+Red+"[error] "+"[%.3fms] ", traceLog,
float64(stopWatch.Nanoseconds())/1e6)
} else {
gl.opts.lr.WithContext(ctx).WithFields(logrusFields).Errorf(
"%s\n [error] [%.3fms] ", traceLog,
float64(stopWatch.Nanoseconds())/1e6)
}
}
if gl.opts.logrusEntry != nil {
if gl.opts.Colorful {
gl.opts.logrusEntry.WithContext(ctx).WithFields(logrusFields).Errorf(
Magenta+"%s\n"+Reset+Red+"[error] "+"[%.3fms] ", traceLog,
float64(stopWatch.Nanoseconds())/1e6)
} else {
gl.opts.logrusEntry.WithContext(ctx).WithFields(logrusFields).Errorf(
"%s\n [error] [%.3fms] ", traceLog,
float64(stopWatch.Nanoseconds())/1e6)
}
}
return
}
}
if gl.SlowThreshold != 0 && stopWatch > gl.SlowThreshold {
if gl.opts.lr != nil {
if gl.opts.Colorful {
gl.opts.lr.WithContext(ctx).WithFields(logrusFields).Warnf(
Green+"SLOW SQL %s\n"+Reset+RedBold+"[%.3fms] ", traceLog,
float64(stopWatch.Nanoseconds())/1e6)
} else {
gl.opts.lr.WithContext(ctx).WithFields(logrusFields).Warnf(
"SLOW SQL %s\n [%.3fms]", traceLog, float64(stopWatch.Nanoseconds())/1e6)
}
}
if gl.opts.logrusEntry != nil {
if gl.opts.Colorful {
gl.opts.logrusEntry.WithContext(ctx).WithFields(logrusFields).Warnf(
Green+"SLOW SQL %s\n"+Reset+RedBold+"[%.3fms] ", traceLog,
float64(stopWatch.Nanoseconds())/1e6)
} else {
gl.opts.logrusEntry.WithContext(ctx).WithFields(logrusFields).Warnf(
"SLOW SQL %s\n [%.3fms]", traceLog, float64(stopWatch.Nanoseconds())/1e6)
}
}
return
}
// Use directly with logrus entry
if gl.opts.lr != nil {
if gl.opts.Colorful {
gl.opts.lr.WithContext(ctx).WithFields(logrusFields).Debugf(
Green+"%s\n"+Reset+Yellow+"[%.3fms] "+BlueBold+"[rows:%v]"+Reset, traceLog,
float64(stopWatch.Nanoseconds())/1e6, rows)
} else {
gl.opts.lr.WithContext(ctx).WithFields(logrusFields).Debugf(
"%s\n [%.3fms] [rows:%v]", traceLog, float64(stopWatch.Nanoseconds())/1e6, rows)
}
}
// Use with logrusEntry
if gl.opts.logrusEntry != nil {
if gl.opts.Colorful {
gl.opts.logrusEntry.WithContext(ctx).WithFields(logrusFields).Debugf(
Green+"%s\n"+Reset+Yellow+"[%.3fms] "+BlueBold+"[rows:%v]"+Reset, traceLog,
float64(stopWatch.Nanoseconds())/1e6, rows)
} else {
gl.opts.logrusEntry.WithContext(ctx).WithFields(logrusFields).Debugf(
"%s\n [%.3fms] [rows:%v]", traceLog, float64(stopWatch.Nanoseconds())/1e6, rows)
}
}
}