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

transit

module
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Oct 21, 2026 License: MIT

README

transit

Shared HTTP & gRPC transport middleware for Go services: logging, OpenTelemetry, circuit breaking, rate limiting and retry, framework-free

Go Reference Pipeline Coverage phpboyscout Go toolkit

Part of the phpboyscout Go toolkit: small, framework-free Go modules extracted from go-tool-base. Docs: transit.go.phpboyscout.uk


gitlab.com/phpboyscout/go/transit is the reusable transport middleware shared by a Go service's HTTP and gRPC edges: structured request logging, OpenTelemetry instrumentation, circuit breaking, rate limiting and client-side retry, plus the resilience primitives (a circuit breaker and a keyed token-bucket store) they are built on.

It is the middleware layer extracted from go-tool-base, which consumes it behind its pkg/http and pkg/grpc server/client constructors. It is framework-free: it carries the gRPC SDK and the OpenTelemetry gRPC/HTTP contrib instrumentation (that is the middleware's job) but nothing else: no config framework, no TUI, no go-tool-base.

Design

  • Framework-free. Dependencies are the gRPC SDK, the OTel contrib instrumentation, golang.org/x/time/rate, go/redact and go/errors. A depfootprint_test.go guard forbids go-tool-base, Viper/Cobra, Charm and the cloud SDKs.
  • *slog.Logger at the seam. Middleware that logs takes a plain *slog.Logger, so nothing here depends on a logging framework.
  • Client and server, both transports. Each of http and grpc provides server handlers/interceptors and client round-trippers/interceptors, so a service and the clients it calls share one implementation of each concern.
  • Resilience is one package. The circuit breaker and the rate-limiter store live together in resilience; the HTTP and gRPC layers wrap them into transport-shaped middleware.

Install

go get gitlab.com/phpboyscout/go/transit

Quick start

package main

import (
	"log/slog"
	"net/http"

	transithttp "gitlab.com/phpboyscout/go/transit/http"
)

func main() {
	log := slog.Default()

	// OTel goes first: it puts the span in the context the logger reads,
	// so the access log carries trace_id and span_id.
	chain := transithttp.NewChain(
		transithttp.OTelMiddleware("my-service"),
		transithttp.LoggingMiddleware(log),
	)

	mux := http.NewServeMux()
	// mux.Handle("/", ...)

	_ = http.ListenAndServe(":8080", chain.Then(mux))
}

What's inside

  • resilience holds the transport-neutral primitives: a Breaker (closed → open → half-open state machine) and a keyed token-bucket Store for rate limiting.
  • http has server middleware (NewChain, LoggingMiddleware, OTelMiddleware, RateLimitMiddleware) and client round-trippers (NewRetryTransport, the ClientChain with WithCircuitBreaker / WithBearerToken / WithBasicAuth / WithRateLimit / WithRequestLogging). The circuit breaker is client-side only; there is no server-side load shedding.
  • grpc has server interceptors (NewInterceptorChain, LoggingInterceptor, RateLimitInterceptor), the OTelStatsHandler server option, the client-side CircuitBreakerInterceptor and CircuitBreakerStreamInterceptor, and the OTelClientHandler client dial option.

Compatibility

The gRPC and OpenTelemetry dependency versions are pinned and kept in lockstep with go-tool-base so a service and this module share one build graph. go.mod holds the current pins for grpc, otel and the gRPC/HTTP contrib instrumentation, and grouped Renovate updates move them together.

What it does not do

  • No distributed state. Circuit breakers and rate limiters are per-process and in-memory: a 50 rps limit across ten replicas admits 500, and a breaker trips per replica.
  • No configuration loading. Constructors take Go structs. The config types carry mapstructure/yaml/json tags so a service can decode onto them, but transit reads no files and no environment variables, and nothing can be reconfigured after construction.
  • No *http.Client constructor. TLS settings, redirect policy and timeouts are connection policy and belong to the layer above.
  • No gRPC retry. The gRPC SDK already implements it as a service config policy.
  • No metrics, no server-side circuit breaker, no timeouts, no CORS.
  • No gRPC panic recovery by default. RecoveryInterceptor is opt-in: a safety net while the bug is found, not a fix for it.

The full list with reasoning is at What transit does not do.

Documentation

Full guides, the middleware model, and a reference tier covering every config field and its default: transit.go.phpboyscout.uk. API reference: pkg.go.dev.

License

See LICENSE.

Directories

Path Synopsis
internal
logtest
Package logtest provides a minimal, stdlib-only slog capture handler for asserting on log output in tests.
Package logtest provides a minimal, stdlib-only slog capture handler for asserting on log output in tests.
Package circuitbreaker implements the transport-agnostic Closed/Open/HalfOpen state machine shared by the HTTP and gRPC client circuit breakers.
Package circuitbreaker implements the transport-agnostic Closed/Open/HalfOpen state machine shared by the HTTP and gRPC client circuit breakers.

Jump to

Keyboard shortcuts

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