diff --git a/entry.go b/entry.go index 9f0a5e1..ba705b5 100644 --- a/entry.go +++ b/entry.go @@ -7,9 +7,6 @@ import ( "time" ) -// assert interface compliance. -var _ Interface = (*Entry)(nil) - // Now returns the current time. var Now = time.Now @@ -32,7 +29,14 @@ func NewEntry(log *Logger) *Entry { } // WithFields returns a new entry with `fields` set. -func (e *Entry) WithFields(fields Fielder) *Entry { +func (e *Entry) WithFields(fields Fielder) Interface { + return e.withFields(fields) +} + +// withFields returns a new entry with `fields` set. +// but to satify the interface WithFields casts *Entry +// back into `Interface` +func (e *Entry) withFields(fields Fielder) *Entry { f := []Fields{} f = append(f, e.fields...) f = append(f, fields.Fields()) @@ -43,7 +47,7 @@ func (e *Entry) WithFields(fields Fielder) *Entry { } // WithField returns a new entry with the `key` and `value` set. -func (e *Entry) WithField(key string, value interface{}) *Entry { +func (e *Entry) WithField(key string, value interface{}) Interface { return e.WithFields(Fields{key: value}) } @@ -51,7 +55,7 @@ func (e *Entry) WithField(key string, value interface{}) *Entry { // // The given error may implement .Fielder, if it does the method // will add all its `.Fields()` into the returned entry. -func (e *Entry) WithError(err error) *Entry { +func (e *Entry) WithError(err error) Interface { ctx := e.WithField("error", err.Error()) if s, ok := err.(stackTracer); ok { @@ -129,9 +133,9 @@ func (e *Entry) Fatalf(msg string, v ...interface{}) { // Trace returns a new entry with a Stop method to fire off // a corresponding completion log, useful with defer. -func (e *Entry) Trace(msg string) *Entry { +func (e *Entry) Trace(msg string) Interface { e.Info(msg) - v := e.WithFields(e.Fields) + v := e.withFields(e.Fields) v.Message = msg v.start = time.Now() return v diff --git a/entry_test.go b/entry_test.go index 328106b..a850a38 100644 --- a/entry_test.go +++ b/entry_test.go @@ -13,9 +13,9 @@ func TestEntry_WithFields(t *testing.T) { b := a.WithFields(Fields{"foo": "bar"}) assert.Equal(t, Fields{}, a.mergedFields()) - assert.Equal(t, Fields{"foo": "bar"}, b.mergedFields()) + assert.Equal(t, Fields{"foo": "bar"}, b.(*Entry).mergedFields()) - c := a.WithFields(Fields{"foo": "hello", "bar": "world"}) + c := a.WithFields(Fields{"foo": "hello", "bar": "world"}).(*Entry) e := c.finalize(InfoLevel, "upload") assert.Equal(t, e.Message, "upload") @@ -28,19 +28,19 @@ func TestEntry_WithField(t *testing.T) { a := NewEntry(nil) b := a.WithField("foo", "bar") assert.Equal(t, Fields{}, a.mergedFields()) - assert.Equal(t, Fields{"foo": "bar"}, b.mergedFields()) + assert.Equal(t, Fields{"foo": "bar"}, b.(*Entry).mergedFields()) } func TestEntry_WithError(t *testing.T) { a := NewEntry(nil) b := a.WithError(fmt.Errorf("boom")) assert.Equal(t, Fields{}, a.mergedFields()) - assert.Equal(t, Fields{"error": "boom"}, b.mergedFields()) + assert.Equal(t, Fields{"error": "boom"}, b.(*Entry).mergedFields()) } func TestEntry_WithErrorFields(t *testing.T) { a := NewEntry(nil) - b := a.WithError(errFields("boom")) + b := a.WithError(errFields("boom")).(*Entry) assert.Equal(t, Fields{}, a.mergedFields()) assert.Equal(t, Fields{ "error": "boom", diff --git a/interface.go b/interface.go index c92ebea..689dd47 100644 --- a/interface.go +++ b/interface.go @@ -1,10 +1,18 @@ package log +// Fields represents a map of entry level data used for structured logging. +type Fields map[string]interface{} + +// Fielder is an interface for providing fields to custom types. +type Fielder interface { + Fields() Fields +} + // Interface represents the API of both Logger and Entry. type Interface interface { - WithFields(fields Fielder) *Entry - WithField(key string, value interface{}) *Entry - WithError(err error) *Entry + WithFields(fields Fielder) Interface + WithField(key string, value interface{}) Interface + WithError(err error) Interface Debug(msg string) Info(msg string) Warn(msg string) @@ -15,5 +23,5 @@ type Interface interface { Warnf(msg string, v ...interface{}) Errorf(msg string, v ...interface{}) Fatalf(msg string, v ...interface{}) - Trace(msg string) *Entry + Trace(msg string) Interface } diff --git a/logger.go b/logger.go index 1755747..c0cf7b3 100644 --- a/logger.go +++ b/logger.go @@ -5,16 +5,7 @@ import ( "sort" ) -// assert interface compliance. -var _ Interface = (*Logger)(nil) - -// Fielder is an interface for providing fields to custom types. -type Fielder interface { - Fields() Fields -} - -// Fields represents a map of entry level data used for structured logging. -type Fields map[string]interface{} +// note: Fields is defined in `interface.go` // Fields implements Fielder. func (f Fields) Fields() Fields { @@ -62,7 +53,7 @@ type Logger struct { } // WithFields returns a new entry with `fields` set. -func (l *Logger) WithFields(fields Fielder) *Entry { +func (l *Logger) WithFields(fields Fielder) Interface { return NewEntry(l).WithFields(fields.Fields()) } @@ -70,12 +61,12 @@ func (l *Logger) WithFields(fields Fielder) *Entry { // // Note that the `key` should not have spaces in it - use camel // case or underscores -func (l *Logger) WithField(key string, value interface{}) *Entry { +func (l *Logger) WithField(key string, value interface{}) Interface { return NewEntry(l).WithField(key, value) } // WithError returns a new entry with the "error" set to `err`. -func (l *Logger) WithError(err error) *Entry { +func (l *Logger) WithError(err error) Interface { return NewEntry(l).WithError(err) } @@ -131,7 +122,7 @@ func (l *Logger) Fatalf(msg string, v ...interface{}) { // Trace returns a new entry with a Stop method to fire off // a corresponding completion log, useful with defer. -func (l *Logger) Trace(msg string) *Entry { +func (l *Logger) Trace(msg string) Interface { return NewEntry(l).Trace(msg) } diff --git a/logger_test.go b/logger_test.go index cd04c44..7c4813e 100644 --- a/logger_test.go +++ b/logger_test.go @@ -93,7 +93,7 @@ func TestLogger_Trace_info(t *testing.T) { } func() (err error) { - defer l.WithField("file", "sloth.png").Trace("upload").Stop(&err) + defer l.WithField("file", "sloth.png").Trace("upload").(*log.Entry).Stop(&err) return nil }() @@ -124,7 +124,7 @@ func TestLogger_Trace_error(t *testing.T) { } func() (err error) { - defer l.WithField("file", "sloth.png").Trace("upload").Stop(&err) + defer l.WithField("file", "sloth.png").Trace("upload").(*log.Entry).Stop(&err) return fmt.Errorf("boom") }() @@ -156,7 +156,7 @@ func TestLogger_Trace_nil(t *testing.T) { } func() { - defer l.WithField("file", "sloth.png").Trace("upload").Stop(nil) + defer l.WithField("file", "sloth.png").Trace("upload").(*log.Entry).Stop(nil) }() assert.Equal(t, 2, len(h.Entries)) @@ -236,13 +236,13 @@ func BenchmarkLogger_large(b *testing.B) { "size": 1 << 20, }). WithFields(log.Fields{ - "some": "more", - "data": "here", - "whatever": "blah blah", - "more": "stuff", - "context": "such useful", - "much": "fun", - }). + "some": "more", + "data": "here", + "whatever": "blah blah", + "more": "stuff", + "context": "such useful", + "much": "fun", + }). WithError(err).Error("upload failed") } } diff --git a/pkg.go b/pkg.go index 9bf51dc..1b7b813 100644 --- a/pkg.go +++ b/pkg.go @@ -29,17 +29,17 @@ func SetLevelFromString(s string) { } // WithFields returns a new entry with `fields` set. -func WithFields(fields Fielder) *Entry { +func WithFields(fields Fielder) Interface { return Log.WithFields(fields) } // WithField returns a new entry with the `key` and `value` set. -func WithField(key string, value interface{}) *Entry { +func WithField(key string, value interface{}) Interface { return Log.WithField(key, value) } // WithError returns a new entry with the "error" set to `err`. -func WithError(err error) *Entry { +func WithError(err error) Interface { return Log.WithError(err) } @@ -95,6 +95,6 @@ func Fatalf(msg string, v ...interface{}) { // Trace returns a new entry with a Stop method to fire off // a corresponding completion log, useful with defer. -func Trace(msg string) *Entry { +func Trace(msg string) Interface { return Log.Trace(msg) } diff --git a/pkg_test.go b/pkg_test.go index f233cf7..e980dd2 100644 --- a/pkg_test.go +++ b/pkg_test.go @@ -71,6 +71,6 @@ func Example_multipleFields() { // Trace can be used to simplify logging of start and completion events, // for example an upload which may fail. func Example_trace() (err error) { - defer log.Trace("upload").Stop(&err) + defer log.Trace("upload").(*log.Entry).Stop(&err) return nil }