Documentation
¶
Overview ¶
Package middleware provides optional Echo middleware helpers for EchoNext applications.
This package COMPLEMENTS Echo's built-in middleware rather than replacing it. Echo already has excellent middleware for logging, recovery, CORS, etc. These helpers add additional functionality that works alongside Echo's middleware.
Features:
- RequestID: Add correlation IDs to requests
- Metrics: Simple request metrics collection
- StructuredLogger: Enhanced logging with structured fields
- OpenTelemetry: Automatic distributed tracing and metrics
OpenTelemetry Integration ¶
The OTEL middleware provides automatic instrumentation for distributed tracing and metrics collection. It supports auto-configuration from environment variables.
Environment Variables:
- OTEL_SERVICE_NAME: Service name (default: "echonext-service")
- OTEL_SERVICE_VERSION: Service version (default: "1.0.0")
- OTEL_ENVIRONMENT: Deployment environment (default: "development")
- OTEL_EXPORTER_OTLP_ENDPOINT: OTLP collector endpoint (default: "localhost:4317")
- OTEL_INSECURE: Use insecure connection (default: "true")
- OTEL_SAMPLE_RATE: Trace sampling rate 0.0-1.0 (default: "1.0")
- OTEL_ENABLE_TRACING: Enable tracing (default: "true")
- OTEL_ENABLE_METRICS: Enable metrics (default: "true")
Example OTEL usage:
import (
"context"
"github.com/abdussamadbello/echonext"
"github.com/abdussamadbello/echonext/pkg/contrib/middleware"
)
func main() {
app := echonext.New()
// Initialize OTEL with auto-configuration from environment
shutdown, err := middleware.InitOTEL(context.Background(), middleware.DefaultOTELConfig())
if err != nil {
log.Fatal(err)
}
defer shutdown.Shutdown(context.Background())
// Add OTEL middleware for automatic request tracing
app.Use(middleware.OTELMiddleware("my-service"))
// Or with custom options
app.Use(middleware.OTELMiddleware("my-service",
middleware.WithSkipper(func(c echo.Context) bool {
return c.Path() == "/health"
}),
middleware.WithCustomAttributes(
attribute.String("custom.key", "value"),
),
))
// Access trace info in handlers
app.GET("/users", func(c echo.Context) error {
traceID := middleware.GetTraceID(c)
middleware.AddSpanEvent(c, "fetching users")
// ...
})
}
Traced HTTP Client (Outgoing Requests) ¶
The package provides an instrumented HTTP client for tracing outgoing requests. This enables full distributed tracing across service boundaries.
Creating a traced client:
// Option 1: Create new traced client
client := middleware.NewTracedHTTPClient()
// Option 2: With custom options
client := middleware.NewTracedHTTPClient(
middleware.WithClientTimeout(10 * time.Second),
middleware.WithBaseTransport(customTransport),
)
// Option 3: Wrap an existing client
client := middleware.WrapHTTPClient(existingClient)
Making traced outgoing requests in handlers:
app.GET("/users/:id", func(c echo.Context) error {
// Get context with trace info from incoming request
ctx := c.Request().Context()
// Make traced GET request - trace context is automatically propagated
resp, err := client.Get(ctx, "http://user-service/api/users")
if err != nil {
return err
}
defer resp.Body.Close()
// Or create a request manually with trace context
req, _ := middleware.NewRequestWithTrace(c, "POST", "http://other-service/api", body)
resp, err = client.Do(req)
})
The traced client automatically:
- Creates spans for each outgoing HTTP request
- Propagates trace context (traceparent, tracestate headers)
- Records HTTP method, URL, status code, and duration
- Links outgoing spans to the parent incoming request span
Helper functions:
- NewTracedHTTPClient: Create a new instrumented HTTP client
- WrapHTTPClient: Wrap an existing http.Client with tracing
- WrapTransport: Wrap an http.RoundTripper with tracing
- NewRequestWithTrace: Create http.Request with trace context from echo.Context
- HTTPClientFromContext: Get context with trace info from echo.Context
Basic Middleware Usage ¶
Example usage:
import (
"github.com/abdussamadbello/echonext"
"github.com/abdussamadbello/echonext/pkg/contrib/middleware"
echomw "github.com/labstack/echo/v4/middleware"
)
app := echonext.New()
// Use Echo's built-in middleware
app.Use(echomw.Recover())
app.Use(echomw.CORS())
// Add contrib middleware
app.Use(middleware.RequestID())
// Create metrics collector
metrics := middleware.NewMetrics()
app.Use(middleware.MetricsMiddleware(metrics))
// Expose metrics endpoint
app.GET("/metrics", middleware.MetricsHandler(metrics))
// Use structured logging with request IDs
app.Use(middleware.StructuredLogger(middleware.StructuredLoggerConfig{
CustomFields: func(c echo.Context) map[string]interface{} {
return map[string]interface{}{
"user_agent": c.Request().UserAgent(),
}
},
}))
Package middleware provides optional Echo middleware helpers for EchoNext applications. These complement Echo's built-in middleware rather than replacing them.
Index ¶
- Constants
- func AddSpanEvent(c echo.Context, name string, attrs ...attribute.KeyValue)
- func GetRequestID(c echo.Context) string
- func GetSpanID(c echo.Context) string
- func GetTraceID(c echo.Context) string
- func HTTPClientFromContext(c echo.Context) context.Context
- func InitDefaultTracedClient(opts ...TracedClientOption)
- func MetricsHandler(metrics *Metrics) echo.HandlerFunc
- func MetricsMiddleware(metrics *Metrics) echo.MiddlewareFunc
- func NewRequestWithTrace(c echo.Context, method, url string, body interface{}) (*http.Request, error)
- func OTELMiddleware(serviceName string, opts ...OTELMiddlewareOption) echo.MiddlewareFunc
- func OTELTracingMiddleware(serviceName string) echo.MiddlewareFunc
- func RecordError(c echo.Context, err error, opts ...trace.EventOption)
- func RequestID() echo.MiddlewareFunc
- func RequestIDWithConfig(config RequestIDConfig) echo.MiddlewareFunc
- func SetSpanAttributes(c echo.Context, attrs ...attribute.KeyValue)
- func SetSpanStatus(c echo.Context, code trace.SpanKind, description string)
- func StartSpan(c echo.Context, name string, opts ...trace.SpanStartOption) (context.Context, trace.Span)
- func StructuredLogger(config StructuredLoggerConfig) echo.MiddlewareFunc
- func WrapTransport(transport http.RoundTripper) http.RoundTripper
- type Metrics
- type OTELConfig
- type OTELMiddlewareOption
- type OTELShutdown
- type RequestIDConfig
- type StructuredLoggerConfig
- type TracedClientOption
- type TracedHTTPClient
- func (c *TracedHTTPClient) Do(req *http.Request) (*http.Response, error)
- func (c *TracedHTTPClient) DoWithContext(ctx context.Context, req *http.Request) (*http.Response, error)
- func (c *TracedHTTPClient) Get(ctx context.Context, url string) (*http.Response, error)
- func (c *TracedHTTPClient) Post(ctx context.Context, url string, contentType string, body interface{}) (*http.Response, error)
Constants ¶
const ( // HeaderXRequestID is the header name for request ID HeaderXRequestID = "X-Request-ID" // ContextKeyRequestID is the context key for storing request ID ContextKeyRequestID = "request_id" )
Variables ¶
This section is empty.
Functions ¶
func AddSpanEvent ¶
AddSpanEvent adds an event to the current span
func GetRequestID ¶
GetRequestID retrieves the request ID from context
func GetTraceID ¶
GetTraceID extracts the trace ID from the current request context
func HTTPClientFromContext ¶
HTTPClientFromContext creates a request with trace context from echo.Context This is a convenience function for making outgoing requests that continue the trace
func InitDefaultTracedClient ¶
func InitDefaultTracedClient(opts ...TracedClientOption)
InitDefaultTracedClient initializes the default traced HTTP client Call this after InitOTEL
func MetricsHandler ¶
func MetricsHandler(metrics *Metrics) echo.HandlerFunc
MetricsHandler returns a handler that exposes metrics
func MetricsMiddleware ¶
func MetricsMiddleware(metrics *Metrics) echo.MiddlewareFunc
MetricsMiddleware returns middleware that collects request metrics
func NewRequestWithTrace ¶
func NewRequestWithTrace(c echo.Context, method, url string, body interface{}) (*http.Request, error)
NewRequestWithTrace creates an http.Request with trace context from echo.Context
func OTELMiddleware ¶
func OTELMiddleware(serviceName string, opts ...OTELMiddlewareOption) echo.MiddlewareFunc
OTELMiddleware returns Echo middleware that instruments HTTP requests with OpenTelemetry This is the primary middleware for automatic OTEL instrumentation
func OTELTracingMiddleware ¶
func OTELTracingMiddleware(serviceName string) echo.MiddlewareFunc
OTELTracingMiddleware returns a simpler tracing-only middleware Use this if you only need distributed tracing without metrics
func RecordError ¶
func RecordError(c echo.Context, err error, opts ...trace.EventOption)
RecordError records an error in the current span
func RequestID ¶
func RequestID() echo.MiddlewareFunc
RequestID returns a middleware that adds a request ID to each request The request ID is added to the response header and stored in context
func RequestIDWithConfig ¶
func RequestIDWithConfig(config RequestIDConfig) echo.MiddlewareFunc
RequestIDWithConfig returns RequestID middleware with custom configuration
func SetSpanAttributes ¶
SetSpanAttributes adds attributes to the current span
func SetSpanStatus ¶
SetSpanStatus sets the status of the current span
func StartSpan ¶
func StartSpan(c echo.Context, name string, opts ...trace.SpanStartOption) (context.Context, trace.Span)
StartSpan starts a new child span from the request context Remember to call span.End() when done
func StructuredLogger ¶
func StructuredLogger(config StructuredLoggerConfig) echo.MiddlewareFunc
StructuredLogger returns a middleware that adds structured logging This complements Echo's built-in logger middleware
func WrapTransport ¶
func WrapTransport(transport http.RoundTripper) http.RoundTripper
WrapTransport wraps an existing http.RoundTripper with OTEL instrumentation Use this to add tracing to an existing HTTP client
Types ¶
type Metrics ¶
type Metrics struct {
TotalRequests int64
TotalErrors int64
RequestsByCode map[int]int64
TotalDuration time.Duration
// contains filtered or unexported fields
}
Metrics holds request metrics
func (*Metrics) GetMetrics ¶
GetMetrics returns current metrics (thread-safe)
type OTELConfig ¶
type OTELConfig struct {
// ServiceName is the name of the service (required)
ServiceName string
// ServiceVersion is the version of the service
ServiceVersion string
// Environment is the deployment environment (e.g., "production", "staging")
Environment string
// Endpoint is the OTLP collector endpoint (e.g., "localhost:4317")
// If empty, uses OTEL_EXPORTER_OTLP_ENDPOINT env var
Endpoint string
// Insecure disables TLS for the OTLP connection
Insecure bool
// SampleRate is the trace sampling rate (0.0 to 1.0)
// Default is 1.0 (sample everything)
SampleRate float64
// EnableTracing enables distributed tracing
// Default is true
EnableTracing bool
// EnableMetrics enables metrics collection
// Default is true
EnableMetrics bool
// Skipper defines a function to skip OTEL for certain requests
Skipper func(echo.Context) bool
// CustomAttributes adds custom attributes to all spans
CustomAttributes []attribute.KeyValue
// PropagateHeaders specifies additional headers to propagate
PropagateHeaders []string
}
OTELConfig configures OpenTelemetry instrumentation
func DefaultOTELConfig ¶
func DefaultOTELConfig() OTELConfig
DefaultOTELConfig returns a default OTEL configuration It reads from environment variables when available
type OTELMiddlewareOption ¶
type OTELMiddlewareOption func(*otelMiddlewareConfig)
OTELMiddlewareOption configures the OTEL middleware
func WithCustomAttributes ¶
func WithCustomAttributes(attrs ...attribute.KeyValue) OTELMiddlewareOption
WithCustomAttributes adds custom attributes to all spans
func WithSkipper ¶
func WithSkipper(skipper func(echo.Context) bool) OTELMiddlewareOption
WithSkipper sets a skipper function for the middleware
type OTELShutdown ¶
type OTELShutdown struct {
// contains filtered or unexported fields
}
OTELShutdown holds shutdown functions for OTEL providers
func InitOTEL ¶
func InitOTEL(ctx context.Context, cfg OTELConfig) (*OTELShutdown, error)
InitOTEL initializes OpenTelemetry with the given configuration Returns a shutdown function that should be called on application exit
type RequestIDConfig ¶
type RequestIDConfig struct {
// Skipper defines a function to skip middleware
Skipper func(c echo.Context) bool
// Generator defines a function to generate request ID
// Default: generates UUID v4
Generator func() string
// RequestIDHeader is the header name for request ID
// Default: X-Request-ID
RequestIDHeader string
// ContextKey is the key used to store request ID in context
// Default: request_id
ContextKey string
}
RequestIDConfig defines configuration for RequestID middleware
func DefaultRequestIDConfig ¶
func DefaultRequestIDConfig() RequestIDConfig
DefaultRequestIDConfig returns default configuration
type StructuredLoggerConfig ¶
type StructuredLoggerConfig struct {
// Skipper defines a function to skip middleware
Skipper middleware.Skipper
// CustomFields allows adding custom fields to log entries
CustomFields func(c echo.Context) map[string]interface{}
}
StructuredLoggerConfig extends Echo's logger with structured fields
type TracedClientOption ¶
type TracedClientOption func(*tracedClientConfig)
TracedClientOption configures the traced HTTP client
func WithBaseTransport ¶
func WithBaseTransport(transport http.RoundTripper) TracedClientOption
WithBaseTransport sets the base transport to wrap
func WithClientTimeout ¶
func WithClientTimeout(timeout time.Duration) TracedClientOption
WithClientTimeout sets the client timeout
func WithSpanNameFormatter ¶
func WithSpanNameFormatter(formatter func(operation string, r *http.Request) string) TracedClientOption
WithSpanNameFormatter sets a custom span name formatter
type TracedHTTPClient ¶
TracedHTTPClient is an HTTP client with OpenTelemetry instrumentation for tracing outgoing requests
var DefaultTracedClient *TracedHTTPClient
DefaultTracedClient is a pre-configured traced HTTP client Initialize after calling InitOTEL
func NewTracedHTTPClient ¶
func NewTracedHTTPClient(opts ...TracedClientOption) *TracedHTTPClient
NewTracedHTTPClient creates a new HTTP client with OTEL instrumentation All outgoing requests will automatically create spans and propagate trace context
func WrapHTTPClient ¶
func WrapHTTPClient(client *http.Client) *TracedHTTPClient
WrapHTTPClient wraps an existing HTTP client with OTEL instrumentation
func (*TracedHTTPClient) Do ¶
Do executes the request with tracing Use this when you have access to echo.Context to propagate the trace
func (*TracedHTTPClient) DoWithContext ¶
func (c *TracedHTTPClient) DoWithContext(ctx context.Context, req *http.Request) (*http.Response, error)
DoWithContext executes the request with the given context The context should contain the trace information (from echo.Context.Request().Context())