How to use gorilla middleware handlers for all requests?

I want to use the handlers specified here for logging everything.

This is what I have:

r := mux.NewRouter() s := r.PathPrefix("/api/v1").Subrouter() s.HandleFunc("/abc", handler.GetAbc).Methods("GET") s.HandleFunc("/xyz", handler.GetXyz).Methods("GET") 

I want to use the logging middleware but I don't want to repeat it in every single line, as they show in github:

r.Handle("/admin", handlers.LoggingHandler(os.Stdout, http.HandlerFunc(ShowAdminDashboard))) r.HandleFunc("/", ShowIndex) 

Is there a way to just pass the general logging middleware to r, and everything that passes the r router will pass by the middleware first?

4 Answers

Use a middleware:

func loggingMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Do stuff here log.Println(r.RequestURI) // Call the next handler, which can be another middleware in the chain, or the final handler. next.ServeHTTP(w, r) }) } r.Use(loggingMiddleware) 

Here's the doc:

1

I wrapped the LoggingHandler with a middleware function

func loggingMiddleware(next http.Handler) http.Handler { return handlers.LoggingHandler(os.Stdout, next) } r.Use(loggingMiddleware) 

This is the approach I took and this worked best for me.

 type Route struct { Name string Method string Pattern string Secure bool HandlerFunc http.HandlerFunc } type Routes []Route var routes = Routes{ Route{ Name: "Docs", Method: "GET", Pattern: "/v2/docs", HandlerFunc: Docs, }, Route{ Name: "GetUserByName", Method: "GET", Pattern: "/v2/user/{username}", HandlerFunc: user.GetUserByName, Secure: true, }, } func NewRouter() *mux.Router { router := mux.NewRouter().StrictSlash(true) router.NotFoundHandler = http.HandlerFunc(notFound) router.MethodNotAllowedHandler = http.HandlerFunc(notAllowed) for _, route := range routes { var handler http.Handler if route.Secure { handler = AuthMiddleware(route.HandlerFunc) } else { handler = route.HandlerFunc } handler = Logger(os.Stderr, handler) router. Methods(route.Method). Path(route.Pattern). Name(route.Name). Handler(handler) } return router } func ApplicationRecovery(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer func() { if err := recover(); err != nil { fmt.Fprintln(os.Stderr, "Recovered from application error occurred") _, _ = fmt.Fprintln(os.Stderr, err) w.WriteHeader(http.StatusInternalServerError) })) } }() next.ServeHTTP(w, r) }) } func Middleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Add("Content-Type", "application/json") next.ServeHTTP(w, r) }) } func AuthMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { //TODO: Add authentication log.Println("Authentication required") next.ServeHTTP(w, r) }) } func Logger(inner http.Handler, name string) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { start := time.Now() log.Printf( "%s %s %s %s", r.Method, r.RequestURI, name, time.Since(start), ) inner.ServeHTTP(w, r) }) } func notFound(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNotFound) } func notAllowed(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusMethodNotAllowed) } func main() { srv := http.Server{ Addr: "0.0.0.0:8080", Handler: ApplicationRecovery(Middleware(NewRouter())), ReadTimeout: 15 * time.Second, WriteTimeout: 15 * time.Second, } log.Fatal(srv.ListenAndServe()) } 

This way I'm covering my bases:

  • panic during the request execution
  • a common middleware that set the response headers for all request
  • a logging middleware for all request logging
  • an authentication middleware for secure resources

Console logs of the handler in action

2020/06/23 22:28:48 Server started 2020/06/23 22:28:51 Authentication required 2020/06/23 22:28:51 Begin x-api-key validation 2020/06/23 22:28:51 x-api-key matched user: 1 2020/06/23 22:28:51 User 1 successfully accessed secure resourecs ::1 - - [23/Jun/2020:22:28:51 +0100] "DELETE /v2/user/john?permanent=true HTTP/1.1" 403 85 
3

More compact solution

r.Use(func(next http.Handler) http.Handler { return handlers.LoggingHandler(os.Stdout, next) }) 

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

You Might Also Like