diff --git a/event.go b/event.go index d9462b0..2707bd5 100644 --- a/event.go +++ b/event.go @@ -5,7 +5,6 @@ import ( "net" "os" "runtime" - "strconv" "sync" "time" ) @@ -673,7 +672,7 @@ func (e *Event) caller(skip int) *Event { if !ok { return e } - e.buf = enc.AppendString(enc.AppendKey(e.buf, CallerFieldName), file+":"+strconv.Itoa(line)) + e.buf = enc.AppendString(enc.AppendKey(e.buf, CallerFieldName), CallerMarshalFunc(file, line)) return e } diff --git a/globals.go b/globals.go index e9d3e77..3e6fc9c 100644 --- a/globals.go +++ b/globals.go @@ -1,6 +1,9 @@ package zerolog -import "time" +import ( + "strconv" + "time" +) import "sync/atomic" var ( @@ -22,6 +25,11 @@ var ( // CallerSkipFrameCount is the number of stack frames to skip to find the caller. CallerSkipFrameCount = 2 + // CallerMarshalFunc allows customization of global caller marshaling + CallerMarshalFunc = func(file string, line int) string { + return file+":"+strconv.Itoa(line) + } + // ErrorStackFieldName is the field name used for error stacks. ErrorStackFieldName = "stack" diff --git a/log_test.go b/log_test.go index 50cd1a6..a99224a 100644 --- a/log_test.go +++ b/log_test.go @@ -7,6 +7,8 @@ import ( "net" "reflect" "runtime" + "strconv" + "strings" "testing" "time" ) @@ -641,6 +643,39 @@ func TestErrorMarshalFunc(t *testing.T) { } } +func TestCallerMarshalFunc(t *testing.T) { + out := &bytes.Buffer{} + log := New(out) + + // test default behaviour this is really brittle due to the line numbers + // actually mattering for validation + _, file, line, _ := runtime.Caller(0) + caller := fmt.Sprintf("%s:%d", file, line + 2) + log.Log().Caller().Msg("msg") + if got, want := decodeIfBinaryToString(out.Bytes()), `{"caller":"` + caller + `","message":"msg"}`+"\n"; got != want { + t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want) + } + out.Reset() + + // test custom behavior. In this case we'll take just the last directory + origCallerMarshalFunc := CallerMarshalFunc + defer func() { CallerMarshalFunc = origCallerMarshalFunc }() + CallerMarshalFunc = func(file string, line int) string { + parts := strings.Split(file, "/") + if len(parts) > 1 { + return strings.Join(parts[len(parts)-2:], "/")+":"+strconv.Itoa(line) + } else { + return file+":"+strconv.Itoa(line) + } + } + _, file, line, _ = runtime.Caller(0) + caller = CallerMarshalFunc(file, line+2) + log.Log().Caller().Msg("msg") + if got, want := decodeIfBinaryToString(out.Bytes()), `{"caller":"` + caller + `","message":"msg"}`+"\n"; got != want { + t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want) + } +} + type errWriter struct { error }