Categorygithub.com/hekmon/httplog/v2
package
2.0.2
Repository: https://github.com/hekmon/httplog.git
Documentation: pkg.go.dev

# Packages

No description provided by the author

# README

HTTP Log

Go Reference

HTTP Log provides a HTTP middleware that use the provided structured logger to log HTTP requests and response within a Go HTTP server. While many web frameworks already provide this, this lightweight package is useful for those who want to stick to a KISS codebase and the standard library as muxer/server.

The middleware will:

  • Pre
    • Generate a uniq request ID used by all log calls within the middleware
    • Logs basic info about the incoming request (host, method, URI, client IP & headers).
    • If logger level is set to Debug it will also dump and log the body up to a certain size while still making the body available thru the original request.
    • Prepare a response catcher (available as a separate package if you want to use only this part)
      • This custom catcher also automatically flush data if the content type is a streaming type, see the catcherflusher sub package for more informations.
    • Pass the uniq request ID within the request context
  • Call the next middleware
  • Post
    • Log the status code (and status) and duration of the request.
    • If logger level is set to Debug it will also dump and log the response body up to a certain size.

Install

go get github.com/hekmon/httplog/v2

Example

package main

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

    "github.com/hekmon/httplog"
)

var (
    // Global logger
    logger *slog.Logger
)

func main() {
    // Initiate a structured main logger.
    logger = slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
        Level: slog.LevelDebug,
    }))

    // Create the httplog middleware
    httplogger := httplog.New(logger)

    // Setup mux and server
    http.HandleFunc("/", httplogger.LogFunc(ActualHandlerFunc))

    // Start the server
    if err := http.ListenAndServe(":80", nil); err != nil {
        panic(err)
    }
}

func ActualHandlerFunc(w http.ResponseWriter, r *http.Request) {
    // Setup a local logger that will always print out the request ID
    logger := logger.With(httplog.GetReqIDSLogAttr(r.Context()))

    /*
        do stuff
    */

    // Let's use our local logger
    logger.Debug("this message will have the request id automatically attached to it")

    fmt.Fprintf(w, "Hello request %v!\n", r.Context().Value(httplog.ReqIDKey))
}

Output

Client

$ curl http://127.0.0.1
Hello request 1!
$ curl http://127.0.0.1
Hello request 2!
$

Server

time=2024-06-04T11:14:56.524+02:00 level=INFO msg="HTTP request received" request_id=1 host=127.0.0.1 method=GET URI=/ client=127.0.0.1:64983 headers="map[Accept:[*/*] User-Agent:[curl/8.6.0]]"
time=2024-06-04T11:14:56.525+02:00 level=DEBUG msg="this message will have the request id automatically attached to it" request_id=1
time=2024-06-04T11:14:56.525+02:00 level=INFO msg="HTTP request handled" request_id=1 response_code=200 response_status=OK response_time=452.417µs
time=2024-06-04T11:14:56.525+02:00 level=DEBUG msg="HTTP response" request_id=1 response_body="Hello request 1!\n" response_size=17
time=2024-06-04T11:14:58.761+02:00 level=INFO msg="HTTP request received" request_id=2 host=127.0.0.1 method=GET URI=/ client=127.0.0.1:64984 headers="map[Accept:[*/*] User-Agent:[curl/8.6.0]]"
time=2024-06-04T11:14:58.761+02:00 level=DEBUG msg="this message will have the request id automatically attached to it" request_id=2
time=2024-06-04T11:14:58.761+02:00 level=INFO msg="HTTP request handled" request_id=2 response_code=200 response_status=OK response_time=103.541µs
time=2024-06-04T11:14:58.761+02:00 level=DEBUG msg="HTTP response" request_id=2 response_body="Hello request 2!\n" response_size=17