Help us shape the future of Go! Take the 2026 Go Developer Survey

requestlog

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Nov 1, 2026 License: MIT Imports: 4 Imported by: 0

README

Request Logging

arkoren.dev/core/http/middleware/requestlog logs returned handler errors and observed HTTP 5xx responses. The concrete path and raw error can contain identifiers or secrets. Choose appropriate redaction, access controls, and retention before sending records to a log destination or telemetry exporter.

With an existing router named routes and your *slog.Logger named logger, install logging before recovery so recovered panics reach the logger as returned errors:

routes.Use(
	requestlog.Middleware(func(log *requestlog.Builder) {
		log.Logger(logger)
	}),
	router.Recover(),
)

Omitting the logger resolves slog.Default() for each request. To correlate records with traces, put telemetry middleware before logging and use its telemetry-enabled logger.

A successful connection hijack does not produce a failure record. If the handler returns an error after hijacking, status is 0 when no final HTTP status passed through the writer. Bytes written directly to the caller-owned connection are not observable through HTTP response hooks; the middleware does not infer 500.

See the Request Logging guide for telemetry correlation and logger placement.

Documentation

Overview

Package requestlog logs returned handler errors and observed 5xx responses to a slog.Logger. Records contain the concrete path and raw error, which can contain personal identifiers or secrets; select appropriate access controls, retention, and redaction before exporting these logs.

Install logging before recovery so recovered panics are observable errors:

routes := router.New()
routes.Use(requestlog.Middleware(), router.Recover())

Successful hijacks are not failures. Status zero means no final status was observed, for example when a handler returns an error after taking ownership of the connection. Direct writes to that connection are outside HTTP hooks.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Middleware

func Middleware(configure ...BuilderFunc) router.Middleware

Middleware logs requests that return an error or respond with a 5xx status. Each record carries the method, path, status, and error. It logs with the request context, so the telemetry log handler adds the trace and span IDs when the telemetry middleware ran earlier. Without a logger it uses slog.Default. A successful hijack is not a failure. A returned error after hijacking is logged with status zero when no final HTTP status passed through the writer; bytes written directly to the owned connection cannot be observed here. Paths and raw errors can contain sensitive values. Use an appropriate logger and export policy, and place router.Recover inside this middleware to observe handler panics as returned errors.

Example:

r.Use(requestlog.Middleware(func(log *requestlog.Builder) {
	log.Logger(logger)
}))

Types

type Builder

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

Builder configures Middleware before publication. Callbacks run directly once, synchronously in order on one fresh draft; nil entries panic. Retaining the draft cannot change published settings. Methods return the same draft.

Example:

r := router.New()
r.Use(requestlog.Middleware(func(log *requestlog.Builder) {
	log.Logger(slog.Default())
}))

func (*Builder) Logger

func (log *Builder) Logger(logger *slog.Logger) *Builder

Logger receives the failed-request records. Nil uses slog.Default, resolved for every request so later slog.SetDefault calls take effect.

The setting replaces the previous value on this construction draft. Publication keeps independent settings; functions and services stay shared.

Example:

r := router.New()
r.Use(requestlog.Middleware(func(log *requestlog.Builder) {
	log.Logger(slog.Default())
}))

type BuilderFunc

type BuilderFunc = func(*Builder)

BuilderFunc edits the construction draft shared by Middleware's callbacks. Callbacks run synchronously in order; a supplied nil callback panics, while expanding a nil or empty callback slice makes no edits. The logger remains a shared service, but retaining the draft cannot replace the published logger.

Example:

configure := requestlog.BuilderFunc(func(log *requestlog.Builder) {
	log.Logger(slog.Default())
})
routes := router.New()
routes.Use(requestlog.Middleware(configure))
Example

ExampleBuilderFunc selects a logger and observes the absence of a failure record for a successful request, without opening a listener.

package main

import (
	"bytes"
	"fmt"
	"log/slog"
	"net/http"
	"net/http/httptest"

	"arkoren.dev/core/http/middleware/requestlog"
	"arkoren.dev/core/http/router"
)

func main() {
	var output bytes.Buffer
	configure := requestlog.BuilderFunc(func(log *requestlog.Builder) {
		log.Logger(slog.New(slog.NewTextHandler(&output, nil)))
	})

	routes := router.New()
	routes.Use(requestlog.Middleware(configure))
	routes.Get("/", func(http.ResponseWriter, *http.Request) error {
		return nil
	})
	routes.ServeHTTP(httptest.NewRecorder(), httptest.NewRequest(http.MethodGet, "/", nil))
	fmt.Println(output.Len())
}
Output:
0

Jump to

Keyboard shortcuts

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