From 27283cbf93c4797a613d801776e9cf657b8d26e8 Mon Sep 17 00:00:00 2001 From: oozan Date: Wed, 20 Nov 2024 17:50:58 +0200 Subject: [PATCH] Add logging functionality to middleware and test its execution --- middleware.go | 36 +++++++++++++++++++++++++++++++++++- middleware_test.go | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/middleware.go b/middleware.go index a79815ca..1c95604d 100644 --- a/middleware.go +++ b/middleware.go @@ -1,6 +1,7 @@ package mux import ( + "log" "net/http" "strings" ) @@ -10,6 +11,13 @@ import ( // to it, and then calls the handler passed as parameter to the MiddlewareFunc. type MiddlewareFunc func(http.Handler) http.Handler +// MiddlewareFuncWithLogging is a middleware function with optional logging. +// It wraps a MiddlewareFunc and adds logging capabilities. +type MiddlewareFuncWithLogging struct { + Handler MiddlewareFunc + Name string +} + // middleware interface is anything which implements a MiddlewareFunc named Middleware. type middleware interface { Middleware(handler http.Handler) http.Handler @@ -20,6 +28,14 @@ func (mw MiddlewareFunc) Middleware(handler http.Handler) http.Handler { return mw(handler) } +// Middleware allows MiddlewareFuncWithLogging to implement the middleware interface. +func (mw MiddlewareFuncWithLogging) Middleware(handler http.Handler) http.Handler { + return mw.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + log.Printf("Executing middleware: %s", mw.Name) + handler.ServeHTTP(w, r) + })) +} + // Use appends a MiddlewareFunc to the chain. Middleware can be used to intercept or otherwise modify requests and/or responses, and are executed in the order that they are applied to the Router. func (r *Router) Use(mwf ...MiddlewareFunc) { for _, fn := range mwf { @@ -27,6 +43,14 @@ func (r *Router) Use(mwf ...MiddlewareFunc) { } } +// UseWithLogging appends a MiddlewareFuncWithLogging to the chain, allowing optional logging. +func (r *Router) UseWithLogging(name string, mw MiddlewareFunc) { + r.useInterface(MiddlewareFuncWithLogging{ + Handler: mw, + Name: name, + }) +} + // useInterface appends a middleware to the chain. Middleware can be used to intercept or otherwise modify requests and/or responses, and are executed in the order that they are applied to the Router. func (r *Router) useInterface(mw middleware) { r.middlewares = append(r.middlewares, mw) @@ -43,7 +67,17 @@ func (r *Route) Use(mwf ...MiddlewareFunc) *Route { return r } -// useInterface appends a MiddlewareFunc to the chain. Middleware can be used to intercept or otherwise modify requests and/or responses, and are executed in the order that they are applied to the Route. Route middleware are executed after the Router middleware but before the Route handler. +// UseWithLogging appends a MiddlewareFuncWithLogging to the route's middleware chain. +func (r *Route) UseWithLogging(name string, mw MiddlewareFunc) *Route { + r.useInterface(MiddlewareFuncWithLogging{ + Handler: mw, + Name: name, + }) + + return r +} + +// useInterface appends a middleware to the chain. Middleware can be used to intercept or otherwise modify requests and/or responses, and are executed in the order that they are applied to the Route. Route middleware are executed after the Router middleware but before the Route handler. func (r *Route) useInterface(mw middleware) { r.middlewares = append(r.middlewares, mw) } diff --git a/middleware_test.go b/middleware_test.go index 8835b56c..28143cac 100644 --- a/middleware_test.go +++ b/middleware_test.go @@ -3,7 +3,9 @@ package mux import ( "bytes" "fmt" + "log" "net/http" + "strings" "testing" ) @@ -117,6 +119,40 @@ func TestMiddleware(t *testing.T) { }) } +func TestMiddlewareExecutionWithLogging(t *testing.T) { + handlerStr := []byte("Logic\n") + logOutput := &bytes.Buffer{} + log.SetOutput(logOutput) // Redirect logs to the buffer for testing + defer log.SetOutput(nil) // Reset log output after the test + + handlerFunc := func(w http.ResponseWriter, e *http.Request) { + _, err := w.Write(handlerStr) + if err != nil { + t.Fatalf("Failed writing HTTP response: %v", err) + } + } + + router := NewRouter() + router.HandleFunc("/", handlerFunc) + + router.UseWithLogging("TestMiddleware", func(h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + h.ServeHTTP(w, r) + }) + }) + + rw := NewRecorder() + req := newRequest("GET", "/") + + router.ServeHTTP(rw, req) + + expectedLog := "Executing middleware: TestMiddleware\n" + if !strings.Contains(logOutput.String(), expectedLog) { + t.Fatalf("Expected log output '%s', but got '%s'", expectedLog, logOutput.String()) + } +} + + func TestMiddlewareSubrouter(t *testing.T) { router := NewRouter() router.HandleFunc("/", dummyHandler).Methods("GET")