Removes hard dependency on logrus for logging

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
This commit is contained in:
Nathan Johnson 2022-06-01 14:35:07 -05:00 committed by Nathan Johnson
parent 87609ae02e
commit 8c6aae6360
5 changed files with 191 additions and 8 deletions

1
go.mod
View File

@ -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
go.sum
View File

@ -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=

View File

@ -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
}
@ -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)

96
logger.go Normal file
View File

@ -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
logger_test.go Normal file
View File

@ -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()
}
}