### Getting Started with Prometheus and Standard Go Handler Source: https://github.com/slok/go-http-metrics/blob/master/Readme.md A basic example demonstrating how to use the go-http-metrics middleware with Prometheus as the metrics recorder and the standard Go http.Handler. Ensure Prometheus client libraries are imported. ```go package main import ( "log" "net/http" "github.com/prometheus/client_golang/prometheus/promhttp" metrics "github.com/slok/go-http-metrics/metrics/prometheus" "github.com/slok/go-http-metrics/middleware" middlewarestd "github.com/slok/go-http-metrics/middleware/std" ) func main() { // Create our middleware. mdlw := middleware.New(middleware.Config{ Recorder: metrics.NewRecorder(metrics.Config{}), }) // Our handler. h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) w.Write([]byte("hello world!")) }) h = middlewarestd.Handler("", mdlw, h) // Serve metrics. log.Printf("serving metrics at: %s", ":9090") go http.ListenAndServe(":9090", promhttp.Handler()) // Serve our handler. log.Printf("listening at: %s", ":8080") if err := http.ListenAndServe(":8080", h); err != nil { log.Panicf("error while serving: %s", err) } } ``` -------------------------------- ### Custom Prometheus Duration Buckets Source: https://github.com/slok/go-http-metrics/blob/master/Readme.md Adjust the buckets for the request duration histogram metric to measure different ranges of time. The example shows buckets from 500ms to 320s. It is not advised to use more than 10 buckets. ```go Buckets: []float64{.5, 1, 2.5, 5, 10, 20, 40, 80, 160, 320} ``` -------------------------------- ### Core Middleware API - middleware.New Source: https://context7.com/slok/go-http-metrics/llms.txt Demonstrates how to create a new middleware instance using `middleware.New` with a default Prometheus recorder and wrap a standard Go HTTP handler. ```APIDOC ## POST /api/users ### Description Creates a new middleware instance with the specified configuration. The middleware wraps HTTP handlers to measure request metrics including duration, response size, and inflight requests. ### Method POST ### Endpoint /api/users ### Parameters #### Path Parameters - **param1** (type) - Required/Optional - Description #### Query Parameters - **param1** (type) - Required/Optional - Description #### Request Body - **field1** (type) - Required/Optional - Description ### Request Example ```json { "example": "request body" } ``` ### Response #### Success Response (200) - **field1** (type) - Description #### Response Example ```json { "example": "response body" } ``` ``` -------------------------------- ### Provide Middleware for Chi, Gorilla, Alice Source: https://context7.com/slok/go-http-metrics/llms.txt Provides a middleware function compatible with frameworks using the `func(http.Handler) http.Handler` pattern, such as Chi, Gorilla, and Alice. Apply middleware globally using HandlerProvider. ```go package main import ( "net/http" "github.com/go-chi/chi/v5" "github.com/prometheus/client_golang/prometheus/promhttp" metrics "github.com/slok/go-http-metrics/metrics/prometheus" "github.com/slok/go-http-metrics/middleware" "github.com/slok/go-http-metrics/middleware/std" ) func main() { mdlw := middleware.New(middleware.Config{ Recorder: metrics.NewRecorder(metrics.Config{}), }) r := chi.NewRouter() // Apply middleware globally using HandlerProvider r.Use(std.HandlerProvider("", mdlw)) r.Get("/", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) w.Write([]byte("Home")) }) r.Get("/users/{id}", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) w.Write([]byte("User")) }) r.Get("/posts/{id}", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) w.Write([]byte("Post")) }) go http.ListenAndServe(":9090", promhttp.Handler()) http.ListenAndServe(":8080", r) } ``` -------------------------------- ### Configure Middleware Options Source: https://context7.com/slok/go-http-metrics/llms.txt Configures middleware with custom options like service identifier, grouped status codes, and ignored paths. Use this to reduce cardinality and tailor metric collection. ```go package main import ( "net/http" metrics "github.com/slok/go-http-metrics/metrics/prometheus" "github.com/slok/go-http-metrics/middleware" "github.com/slok/go-http-metrics/middleware/std" ) func main() { mdlw := middleware.New(middleware.Config{ // Recorder backend (required for actual metrics) Recorder: metrics.NewRecorder(metrics.Config{}), // Service identifier for multi-service apps Service: "api-server", // Group status codes as 2xx, 3xx, 4xx, 5xx (reduces cardinality) GroupedStatus: true, // Disable response size measurement DisableMeasureSize: false, // Disable inflight request counting DisableMeasureInflight: false, // Paths to exclude from duration/size metrics (still counted in inflight) IgnoredPaths: []string{"/health", "/ready"}, }) mux := http.NewServeMux() mux.HandleFunc("/api/users", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) }) mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) }) h := std.Handler("", mdlw, mux) http.ListenAndServe(":8080", h) } ``` -------------------------------- ### Implement custom metrics recorder Source: https://context7.com/slok/go-http-metrics/llms.txt Create a custom metrics backend by implementing the metrics.Recorder interface. This allows for custom logging or integration with non-Prometheus systems. ```go package main import ( "context" "fmt" "net/http" "sync/atomic" "time" "github.com/slok/go-http-metrics/metrics" "github.com/slok/go-http-metrics/middleware" "github.com/slok/go-http-metrics/middleware/std" ) // CustomRecorder implements metrics.Recorder for custom logging type CustomRecorder struct { totalRequests int64 inflightCount int64 } func (r *CustomRecorder) ObserveHTTPRequestDuration(ctx context.Context, props metrics.HTTPReqProperties, duration time.Duration) { atomic.AddInt64(&r.totalRequests, 1) fmt.Printf("[METRIC] handler=%s method=%s code=%s duration=%v total=%d\n", props.ID, props.Method, props.Code, duration, atomic.LoadInt64(&r.totalRequests)) } func (r *CustomRecorder) ObserveHTTPResponseSize(ctx context.Context, props metrics.HTTPReqProperties, sizeBytes int64) { fmt.Printf("[METRIC] handler=%s method=%s code=%s size=%d bytes\n", props.ID, props.Method, props.Code, sizeBytes) } func (r *CustomRecorder) AddInflightRequests(ctx context.Context, props metrics.HTTPProperties, quantity int) { current := atomic.AddInt64(&r.inflightCount, int64(quantity)) fmt.Printf("[METRIC] handler=%s inflight=%d (delta=%d)\n", props.ID, current, quantity) } func main() { recorder := &CustomRecorder{} mdlw := middleware.New(middleware.Config{ Recorder: recorder, Service: "my-service", }) handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { time.Sleep(100 * time.Millisecond) // Simulate work w.WriteHeader(http.StatusOK) w.Write([]byte("Hello from custom recorder!")) }) h := std.Handler("/api/hello", mdlw, handler) http.ListenAndServe(":8080", h) } // Output for each request: // [METRIC] handler=/api/hello inflight=1 (delta=1) // [METRIC] handler=/api/hello inflight=0 (delta=-1) // [METRIC] handler=/api/hello method=GET code=200 duration=100.123ms total=1 // [METRIC] handler=/api/hello method=GET code=200 size=27 bytes ``` -------------------------------- ### Wrap fasthttp handler with metrics middleware Source: https://context7.com/slok/go-http-metrics/llms.txt Use the fasthttpmiddleware to instrument fasthttp handlers. Requires the prometheus recorder and middleware configuration. ```go package main import ( "log" "net/http" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/valyala/fasthttp" metrics "github.com/slok/go-http-metrics/metrics/prometheus" "github.com/slok/go-http-metrics/middleware" fasthttpmiddleware "github.com/slok/go-http-metrics/middleware/fasthttp" ) func main() { mdlw := middleware.New(middleware.Config{ Recorder: metrics.NewRecorder(metrics.Config{}), }) handler := func(ctx *fasthttp.RequestCtx) { switch string(ctx.Path()) { case "/": ctx.SetStatusCode(fasthttp.StatusOK) ctx.WriteString("Hello World") case "/users": ctx.SetStatusCode(fasthttp.StatusOK) ctx.WriteString("Users list") default: ctx.SetStatusCode(fasthttp.StatusNotFound) ctx.WriteString("Not Found") } } // Wrap handler with metrics middleware h := fasthttpmiddleware.Handler("/", mdlw, handler) // Serve Prometheus metrics on standard HTTP go http.ListenAndServe(":9090", promhttp.Handler()) log.Println("Server listening on :8080") fasthttp.ListenAndServe(":8080", h) } ``` -------------------------------- ### opencensus.NewRecorder Source: https://context7.com/slok/go-http-metrics/llms.txt Creates an OpenCensus metrics recorder that implements the metrics.Recorder interface, supporting various exporters. ```APIDOC ## opencensus.NewRecorder ### Description Creates an OpenCensus metrics recorder that implements the metrics.Recorder interface. Supports multiple exporters including Prometheus, Stackdriver, and others. ### Parameters #### Request Body - **Config** (struct) - Required - Configuration object containing: - **DurationBuckets** ([]float64) - Optional - Custom duration buckets. - **SizeBuckets** ([]float64) - Optional - Custom size buckets. - **HandlerIDLabel** (string) - Optional - Custom label name for handler ID. - **StatusCodeLabel** (string) - Optional - Custom label name for status code. - **MethodLabel** (string) - Optional - Custom label name for HTTP method. - **ServiceLabel** (string) - Optional - Custom label name for service. ``` -------------------------------- ### Create New Middleware Instance Source: https://context7.com/slok/go-http-metrics/llms.txt Creates a new middleware instance with default Prometheus recorder. Wraps HTTP handlers to measure request metrics. Ensure Prometheus metrics handler is served separately. ```go package main import ( "log" "net/http" "github.com/prometheus/client_golang/prometheus/promhttp" metrics "github.com/slok/go-http-metrics/metrics/prometheus" "github.com/slok/go-http-metrics/middleware" "github.com/slok/go-http-metrics/middleware/std" ) func main() { // Create middleware with default Prometheus recorder mdlw := middleware.New(middleware.Config{ Recorder: metrics.NewRecorder(metrics.Config{}), }) // Create handler handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) w.Write([]byte("Hello, World!")) }) // Wrap handler with metrics middleware h := std.Handler("/api/hello", mdlw, handler) // Serve metrics on separate port go http.ListenAndServe(":9090", promhttp.Handler()) // Start main server log.Println("Server listening on :8080") http.ListenAndServe(":8080", h) } ``` -------------------------------- ### Create Prometheus Recorder Source: https://context7.com/slok/go-http-metrics/llms.txt Creates a Prometheus metrics recorder with custom configuration, including a custom registry, metric name prefix, and custom bucket configurations for duration and response size. It also allows for custom label names. This is useful for integrating with Prometheus monitoring systems. ```go package main import ( "net/http" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" metrics "github.com/slok/go-http-metrics/metrics/prometheus" "github.com/slok/go-http-metrics/middleware" "github.com/slok/go-http-metrics/middleware/std" ) func main() { // Create custom Prometheus registry reg := prometheus.NewRegistry() // Create recorder with custom configuration recorder := metrics.NewRecorder(metrics.Config{ // Custom registry (default: prometheus.DefaultRegisterer) Registry: reg, // Metric name prefix (e.g., myapp_http_request_duration_seconds) Prefix: "myapp", // Custom duration histogram buckets (default: Prometheus default buckets) DurationBuckets: []float64{0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1, 2.5, 5, 10}, // Custom response size buckets (default: exponential 100B to 1GB) SizeBuckets: []float64{100, 1000, 10000, 100000, 1000000}, // Custom label names HandlerIDLabel: "handler", StatusCodeLabel: "code", MethodLabel: "method", ServiceLabel: "service", }) mdlw := middleware.New(middleware.Config{ Recorder: recorder, GroupedStatus: true, }) mux := http.NewServeMux() mux.Handle("/", std.Handler("/", mdlw, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) }))) mux.Handle("/users/:id", std.Handler("/users/:id", mdlw, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) }))) // Serve metrics with custom registry go http.ListenAndServe(":9090", promhttp.HandlerFor(reg, promhttp.HandlerOpts{})) http.ListenAndServe(":8080", mux) } // Metrics exposed: // - myapp_http_request_duration_seconds{service,handler,method,code} // - myapp_http_response_size_bytes{service,handler,method,code} // - myapp_http_requests_inflight{service,handler} ``` -------------------------------- ### Gin Middleware for HTTP Metrics Source: https://context7.com/slok/go-http-metrics/llms.txt Returns a Gin-compatible middleware function for measuring HTTP metrics. Apply this middleware globally to your Gin engine. ```go package main import ( "net/http" "github.com/gin-gonic/gin" "github.com/prometheus/client_golang/prometheus/promhttp" metrics "github.com/slok/go-http-metrics/metrics/prometheus" "github.com/slok/go-http-metrics/middleware" ginmiddleware "github.com/slok/go-http-metrics/middleware/gin" ) func main() { mdlw := middleware.New(middleware.Config{ Recorder: metrics.NewRecorder(metrics.Config{}), }) engine := gin.New() engine.Use(gin.Recovery()) // Apply metrics middleware globally engine.Use(ginmiddleware.Handler("", mdlw)) engine.GET("/", func(c *gin.Context) { c.String(http.StatusOK, "Hello World") }) engine.GET("/users/:id", func(c *gin.Context) { id := c.Param("id") c.JSON(http.StatusOK, gin.H{"id": id}) }) engine.POST("/users", func(c *gin.Context) { c.JSON(http.StatusCreated, gin.H{"status": "created"}) }) engine.GET("/error", func(c *gin.Context) { c.String(http.StatusInternalServerError, "error") }) go http.ListenAndServe(":9090", promhttp.Handler()) engine.Run(":8080") } ``` -------------------------------- ### Echo Middleware for HTTP Metrics Source: https://context7.com/slok/go-http-metrics/llms.txt Returns an Echo-compatible middleware function for measuring HTTP metrics. Apply this middleware globally to your Echo instance. ```go package main import ( "net/http" "github.com/labstack/echo/v4" "github.com/prometheus/client_golang/prometheus/promhttp" metrics "github.com/slok/go-http-metrics/metrics/prometheus" "github.com/slok/go-http-metrics/middleware" echomiddleware "github.com/slok/go-http-metrics/middleware/echo" ) func main() { mdlw := middleware.New(middleware.Config{ Recorder: metrics.NewRecorder(metrics.Config{}), }) e := echo.New() // Apply metrics middleware globally e.Use(echomiddleware.Handler("", mdlw)) e.GET("/", func(c echo.Context) error { return c.String(http.StatusOK, "Hello World") }) e.GET("/users/:id", func(c echo.Context) error { id := c.Param("id") return c.JSON(http.StatusOK, map[string]string{"id": id}) }) e.POST("/users", func(c echo.Context) error { return c.JSON(http.StatusCreated, map[string]string{"status": "created"}) }) go http.ListenAndServe(":9090", promhttp.Handler()) e.Start(":8080") } ``` -------------------------------- ### prometheus.NewRecorder Source: https://context7.com/slok/go-http-metrics/llms.txt Creates a Prometheus metrics recorder that implements the metrics.Recorder interface to track HTTP request metrics. ```APIDOC ## prometheus.NewRecorder ### Description Creates a Prometheus metrics recorder that implements the metrics.Recorder interface. Records HTTP request duration, response size, and inflight requests as Prometheus metrics. ### Parameters #### Request Body - **Config** (struct) - Required - Configuration object containing: - **Registry** (prometheus.Registry) - Optional - Custom Prometheus registry. - **Prefix** (string) - Optional - Metric name prefix. - **DurationBuckets** ([]float64) - Optional - Custom duration histogram buckets. - **SizeBuckets** ([]float64) - Optional - Custom response size buckets. - **HandlerIDLabel** (string) - Optional - Custom label name for handler ID. - **StatusCodeLabel** (string) - Optional - Custom label name for status code. - **MethodLabel** (string) - Optional - Custom label name for HTTP method. - **ServiceLabel** (string) - Optional - Custom label name for service. ``` -------------------------------- ### Core Middleware API - middleware.Config Source: https://context7.com/slok/go-http-metrics/llms.txt Illustrates the configuration options available for the middleware factory, including setting a custom service identifier, grouping status codes, and disabling specific measurements. ```APIDOC ## POST /api/users ### Description Configuration options for the middleware factory. Allows customization of metric recording behavior, status code grouping, and selective metric collection. ### Method POST ### Endpoint /api/users ### Parameters #### Path Parameters - **param1** (type) - Required/Optional - Description #### Query Parameters - **param1** (type) - Required/Optional - Description #### Request Body - **field1** (type) - Required/Optional - Description ### Request Example ```json { "example": "request body" } ``` ### Response #### Success Response (200) - **field1** (type) - Description #### Response Example ```json { "example": "response body" } ``` ``` -------------------------------- ### Create OpenCensus Recorder Source: https://context7.com/slok/go-http-metrics/llms.txt Creates an OpenCensus metrics recorder with custom duration and size buckets, and custom label names. It requires an OpenCensus Prometheus exporter to be registered and serves metrics via the exporter. This is suitable for applications using OpenCensus for metrics collection. ```go package main import ( "log" "net/http" ocprometheus "contrib.go.opencensus.io/exporter/prometheus" "go.opencensus.io/stats/view" ocmetrics "github.com/slok/go-http-metrics/metrics/opencensus" "github.com/slok/go-http-metrics/middleware" "github.com/slok/go-http-metrics/middleware/std" ) func main() { // Create OpenCensus Prometheus exporter exporter, err := ocprometheus.NewExporter(ocprometheus.Options{}) if err != nil { log.Fatalf("failed to create exporter: %v", err) } view.RegisterExporter(exporter) // Create OpenCensus recorder recorder, err := ocmetrics.NewRecorder(ocmetrics.Config{ // Custom duration buckets DurationBuckets: []float64{0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10}, // Custom size buckets SizeBuckets: []float64{100, 1000, 10000, 100000, 1000000, 10000000}, // Custom label names HandlerIDLabel: "handler", StatusCodeLabel: "code", MethodLabel: "method", ServiceLabel: "service", }) if err != nil { log.Fatalf("failed to create recorder: %v", err) } mdlw := middleware.New(middleware.Config{ Recorder: recorder, }) mux := http.NewServeMux() mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) }) h := std.Handler("", mdlw, mux) // Serve metrics via OpenCensus exporter go http.ListenAndServe(":9090", exporter) http.ListenAndServe(":8080", h) } ``` -------------------------------- ### Wrap Standard http.Handler with Metrics Source: https://context7.com/slok/go-http-metrics/llms.txt Wraps a standard http.Handler with metrics collection. Use this for Go standard library or frameworks supporting http.Handler. Consider using predefined handler IDs for low cardinality. ```go package main import ( "net/http" "github.com/prometheus/client_golang/prometheus/promhttp" metrics "github.com/slok/go-http-metrics/metrics/prometheus" "github.com/slok/go-http-metrics/middleware" "github.com/slok/go-http-metrics/middleware/std" ) func main() { mdlw := middleware.New(middleware.Config{ Recorder: metrics.NewRecorder(metrics.Config{}), }) mux := http.NewServeMux() // Empty handlerID: uses URL path as handler label (high cardinality warning) mux.Handle("/dynamic/", std.Handler("", mdlw, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) }))) // Predefined handlerID: low cardinality, recommended for dynamic paths mux.Handle("/users/", std.Handler("/users/:id", mdlw, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) }))) go http.ListenAndServe(":9090", promhttp.Handler()) http.ListenAndServe(":8080", mux) } ``` -------------------------------- ### Prometheus Prefix Option Source: https://github.com/slok/go-http-metrics/blob/master/Readme.md Configure a prefix for all exposed Prometheus metrics. This is useful for namespacing metrics, especially in applications with multiple services. ```go Prefix: "batman" ``` -------------------------------- ### Common PromQL queries for HTTP metrics Source: https://context7.com/slok/go-http-metrics/llms.txt Essential Prometheus queries for monitoring request rates, latency, error rates, and inflight requests. ```promql # Request rate by handler (requests per second) sum(rate(http_request_duration_seconds_count[5m])) by (handler) # Error rate (5xx responses) rate(http_request_duration_seconds_count{code=~"5.."}[5m]) # Error percentage by handler sum(rate(http_request_duration_seconds_count{code=~"5.."}[5m])) by (handler) / sum(rate(http_request_duration_seconds_count[5m])) by (handler) * 100 # 99th percentile latency (service-wide) histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m])) # 90th percentile latency by handler histogram_quantile(0.90, sum(rate(http_request_duration_seconds_bucket[5m])) by (handler, le) ) # Average request duration by handler sum(rate(http_request_duration_seconds_sum[5m])) by (handler) / sum(rate(http_request_duration_seconds_count[5m])) by (handler) # Current inflight requests by handler http_requests_inflight # Average response size by handler sum(rate(http_response_size_bytes_sum[5m])) by (handler) / sum(rate(http_response_size_bytes_count[5m])) by (handler) # Request rate by method and status code sum(rate(http_request_duration_seconds_count[5m])) by (method, code) ``` -------------------------------- ### Custom Handler ID with Predefined Path Source: https://github.com/slok/go-http-metrics/blob/master/Readme.md Pass a predefined handler ID to keep cardinality low, ensuring that similar dynamic URLs share the same handler label. This is recommended for URLs with parameters. ```go mdwr.Handler("/p/:userID/dashboard/:page", h) ``` -------------------------------- ### Custom Handler ID with Dynamic Paths Source: https://github.com/slok/go-http-metrics/blob/master/Readme.md Use an empty string for handlerID when URLs are dynamic or have parameters to automatically derive the handler label from the URL path. This method is only recommended when URLs are fixed and do not contain parameters. ```go mdwr.Handler("", h) ``` -------------------------------- ### Prometheus Query: Request Rate by Handler Source: https://github.com/slok/go-http-metrics/blob/master/Readme.md This Prometheus query calculates the request rate per handler over a 30-second window using the http_request_duration_seconds_count metric. ```text sum( rate(http_request_duration_seconds_count[30s]) ) by (handler) ``` -------------------------------- ### Prometheus Query: 90th Percentile per Handler Source: https://github.com/slok/go-http-metrics/blob/master/Readme.md This Prometheus query calculates the 90th percentile of request durations for each handler over a 10-minute window, aggregating buckets by handler. ```text histogram_quantile(0.9, sum( rate(http_request_duration_seconds_bucket[10m]) ) by (handler, le) ) ``` -------------------------------- ### Prometheus Query: 99th Percentile of Service Requests Source: https://github.com/slok/go-http-metrics/blob/master/Readme.md This Prometheus query calculates the 99th percentile of request durations for the entire service over a 5-minute window using histogram_quantile. ```text histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m])) ``` -------------------------------- ### Prometheus Query: Request Error Rate Source: https://github.com/slok/go-http-metrics/blob/master/Readme.md This Prometheus query calculates the error rate for HTTP requests over a 30-second window, specifically targeting responses with status codes in the 5xx range. ```text rate(http_request_duration_seconds_count{code=~"5.."}[30s]) ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.