DEV Community

Carlos Armando Marcano Vargas
Carlos Armando Marcano Vargas

Posted on • Originally published at carlosmv.hashnode.dev on

Building a Logging Middleware For A Go Server

In this article, we are going to build a Logging middleware for a Go server built with the package net/http from the standard library. And using the new slog library added to Go 1.21 to create the logging feature.

This article is for people who are starting to learn the Go programming language and want to log the requests made to their servers.

main.go

func LoggingMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        logger := slog.New(slog.NewTextHandler(os.Stdout, nil))
        logger.Info("Request Info",
            slog.String("method", r.Method),
            slog.String("path", r.RequestURI),
            slog.String("host", r.Host),
        )
        next.ServeHTTP(w, r)
    })
}

Enter fullscreen mode Exit fullscreen mode

In the main.go file, we create a LoggingMiddleware() function, it has an http.Handler as an argument and returns an http.Handler.

Inside the function, we create an instance of the Slog to create the TextHandler.

Then, we create a logger to show the information about the request made to the server, like the HTTP method, the path and the host.

package main

import (
    "log/slog"
    "net/http"
    "os"
)

func main() {
    mux := http.NewServeMux()
    port := ":8000"

    finalHandler := http.HandlerFunc(homeHandler)
    mux.Handle("/", LoggingMiddleware(finalHandler))

    slog.Info("Listening on ", "port", port)

    err := http.ListenAndServe(port, mux)
    if err != nil {
        slog.Warn("Problem starting the server", "error", err)
    }

}

func homeHandler(w http.ResponseWriter, r *http.Request) {

    w.Write([]byte("Hello this is a home page"))

}

Enter fullscreen mode Exit fullscreen mode

In the main() function, we create an instance of the ServeMux(), we define in the port variable the port where the server is going to listen.

Then, we create the finalHandler variable to wrap the homeHandler() handler into the HandlerFunc(), which is an adapter to allows the use of ordinary functions as HTTP handlers.

For more information about the HandlerFunc type, visit the documentation.

Next, we call the mux.handle() function, to register the handler for the pattern "/", but instead of just registering the finalHandler, we wrap it into the LoggingMiddleware. Every request to the path "/" will call the LoggingMiddleware before the finalHandler() .

Finally, we create a logger to show info about the port where the server will listen and pass the port and mux variable to http.ListenAndServe() function to start the server.

We start the server and navigate to localhost:8000/. We should receive the following output in the terminal.


func helloHandler(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("Helloooo"))
}

func main() {
    mux := http.NewServeMux()
    port := ":8000"

    logger := slog.Default()
    finalHandler := http.HandlerFunc(homeHandler)

    mux.Handle("/", LoggingMiddleware(finalHandler))
    mux.Handle("/hello", LoggingMiddleware(http.HandlerFunc(helloHandler)))

    logger.Info("Listening on ", "port", port)

    err := http.ListenAndServe(port, mux)
    if err != nil {
        logger.Error("Problem starting the server", "error", err)
    }

}

Enter fullscreen mode Exit fullscreen mode

In the code snippet above we just add another handler, but instead of creating a new variable to apply the http.HandlerFunc type, we applied directly in the mux.handle() function.

Conclusion

I wrote this article just for education purposes if anyone wants to create their logging middleware using the new Slog package.

Many web frameworks in Go have a logging middleware like Chi-router or Gorilla. Also, Gin has a logging feature integrated.

Thank you for taking the time to read this article.

If you have any recommendations about other packages, architectures, how to improve my code, my English, or anything; please leave a comment or contact me through Twitter, or LinkedIn.

The source code is here.

Resources

HTTP package documentation

Go REST Guide. The Standard Library

Making and Using HTTP Middleware

How To Make an HTTP Server in Go

Slog Documentation

Structured Logging with slog

A Comprehensive Guide to Logging in Go with Slog

Logging in Go with slog

Top comments (0)