Mercurial > yakumo_izuru > aya
comparison vendor/github.com/sirupsen/logrus/entry.go @ 66:787b5ee0289d draft
Use vendored modules
Signed-off-by: Izuru Yakumo <yakumo.izuru@chaotic.ninja>
author | yakumo.izuru |
---|---|
date | Sun, 23 Jul 2023 13:18:53 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
65:6d985efa0f7a | 66:787b5ee0289d |
---|---|
1 package logrus | |
2 | |
3 import ( | |
4 "bytes" | |
5 "context" | |
6 "fmt" | |
7 "os" | |
8 "reflect" | |
9 "runtime" | |
10 "strings" | |
11 "sync" | |
12 "time" | |
13 ) | |
14 | |
15 var ( | |
16 | |
17 // qualified package name, cached at first use | |
18 logrusPackage string | |
19 | |
20 // Positions in the call stack when tracing to report the calling method | |
21 minimumCallerDepth int | |
22 | |
23 // Used for caller information initialisation | |
24 callerInitOnce sync.Once | |
25 ) | |
26 | |
27 const ( | |
28 maximumCallerDepth int = 25 | |
29 knownLogrusFrames int = 4 | |
30 ) | |
31 | |
32 func init() { | |
33 // start at the bottom of the stack before the package-name cache is primed | |
34 minimumCallerDepth = 1 | |
35 } | |
36 | |
37 // Defines the key when adding errors using WithError. | |
38 var ErrorKey = "error" | |
39 | |
40 // An entry is the final or intermediate Logrus logging entry. It contains all | |
41 // the fields passed with WithField{,s}. It's finally logged when Trace, Debug, | |
42 // Info, Warn, Error, Fatal or Panic is called on it. These objects can be | |
43 // reused and passed around as much as you wish to avoid field duplication. | |
44 type Entry struct { | |
45 Logger *Logger | |
46 | |
47 // Contains all the fields set by the user. | |
48 Data Fields | |
49 | |
50 // Time at which the log entry was created | |
51 Time time.Time | |
52 | |
53 // Level the log entry was logged at: Trace, Debug, Info, Warn, Error, Fatal or Panic | |
54 // This field will be set on entry firing and the value will be equal to the one in Logger struct field. | |
55 Level Level | |
56 | |
57 // Calling method, with package name | |
58 Caller *runtime.Frame | |
59 | |
60 // Message passed to Trace, Debug, Info, Warn, Error, Fatal or Panic | |
61 Message string | |
62 | |
63 // When formatter is called in entry.log(), a Buffer may be set to entry | |
64 Buffer *bytes.Buffer | |
65 | |
66 // Contains the context set by the user. Useful for hook processing etc. | |
67 Context context.Context | |
68 | |
69 // err may contain a field formatting error | |
70 err string | |
71 } | |
72 | |
73 func NewEntry(logger *Logger) *Entry { | |
74 return &Entry{ | |
75 Logger: logger, | |
76 // Default is three fields, plus one optional. Give a little extra room. | |
77 Data: make(Fields, 6), | |
78 } | |
79 } | |
80 | |
81 func (entry *Entry) Dup() *Entry { | |
82 data := make(Fields, len(entry.Data)) | |
83 for k, v := range entry.Data { | |
84 data[k] = v | |
85 } | |
86 return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time, Context: entry.Context, err: entry.err} | |
87 } | |
88 | |
89 // Returns the bytes representation of this entry from the formatter. | |
90 func (entry *Entry) Bytes() ([]byte, error) { | |
91 return entry.Logger.Formatter.Format(entry) | |
92 } | |
93 | |
94 // Returns the string representation from the reader and ultimately the | |
95 // formatter. | |
96 func (entry *Entry) String() (string, error) { | |
97 serialized, err := entry.Bytes() | |
98 if err != nil { | |
99 return "", err | |
100 } | |
101 str := string(serialized) | |
102 return str, nil | |
103 } | |
104 | |
105 // Add an error as single field (using the key defined in ErrorKey) to the Entry. | |
106 func (entry *Entry) WithError(err error) *Entry { | |
107 return entry.WithField(ErrorKey, err) | |
108 } | |
109 | |
110 // Add a context to the Entry. | |
111 func (entry *Entry) WithContext(ctx context.Context) *Entry { | |
112 dataCopy := make(Fields, len(entry.Data)) | |
113 for k, v := range entry.Data { | |
114 dataCopy[k] = v | |
115 } | |
116 return &Entry{Logger: entry.Logger, Data: dataCopy, Time: entry.Time, err: entry.err, Context: ctx} | |
117 } | |
118 | |
119 // Add a single field to the Entry. | |
120 func (entry *Entry) WithField(key string, value interface{}) *Entry { | |
121 return entry.WithFields(Fields{key: value}) | |
122 } | |
123 | |
124 // Add a map of fields to the Entry. | |
125 func (entry *Entry) WithFields(fields Fields) *Entry { | |
126 data := make(Fields, len(entry.Data)+len(fields)) | |
127 for k, v := range entry.Data { | |
128 data[k] = v | |
129 } | |
130 fieldErr := entry.err | |
131 for k, v := range fields { | |
132 isErrField := false | |
133 if t := reflect.TypeOf(v); t != nil { | |
134 switch { | |
135 case t.Kind() == reflect.Func, t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Func: | |
136 isErrField = true | |
137 } | |
138 } | |
139 if isErrField { | |
140 tmp := fmt.Sprintf("can not add field %q", k) | |
141 if fieldErr != "" { | |
142 fieldErr = entry.err + ", " + tmp | |
143 } else { | |
144 fieldErr = tmp | |
145 } | |
146 } else { | |
147 data[k] = v | |
148 } | |
149 } | |
150 return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time, err: fieldErr, Context: entry.Context} | |
151 } | |
152 | |
153 // Overrides the time of the Entry. | |
154 func (entry *Entry) WithTime(t time.Time) *Entry { | |
155 dataCopy := make(Fields, len(entry.Data)) | |
156 for k, v := range entry.Data { | |
157 dataCopy[k] = v | |
158 } | |
159 return &Entry{Logger: entry.Logger, Data: dataCopy, Time: t, err: entry.err, Context: entry.Context} | |
160 } | |
161 | |
162 // getPackageName reduces a fully qualified function name to the package name | |
163 // There really ought to be to be a better way... | |
164 func getPackageName(f string) string { | |
165 for { | |
166 lastPeriod := strings.LastIndex(f, ".") | |
167 lastSlash := strings.LastIndex(f, "/") | |
168 if lastPeriod > lastSlash { | |
169 f = f[:lastPeriod] | |
170 } else { | |
171 break | |
172 } | |
173 } | |
174 | |
175 return f | |
176 } | |
177 | |
178 // getCaller retrieves the name of the first non-logrus calling function | |
179 func getCaller() *runtime.Frame { | |
180 // cache this package's fully-qualified name | |
181 callerInitOnce.Do(func() { | |
182 pcs := make([]uintptr, maximumCallerDepth) | |
183 _ = runtime.Callers(0, pcs) | |
184 | |
185 // dynamic get the package name and the minimum caller depth | |
186 for i := 0; i < maximumCallerDepth; i++ { | |
187 funcName := runtime.FuncForPC(pcs[i]).Name() | |
188 if strings.Contains(funcName, "getCaller") { | |
189 logrusPackage = getPackageName(funcName) | |
190 break | |
191 } | |
192 } | |
193 | |
194 minimumCallerDepth = knownLogrusFrames | |
195 }) | |
196 | |
197 // Restrict the lookback frames to avoid runaway lookups | |
198 pcs := make([]uintptr, maximumCallerDepth) | |
199 depth := runtime.Callers(minimumCallerDepth, pcs) | |
200 frames := runtime.CallersFrames(pcs[:depth]) | |
201 | |
202 for f, again := frames.Next(); again; f, again = frames.Next() { | |
203 pkg := getPackageName(f.Function) | |
204 | |
205 // If the caller isn't part of this package, we're done | |
206 if pkg != logrusPackage { | |
207 return &f //nolint:scopelint | |
208 } | |
209 } | |
210 | |
211 // if we got here, we failed to find the caller's context | |
212 return nil | |
213 } | |
214 | |
215 func (entry Entry) HasCaller() (has bool) { | |
216 return entry.Logger != nil && | |
217 entry.Logger.ReportCaller && | |
218 entry.Caller != nil | |
219 } | |
220 | |
221 func (entry *Entry) log(level Level, msg string) { | |
222 var buffer *bytes.Buffer | |
223 | |
224 newEntry := entry.Dup() | |
225 | |
226 if newEntry.Time.IsZero() { | |
227 newEntry.Time = time.Now() | |
228 } | |
229 | |
230 newEntry.Level = level | |
231 newEntry.Message = msg | |
232 | |
233 newEntry.Logger.mu.Lock() | |
234 reportCaller := newEntry.Logger.ReportCaller | |
235 bufPool := newEntry.getBufferPool() | |
236 newEntry.Logger.mu.Unlock() | |
237 | |
238 if reportCaller { | |
239 newEntry.Caller = getCaller() | |
240 } | |
241 | |
242 newEntry.fireHooks() | |
243 buffer = bufPool.Get() | |
244 defer func() { | |
245 newEntry.Buffer = nil | |
246 buffer.Reset() | |
247 bufPool.Put(buffer) | |
248 }() | |
249 buffer.Reset() | |
250 newEntry.Buffer = buffer | |
251 | |
252 newEntry.write() | |
253 | |
254 newEntry.Buffer = nil | |
255 | |
256 // To avoid Entry#log() returning a value that only would make sense for | |
257 // panic() to use in Entry#Panic(), we avoid the allocation by checking | |
258 // directly here. | |
259 if level <= PanicLevel { | |
260 panic(newEntry) | |
261 } | |
262 } | |
263 | |
264 func (entry *Entry) getBufferPool() (pool BufferPool) { | |
265 if entry.Logger.BufferPool != nil { | |
266 return entry.Logger.BufferPool | |
267 } | |
268 return bufferPool | |
269 } | |
270 | |
271 func (entry *Entry) fireHooks() { | |
272 var tmpHooks LevelHooks | |
273 entry.Logger.mu.Lock() | |
274 tmpHooks = make(LevelHooks, len(entry.Logger.Hooks)) | |
275 for k, v := range entry.Logger.Hooks { | |
276 tmpHooks[k] = v | |
277 } | |
278 entry.Logger.mu.Unlock() | |
279 | |
280 err := tmpHooks.Fire(entry.Level, entry) | |
281 if err != nil { | |
282 fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err) | |
283 } | |
284 } | |
285 | |
286 func (entry *Entry) write() { | |
287 entry.Logger.mu.Lock() | |
288 defer entry.Logger.mu.Unlock() | |
289 serialized, err := entry.Logger.Formatter.Format(entry) | |
290 if err != nil { | |
291 fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err) | |
292 return | |
293 } | |
294 if _, err := entry.Logger.Out.Write(serialized); err != nil { | |
295 fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err) | |
296 } | |
297 } | |
298 | |
299 // Log will log a message at the level given as parameter. | |
300 // Warning: using Log at Panic or Fatal level will not respectively Panic nor Exit. | |
301 // For this behaviour Entry.Panic or Entry.Fatal should be used instead. | |
302 func (entry *Entry) Log(level Level, args ...interface{}) { | |
303 if entry.Logger.IsLevelEnabled(level) { | |
304 entry.log(level, fmt.Sprint(args...)) | |
305 } | |
306 } | |
307 | |
308 func (entry *Entry) Trace(args ...interface{}) { | |
309 entry.Log(TraceLevel, args...) | |
310 } | |
311 | |
312 func (entry *Entry) Debug(args ...interface{}) { | |
313 entry.Log(DebugLevel, args...) | |
314 } | |
315 | |
316 func (entry *Entry) Print(args ...interface{}) { | |
317 entry.Info(args...) | |
318 } | |
319 | |
320 func (entry *Entry) Info(args ...interface{}) { | |
321 entry.Log(InfoLevel, args...) | |
322 } | |
323 | |
324 func (entry *Entry) Warn(args ...interface{}) { | |
325 entry.Log(WarnLevel, args...) | |
326 } | |
327 | |
328 func (entry *Entry) Warning(args ...interface{}) { | |
329 entry.Warn(args...) | |
330 } | |
331 | |
332 func (entry *Entry) Error(args ...interface{}) { | |
333 entry.Log(ErrorLevel, args...) | |
334 } | |
335 | |
336 func (entry *Entry) Fatal(args ...interface{}) { | |
337 entry.Log(FatalLevel, args...) | |
338 entry.Logger.Exit(1) | |
339 } | |
340 | |
341 func (entry *Entry) Panic(args ...interface{}) { | |
342 entry.Log(PanicLevel, args...) | |
343 } | |
344 | |
345 // Entry Printf family functions | |
346 | |
347 func (entry *Entry) Logf(level Level, format string, args ...interface{}) { | |
348 if entry.Logger.IsLevelEnabled(level) { | |
349 entry.Log(level, fmt.Sprintf(format, args...)) | |
350 } | |
351 } | |
352 | |
353 func (entry *Entry) Tracef(format string, args ...interface{}) { | |
354 entry.Logf(TraceLevel, format, args...) | |
355 } | |
356 | |
357 func (entry *Entry) Debugf(format string, args ...interface{}) { | |
358 entry.Logf(DebugLevel, format, args...) | |
359 } | |
360 | |
361 func (entry *Entry) Infof(format string, args ...interface{}) { | |
362 entry.Logf(InfoLevel, format, args...) | |
363 } | |
364 | |
365 func (entry *Entry) Printf(format string, args ...interface{}) { | |
366 entry.Infof(format, args...) | |
367 } | |
368 | |
369 func (entry *Entry) Warnf(format string, args ...interface{}) { | |
370 entry.Logf(WarnLevel, format, args...) | |
371 } | |
372 | |
373 func (entry *Entry) Warningf(format string, args ...interface{}) { | |
374 entry.Warnf(format, args...) | |
375 } | |
376 | |
377 func (entry *Entry) Errorf(format string, args ...interface{}) { | |
378 entry.Logf(ErrorLevel, format, args...) | |
379 } | |
380 | |
381 func (entry *Entry) Fatalf(format string, args ...interface{}) { | |
382 entry.Logf(FatalLevel, format, args...) | |
383 entry.Logger.Exit(1) | |
384 } | |
385 | |
386 func (entry *Entry) Panicf(format string, args ...interface{}) { | |
387 entry.Logf(PanicLevel, format, args...) | |
388 } | |
389 | |
390 // Entry Println family functions | |
391 | |
392 func (entry *Entry) Logln(level Level, args ...interface{}) { | |
393 if entry.Logger.IsLevelEnabled(level) { | |
394 entry.Log(level, entry.sprintlnn(args...)) | |
395 } | |
396 } | |
397 | |
398 func (entry *Entry) Traceln(args ...interface{}) { | |
399 entry.Logln(TraceLevel, args...) | |
400 } | |
401 | |
402 func (entry *Entry) Debugln(args ...interface{}) { | |
403 entry.Logln(DebugLevel, args...) | |
404 } | |
405 | |
406 func (entry *Entry) Infoln(args ...interface{}) { | |
407 entry.Logln(InfoLevel, args...) | |
408 } | |
409 | |
410 func (entry *Entry) Println(args ...interface{}) { | |
411 entry.Infoln(args...) | |
412 } | |
413 | |
414 func (entry *Entry) Warnln(args ...interface{}) { | |
415 entry.Logln(WarnLevel, args...) | |
416 } | |
417 | |
418 func (entry *Entry) Warningln(args ...interface{}) { | |
419 entry.Warnln(args...) | |
420 } | |
421 | |
422 func (entry *Entry) Errorln(args ...interface{}) { | |
423 entry.Logln(ErrorLevel, args...) | |
424 } | |
425 | |
426 func (entry *Entry) Fatalln(args ...interface{}) { | |
427 entry.Logln(FatalLevel, args...) | |
428 entry.Logger.Exit(1) | |
429 } | |
430 | |
431 func (entry *Entry) Panicln(args ...interface{}) { | |
432 entry.Logln(PanicLevel, args...) | |
433 } | |
434 | |
435 // Sprintlnn => Sprint no newline. This is to get the behavior of how | |
436 // fmt.Sprintln where spaces are always added between operands, regardless of | |
437 // their type. Instead of vendoring the Sprintln implementation to spare a | |
438 // string allocation, we do the simplest thing. | |
439 func (entry *Entry) sprintlnn(args ...interface{}) string { | |
440 msg := fmt.Sprintln(args...) | |
441 return msg[:len(msg)-1] | |
442 } |