requestid

package module
v0.3.1 Latest Latest
Warning

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

Go to latest
Published: Feb 27, 2025 License: MIT Imports: 5 Imported by: 0

README

go-requestid

CI codecov Enabled Linters Go Report Card Documentation license

Overview

github.com/akm/go-requestid is a go module for request ID. The package name is requestid. It works in the following sequence for each request processing:

  1. requestid gets request ID from HTTP request header or generates request ID
  2. requestid create a new context.Context with request ID
  3. When your application logs with slog.Logger by requestid, the request ID is added to a log record as an attribute.

Install

go get github.com/akm/go-requestid

How to use

import
import "github.com/akm/go-requestid"
Easy way
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    // Get the request ID by using requestid.Get in your http handler
    requestID := requestid.Get(r.Context())
    w.Write([]byte(fmt.Sprintf("Request ID", requestID)))
    w.WriteHeader(http.StatusOK)
})

// Wrap your http handler in order to process requestid
handlerWithRequestID := requestid.Wrap(handler)
With slog Logger

Setup logger

logger := requestid.NewLoger(slog.NewTextHandler(os.Stdout, nil))

And setup slog Handler for requestid.

See example_test.go for more details.

X-Request-ID

X-Request-ID is an unofficial HTTP request/response header. But it is supported by some services, middlewares, frameworks and libraries.

How to use X-Request-ID varies depending on the situation. X-Request-ID header can be trusted if the application runs behind a proxy such as Envoy or nginx that generates that header. X-Request-ID header is unreliable if your application communicates with the client directly or if your proxy does not modify that header. In the latter case, you should consider using X-Client-Request-ID.

ID generators

requestid provides two ID generators which work with the following packages:

  • math/rand/v2
  • crypto/rand

Documentation

Overview

Package requestid provides a middleware that sets a unique request ID for each incoming HTTP request. And it also provides a logger that logs the request ID for each incoming HTTP request.

Example
logger := requestid.NewLogger(slog.NewTextHandler(os.Stdout, testOptions))

helloHandler := func(w http.ResponseWriter, req *http.Request) {
	ctx := req.Context()
	logger.InfoContext(ctx, "Start")
	defer logger.InfoContext(ctx, "End")
	io.WriteString(w, "Hello, world!\n") //nolint:errcheck
}

ts := httptest.NewServer(
	requestid.Wrap(http.HandlerFunc(helloHandler)),
)
defer ts.Close()

resp, _ := http.Get(ts.URL) //nolint:errcheck
defer resp.Body.Close()     //nolint:govet

b, _ := io.ReadAll(resp.Body) //nolint:errcheck
fmt.Println(string(b))

// Output logs with req_id with generated ID
// level=INFO msg=Start req_id=k3pGQp5T
// level=INFO msg=End req_id=k3pGQp5T
// Hello, world!

Index

Examples

Constants

This section is empty.

Variables

View Source
var IDGeneratorDefault = IDGenErrorSuppressor(
	RandReadIDGenerator(rand.Read, defaultIDLetters, defaultIDLength),
	ErrorLoggingRecoveryFunc(slog.LevelWarn, "id-gen-error"),
)

IDGeneratorDefault is the default ID generator.

Functions

func ErrorLoggingRecoveryFunc added in v0.3.0

func ErrorLoggingRecoveryFunc(logLevel slog.Level, alt string) func(error) string

ErrorLoggingRecoveryFunc returns a recovery function that logs an error with the specified log level.

func IDGenErrorSuppressor added in v0.3.0

func IDGenErrorSuppressor(idGen func() (string, error), recoveryFunc func(error) string) func() string

IDGenErrorSuppressor returns an ID generator that suppresses errors. If an error occurs, the recover function is called with the error and the result is returned.

func NewLogger added in v0.3.0

func NewLogger(h slog.Handler) *slog.Logger

NewLogger returns a new logger with the default Namespace.

Example
handler := slog.NewTextHandler(os.Stdout, testOptions)
logger := slog.New(requestid.WrapSlogHandler(handler))

helloHandler := func(w http.ResponseWriter, req *http.Request) {
	ctx := req.Context()
	logger.InfoContext(ctx, "Start")
	defer logger.InfoContext(ctx, "End")
	io.WriteString(w, "Hello, world!\n") //nolint:errcheck
}

ts := httptest.NewServer(
	requestid.Wrap(http.HandlerFunc(helloHandler)),
)
defer ts.Close()

resp, _ := http.Get(ts.URL) //nolint:errcheck
defer resp.Body.Close()     //nolint:govet

b, _ := io.ReadAll(resp.Body) //nolint:errcheck
fmt.Println(string(b))

// Output logs with req_id with generated ID
// level=INFO msg=Start req_id=k3pGQp5T
// level=INFO msg=End req_id=k3pGQp5T
// Hello, world!

