gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

entry.go (11125B)


      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 }