Skip to content

Commit

Permalink
Removes hard dependency on logrus for logging
Browse files Browse the repository at this point in the history
Provides backwards compatibility with existing logrus via SetLogger() method

Introduces a Logger interface that others can implement for other
structured loggers such as zerolog.

Add SetLoggerFromLogger method that allows caller to pass in an implementation
of the new Logger interface.

Bumps the golang.org/x/sys dependency since tests fail to run on go 1.18 with the old version.

adding a test case for LogrusLogger

adding benchmark, add WithFields method because it's a lot faster apparently
  • Loading branch information
nathanejohnson committed Jun 2, 2022
1 parent 87609ae commit 8c6aae6
Show file tree
Hide file tree
Showing 5 changed files with 191 additions and 8 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ require (
github.com/golang/protobuf v1.3.1
github.com/segmentio/fasthash v1.0.3
github.com/sirupsen/logrus v1.6.0
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
)

go 1.15
6 changes: 4 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJ
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/segmentio/fasthash v1.0.3 h1:EI9+KE1EwvMLBWwjpRDc+fEM+prwxDYbslddQGtrmhM=
github.com/segmentio/fasthash v1.0.3/go.mod h1:waKX8l2N8yckOgmSsXJi7x1ZfdKZ4x7KRMzBtS3oedY=
github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
github.com/segmentio/fasthash v1.0.3 h1:EI9+KE1EwvMLBWwjpRDc+fEM+prwxDYbslddQGtrmhM=
github.com/segmentio/fasthash v1.0.3/go.mod h1:waKX8l2N8yckOgmSsXJi7x1ZfdKZ4x7KRMzBtS3oedY=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
19 changes: 13 additions & 6 deletions groupcache.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,15 @@ import (
"github.com/sirupsen/logrus"
)

var logger *logrus.Entry
var logger Logger

// SetLogger - this is legacy to provide backwards compatibility with logrus.
func SetLogger(log *logrus.Entry) {
logger = LogrusLogger{Entry: log}
}

// SetLoggerFromLogger - set the logger to an implementation of the Logger interface
func SetLoggerFromLogger(log Logger) {
logger = log
}

Expand Down Expand Up @@ -392,11 +398,12 @@ func (g *Group) load(ctx context.Context, key string, dest Sink) (value ByteView
}

if logger != nil {
logger.WithFields(logrus.Fields{
"err": err,
"key": key,
"category": "groupcache",
}).Errorf("error retrieving key from peer '%s'", peer.GetURL())
logger.Error().
WithFields(map[string]interface{}{
"err": err,
"key": key,
"category": "groupcache",
}).Printf("error retrieving key from peer '%s'", peer.GetURL())
}

g.Stats.PeerErrors.Add(1)
Expand Down
96 changes: 96 additions & 0 deletions logger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package groupcache

import (
"github.com/sirupsen/logrus"
)

// Logger is a minimal interface that will allow us to use structured loggers,
// including (but not limited to) logrus.
type Logger interface {
// Error logging level
Error() Logger

// Warn logging level
Warn() Logger

// Info logging level
Info() Logger

// Debug logging level
Debug() Logger

// ErrorField is a field with an error value
ErrorField(label string, err error) Logger

// StringField is a field with a string value
StringField(label string, val string) Logger

// WithFields is willy-nilly key value pairs.
WithFields(fields map[string]interface{}) Logger

// Printf is called last to emit the log at the given
// level.
Printf(format string, args ...interface{})
}

// LogrusLogger is an implementation of Logger that wraps logrus... who knew?
type LogrusLogger struct {
Entry *logrus.Entry
level logrus.Level
}

func (l LogrusLogger) Info() Logger {
return LogrusLogger{
Entry: l.Entry,
level: logrus.InfoLevel,
}
}

func (l LogrusLogger) Debug() Logger {
return LogrusLogger{
Entry: l.Entry,
level: logrus.DebugLevel,
}
}

func (l LogrusLogger) Warn() Logger {
return LogrusLogger{
Entry: l.Entry,
level: logrus.WarnLevel,
}
}

func (l LogrusLogger) Error() Logger {
return LogrusLogger{
Entry: l.Entry,
level: logrus.ErrorLevel,
}
}

func (l LogrusLogger) WithFields(fields map[string]interface{}) Logger {
return LogrusLogger{
Entry: l.Entry.WithFields(fields),
level: l.level,
}
}

// ErrorField - create a field for an error
func (l LogrusLogger) ErrorField(label string, err error) Logger {
return LogrusLogger{
Entry: l.Entry.WithField(label, err),
level: l.level,
}

}

// StringField - create a field for a string.
func (l LogrusLogger) StringField(label string, val string) Logger {
return LogrusLogger{
Entry: l.Entry.WithField(label, val),
level: l.level,
}
}

func (l LogrusLogger) Printf(format string, args ...interface{}) {
l.Entry.Logf(l.level, format, args...)
}
77 changes: 77 additions & 0 deletions logger_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package groupcache

import (
"bytes"
"errors"
"github.com/sirupsen/logrus"
"testing"
)

// This tests the compatibility of the LogrusLogger with the previous behavior.
func TestLogrusLogger(t *testing.T) {
var buf bytes.Buffer
l := logrus.New()
l.SetFormatter(&logrus.TextFormatter{
DisableTimestamp: true,
})
l.Out = &buf
e := logrus.NewEntry(l)
e = e.WithField("ContextKey", "ContextVal")
SetLogger(e)
logger.Error().
WithFields(map[string]interface{}{
"err": errors.New("test error"),
"key": "keyValue",
"category": "groupcache",
}).Printf("error retrieving key from peer %s", "http://127.0.0.1:8080")

interfaceOut := buf.String()
buf.Reset()
e.WithFields(logrus.Fields{
"err": errors.New("test error"),
"key": "keyValue",
"category": "groupcache",
}).Errorf("error retrieving key from peer %s", "http://127.0.0.1:8080")
logrusOut := buf.String()
if interfaceOut != logrusOut {
t.Errorf("output is not the same.\ngot:\n%s\nwant:\n%s", interfaceOut, logrusOut)
}
}

func BenchmarkLogrusLogger(b *testing.B) {
var buf bytes.Buffer
l := logrus.New()
l.SetFormatter(&logrus.TextFormatter{
DisableTimestamp: true,
})
l.Out = &buf
e := logrus.NewEntry(l)
SetLogger(e)
for i := 0; i < b.N; i++ {
logger.Error().
WithFields(map[string]interface{}{
"err": errors.New("test error"),
"key": "keyValue",
"category": "groupcache",
}).Printf("error retrieving key from peer %s", "http://127.0.0.1:8080")
buf.Reset()
}
}

func BenchmarkLogrus(b *testing.B) {
var buf bytes.Buffer
l := logrus.New()
l.SetFormatter(&logrus.TextFormatter{
DisableTimestamp: true,
})
l.Out = &buf
e := logrus.NewEntry(l)
for i := 0; i < b.N; i++ {
e.WithFields(logrus.Fields{
"err": errors.New("test error"),
"key": "keyValue",
"category": "groupcache",
}).Errorf("error retrieving key from peer %s", "http://127.0.0.1:8080")
buf.Reset()
}
}

0 comments on commit 8c6aae6

Please sign in to comment.