From 3fa5606b731782ff920f929f3a0984a17f895a14 Mon Sep 17 00:00:00 2001 From: David Hontecillas Date: Tue, 31 Oct 2023 15:38:54 +0100 Subject: [PATCH 1/3] create logger wrapper to store additional information Signed-off-by: David Hontecillas --- logging/annotated_logger.go | 66 ++++++++++++++++++++++++++++++++ logging/annotated_logger_test.go | 36 +++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 logging/annotated_logger.go create mode 100644 logging/annotated_logger_test.go diff --git a/logging/annotated_logger.go b/logging/annotated_logger.go new file mode 100644 index 000000000..8b89e46e6 --- /dev/null +++ b/logging/annotated_logger.go @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: Apache-2.0 + +package logging + +// AnnotatedLogger wraps a Logger and appends information to +// each one of the received logs. +type AnnotatedLogger struct { + appendAnnotation string + wrapped Logger +} + +// NewAnnotatedLogger creates and returns a Logger object +func NewAnnotatedLogger(l Logger, appendAnnotation string) (AnnotatedLogger, error) { + if al, ok := l.(AnnotatedLogger); ok { + // if the given logger is already an annotated logger, we + // can combine the two appended anotations and save a wrap around + if len(al.appendAnnotation) > 0 { + appendAnnotation = al.appendAnnotation + " " + appendAnnotation + } + l = al.wrapped + } + return AnnotatedLogger{ + appendAnnotation: appendAnnotation, + wrapped: l, + }, nil +} + +// Debug logs a message using DEBUG as log level. +func (l AnnotatedLogger) Debug(v ...interface{}) { + l.wrapped.Debug(l.appendLog(v)) +} + +// Info logs a message using INFO as log level. +func (l AnnotatedLogger) Info(v ...interface{}) { + l.wrapped.Info(l.appendLog(v)) +} + +// Warning logs a message using WARNING as log level. +func (l AnnotatedLogger) Warning(v ...interface{}) { + l.wrapped.Warning(l.appendLog(v)) +} + +// Error logs a message using ERROR as log level. +func (l AnnotatedLogger) Error(v ...interface{}) { + l.wrapped.Error(l.appendLog(v)) +} + +// Critical logs a message using CRITICAL as log level. +func (l AnnotatedLogger) Critical(v ...interface{}) { + l.wrapped.Critical(l.appendLog(v)) +} + +// Fatal is equivalent to l.Critical(fmt.Sprint()) followed by a call to os.Exit(1). +func (l AnnotatedLogger) Fatal(v ...interface{}) { + l.wrapped.Fatal(l.appendLog(v)) +} + +func (l AnnotatedLogger) appendLog(v ...interface{}) []interface{} { + if len(l.appendAnnotation) == 0 { + return v + } + msg := make([]interface{}, len(v)+1) + copy(msg, v) + msg[len(v)] = l.appendAnnotation + return msg +} diff --git a/logging/annotated_logger_test.go b/logging/annotated_logger_test.go new file mode 100644 index 000000000..3a2e06587 --- /dev/null +++ b/logging/annotated_logger_test.go @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: Apache-2.0 + +package logging + +import ( + "bytes" + "strings" + "testing" +) + +func TestNewAnnotatedLogger(t *testing.T) { + buff := bytes.NewBuffer(make([]byte, 1024)) + bl, _ := NewLogger("DEBUG", buff, "PREFIX") + + al, _ := NewAnnotatedLogger(bl, "Mortadelo") + al.Info("A") + + s := buff.String() + if !strings.HasSuffix(s, "A Mortadelo") { + t.Errorf("missing suffix: %s", s) + } +} + +func TestWrappedAnnotatedLogger(t *testing.T) { + buff := bytes.NewBuffer(make([]byte, 1024)) + bl, _ := NewLogger("DEBUG", buff, "PREFIX") + + al, _ := NewAnnotatedLogger(bl, "Mortadelo") + al, _ = NewAnnotatedLogger(al, "Filemon") + al.Warning("B") + + s := buff.String() + if !strings.HasSuffix(s, "B Mortadelo Filemon") { + t.Errorf("missing suffix: %s", s) + } +} From 0c0b57c0a447fd9bdbd415bf9d3e25f6797aaf9f Mon Sep 17 00:00:00 2001 From: David Hontecillas Date: Tue, 31 Oct 2023 15:50:36 +0100 Subject: [PATCH 2/3] add log wrapper for extra suffix info to backends Signed-off-by: David Hontecillas --- proxy/factory.go | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/proxy/factory.go b/proxy/factory.go index be2df8c28..ad60e5224 100644 --- a/proxy/factory.go +++ b/proxy/factory.go @@ -3,6 +3,8 @@ package proxy import ( + "fmt" + "github.com/luraproject/lura/v2/config" "github.com/luraproject/lura/v2/logging" "github.com/luraproject/lura/v2/sd" @@ -56,47 +58,48 @@ type defaultFactory struct { // New implements the Factory interface func (pf defaultFactory) New(cfg *config.EndpointConfig) (p Proxy, err error) { + l, _ := logging.NewAnnotatedLogger(pf.logger, fmt.Sprintf("%s %s", cfg.Method, cfg.Endpoint)) switch len(cfg.Backend) { case 0: err = ErrNoBackends case 1: - p, err = pf.newSingle(cfg) + p, err = pf.newSingle(l, cfg) default: - p, err = pf.newMulti(cfg) + p, err = pf.newMulti(l, cfg) } if err != nil { return } - p = NewPluginMiddleware(pf.logger, cfg)(p) - p = NewStaticMiddleware(pf.logger, cfg)(p) + p = NewPluginMiddleware(l, cfg)(p) + p = NewStaticMiddleware(l, cfg)(p) return } -func (pf defaultFactory) newMulti(cfg *config.EndpointConfig) (p Proxy, err error) { +func (pf defaultFactory) newMulti(l logging.Logger, cfg *config.EndpointConfig) (p Proxy, err error) { backendProxy := make([]Proxy, len(cfg.Backend)) for i, backend := range cfg.Backend { - backendProxy[i] = pf.newStack(backend) + backendProxy[i] = pf.newStack(l, backend) } - p = NewMergeDataMiddleware(pf.logger, cfg)(backendProxy...) - p = NewFlatmapMiddleware(pf.logger, cfg)(p) + p = NewMergeDataMiddleware(l, cfg)(backendProxy...) + p = NewFlatmapMiddleware(l, cfg)(p) return } -func (pf defaultFactory) newSingle(cfg *config.EndpointConfig) (Proxy, error) { - return pf.newStack(cfg.Backend[0]), nil +func (pf defaultFactory) newSingle(l logging.Logger, cfg *config.EndpointConfig) (Proxy, error) { + return pf.newStack(l, cfg.Backend[0]), nil } -func (pf defaultFactory) newStack(backend *config.Backend) (p Proxy) { +func (pf defaultFactory) newStack(l logging.Logger, backend *config.Backend) (p Proxy) { p = pf.backendFactory(backend) - p = NewBackendPluginMiddleware(pf.logger, backend)(p) - p = NewGraphQLMiddleware(pf.logger, backend)(p) - p = NewFilterHeadersMiddleware(pf.logger, backend)(p) - p = NewFilterQueryStringsMiddleware(pf.logger, backend)(p) - p = NewLoadBalancedMiddlewareWithSubscriberAndLogger(pf.logger, pf.subscriberFactory(backend))(p) + p = NewBackendPluginMiddleware(l, backend)(p) + p = NewGraphQLMiddleware(l, backend)(p) + p = NewFilterHeadersMiddleware(l, backend)(p) + p = NewFilterQueryStringsMiddleware(l, backend)(p) + p = NewLoadBalancedMiddlewareWithSubscriberAndLogger(l, pf.subscriberFactory(backend))(p) if backend.ConcurrentCalls > 1 { - p = NewConcurrentMiddlewareWithLogger(pf.logger, backend)(p) + p = NewConcurrentMiddlewareWithLogger(l, backend)(p) } - p = NewRequestBuilderMiddlewareWithLogger(pf.logger, backend)(p) + p = NewRequestBuilderMiddlewareWithLogger(l, backend)(p) return } From 6e3b3b3cf4089670c41e9712c728328e74aed046 Mon Sep 17 00:00:00 2001 From: David Hontecillas Date: Tue, 31 Oct 2023 16:28:22 +0100 Subject: [PATCH 3/3] fix append log implementation Signed-off-by: David Hontecillas --- logging/annotated_logger.go | 14 +++++++------- logging/annotated_logger_test.go | 20 ++++++++++++++++---- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/logging/annotated_logger.go b/logging/annotated_logger.go index 8b89e46e6..27a84af90 100644 --- a/logging/annotated_logger.go +++ b/logging/annotated_logger.go @@ -27,35 +27,35 @@ func NewAnnotatedLogger(l Logger, appendAnnotation string) (AnnotatedLogger, err // Debug logs a message using DEBUG as log level. func (l AnnotatedLogger) Debug(v ...interface{}) { - l.wrapped.Debug(l.appendLog(v)) + l.wrapped.Debug(l.appendLog(v)...) } // Info logs a message using INFO as log level. func (l AnnotatedLogger) Info(v ...interface{}) { - l.wrapped.Info(l.appendLog(v)) + l.wrapped.Info(l.appendLog(v)...) } // Warning logs a message using WARNING as log level. func (l AnnotatedLogger) Warning(v ...interface{}) { - l.wrapped.Warning(l.appendLog(v)) + l.wrapped.Warning(l.appendLog(v)...) } // Error logs a message using ERROR as log level. func (l AnnotatedLogger) Error(v ...interface{}) { - l.wrapped.Error(l.appendLog(v)) + l.wrapped.Error(l.appendLog(v)...) } // Critical logs a message using CRITICAL as log level. func (l AnnotatedLogger) Critical(v ...interface{}) { - l.wrapped.Critical(l.appendLog(v)) + l.wrapped.Critical(l.appendLog(v)...) } // Fatal is equivalent to l.Critical(fmt.Sprint()) followed by a call to os.Exit(1). func (l AnnotatedLogger) Fatal(v ...interface{}) { - l.wrapped.Fatal(l.appendLog(v)) + l.wrapped.Fatal(l.appendLog(v)...) } -func (l AnnotatedLogger) appendLog(v ...interface{}) []interface{} { +func (l AnnotatedLogger) appendLog(v []interface{}) []interface{} { if len(l.appendAnnotation) == 0 { return v } diff --git a/logging/annotated_logger_test.go b/logging/annotated_logger_test.go index 3a2e06587..a40e24346 100644 --- a/logging/annotated_logger_test.go +++ b/logging/annotated_logger_test.go @@ -8,15 +8,27 @@ import ( "testing" ) +func TestRegularLogger(t *testing.T) { + buff := bytes.NewBuffer(make([]byte, 1024)) + bl, _ := NewLogger("DEBUG", buff, "PREFIX") + + bl.Info("A", "B", "C") + + s := buff.String() + if !strings.Contains(s, "A B C") { + t.Errorf("missing: A B C : %s", s) + } +} + func TestNewAnnotatedLogger(t *testing.T) { buff := bytes.NewBuffer(make([]byte, 1024)) bl, _ := NewLogger("DEBUG", buff, "PREFIX") al, _ := NewAnnotatedLogger(bl, "Mortadelo") - al.Info("A") + al.Info("A", "B", "C") s := buff.String() - if !strings.HasSuffix(s, "A Mortadelo") { + if !strings.Contains(s, "A B C Mortadelo") { t.Errorf("missing suffix: %s", s) } } @@ -27,10 +39,10 @@ func TestWrappedAnnotatedLogger(t *testing.T) { al, _ := NewAnnotatedLogger(bl, "Mortadelo") al, _ = NewAnnotatedLogger(al, "Filemon") - al.Warning("B") + al.Warning("B", "C", "D") s := buff.String() - if !strings.HasSuffix(s, "B Mortadelo Filemon") { + if !strings.Contains(s, "B C D Mortadelo Filemon") { t.Errorf("missing suffix: %s", s) } }