Building a Logging Middleware For A Go Server
Tags: go, slog, logging, middleware
Published: 2023-09-06 14:36:32

---
title: Building a Logging Middleware For A Go Server
published: true
date: 2023-09-04 19:21:47 UTC
tags: #go #slog #logging #middleware
canonical_url: https://carlosmv.hashnode.dev/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)
    })
}

```

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"))

}

```

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](https://pkg.go.dev/net/http#HandlerFunc).

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.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1693360887633/7cfaa868-2adb-444d-9544-db6bb330f6f1.png)

```
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)
    }

}

```

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.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1693360977101/01582e06-104e-45d3-8343-bae669f446e4.png)

### 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**](https://twitter.com/Carlos_marcv), or [**LinkedIn**](https://www.linkedin.com/in/carlos-marcano-a2135a134/).

The source code is [here](https://github.com/carlosm27/slog-middleware).

### Resources

[HTTP package documentation](https://pkg.go.dev/net/http#pkg-index)

[Go REST Guide. The Standard Library](https://www.jetbrains.com/go/guide/tutorials/rest_api_series/stdlib/)

[Making and Using HTTP Middleware](https://www.alexedwards.net/blog/making-and-using-middleware)

[How To Make an HTTP Server in Go](https://www.digitalocean.com/community/tutorials/how-to-make-an-http-server-in-go)

[Slog Documentation](https://pkg.go.dev/golang.org/x/exp/slog)

[Structured Logging with slog](https://go.dev/blog/slog)

[A Comprehensive Guide to Logging in Go with Slog](https://betterstack.com/community/guides/logging/logging-in-go/)

[Logging in Go with slog](https://thedevelopercafe.com/articles/logging-in-go-with-slog-a7bb489755c2)