func RandIntIDGenerator added in v0.3.0

func RandIntIDGenerator(
	randInt func() int,
	letters []byte,
	length int,
) func() string

Returns a random ID generator that generates a string of length characters using randInt to generate random integers such as Int function from math/rand/v2 package.

func RandReadIDGenerator added in v0.3.0

func RandReadIDGenerator(
	randRead func(b []byte) (n int, err error),
	letters []byte,
	length int,
) func() (string, error)

Returns a random ID generator that generates a string of length characters using randRead to generate random bytes such as Read function from crypto/rand package.

func ResetDefault added in v0.3.0

func ResetDefault()

ResetDefault resets the default Namespace to the initial state.

func SetDefault added in v0.3.0

func SetDefault(ns *Middleware)

SetDefault sets the default Namespace.

func Wrap

func Wrap(next http.Handler) http.Handler

Wrap wraps the given http.Handler with the default Namespace.

func WrapSlogHandler added in v0.3.0

func WrapSlogHandler(h slog.Handler) slog.Handler

WrapSlogHandler wraps the given slog.Handler with the default Namespace.

Types

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

func (*Header) Get added in v0.3.0

func (h *Header) Get(ctx context.Context) string

func (*Header) Wrap added in v0.3.0

func (h *Header) Wrap(hdlr http.Handler) http.Handler

type HeaderOption added in v0.3.0

type HeaderOption = func(*HeaderOptions)

type HeaderOptions added in v0.3.0

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

type Middleware added in v0.3.0

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

Middleware provides a middleware for generating and setting request ID.

Example
initializeSlogctx()

mw := requestid.New(
	requestid.LogAttr("req-id"),
	requestid.Generator(func() string { return "(id-for-test)" }),
)

logger := mw.NewLogger(slog.NewTextHandler(os.Stdout, testOptions))

helloHandler := func(w http.ResponseWriter, req *http.Request) {
	ctx := req.Context()
	logger.InfoContext(ctx, "Start")
	defer logger.InfoContext(ctx, "End")
	io.WriteString(w, "Hello, world!\n") //nolint:errcheck
}

ts := httptest.NewServer(
	mw.Wrap(http.HandlerFunc(helloHandler)),
)
defer ts.Close()

resp, _ := http.Get(ts.URL) //nolint:errcheck
defer resp.Body.Close()     //nolint:govet

b, _ := io.ReadAll(resp.Body) //nolint:errcheck
fmt.Println(string(b))
Output:

level=INFO msg=Start req-id=(id-for-test)
level=INFO msg=End req-id=(id-for-test)
Hello, world!

func Default

func Default() *Middleware

Default returns the default Namespace.

func New added in v0.2.0

func New(opts ...Option) *Middleware

New returns a new Namespace from the given options.

func (*Middleware) GetNamespace added in v0.3.0

func (f *Middleware) GetNamespace() *slogctx.Namespace

GetNamespace returns the slogctx.Namespace for logging with request ID.

func (*Middleware) NewLogger added in v0.3.0

func (f *Middleware) NewLogger(h slog.Handler) *slog.Logger

NewLogger returns a new logger with the Middleware.

func (*Middleware) Wrap added in v0.3.0

func (f *Middleware) Wrap(h http.Handler) http.Handler

Wrap wraps the given http.Handler with the middleware. The middleware generates a request ID and sets it to the request context.

func (*Middleware) WrapSlogHandler added in v0.3.0

func (f *Middleware) WrapSlogHandler(h slog.Handler) slog.Handler

WrapSlogHandler wraps the given slog.Handler with the Middleware.

type Option

type Option func(o *Options)

Option represents the option for the request ID middleware and logging request ID with slog.

func Generator

func Generator(g generator) Option

Generator sets the request ID generator.

func LogAttr added in v0.3.0

func LogAttr(attr string) Option

LogAttr sets the attribute name for logging request ID with slog.

func RequestHeader

func RequestHeader(h string) Option

RequestHeader sets the request header name for the request ID. Set "X-Cloud-Trace-Context" for Google Cloud https://cloud.google.com/trace/docs/trace-context?hl=ja#http-requests Set "X-Amzn-Trace-Id" for AWS https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/application/load-balancer-request-tracing.html

func ResponseHeader

func ResponseHeader(h string) Option

ResponseHeader sets the response header name for the request ID. Skip setting the response header by setting an empty string.

func SlogwNamespace added in v0.2.0

func SlogwNamespace(ns *slogctx.Namespace) Option

SlogwNamespace sets the slogctx.Namespace for logging request ID with slog.

type Options

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

Options represents the options for the request ID middleware and logging request ID with slog.

Jump to

Keyboard shortcuts

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