fdhttp

package
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Sep 24, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package fdhttp connects net/http to FiveDock. On the server side every request gets its own hub, so its scope and trace never mix with another request's, runs inside an http.server transaction named after its route, and a panicking handler is reported before the response goes out:

handler := fdhttp.New(fdhttp.Options{})
http.ListenAndServe(":8080", handler.Handle(mux))

On the client side Transport records http.client spans and passes the trace on:

client := &http.Client{Transport: fdhttp.NewTransport(nil)}

Inside a handler, fivedock.GetHubFromContext(r.Context()) is the request's hub and fivedock.SpanFromContext(r.Context()) its transaction. Like the fivedock package, fdhttp uses only the standard library.

Index

Examples

Constants

View Source
const (
	OpServer = "http.server"
	OpClient = "http.client"
	Origin   = fivedock.SpanOrigin("auto.http.fdhttp")
)

Operations and origin of the spans this package records.

View Source
const MechanismType = "http.server"

MechanismType is how a panic caught by this package is labeled.

Variables

This section is empty.

Functions

func SetRoute

func SetRoute(ctx context.Context, pattern string)

SetRoute names the route that serves the request of ctx, for routers fdhttp cannot read on its own, such as chi:

fdhttp.SetRoute(r.Context(), chi.RouteContext(r.Context()).RoutePattern())

pattern is a template such as "/orders/{id}"; the request's method is added unless pattern starts with one. It renames the request's transaction at once, with source "route", and names errors captured from then on. Outside a request served by Handle it does nothing.

Example
package main

import (
	"net/http"

	"fivedock.dev/go/fdhttp"
)

func main() {
	// For a router fdhttp cannot read, such as chi: after the router
	// matched, hand it the route template.
	router := http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) {
		fdhttp.SetRoute(r.Context(), "/projects/{id}") // chi.RouteContext(r.Context()).RoutePattern()
	})
	_ = fdhttp.New(fdhttp.Options{}).Handle(router)
}

Types

type Handler

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

Handler wraps http.Handlers with FiveDock's per-request hub, transaction and panic reporting.

func New

func New(options Options) *Handler

New returns a Handler configured by options.

func (*Handler) Handle

func (h *Handler) Handle(next http.Handler) http.Handler

Handle wraps next. Each request gets a clone of the hub on its context (or of the current hub) carrying the request and the trace continued from its traceparent and baggage headers (or a new one), and runs inside an http.server transaction on that trace, sent when tracing is enabled.

The transaction is named after the route when the handler returns: the pattern an http.ServeMux matched (r.Pattern, which the mux sets on the request fdhttp passes it), or one given to SetRoute, else the method and path with source "url". Errors captured during the request carry the same name. Its status and http.response.status_code come from the response.

Requests whose context is marked with fivedock.SuppressContext pass through untouched.

Example
package main

import (
	"log"
	"net/http"

	fivedock "fivedock.dev/go"
	"fivedock.dev/go/fdhttp"
)

func main() {
	mux := http.NewServeMux()
	mux.HandleFunc("GET /orders/{id}", func(w http.ResponseWriter, r *http.Request) {
		// r.Context() carries the request's hub and its http.server
		// transaction, named "GET /orders/{id}" once the handler returns.
		fivedock.GetHubFromContext(r.Context()).Scope().SetTag("order", r.PathValue("id"))
		w.WriteHeader(http.StatusNoContent)
	})
	handler := fdhttp.New(fdhttp.Options{})
	log.Fatal(http.ListenAndServe(":8080", handler.Handle(mux)))
}

func (*Handler) HandleFunc

func (h *Handler) HandleFunc(next http.HandlerFunc) http.HandlerFunc

HandleFunc is Handle for a handler function.

type Options

type Options struct {
	// Repanic panics again after reporting, for an outer recovery layer
	// (or net/http itself) to deal with. Without it the handler answers 500
	// when nothing was written yet.
	Repanic bool
	// WaitForDelivery waits, up to Timeout, for a reported panic to be
	// delivered before the handler returns: for processes that may exit
	// right after.
	WaitForDelivery bool
	// Timeout bounds WaitForDelivery: 0 means 2 s.
	Timeout time.Duration
}

Options configures a Handler.

type Transport

type Transport struct {
	// Base sends the requests: nil means http.DefaultTransport.
	Base http.RoundTripper
}

Transport is an http.RoundTripper that traces outgoing requests. With a span running on the request's context it records an http.client span around the round trip, and it adds traceparent and baggage headers to requests whose URL matches ClientOptions.TracePropagationTargets (every URL by default), so the service called continues the trace (§6.2). The hub on the request's context, or the current hub, decides.

Requests whose context is marked with fivedock.SuppressContext pass through untouched. The SDK marks its own, so a Transport never traces the SDK's deliveries, even when it is ClientOptions.HTTPTransport.

The span ends when the response headers arrive, as with sentry-go: the time spent reading the body is not part of it.

func NewTransport

func NewTransport(base http.RoundTripper) *Transport

NewTransport returns a Transport that sends through base (nil means http.DefaultTransport).

Example
package main

import (
	"context"
	"net/http"

	fivedock "fivedock.dev/go"
	"fivedock.dev/go/fdhttp"
)

func main() {
	client := &http.Client{Transport: fdhttp.NewTransport(nil)}

	tx := fivedock.StartTransaction(context.Background(), "sync stock")
	defer tx.Finish()
	req, _ := http.NewRequestWithContext(tx.Context(), http.MethodGet, "https://inventory.internal/stock/42", nil)
	if resp, err := client.Do(req); err == nil { // an http.client span, and traceparent and baggage on the request
		_ = resp.Body.Close()
	}
}

func (*Transport) CloseIdleConnections

func (t *Transport) CloseIdleConnections()

CloseIdleConnections passes through to Base, so http.Client's works.

func (*Transport) RoundTrip

func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error)

RoundTrip sends req, traced as the type describes. It does not modify req: headers go on a clone.

Source Files

  • fdhttp.go
  • transport.go

Jump to

Keyboard shortcuts

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