diff options
Diffstat (limited to 'vendor/github.com/mattermost/logr/logrec.go')
-rw-r--r-- | vendor/github.com/mattermost/logr/logrec.go | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/vendor/github.com/mattermost/logr/logrec.go b/vendor/github.com/mattermost/logr/logrec.go new file mode 100644 index 00000000..9428aaec --- /dev/null +++ b/vendor/github.com/mattermost/logr/logrec.go @@ -0,0 +1,189 @@ +package logr + +import ( + "fmt" + "runtime" + "strings" + "sync" + "time" +) + +var ( + logrPkg string +) + +func init() { + // Calc current package name + pcs := make([]uintptr, 2) + _ = runtime.Callers(0, pcs) + tmp := runtime.FuncForPC(pcs[1]).Name() + logrPkg = getPackageName(tmp) +} + +// LogRec collects raw, unformatted data to be logged. +// TODO: pool these? how to reliably know when targets are done with them? Copy for each target? +type LogRec struct { + mux sync.RWMutex + time time.Time + + level Level + logger Logger + + template string + newline bool + args []interface{} + + stackPC []uintptr + stackCount int + + // flushes Logr and target queues when not nil. + flush chan struct{} + + // remaining fields calculated by `prep` + msg string + frames []runtime.Frame +} + +// NewLogRec creates a new LogRec with the current time and optional stack trace. +func NewLogRec(lvl Level, logger Logger, template string, args []interface{}, incStacktrace bool) *LogRec { + rec := &LogRec{time: time.Now(), logger: logger, level: lvl, template: template, args: args} + if incStacktrace { + rec.stackPC = make([]uintptr, DefaultMaxStackFrames) + rec.stackCount = runtime.Callers(2, rec.stackPC) + } + return rec +} + +// newFlushLogRec creates a LogRec that flushes the Logr queue and +// any target queues that support flushing. +func newFlushLogRec(logger Logger) *LogRec { + return &LogRec{logger: logger, flush: make(chan struct{})} +} + +// prep resolves all args and field values to strings, and +// resolves stack trace to frames. +func (rec *LogRec) prep() { + rec.mux.Lock() + defer rec.mux.Unlock() + + // resolve args + if rec.template == "" { + if rec.newline { + rec.msg = fmt.Sprintln(rec.args...) + } else { + rec.msg = fmt.Sprint(rec.args...) + } + } else { + rec.msg = fmt.Sprintf(rec.template, rec.args...) + } + + // resolve stack trace + if rec.stackCount > 0 { + frames := runtime.CallersFrames(rec.stackPC[:rec.stackCount]) + for { + f, more := frames.Next() + rec.frames = append(rec.frames, f) + if !more { + break + } + } + + // remove leading logr package entries. + var start int + for i, frame := range rec.frames { + pkg := getPackageName(frame.Function) + if pkg != "" && pkg != logrPkg { + start = i + break + } + } + rec.frames = rec.frames[start:] + } +} + +// WithTime returns a shallow copy of the log record while replacing +// the time. This can be used by targets and formatters to adjust +// the time, or take ownership of the log record. +func (rec *LogRec) WithTime(time time.Time) *LogRec { + rec.mux.RLock() + defer rec.mux.RUnlock() + + return &LogRec{ + time: time, + level: rec.level, + logger: rec.logger, + template: rec.template, + newline: rec.newline, + args: rec.args, + msg: rec.msg, + stackPC: rec.stackPC, + stackCount: rec.stackCount, + frames: rec.frames, + } +} + +// Logger returns the `Logger` that created this `LogRec`. +func (rec *LogRec) Logger() Logger { + return rec.logger +} + +// Time returns this log record's time stamp. +func (rec *LogRec) Time() time.Time { + // no locking needed as this field is not mutated. + return rec.time +} + +// Level returns this log record's Level. +func (rec *LogRec) Level() Level { + // no locking needed as this field is not mutated. + return rec.level +} + +// Fields returns this log record's Fields. +func (rec *LogRec) Fields() Fields { + // no locking needed as this field is not mutated. + return rec.logger.fields +} + +// Msg returns this log record's message text. +func (rec *LogRec) Msg() string { + rec.mux.RLock() + defer rec.mux.RUnlock() + return rec.msg +} + +// StackFrames returns this log record's stack frames or +// nil if no stack trace was required. +func (rec *LogRec) StackFrames() []runtime.Frame { + rec.mux.RLock() + defer rec.mux.RUnlock() + return rec.frames +} + +// String returns a string representation of this log record. +func (rec *LogRec) String() string { + if rec.flush != nil { + return "[flusher]" + } + + f := &DefaultFormatter{} + buf := rec.logger.logr.BorrowBuffer() + defer rec.logger.logr.ReleaseBuffer(buf) + buf, _ = f.Format(rec, true, buf) + return strings.TrimSpace(buf.String()) +} + +// getPackageName reduces a fully qualified function name to the package name +// By sirupsen: https://github.com/sirupsen/logrus/blob/master/entry.go +func getPackageName(f string) string { + for { + lastPeriod := strings.LastIndex(f, ".") + lastSlash := strings.LastIndex(f, "/") + if lastPeriod > lastSlash { + f = f[:lastPeriod] + } else { + break + } + } + return f +} |