Skip to content

Commit

Permalink
Add logging functionality to middleware and test its execution
Browse files Browse the repository at this point in the history
  • Loading branch information
oozan committed Nov 20, 2024
1 parent db9d1d0 commit 27283cb
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 1 deletion.
36 changes: 35 additions & 1 deletion middleware.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package mux

import (
"log"
"net/http"
"strings"
)
Expand All @@ -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
Expand All @@ -20,13 +28,29 @@ 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 {
r.middlewares = append(r.middlewares, fn)
}
}

// 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)
Expand All @@ -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)
}
Expand Down
36 changes: 36 additions & 0 deletions middleware_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package mux
import (
"bytes"
"fmt"
"log"
"net/http"
"strings"
"testing"
)

Expand Down Expand Up @@ -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")
Expand Down

0 comments on commit 27283cb

Please sign in to comment.