diff --git a/entry.go b/entry.go index 5f40c58..cc85d3a 100644 --- a/entry.go +++ b/entry.go @@ -61,7 +61,7 @@ type Entry struct { Level Level // Calling method, with package name - Caller string + Caller *runtime.Frame // Message passed to Trace, Debug, Info, Warn, Error, Fatal or Panic Message string @@ -144,10 +144,11 @@ func getPackageName(f string) string { } // 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 pcs := make([]uintptr, maximumCallerDepth) depth := runtime.Callers(minimumCallerDepth, pcs) + frames := runtime.CallersFrames(pcs[:depth]) // cache this package's fully-qualified name callerInitOnce.Do(func() { @@ -158,24 +159,23 @@ func getCaller() (method string) { minimumCallerDepth = knownLogrusFrames }) - for i := 0; i < depth; i++ { - fullFuncName := runtime.FuncForPC(pcs[i]).Name() - pkg := getPackageName(fullFuncName) + for f, again := frames.Next(); again; f, again = frames.Next() { + pkg := getPackageName(f.Function) // If the caller isn't part of this package, we're done if pkg != logrusPackage { - return fullFuncName + return &f } } // if we got here, we failed to find the caller's context - return "" + return nil } func (entry Entry) HasCaller() (has bool) { return entry.Logger != nil && entry.Logger.ReportCaller && - entry.Caller != "" + entry.Caller != nil } // This function is not declared with a pointer value because otherwise diff --git a/json_formatter.go b/json_formatter.go index bdb569e..f5d45bb 100644 --- a/json_formatter.go +++ b/json_formatter.go @@ -82,7 +82,7 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) { data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String() if entry.HasCaller() { - data[f.FieldMap.resolve(FieldKeyFunc)] = entry.Caller + data[f.FieldMap.resolve(FieldKeyFunc)] = entry.Caller.Function } var b *bytes.Buffer diff --git a/json_formatter_test.go b/json_formatter_test.go index 13fbf31..695c36e 100644 --- a/json_formatter_test.go +++ b/json_formatter_test.go @@ -4,6 +4,7 @@ import ( "encoding/json" "errors" "fmt" + "runtime" "strings" "testing" ) @@ -167,8 +168,8 @@ func TestFieldsInNestedDictionary(t *testing.T) { } logEntry := WithFields(Fields{ - "level": "level", - "test": "test", + "level": "level", + "test": "test", }) logEntry.Level = InfoLevel @@ -291,7 +292,7 @@ func TestFieldClashWithCaller(t *testing.T) { SetReportCaller(true) formatter := &JSONFormatter{} e := WithField("func", "howdy pardner") - e.Caller = "somefunc" + e.Caller = &runtime.Frame{Function: "somefunc"} b, err := formatter.Format(e) if err != nil { t.Fatal("Unable to format entry: ", err) diff --git a/text_formatter.go b/text_formatter.go index 409edc0..354387c 100644 --- a/text_formatter.go +++ b/text_formatter.go @@ -208,7 +208,7 @@ func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []strin caller := "" if entry.HasCaller() { - caller = fmt.Sprintf(" %s()", entry.Caller) + caller = fmt.Sprintf(" %s()", entry.Caller.Function) } if f.DisableTimestamp {