diff options
author | Valery Piashchynski <[email protected]> | 2021-09-08 11:26:20 +0300 |
---|---|---|
committer | GitHub <[email protected]> | 2021-09-08 11:26:20 +0300 |
commit | 2df4696d85f76c58b014748bf06bf50d84116903 (patch) | |
tree | e295db2c8412fd387e3b4035b2938b979de3e827 | |
parent | 6749db4a2d39fa70b426bcf50edf66a176c07f57 (diff) | |
parent | 5247e30957b491c1bf42db7af0976280cc7b6c36 (diff) |
[#782]: feat(logger): Zap fields can be used as arguments to the logger
[#782]: feat(logger): Zap fields can be used as arguments to the logger
-rw-r--r-- | plugins/logger/zap_adapter.go | 25 | ||||
-rw-r--r-- | tests/plugins/logger/logger_test.go | 71 | ||||
-rw-r--r-- | tests/plugins/logger/plugin.go | 24 |
3 files changed, 119 insertions, 1 deletions
diff --git a/plugins/logger/zap_adapter.go b/plugins/logger/zap_adapter.go index fab59844..1c68cf25 100644 --- a/plugins/logger/zap_adapter.go +++ b/plugins/logger/zap_adapter.go @@ -4,6 +4,7 @@ import ( "fmt" "go.uber.org/zap" + core "go.uber.org/zap/zapcore" ) type ZapAdapter struct { @@ -17,13 +18,33 @@ func NewZapAdapter(zapLogger *zap.Logger) *ZapAdapter { } } +func separateFields(keyVals []interface{}) ([]zap.Field, []interface{}) { + var fields []zap.Field + var pairedKeyVals []interface{} + + for key := range keyVals { + switch value := keyVals[key].(type) { + case zap.Field: + fields = append(fields, value) + case core.ObjectMarshaler: + fields = append(fields, zap.Inline(value)) + default: + pairedKeyVals = append(pairedKeyVals, value) + } + } + return fields, pairedKeyVals +} + func (log *ZapAdapter) fields(keyvals []interface{}) []zap.Field { + // separate any zap fields from other structs + zapFields, keyvals := separateFields(keyvals) + // we should have even number of keys and values if len(keyvals)%2 != 0 { return []zap.Field{zap.Error(fmt.Errorf("odd number of keyvals pairs: %v", keyvals))} } - fields := make([]zap.Field, 0, len(keyvals)/2) + fields := make([]zap.Field, 0, len(keyvals)/2+len(zapFields)) for i := 0; i < len(keyvals); i += 2 { key, ok := keyvals[i].(string) if !ok { @@ -31,6 +52,8 @@ func (log *ZapAdapter) fields(keyvals []interface{}) []zap.Field { } fields = append(fields, zap.Any(key, keyvals[i+1])) } + // add all the fields + fields = append(fields, zapFields...) return fields } diff --git a/tests/plugins/logger/logger_test.go b/tests/plugins/logger/logger_test.go index 174ee743..05ca2d53 100644 --- a/tests/plugins/logger/logger_test.go +++ b/tests/plugins/logger/logger_test.go @@ -357,3 +357,74 @@ func httpEcho(t *testing.T) { err = r.Body.Close() assert.NoError(t, err) } + +func TestMarshalObjectLogging(t *testing.T) { + container, err := endure.NewContainer(nil, endure.RetryOnFail(true), endure.SetLogLevel(endure.ErrorLevel)) + if err != nil { + t.Fatal(err) + } + // config plugin + vp := &config.Viper{} + vp.Path = "configs/.rr-file-logger.yaml" + vp.Prefix = "rr" + + err = container.RegisterAll( + vp, + &Plugin{}, + &logger.ZapLogger{}, + ) + assert.NoError(t, err) + + err = container.Init() + if err != nil { + t.Fatal(err) + } + + errCh, err := container.Serve() + if err != nil { + t.Fatal(err) + } + + // stop by CTRL+C + c := make(chan os.Signal, 1) + signal.Notify(c, os.Interrupt) + + stopCh := make(chan struct{}, 1) + + wg := &sync.WaitGroup{} + wg.Add(1) + + go func() { + defer wg.Done() + for { + select { + case e := <-errCh: + assert.NoError(t, e.Error) + assert.NoError(t, container.Stop()) + return + case <-c: + err = container.Stop() + assert.NoError(t, err) + return + case <-stopCh: + assert.NoError(t, container.Stop()) + return + } + } + }() + + time.Sleep(time.Second * 2) + + f, err := os.ReadFile("test.log") + if err != nil { + t.Fatal(err) + } + + assert.Contains(t, string(f), "Example marshaller error") + assert.Equal(t, 4, strings.Count(string(f), "Example marshaller error")) + + _ = os.Remove("test.log") + + stopCh <- struct{}{} + wg.Wait() +} diff --git a/tests/plugins/logger/plugin.go b/tests/plugins/logger/plugin.go index aa62f2b3..54e78d7b 100644 --- a/tests/plugins/logger/plugin.go +++ b/tests/plugins/logger/plugin.go @@ -6,6 +6,8 @@ import ( "github.com/spiral/errors" "github.com/spiral/roadrunner/v2/plugins/config" "github.com/spiral/roadrunner/v2/plugins/logger" + "go.uber.org/zap" + core "go.uber.org/zap/zapcore" ) type Plugin struct { @@ -13,6 +15,14 @@ type Plugin struct { log logger.Logger } +type Loggable struct { +} + +func (l *Loggable) MarshalLogObject(encoder core.ObjectEncoder) error { + encoder.AddString("error", "Example marshaller error") + return nil +} + func (p1 *Plugin) Init(cfg config.Configurer, log logger.Logger) error { p1.config = cfg p1.log = log @@ -26,6 +36,20 @@ func (p1 *Plugin) Serve() chan error { p1.log.Debug("error", "test", errors.E(errors.Str("test"))) p1.log.Warn("error", "test", errors.E(errors.Str("test"))) + field := zap.String("error", "Example field error") + + p1.log.Error("error", field) + p1.log.Info("error", field) + p1.log.Debug("error", field) + p1.log.Warn("error", field) + + marshalledObject := &Loggable{} + + p1.log.Error("error", marshalledObject) + p1.log.Info("error", marshalledObject) + p1.log.Debug("error", marshalledObject) + p1.log.Warn("error", marshalledObject) + p1.log.Error("error", "test") p1.log.Info("error", "test") p1.log.Debug("error", "test") |