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) c.l.context = json.AppendInterface(json.AppendKey(c.l.context, key), i)
return c 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" "fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"runtime"
"strconv"
"sync" "sync"
"time" "time"
@ -561,3 +563,20 @@ func (e *Event) Interface(key string, i interface{}) *Event {
e.buf = json.AppendInterface(json.AppendKey(e.buf, key), i) e.buf = json.AppendInterface(json.AppendKey(e.buf, key), i)
return e 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 is the field name used for error fields.
ErrorFieldName = "error" ErrorFieldName = "error"
// CallerFieldName is the field name used for caller field.
CallerFieldName = "caller"
// TimeFieldFormat defines the time format of the Time field type. // TimeFieldFormat defines the time format of the Time field type.
// If set to an empty string, the time is formatted as an UNIX timestamp // If set to an empty string, the time is formatted as an UNIX timestamp
// as integer. // as integer.

View File

@ -3,7 +3,9 @@ package zerolog
import ( import (
"bytes" "bytes"
"errors" "errors"
"fmt"
"reflect" "reflect"
"runtime"
"testing" "testing"
"time" "time"
) )
@ -74,7 +76,7 @@ func TestInfo(t *testing.T) {
func TestWith(t *testing.T) { func TestWith(t *testing.T) {
out := &bytes.Buffer{} out := &bytes.Buffer{}
log := New(out).With(). ctx := New(out).With().
Str("foo", "bar"). Str("foo", "bar").
AnErr("some_err", nil). AnErr("some_err", nil).
Err(errors.New("some error")). Err(errors.New("some error")).
@ -91,10 +93,12 @@ func TestWith(t *testing.T) {
Uint64("uint64", 10). Uint64("uint64", 10).
Float32("float32", 11). Float32("float32", 11).
Float64("float64", 12). Float64("float64", 12).
Time("time", time.Time{}). Time("time", time.Time{})
Logger() _, file, line, _ := runtime.Caller(0)
caller := fmt.Sprintf("%s:%d", file, line+3)
log := ctx.Caller().Logger()
log.Log().Msg("") 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) t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
} }
} }
@ -132,7 +136,10 @@ func TestFields(t *testing.T) {
out := &bytes.Buffer{} out := &bytes.Buffer{}
log := New(out) log := New(out)
now := time.Now() now := time.Now()
_, file, line, _ := runtime.Caller(0)
caller := fmt.Sprintf("%s:%d", file, line+3)
log.Log(). log.Log().
Caller().
Str("string", "foo"). Str("string", "foo").
Bytes("bytes", []byte("bar")). Bytes("bytes", []byte("bar")).
AnErr("some_err", nil). AnErr("some_err", nil).
@ -154,7 +161,7 @@ func TestFields(t *testing.T) {
Time("time", time.Time{}). Time("time", time.Time{}).
TimeDiff("diff", now, now.Add(-10*time.Second)). TimeDiff("diff", now, now.Add(-10*time.Second)).
Msg("") 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) t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
} }
} }