httplog

package module
v1.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 8, 2024 License: MIT Imports: 9 Imported by: 0

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.

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.Log(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(ctx))

    /*
        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 %d!\n", reqID)
}
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

Documentation

Index

Constants

View Source
const (
	// ReqIDKey is a reference key to store a unique ID for each HTTP request within the context.
	// Use it to retreive the unique ID of a HTTP request in the wrapped handler from the request context.
	ReqIDKey ReqIDType = "reqid"
	// ReqIDKeyName is a reference slog key name that you can use to be consistent on how the key should be name.
	ReqIDKeyName string = "request_id"
)

Variables

View Source
var (
	// DefaultBodyMaxRead is the default maximum number of bytes a body must have to be logged.
	// Its value is copied in the New() constructor.
	DefaultBodyMaxRead int64 = 10000
	// DefaultSanitizeHeaders is the default list of headers to sanitize in the debug log.
	SanitizeHeaders = []string{"Authorization"}
)

Functions

func GetReqIDSLogAttr added in v1.2.0

func GetReqIDSLogAttr(reqCtx context.Context) slog.Attr

Types

type Logger

type Logger struct {
	// contains filtered or unexported fields
}

Logger is a HTTP request/response logging utility. It wraps a slog.Logger and provides additional functionality for logging HTTP requests and responses. Instanciate with New().

func New

func New(logger *slog.Logger) (l *Logger)

New creates a new HTTP request/response logging utility.

func (*Logger) Log

func (l *Logger) Log(next http.HandlerFunc) http.HandlerFunc

Log is a HTTP middleware that logs HTTP requests and responses. Use it to decorates your actual http handlers. Request body and response body are logged only if the wrapped slogger's level is set to LevelDebug or lower.

func (*Logger) TotalRequests added in v1.1.0

func (l *Logger) TotalRequests() uint64

TotalRequests returns the number of requests that went thru the logger. Current, yet unfulfilled, requests are also taking into account.

type ReqIDType

type ReqIDType string

ReqIDType is a custom type for storing a unique ID for each HTTP request within the request context.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL