Add the ability to capture the logger caller file and line number

Fixes #34, #22
This commit is contained in:
Olivier Poitrey 2018-02-07 13:54:26 -08:00
parent fcbdf23e9e
commit 27e0a22cbc
4 changed files with 48 additions and 5 deletions

View File

@ -302,3 +302,17 @@ func (c Context) Interface(key string, i interface{}) Context {
c.l.context = json.AppendInterface(json.AppendKey(c.l.context, key), i)
return c
}
type callerHook struct{}
func (ch callerHook) Run(e *Event, level Level, msg string) {
e.caller(4)
}
var ch = callerHook{}
// Caller adds the file:line of the caller with the zerolog.CallerFieldName key.
func (c Context) Caller() Context {
c.l = c.l.Hook(ch)
return c
}

View File

@ -4,6 +4,8 @@ import (
"fmt"
"io/ioutil"
"os"
"runtime"
"strconv"
"sync"
"time"
@ -561,3 +563,20 @@ func (e *Event) Interface(key string, i interface{}) *Event {
e.buf = json.AppendInterface(json.AppendKey(e.buf, key), i)
return e
}
// Caller adds the file:line of the caller with the zerolog.CallerFieldName key.
func (e *Event) Caller() *Event {
return e.caller(2)
}
func (e *Event) caller(skip int) *Event {
if e == nil {
return e
}
_, file, line, ok := runtime.Caller(skip)
if !ok {
return e
}
e.buf = json.AppendString(json.AppendKey(e.buf, CallerFieldName), file+":"+strconv.Itoa(line))
return e
}

View File

@ -16,6 +16,9 @@ var (
// ErrorFieldName is the field name used for error fields.
ErrorFieldName = "error"
// CallerFieldName is the field name used for caller field.
CallerFieldName = "caller"
// TimeFieldFormat defines the time format of the Time field type.
// If set to an empty string, the time is formatted as an UNIX timestamp
// as integer.

View File

@ -3,7 +3,9 @@ package zerolog
import (
"bytes"
"errors"
"fmt"
"reflect"
"runtime"
"testing"
"time"
)
@ -74,7 +76,7 @@ func TestInfo(t *testing.T) {
func TestWith(t *testing.T) {
out := &bytes.Buffer{}
log := New(out).With().
ctx := New(out).With().
Str("foo", "bar").
AnErr("some_err", nil).
Err(errors.New("some error")).
@ -91,10 +93,12 @@ func TestWith(t *testing.T) {
Uint64("uint64", 10).
Float32("float32", 11).
Float64("float64", 12).
Time("time", time.Time{}).
Logger()
Time("time", time.Time{})
_, file, line, _ := runtime.Caller(0)
caller := fmt.Sprintf("%s:%d", file, line+3)
log := ctx.Caller().Logger()
log.Log().Msg("")
if got, want := out.String(), `{"foo":"bar","error":"some error","bool":true,"int":1,"int8":2,"int16":3,"int32":4,"int64":5,"uint":6,"uint8":7,"uint16":8,"uint32":9,"uint64":10,"float32":11,"float64":12,"time":"0001-01-01T00:00:00Z"}`+"\n"; got != want {
if got, want := out.String(), `{"foo":"bar","error":"some error","bool":true,"int":1,"int8":2,"int16":3,"int32":4,"int64":5,"uint":6,"uint8":7,"uint16":8,"uint32":9,"uint64":10,"float32":11,"float64":12,"time":"0001-01-01T00:00:00Z","caller":"`+caller+`"}`+"\n"; got != want {
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
}
}
@ -132,7 +136,10 @@ func TestFields(t *testing.T) {
out := &bytes.Buffer{}
log := New(out)
now := time.Now()
_, file, line, _ := runtime.Caller(0)
caller := fmt.Sprintf("%s:%d", file, line+3)
log.Log().
Caller().
Str("string", "foo").
Bytes("bytes", []byte("bar")).
AnErr("some_err", nil).
@ -154,7 +161,7 @@ func TestFields(t *testing.T) {
Time("time", time.Time{}).
TimeDiff("diff", now, now.Add(-10*time.Second)).
Msg("")
if got, want := out.String(), `{"string":"foo","bytes":"bar","error":"some error","bool":true,"int":1,"int8":2,"int16":3,"int32":4,"int64":5,"uint":6,"uint8":7,"uint16":8,"uint32":9,"uint64":10,"float32":11,"float64":12,"dur":1000,"time":"0001-01-01T00:00:00Z","diff":10000}`+"\n"; got != want {
if got, want := out.String(), `{"caller":"`+caller+`","string":"foo","bytes":"bar","error":"some error","bool":true,"int":1,"int8":2,"int16":3,"int32":4,"int64":5,"uint":6,"uint8":7,"uint16":8,"uint32":9,"uint64":10,"float32":11,"float64":12,"dur":1000,"time":"0001-01-01T00:00:00Z","diff":10000}`+"\n"; got != want {
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
}
}