store a runtime.Frame in Entry instead of the caller function name

This commit is contained in:
David Bariod 2018-10-28 10:12:11 +01:00
parent 975c406ddb
commit ec57031db1
4 changed files with 14 additions and 13 deletions

View File

@ -61,7 +61,7 @@ type Entry struct {
Level Level Level Level
// Calling method, with package name // Calling method, with package name
Caller string Caller *runtime.Frame
// Message passed to Trace, Debug, Info, Warn, Error, Fatal or Panic // Message passed to Trace, Debug, Info, Warn, Error, Fatal or Panic
Message string Message string
@ -144,10 +144,11 @@ func getPackageName(f string) string {
} }
// getCaller retrieves the name of the first non-logrus calling function // getCaller retrieves the name of the first non-logrus calling function
func getCaller() (method string) { func getCaller() *runtime.Frame {
// Restrict the lookback frames to avoid runaway lookups // Restrict the lookback frames to avoid runaway lookups
pcs := make([]uintptr, maximumCallerDepth) pcs := make([]uintptr, maximumCallerDepth)
depth := runtime.Callers(minimumCallerDepth, pcs) depth := runtime.Callers(minimumCallerDepth, pcs)
frames := runtime.CallersFrames(pcs[:depth])
// cache this package's fully-qualified name // cache this package's fully-qualified name
callerInitOnce.Do(func() { callerInitOnce.Do(func() {
@ -158,24 +159,23 @@ func getCaller() (method string) {
minimumCallerDepth = knownLogrusFrames minimumCallerDepth = knownLogrusFrames
}) })
for i := 0; i < depth; i++ { for f, again := frames.Next(); again; f, again = frames.Next() {
fullFuncName := runtime.FuncForPC(pcs[i]).Name() pkg := getPackageName(f.Function)
pkg := getPackageName(fullFuncName)
// If the caller isn't part of this package, we're done // If the caller isn't part of this package, we're done
if pkg != logrusPackage { if pkg != logrusPackage {
return fullFuncName return &f
} }
} }
// if we got here, we failed to find the caller's context // if we got here, we failed to find the caller's context
return "" return nil
} }
func (entry Entry) HasCaller() (has bool) { func (entry Entry) HasCaller() (has bool) {
return entry.Logger != nil && return entry.Logger != nil &&
entry.Logger.ReportCaller && entry.Logger.ReportCaller &&
entry.Caller != "" entry.Caller != nil
} }
// This function is not declared with a pointer value because otherwise // This function is not declared with a pointer value because otherwise

View File

@ -82,7 +82,7 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message
data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String() data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String()
if entry.HasCaller() { if entry.HasCaller() {
data[f.FieldMap.resolve(FieldKeyFunc)] = entry.Caller data[f.FieldMap.resolve(FieldKeyFunc)] = entry.Caller.Function
} }
var b *bytes.Buffer var b *bytes.Buffer

View File

@ -4,6 +4,7 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"runtime"
"strings" "strings"
"testing" "testing"
) )
@ -167,8 +168,8 @@ func TestFieldsInNestedDictionary(t *testing.T) {
} }
logEntry := WithFields(Fields{ logEntry := WithFields(Fields{
"level": "level", "level": "level",
"test": "test", "test": "test",
}) })
logEntry.Level = InfoLevel logEntry.Level = InfoLevel
@ -291,7 +292,7 @@ func TestFieldClashWithCaller(t *testing.T) {
SetReportCaller(true) SetReportCaller(true)
formatter := &JSONFormatter{} formatter := &JSONFormatter{}
e := WithField("func", "howdy pardner") e := WithField("func", "howdy pardner")
e.Caller = "somefunc" e.Caller = &runtime.Frame{Function: "somefunc"}
b, err := formatter.Format(e) b, err := formatter.Format(e)
if err != nil { if err != nil {
t.Fatal("Unable to format entry: ", err) t.Fatal("Unable to format entry: ", err)

View File

@ -208,7 +208,7 @@ func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []strin
caller := "" caller := ""
if entry.HasCaller() { if entry.HasCaller() {
caller = fmt.Sprintf(" %s()", entry.Caller) caller = fmt.Sprintf(" %s()", entry.Caller.Function)
} }
if f.DisableTimestamp { if f.DisableTimestamp {