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 ¶
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