From e40d3c63c2ac6ea4f41e5443dade3d814e319cb5 Mon Sep 17 00:00:00 2001 From: hn8 <10730886+hn8@users.noreply.github.com> Date: Sat, 31 Jul 2021 03:38:59 +0000 Subject: [PATCH 1/2] Add logr implementation Also split appendFields type switch into concrete vs interface type, and add type assert of json.RawMessage --- fields.go | 106 ++++++++++--------- go.mod | 1 + go.sum | 2 + logr/README.md | 31 ++++++ logr/benchmark_test.go | 157 ++++++++++++++++++++++++++++ logr/logr.go | 209 ++++++++++++++++++++++++++++++++++++++ logr/logr_example_test.go | 48 +++++++++ 7 files changed, 505 insertions(+), 49 deletions(-) create mode 100644 logr/README.md create mode 100644 logr/benchmark_test.go create mode 100644 logr/logr.go create mode 100644 logr/logr_example_test.go diff --git a/fields.go b/fields.go index cf3c3e91..e08f58a0 100644 --- a/fields.go +++ b/fields.go @@ -1,6 +1,7 @@ package zerolog import ( + "encoding/json" "net" "sort" "time" @@ -28,57 +29,12 @@ func appendFields(dst []byte, fields map[string]interface{}) []byte { putEvent(e) continue } + // concrete type switch: binary search of sorted typehash switch val := val.(type) { case string: dst = enc.AppendString(dst, val) case []byte: dst = enc.AppendBytes(dst, val) - case error: - switch m := ErrorMarshalFunc(val).(type) { - case LogObjectMarshaler: - e := newEvent(nil, 0) - e.buf = e.buf[:0] - e.appendObject(m) - dst = append(dst, e.buf...) - putEvent(e) - case error: - if m == nil || isNilValue(m) { - dst = enc.AppendNil(dst) - } else { - dst = enc.AppendString(dst, m.Error()) - } - case string: - dst = enc.AppendString(dst, m) - default: - dst = enc.AppendInterface(dst, m) - } - case []error: - dst = enc.AppendArrayStart(dst) - for i, err := range val { - switch m := ErrorMarshalFunc(err).(type) { - case LogObjectMarshaler: - e := newEvent(nil, 0) - e.buf = e.buf[:0] - e.appendObject(m) - dst = append(dst, e.buf...) - putEvent(e) - case error: - if m == nil || isNilValue(m) { - dst = enc.AppendNil(dst) - } else { - dst = enc.AppendString(dst, m.Error()) - } - case string: - dst = enc.AppendString(dst, m) - default: - dst = enc.AppendInterface(dst, m) - } - - if i < (len(val) - 1) { - enc.AppendArrayDelim(dst) - } - } - dst = enc.AppendArrayEnd(dst) case bool: dst = enc.AppendBool(dst, val) case int: @@ -237,16 +193,68 @@ func appendFields(dst []byte, fields map[string]interface{}) []byte { dst = enc.AppendTimes(dst, val, TimeFieldFormat) case []time.Duration: dst = enc.AppendDurations(dst, val, DurationFieldUnit, DurationFieldInteger) - case nil: - dst = enc.AppendNil(dst) case net.IP: dst = enc.AppendIPAddr(dst, val) case net.IPNet: dst = enc.AppendIPPrefix(dst, val) case net.HardwareAddr: dst = enc.AppendMACAddr(dst, val) + case json.RawMessage: + dst = appendJSON(dst, val) default: - dst = enc.AppendInterface(dst, val) + // interface type switch + switch val := val.(type) { + case error: + switch m := ErrorMarshalFunc(val).(type) { + case LogObjectMarshaler: + e := newEvent(nil, 0) + e.buf = e.buf[:0] + e.appendObject(m) + dst = append(dst, e.buf...) + putEvent(e) + case error: + if m == nil || isNilValue(m) { + dst = enc.AppendNil(dst) + } else { + dst = enc.AppendString(dst, m.Error()) + } + case string: + dst = enc.AppendString(dst, m) + default: + dst = enc.AppendInterface(dst, m) + } + case []error: + dst = enc.AppendArrayStart(dst) + for i, err := range val { + switch m := ErrorMarshalFunc(err).(type) { + case LogObjectMarshaler: + e := newEvent(nil, 0) + e.buf = e.buf[:0] + e.appendObject(m) + dst = append(dst, e.buf...) + putEvent(e) + case error: + if m == nil || isNilValue(m) { + dst = enc.AppendNil(dst) + } else { + dst = enc.AppendString(dst, m.Error()) + } + case string: + dst = enc.AppendString(dst, m) + default: + dst = enc.AppendInterface(dst, m) + } + + if i < (len(val) - 1) { + enc.AppendArrayDelim(dst) + } + } + dst = enc.AppendArrayEnd(dst) + case nil: + dst = enc.AppendNil(dst) + default: + dst = enc.AppendInterface(dst, val) + } } } return dst diff --git a/go.mod b/go.mod index 5b769bb3..70761c99 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.15 require ( github.com/coreos/go-systemd/v22 v22.3.2 + github.com/go-logr/logr v1.0.0 github.com/pkg/errors v0.9.1 github.com/rs/xid v1.2.1 golang.org/x/tools v0.1.3 diff --git a/go.sum b/go.sum index dbf7ab7b..2509e751 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/go-logr/logr v1.0.0 h1:kH951GinvFVaQgy/ki/B3YYmQtRpExGigSJg6O8z5jo= +github.com/go-logr/logr v1.0.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= diff --git a/logr/README.md b/logr/README.md new file mode 100644 index 00000000..715cb07d --- /dev/null +++ b/logr/README.md @@ -0,0 +1,31 @@ +# Zerologr + +The fastest [logr](https://github.com/go-logr/logr) implementation. + +## Usage + +```go +import ( + "os" + + "github.com/rs/zerolog" + "github.com/rs/zerolog/logr" +) + +func main() { + zl := zerolog.New(os.Stderr) + var log logr.Logger = logr.New(&zl) + + log.Info("Logr in action!", "the answer", 42) +} +``` + +## Implementation Details + +For the most part, concepts in Zerolog correspond directly with those in logr. + +Levels in logr correspond to custom debug levels in Zerolog. Any given level +in logr is represents by `zerologLevel = 1 - logrLevel`. + +For example `V(2)` is equivalent to Zerolog's `TraceLevel`, while `V(1)` is +equivalent to Zerolog's `DebugLevel`. diff --git a/logr/benchmark_test.go b/logr/benchmark_test.go new file mode 100644 index 00000000..e452071a --- /dev/null +++ b/logr/benchmark_test.go @@ -0,0 +1,157 @@ +package logr_test + +import ( + "fmt" + "os" + "testing" + + "github.com/rs/zerolog" + "github.com/rs/zerolog/logr" +) + +func init() { + zerolog.SetGlobalLevel(zerolog.DebugLevel) + os.Stderr, _ = os.Open("/dev/null") +} + +//go:noinline +func doInfoOneArg(b *testing.B, log logr.Logger) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + log.Info("this is", "a", "string") + } +} + +//go:noinline +func doInfoSeveralArgs(b *testing.B, log logr.Logger) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + log.Info("multi", + "bool", true, "string", "str", "int", 42, + "float", 3.14, "struct", struct{ X, Y int }{93, 76}) + } +} + +//go:noinline +func doV0Info(b *testing.B, log logr.Logger) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + log.V(0).Info("multi", + "bool", true, "string", "str", "int", 42, + "float", 3.14, "struct", struct{ X, Y int }{93, 76}) + } +} + +//go:noinline +func doV9Info(b *testing.B, log logr.Logger) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + log.V(9).Info("multi", + "bool", true, "string", "str", "int", 42, + "float", 3.14, "struct", struct{ X, Y int }{93, 76}) + } +} + +//go:noinline +func doError(b *testing.B, log logr.Logger) { + b.ReportAllocs() + err := fmt.Errorf("error message") + for i := 0; i < b.N; i++ { + log.Error(err, "multi", + "bool", true, "string", "str", "int", 42, + "float", 3.14, "struct", struct{ X, Y int }{93, 76}) + } +} + +//go:noinline +func doWithValues(b *testing.B, log logr.Logger) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + l := log.WithValues("k1", "v1", "k2", "v2") + _ = l + } +} + +//go:noinline +func doWithName(b *testing.B, log logr.Logger) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + l := log.WithName("name") + _ = l + } +} + +func logger() logr.Logger { + zl := zerolog.New(os.Stderr) + return logr.New(&zl) +} + +func BenchmarkDiscardInfoOneArg(b *testing.B) { + var log logr.Logger = logger() + doInfoOneArg(b, log) +} + +func BenchmarkDiscardInfoSeveralArgs(b *testing.B) { + var log logr.Logger = logger() + doInfoSeveralArgs(b, log) +} + +func BenchmarkDiscardV0Info(b *testing.B) { + var log logr.Logger = logger() + doV0Info(b, log) +} + +func BenchmarkDiscardV9Info(b *testing.B) { + var log logr.Logger = logger() + doV9Info(b, log) +} + +func BenchmarkDiscardError(b *testing.B) { + var log logr.Logger = logger() + doError(b, log) +} + +func BenchmarkDiscardWithValues(b *testing.B) { + var log logr.Logger = logger() + doWithValues(b, log) +} + +func BenchmarkDiscardWithName(b *testing.B) { + var log logr.Logger = logger() + doWithName(b, log) +} + +func BenchmarkFuncrInfoOneArg(b *testing.B) { + var log logr.Logger = logger() + doInfoOneArg(b, log) +} + +func BenchmarkFuncrInfoSeveralArgs(b *testing.B) { + var log logr.Logger = logger() + doInfoSeveralArgs(b, log) +} + +func BenchmarkFuncrV0Info(b *testing.B) { + var log logr.Logger = logger() + doV0Info(b, log) +} + +func BenchmarkFuncrV9Info(b *testing.B) { + var log logr.Logger = logger() + doV9Info(b, log) +} + +func BenchmarkFuncrError(b *testing.B) { + var log logr.Logger = logger() + doError(b, log) +} + +func BenchmarkFuncrWithValues(b *testing.B) { + var log logr.Logger = logger() + doWithValues(b, log) +} + +func BenchmarkFuncrWithName(b *testing.B) { + var log logr.Logger = logger() + doWithName(b, log) +} diff --git a/logr/logr.go b/logr/logr.go new file mode 100644 index 00000000..224a6dd1 --- /dev/null +++ b/logr/logr.go @@ -0,0 +1,209 @@ +// Package logr provides a logr.LogSink implementation using zerolog +package logr + +import ( + "encoding/json" + "net" + "time" + + "github.com/go-logr/logr" + + "github.com/rs/zerolog" +) + +type Logger = logr.Logger + +// New returns a logr.Logger with logr.LogSink implemented by zerolog. +func New(l *zerolog.Logger) Logger { + ls := &logSink{ + l: l, + } + return logr.New(ls) +} + +var ( + NameKey = "logger" + NameSeparator = "/" +) + +const ( + infoLevel = 1 - int(zerolog.InfoLevel) + debugLevel = 1 - int(zerolog.DebugLevel) + traceLevel = 1 - int(zerolog.TraceLevel) +) + +type logSink struct { + l *zerolog.Logger + prefix string + values []interface{} + depth int +} + +var _ logr.LogSink = &logSink{} +var _ logr.CallDepthLogSink = &logSink{} + +func handleFields(e *zerolog.Event, kvList []interface{}) *zerolog.Event { + kvLen := len(kvList) + if kvLen&0x1 == 1 { // odd number + kvList = append(kvList, "") + } + for i := 0; i < kvLen; i += 2 { + key, val := kvList[i], kvList[i+1] + k, ok := key.(string) + if !ok { + k = "" + } + // concrete type switch: binary search of sorted typehash + switch v := val.(type) { + case string: + e.Str(k, v) + case []byte: + e.Bytes(k, v) + case bool: + e.Bool(k, v) + case int: + e.Int(k, v) + case int8: + e.Int8(k, v) + case int16: + e.Int16(k, v) + case int32: + e.Int32(k, v) + case int64: + e.Int64(k, v) + case uint: + e.Uint(k, v) + case uint8: + e.Uint8(k, v) + case uint16: + e.Uint16(k, v) + case uint32: + e.Uint32(k, v) + case uint64: + e.Uint64(k, v) + case float32: + e.Float32(k, v) + case float64: + e.Float64(k, v) + case time.Time: + e.Time(k, v) + case time.Duration: + e.Dur(k, v) + case []string: + e.Strs(k, v) + case []bool: + e.Bools(k, v) + case []int: + e.Ints(k, v) + case []int8: + e.Ints8(k, v) + case []int16: + e.Ints16(k, v) + case []int32: + e.Ints32(k, v) + case []int64: + e.Ints64(k, v) + case []uint: + e.Uints(k, v) + case []uint16: + e.Uints16(k, v) + case []uint32: + e.Uints32(k, v) + case []uint64: + e.Uints64(k, v) + case []float32: + e.Floats32(k, v) + case []float64: + e.Floats64(k, v) + case []time.Time: + e.Times(k, v) + case []time.Duration: + e.Durs(k, v) + case net.IP: + e.IPAddr(k, v) + case net.IPNet: + e.IPPrefix(k, v) + case net.HardwareAddr: + e.MACAddr(k, v) + case json.RawMessage: + e.RawJSON(k, v) + default: + // interface type switch + switch v := val.(type) { + case error: + e.AnErr(k, v) + case []error: + e.Errs(k, v) + default: + e.Interface(k, val) + } + } + } + return e +} + +func (ls *logSink) Init(ri logr.RuntimeInfo) { + ls.depth += ri.CallDepth + 2 +} + +func (*logSink) Enabled(level int) bool { + // Info() checks zerolog.GlobalLevel() internally + return level <= traceLevel +} + +func (ls *logSink) Info(level int, msg string, kvList ...interface{}) { + var e *zerolog.Event + // small switch: linear search + switch level { + case infoLevel: + e = ls.l.Info() + case debugLevel: + e = ls.l.Debug() + case traceLevel: + e = ls.l.Trace() + } + ls.msg(e, msg, kvList) +} + +func (ls *logSink) Error(err error, msg string, kvList ...interface{}) { + e := ls.l.Error().Err(err) + ls.msg(e, msg, kvList) +} + +func (ls *logSink) msg(e *zerolog.Event, msg string, kvList []interface{}) { + if e == nil { + return + } + if len(ls.values) > 0 { + e = handleFields(e, ls.values) + } + e = handleFields(e, kvList) + if len(ls.prefix) > 0 { + e.Str(NameKey, ls.prefix) + } + e.CallerSkipFrame(ls.depth) + e.Msg(msg) +} + +func (ls logSink) WithValues(kvList ...interface{}) logr.LogSink { + n := len(ls.values) + ls.values = append(ls.values[:n:n], kvList...) + return &ls +} + +// WithName returns a new logr.Logger with the specified name with NameKey. +// It uses NameSeparator characters to separate name elements. Callers should not pass +// NameSeparator in the provided name string, but this library does not actually enforce that. +func (ls logSink) WithName(name string) logr.LogSink { + if len(ls.prefix) > 0 { + ls.prefix += NameSeparator + name + } else { + ls.prefix = name + } + return &ls +} + +func (ls logSink) WithCallDepth(depth int) logr.LogSink { + ls.depth += depth + return &ls +} diff --git a/logr/logr_example_test.go b/logr/logr_example_test.go new file mode 100644 index 00000000..c2b59cae --- /dev/null +++ b/logr/logr_example_test.go @@ -0,0 +1,48 @@ +// +build !binary_log + +package logr_test + +import ( + "os" + + "github.com/rs/zerolog" + "github.com/rs/zerolog/logr" +) + +type E struct { + str string +} + +func (e E) Error() string { + return e.str +} + +func Helper(log logr.Logger, msg string) { + helper2(log, msg) +} + +func helper2(log logr.Logger, msg string) { + log.WithCallDepth(2).Info(msg) +} + +func ExampleNew() { + zerolog.SetGlobalLevel(zerolog.DebugLevel) + zl := zerolog.New(os.Stdout) + log := logr.New(&zl) + log = log.WithName("MyName") + log = log.WithValues("module", "example") + + log.Info("hello", "val1", 1, "val2", map[string]int{"k": 1}) + log.V(1).Info("you should see this") + log.V(1).V(1).Info("you should NOT see this") + log.Error(nil, "uh oh", "trouble", true, "reasons", []float64{0.1, 0.11, 3.14}) + log.Error(E{"an error occurred"}, "goodbye", "code", -1) + Helper(log, "thru a helper") + + // Output: + // {"level":"info","module":"example","val1":1,"val2":{"k":1},"logger":"MyName","message":"hello"} + // {"level":"debug","module":"example","logger":"MyName","message":"you should see this"} + // {"level":"error","module":"example","trouble":true,"reasons":[0.1,0.11,3.14],"logger":"MyName","message":"uh oh"} + // {"level":"error","error":"an error occurred","module":"example","code":-1,"logger":"MyName","message":"goodbye"} + // {"level":"info","message":"thru a helper"} +} From 1c1e0de2b8eb540ee508f0c241ba78b8b7c4127c Mon Sep 17 00:00:00 2001 From: hn8 <10730886+hn8@users.noreply.github.com> Date: Sat, 31 Jul 2021 18:57:22 +0000 Subject: [PATCH 2/2] Revert logr subpackage Added to README instead --- README.md | 1 + fields.go | 103 +++++++++---------- go.mod | 1 - go.sum | 2 - logr/README.md | 31 ------ logr/benchmark_test.go | 157 ---------------------------- logr/logr.go | 209 -------------------------------------- logr/logr_example_test.go | 48 --------- 8 files changed, 50 insertions(+), 502 deletions(-) delete mode 100644 logr/README.md delete mode 100644 logr/benchmark_test.go delete mode 100644 logr/logr.go delete mode 100644 logr/logr_example_test.go diff --git a/README.md b/README.md index 51e3e36d..536e3e41 100644 --- a/README.md +++ b/README.md @@ -617,6 +617,7 @@ with zerolog library is [CSD](https://github.com/toravir/csd/). * [grpc-zerolog](https://github.com/cheapRoc/grpc-zerolog): Implementation of `grpclog.LoggerV2` interface using `zerolog` * [overlog](https://github.com/Trendyol/overlog): Implementation of `Mapped Diagnostic Context` interface using `zerolog` +* [zerologr](https://github.com/hn8/zerologr): Implementation of `logr.LogSink` interface using `zerolog` ## Benchmarks diff --git a/fields.go b/fields.go index e08f58a0..907b3f04 100644 --- a/fields.go +++ b/fields.go @@ -29,12 +29,57 @@ func appendFields(dst []byte, fields map[string]interface{}) []byte { putEvent(e) continue } - // concrete type switch: binary search of sorted typehash switch val := val.(type) { case string: dst = enc.AppendString(dst, val) case []byte: dst = enc.AppendBytes(dst, val) + case error: + switch m := ErrorMarshalFunc(val).(type) { + case LogObjectMarshaler: + e := newEvent(nil, 0) + e.buf = e.buf[:0] + e.appendObject(m) + dst = append(dst, e.buf...) + putEvent(e) + case error: + if m == nil || isNilValue(m) { + dst = enc.AppendNil(dst) + } else { + dst = enc.AppendString(dst, m.Error()) + } + case string: + dst = enc.AppendString(dst, m) + default: + dst = enc.AppendInterface(dst, m) + } + case []error: + dst = enc.AppendArrayStart(dst) + for i, err := range val { + switch m := ErrorMarshalFunc(err).(type) { + case LogObjectMarshaler: + e := newEvent(nil, 0) + e.buf = e.buf[:0] + e.appendObject(m) + dst = append(dst, e.buf...) + putEvent(e) + case error: + if m == nil || isNilValue(m) { + dst = enc.AppendNil(dst) + } else { + dst = enc.AppendString(dst, m.Error()) + } + case string: + dst = enc.AppendString(dst, m) + default: + dst = enc.AppendInterface(dst, m) + } + + if i < (len(val) - 1) { + enc.AppendArrayDelim(dst) + } + } + dst = enc.AppendArrayEnd(dst) case bool: dst = enc.AppendBool(dst, val) case int: @@ -193,6 +238,8 @@ func appendFields(dst []byte, fields map[string]interface{}) []byte { dst = enc.AppendTimes(dst, val, TimeFieldFormat) case []time.Duration: dst = enc.AppendDurations(dst, val, DurationFieldUnit, DurationFieldInteger) + case nil: + dst = enc.AppendNil(dst) case net.IP: dst = enc.AppendIPAddr(dst, val) case net.IPNet: @@ -202,59 +249,7 @@ func appendFields(dst []byte, fields map[string]interface{}) []byte { case json.RawMessage: dst = appendJSON(dst, val) default: - // interface type switch - switch val := val.(type) { - case error: - switch m := ErrorMarshalFunc(val).(type) { - case LogObjectMarshaler: - e := newEvent(nil, 0) - e.buf = e.buf[:0] - e.appendObject(m) - dst = append(dst, e.buf...) - putEvent(e) - case error: - if m == nil || isNilValue(m) { - dst = enc.AppendNil(dst) - } else { - dst = enc.AppendString(dst, m.Error()) - } - case string: - dst = enc.AppendString(dst, m) - default: - dst = enc.AppendInterface(dst, m) - } - case []error: - dst = enc.AppendArrayStart(dst) - for i, err := range val { - switch m := ErrorMarshalFunc(err).(type) { - case LogObjectMarshaler: - e := newEvent(nil, 0) - e.buf = e.buf[:0] - e.appendObject(m) - dst = append(dst, e.buf...) - putEvent(e) - case error: - if m == nil || isNilValue(m) { - dst = enc.AppendNil(dst) - } else { - dst = enc.AppendString(dst, m.Error()) - } - case string: - dst = enc.AppendString(dst, m) - default: - dst = enc.AppendInterface(dst, m) - } - - if i < (len(val) - 1) { - enc.AppendArrayDelim(dst) - } - } - dst = enc.AppendArrayEnd(dst) - case nil: - dst = enc.AppendNil(dst) - default: - dst = enc.AppendInterface(dst, val) - } + dst = enc.AppendInterface(dst, val) } } return dst diff --git a/go.mod b/go.mod index 70761c99..5b769bb3 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,6 @@ go 1.15 require ( github.com/coreos/go-systemd/v22 v22.3.2 - github.com/go-logr/logr v1.0.0 github.com/pkg/errors v0.9.1 github.com/rs/xid v1.2.1 golang.org/x/tools v0.1.3 diff --git a/go.sum b/go.sum index 2509e751..dbf7ab7b 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,5 @@ github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/go-logr/logr v1.0.0 h1:kH951GinvFVaQgy/ki/B3YYmQtRpExGigSJg6O8z5jo= -github.com/go-logr/logr v1.0.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= diff --git a/logr/README.md b/logr/README.md deleted file mode 100644 index 715cb07d..00000000 --- a/logr/README.md +++ /dev/null @@ -1,31 +0,0 @@ -# Zerologr - -The fastest [logr](https://github.com/go-logr/logr) implementation. - -## Usage - -```go -import ( - "os" - - "github.com/rs/zerolog" - "github.com/rs/zerolog/logr" -) - -func main() { - zl := zerolog.New(os.Stderr) - var log logr.Logger = logr.New(&zl) - - log.Info("Logr in action!", "the answer", 42) -} -``` - -## Implementation Details - -For the most part, concepts in Zerolog correspond directly with those in logr. - -Levels in logr correspond to custom debug levels in Zerolog. Any given level -in logr is represents by `zerologLevel = 1 - logrLevel`. - -For example `V(2)` is equivalent to Zerolog's `TraceLevel`, while `V(1)` is -equivalent to Zerolog's `DebugLevel`. diff --git a/logr/benchmark_test.go b/logr/benchmark_test.go deleted file mode 100644 index e452071a..00000000 --- a/logr/benchmark_test.go +++ /dev/null @@ -1,157 +0,0 @@ -package logr_test - -import ( - "fmt" - "os" - "testing" - - "github.com/rs/zerolog" - "github.com/rs/zerolog/logr" -) - -func init() { - zerolog.SetGlobalLevel(zerolog.DebugLevel) - os.Stderr, _ = os.Open("/dev/null") -} - -//go:noinline -func doInfoOneArg(b *testing.B, log logr.Logger) { - b.ReportAllocs() - for i := 0; i < b.N; i++ { - log.Info("this is", "a", "string") - } -} - -//go:noinline -func doInfoSeveralArgs(b *testing.B, log logr.Logger) { - b.ReportAllocs() - for i := 0; i < b.N; i++ { - log.Info("multi", - "bool", true, "string", "str", "int", 42, - "float", 3.14, "struct", struct{ X, Y int }{93, 76}) - } -} - -//go:noinline -func doV0Info(b *testing.B, log logr.Logger) { - b.ReportAllocs() - for i := 0; i < b.N; i++ { - log.V(0).Info("multi", - "bool", true, "string", "str", "int", 42, - "float", 3.14, "struct", struct{ X, Y int }{93, 76}) - } -} - -//go:noinline -func doV9Info(b *testing.B, log logr.Logger) { - b.ReportAllocs() - for i := 0; i < b.N; i++ { - log.V(9).Info("multi", - "bool", true, "string", "str", "int", 42, - "float", 3.14, "struct", struct{ X, Y int }{93, 76}) - } -} - -//go:noinline -func doError(b *testing.B, log logr.Logger) { - b.ReportAllocs() - err := fmt.Errorf("error message") - for i := 0; i < b.N; i++ { - log.Error(err, "multi", - "bool", true, "string", "str", "int", 42, - "float", 3.14, "struct", struct{ X, Y int }{93, 76}) - } -} - -//go:noinline -func doWithValues(b *testing.B, log logr.Logger) { - b.ReportAllocs() - for i := 0; i < b.N; i++ { - l := log.WithValues("k1", "v1", "k2", "v2") - _ = l - } -} - -//go:noinline -func doWithName(b *testing.B, log logr.Logger) { - b.ReportAllocs() - for i := 0; i < b.N; i++ { - l := log.WithName("name") - _ = l - } -} - -func logger() logr.Logger { - zl := zerolog.New(os.Stderr) - return logr.New(&zl) -} - -func BenchmarkDiscardInfoOneArg(b *testing.B) { - var log logr.Logger = logger() - doInfoOneArg(b, log) -} - -func BenchmarkDiscardInfoSeveralArgs(b *testing.B) { - var log logr.Logger = logger() - doInfoSeveralArgs(b, log) -} - -func BenchmarkDiscardV0Info(b *testing.B) { - var log logr.Logger = logger() - doV0Info(b, log) -} - -func BenchmarkDiscardV9Info(b *testing.B) { - var log logr.Logger = logger() - doV9Info(b, log) -} - -func BenchmarkDiscardError(b *testing.B) { - var log logr.Logger = logger() - doError(b, log) -} - -func BenchmarkDiscardWithValues(b *testing.B) { - var log logr.Logger = logger() - doWithValues(b, log) -} - -func BenchmarkDiscardWithName(b *testing.B) { - var log logr.Logger = logger() - doWithName(b, log) -} - -func BenchmarkFuncrInfoOneArg(b *testing.B) { - var log logr.Logger = logger() - doInfoOneArg(b, log) -} - -func BenchmarkFuncrInfoSeveralArgs(b *testing.B) { - var log logr.Logger = logger() - doInfoSeveralArgs(b, log) -} - -func BenchmarkFuncrV0Info(b *testing.B) { - var log logr.Logger = logger() - doV0Info(b, log) -} - -func BenchmarkFuncrV9Info(b *testing.B) { - var log logr.Logger = logger() - doV9Info(b, log) -} - -func BenchmarkFuncrError(b *testing.B) { - var log logr.Logger = logger() - doError(b, log) -} - -func BenchmarkFuncrWithValues(b *testing.B) { - var log logr.Logger = logger() - doWithValues(b, log) -} - -func BenchmarkFuncrWithName(b *testing.B) { - var log logr.Logger = logger() - doWithName(b, log) -} diff --git a/logr/logr.go b/logr/logr.go deleted file mode 100644 index 224a6dd1..00000000 --- a/logr/logr.go +++ /dev/null @@ -1,209 +0,0 @@ -// Package logr provides a logr.LogSink implementation using zerolog -package logr - -import ( - "encoding/json" - "net" - "time" - - "github.com/go-logr/logr" - - "github.com/rs/zerolog" -) - -type Logger = logr.Logger - -// New returns a logr.Logger with logr.LogSink implemented by zerolog. -func New(l *zerolog.Logger) Logger { - ls := &logSink{ - l: l, - } - return logr.New(ls) -} - -var ( - NameKey = "logger" - NameSeparator = "/" -) - -const ( - infoLevel = 1 - int(zerolog.InfoLevel) - debugLevel = 1 - int(zerolog.DebugLevel) - traceLevel = 1 - int(zerolog.TraceLevel) -) - -type logSink struct { - l *zerolog.Logger - prefix string - values []interface{} - depth int -} - -var _ logr.LogSink = &logSink{} -var _ logr.CallDepthLogSink = &logSink{} - -func handleFields(e *zerolog.Event, kvList []interface{}) *zerolog.Event { - kvLen := len(kvList) - if kvLen&0x1 == 1 { // odd number - kvList = append(kvList, "") - } - for i := 0; i < kvLen; i += 2 { - key, val := kvList[i], kvList[i+1] - k, ok := key.(string) - if !ok { - k = "" - } - // concrete type switch: binary search of sorted typehash - switch v := val.(type) { - case string: - e.Str(k, v) - case []byte: - e.Bytes(k, v) - case bool: - e.Bool(k, v) - case int: - e.Int(k, v) - case int8: - e.Int8(k, v) - case int16: - e.Int16(k, v) - case int32: - e.Int32(k, v) - case int64: - e.Int64(k, v) - case uint: - e.Uint(k, v) - case uint8: - e.Uint8(k, v) - case uint16: - e.Uint16(k, v) - case uint32: - e.Uint32(k, v) - case uint64: - e.Uint64(k, v) - case float32: - e.Float32(k, v) - case float64: - e.Float64(k, v) - case time.Time: - e.Time(k, v) - case time.Duration: - e.Dur(k, v) - case []string: - e.Strs(k, v) - case []bool: - e.Bools(k, v) - case []int: - e.Ints(k, v) - case []int8: - e.Ints8(k, v) - case []int16: - e.Ints16(k, v) - case []int32: - e.Ints32(k, v) - case []int64: - e.Ints64(k, v) - case []uint: - e.Uints(k, v) - case []uint16: - e.Uints16(k, v) - case []uint32: - e.Uints32(k, v) - case []uint64: - e.Uints64(k, v) - case []float32: - e.Floats32(k, v) - case []float64: - e.Floats64(k, v) - case []time.Time: - e.Times(k, v) - case []time.Duration: - e.Durs(k, v) - case net.IP: - e.IPAddr(k, v) - case net.IPNet: - e.IPPrefix(k, v) - case net.HardwareAddr: - e.MACAddr(k, v) - case json.RawMessage: - e.RawJSON(k, v) - default: - // interface type switch - switch v := val.(type) { - case error: - e.AnErr(k, v) - case []error: - e.Errs(k, v) - default: - e.Interface(k, val) - } - } - } - return e -} - -func (ls *logSink) Init(ri logr.RuntimeInfo) { - ls.depth += ri.CallDepth + 2 -} - -func (*logSink) Enabled(level int) bool { - // Info() checks zerolog.GlobalLevel() internally - return level <= traceLevel -} - -func (ls *logSink) Info(level int, msg string, kvList ...interface{}) { - var e *zerolog.Event - // small switch: linear search - switch level { - case infoLevel: - e = ls.l.Info() - case debugLevel: - e = ls.l.Debug() - case traceLevel: - e = ls.l.Trace() - } - ls.msg(e, msg, kvList) -} - -func (ls *logSink) Error(err error, msg string, kvList ...interface{}) { - e := ls.l.Error().Err(err) - ls.msg(e, msg, kvList) -} - -func (ls *logSink) msg(e *zerolog.Event, msg string, kvList []interface{}) { - if e == nil { - return - } - if len(ls.values) > 0 { - e = handleFields(e, ls.values) - } - e = handleFields(e, kvList) - if len(ls.prefix) > 0 { - e.Str(NameKey, ls.prefix) - } - e.CallerSkipFrame(ls.depth) - e.Msg(msg) -} - -func (ls logSink) WithValues(kvList ...interface{}) logr.LogSink { - n := len(ls.values) - ls.values = append(ls.values[:n:n], kvList...) - return &ls -} - -// WithName returns a new logr.Logger with the specified name with NameKey. -// It uses NameSeparator characters to separate name elements. Callers should not pass -// NameSeparator in the provided name string, but this library does not actually enforce that. -func (ls logSink) WithName(name string) logr.LogSink { - if len(ls.prefix) > 0 { - ls.prefix += NameSeparator + name - } else { - ls.prefix = name - } - return &ls -} - -func (ls logSink) WithCallDepth(depth int) logr.LogSink { - ls.depth += depth - return &ls -} diff --git a/logr/logr_example_test.go b/logr/logr_example_test.go deleted file mode 100644 index c2b59cae..00000000 --- a/logr/logr_example_test.go +++ /dev/null @@ -1,48 +0,0 @@ -// +build !binary_log - -package logr_test - -import ( - "os" - - "github.com/rs/zerolog" - "github.com/rs/zerolog/logr" -) - -type E struct { - str string -} - -func (e E) Error() string { - return e.str -} - -func Helper(log logr.Logger, msg string) { - helper2(log, msg) -} - -func helper2(log logr.Logger, msg string) { - log.WithCallDepth(2).Info(msg) -} - -func ExampleNew() { - zerolog.SetGlobalLevel(zerolog.DebugLevel) - zl := zerolog.New(os.Stdout) - log := logr.New(&zl) - log = log.WithName("MyName") - log = log.WithValues("module", "example") - - log.Info("hello", "val1", 1, "val2", map[string]int{"k": 1}) - log.V(1).Info("you should see this") - log.V(1).V(1).Info("you should NOT see this") - log.Error(nil, "uh oh", "trouble", true, "reasons", []float64{0.1, 0.11, 3.14}) - log.Error(E{"an error occurred"}, "goodbye", "code", -1) - Helper(log, "thru a helper") - - // Output: - // {"level":"info","module":"example","val1":1,"val2":{"k":1},"logger":"MyName","message":"hello"} - // {"level":"debug","module":"example","logger":"MyName","message":"you should see this"} - // {"level":"error","module":"example","trouble":true,"reasons":[0.1,0.11,3.14],"logger":"MyName","message":"uh oh"} - // {"level":"error","error":"an error occurred","module":"example","code":-1,"logger":"MyName","message":"goodbye"} - // {"level":"info","message":"thru a helper"} -}