### Quick-start Prometheus Setup with PrometheusMetricLayer::pair Source: https://context7.com/ptrskay3/axum-prometheus/llms.txt This example demonstrates how to quickly set up Prometheus metrics in an Axum application. It creates a Tower middleware layer and a PrometheusHandle for exposing metrics at the /metrics endpoint. The recorder is automatically installed globally with sensible defaults. ```rust use std::{net::SocketAddr, time::Duration}; use axum::{routing::get, Router}; use axum_prometheus::PrometheusMetricLayer; #[tokio::main] async fn main() { // Returns (layer, PrometheusHandle) let (prometheus_layer, metric_handle) = PrometheusMetricLayer::pair(); let app = Router::<()>::new() .route("/fast", get(|| async {{}})) .route("/slow", get(|| async {{ tokio::time::sleep(Duration::from_secs(1)).await; }})) // Expose Prometheus metrics at /metrics .route("/metrics", get(|| async move {{ metric_handle.render() }})) .layer(prometheus_layer); let listener = tokio::net::TcpListener::bind(SocketAddr::from(([127, 0, 0, 1], 3000))) .await .unwrap(); axum::serve(listener, app).await.unwrap(); } // Hitting GET /metrics produces output like: // axum_http_requests_total{method="GET",endpoint="/fast",status="200"} 3 // axum_http_requests_pending{method="GET",endpoint="/slow"} 1 // axum_http_requests_duration_seconds_bucket{method="GET",status="200",endpoint="/fast",le="0.005"} 3 // axum_http_requests_duration_seconds_sum{method="GET",status="200",endpoint="/fast"} 0.000312 // axum_http_requests_duration_seconds_count{method="GET",status="200",endpoint="/fast"} 3 ``` -------------------------------- ### Setup GenericMetricLayer with StatsD Recorder Source: https://context7.com/ptrskay3/axum-prometheus/llms.txt Use `GenericMetricLayer` with a custom exporter backend by implementing `MakeDefaultHandle`. This example shows integration with StatsD. ```rust use axum::{routing::get, Router}; use axum_prometheus::{metrics, GenericMetricLayer, MakeDefaultHandle}; use metrics_exporter_statsd::StatsdBuilder; use std::net::SocketAddr; // Define a struct that holds configuration for your exporter struct StatsdRecorder<'a> { host: &'a str, port: u16, prefix: Option<&'a str>, } // Implement MakeDefaultHandle to wire up initialization impl<'a> MakeDefaultHandle for StatsdRecorder<'a> { type Out = (); // StatsD has no render handle; return () fn make_default_handle(self) -> Self::Out { let recorder = StatsdBuilder::from(self.host, self.port) .with_queue_size(5000) .with_buffer_size(1024) .build(self.prefix) .expect("Could not create StatsDRecorder"); metrics::set_global_recorder(recorder).unwrap(); } } #[tokio::main] async fn main() { // pair_from accepts a concrete initialized struct (no Default required) let (metric_layer, _) = GenericMetricLayer::pair_from(StatsdRecorder { host: "127.0.0.1", port: 8125, prefix: Some("myapp"), }); let app = Router::new() .route("/foo", get(|| async {{}})) .route("/bar", get(|| async {{}})) .layer(metric_layer); // No /metrics endpoint needed; StatsD pushes data let listener = tokio::net::TcpListener::bind(SocketAddr::from(([127, 0, 0, 1], 3000))) .await.unwrap(); axum::serve(listener, app).await.unwrap(); } // If your struct also implements Default, you may use the shorter pair(): // #[derive(Default)] // struct StatsdRecorder { ... } // let (layer, _) = GenericMetricLayer::<_, StatsdRecorder>::pair(); ``` -------------------------------- ### Setup BaseMetricLayer with PrometheusRecorder Source: https://context7.com/ptrskay3/axum-prometheus/llms.txt Use `BaseMetricLayer` for recorder-agnostic metric emission. Manually install the recorder and configure it before setting up the layer. Ideal for push-gateway scenarios. ```rust use axum::{routing::get, Router}; use axum_prometheus::{ metrics_exporter_prometheus::PrometheusBuilder, utils::SECONDS_DURATION_BUCKETS, BaseMetricLayer, AXUM_HTTP_REQUESTS_DURATION_SECONDS, }; use axum_prometheus::metrics_exporter_prometheus::Matcher; use std::{net::SocketAddr, time::Duration}; #[tokio::main] async fn main() { // Manually install the recorder with custom configuration let metric_handle = PrometheusBuilder::new() .set_buckets_for_metric( Matcher::Full(AXUM_HTTP_REQUESTS_DURATION_SECONDS.to_string()), SECONDS_DURATION_BUCKETS, ) .unwrap() .install_recorder() .unwrap(); let app = Router::<()>::new() .route("/fast", get(|| async {{}})) .route("/slow", get(|| async {{ tokio::time::sleep(Duration::from_secs(1)).await; }})) .route("/metrics", get(|| async move {{ metric_handle.render() }})) // BaseMetricLayer::new() has no exporter opinions whatsoever .layer(BaseMetricLayer::new()); let listener = tokio::net::TcpListener::bind(SocketAddr::from(([127, 0, 0, 1], 3000))) .await.unwrap(); axum::serve(listener, app).await.unwrap(); } // For push-gateway (requires "push-gateway" feature): // PrometheusBuilder::new() // .with_push_gateway("http://127.0.0.1:9091/metrics/job/myapp", Duration::from_secs(10), None, None, true) // .expect("invalid push gateway endpoint") // .install() // .expect("failed to install recorder"); // let app = Router::new().layer(BaseMetricLayer::new()); ``` -------------------------------- ### Supply Custom Prometheus Recorder with `with_metrics_from_fn` Source: https://context7.com/ptrskay3/axum-prometheus/llms.txt Provides a closure that constructs and installs the Prometheus recorder, offering full control over histogram bucket configuration and recorder settings before the layer is finalized. This is useful for tuning latency profiles. ```rust use axum_prometheus::{ PrometheusMetricLayerBuilder, AXUM_HTTP_REQUESTS_DURATION_SECONDS, utils::SECONDS_DURATION_BUCKETS, }; use axum_prometheus::metrics_exporter_prometheus::{Matcher, PrometheusBuilder}; let (layer, handle) = PrometheusMetricLayerBuilder::new() .with_ignore_pattern("/healthz") .with_metrics_from_fn(|| { PrometheusBuilder::new() .set_buckets_for_metric( Matcher::Full(AXUM_HTTP_REQUESTS_DURATION_SECONDS.to_string()), // Custom buckets tuned for your latency profile &[0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1.0, 5.0], ) .unwrap() .install_recorder() .unwrap() }) .build_pair(); ``` -------------------------------- ### Example Prometheus Metrics Output Source: https://github.com/ptrskay3/axum-prometheus/blob/master/README.md This is an example of the metrics output that can be scraped from the /metrics endpoint. ```text axum_http_requests_total{method="GET",endpoint="/metrics",status="200"} 5 axum_http_requests_pending{method="GET",endpoint="/metrics"} 1 axum_http_requests_duration_seconds_bucket{method="GET",status="200",endpoint="/metrics",le="0.005"} 4 axum_http_requests_duration_seconds_bucket{method="GET",status="200",endpoint="/metrics",le="0.01"} 4 axum_http_requests_duration_seconds_bucket{method="GET",status="200",endpoint="/metrics",le="0.025"} 4 axum_http_requests_duration_seconds_bucket{method="GET",status="200",endpoint="/metrics",le="0.05"} 4 axum_http_requests_duration_seconds_bucket{method="GET",status="200",endpoint="/metrics",le="0.1"} 4 axum_http_requests_duration_seconds_bucket{method="GET",status="200",endpoint="/metrics",le="0.25"} 4 axum_http_requests_duration_seconds_bucket{method="GET",status="200",endpoint="/metrics",le="0.5"} 4 axum_http_requests_duration_seconds_bucket{method="GET",status="200",endpoint="/metrics",le="1"} 4 axum_http_requests_duration_seconds_bucket{method="GET",status="200",endpoint="/metrics",le="2.5"} 4 axum_http_requests_duration_seconds_bucket{method="GET",status="200",endpoint="/metrics",le="5"} 4 axum_http_requests_duration_seconds_bucket{method="GET",status="200",endpoint="/metrics",le="10"} 4 axum_http_requests_duration_seconds_bucket{method="GET",status="200",endpoint="/metrics",le="+Inf"} 4 axum_http_requests_duration_seconds_sum{method="GET",status="200",endpoint="/metrics"} 0.001997171 axum_http_requests_duration_seconds_count{method="GET",status="200",endpoint="/metrics"} 4 ``` -------------------------------- ### Configure PrometheusMetricLayerBuilder with various options Source: https://context7.com/ptrskay3/axum-prometheus/llms.txt Use `PrometheusMetricLayerBuilder` for fluent customization of metric collection. This example shows setting a prefix, ignoring specific paths, grouping parametric routes, setting endpoint label types, enabling response body size metrics, and providing a custom Prometheus builder with specific histogram buckets. ```rust use axum::{routing::get, Router}; use axum_prometheus::{ metrics_exporter_prometheus::{Matcher, PrometheusBuilder}, utils::SECONDS_DURATION_BUCKETS, EndpointLabel, PrometheusMetricLayerBuilder, AXUM_HTTP_REQUESTS_DURATION_SECONDS, }; use std::{net::SocketAddr, time::Duration}; #[tokio::main] async fn main() { let (prometheus_layer, metric_handle) = PrometheusMetricLayerBuilder::new() // Prefix all metric names: myapp_http_requests_total, etc. .with_prefix("myapp") // Never report requests to /metrics or /healthz .with_ignore_patterns(&["/metrics", "/healthz"]) // Collapse /users/{id} and /users/{id}/posts into a single "/users" label .with_group_patterns_as("/users", &["/users/{id}", "/users/{id}/posts"]) // Use matched route pattern as label (default); fall back to exact path for nested routers .with_endpoint_label_type(EndpointLabel::MatchedPath) // Enable response body size histogram (adds axum_http_response_body_size metric) .enable_response_body_size(true) // Supply a custom PrometheusBuilder with hand-picked histogram buckets .with_metrics_from_fn(|| { PrometheusBuilder::new() .set_buckets_for_metric( Matcher::Full(AXUM_HTTP_REQUESTS_DURATION_SECONDS.to_string()), SECONDS_DURATION_BUCKETS, ) .unwrap() .install_recorder() .unwrap() }) .build_pair(); let app = Router::new() .route("/fast", get(|| async {{}})) .route("/slow", get(|| async {{ tokio::time::sleep(Duration::from_secs(1)).await; }})) .route("/users/{id}", get(|| async {{}})) .route("/users/{id}/posts", get(|| async {{}})) .route("/metrics", get(|| async move {{ metric_handle.render() }})) .layer(prometheus_layer); let listener = tokio::net::TcpListener::bind(SocketAddr::from(([127, 0, 0, 1], 3000))) .await.unwrap(); axum::serve(listener, app).await.unwrap(); } ``` -------------------------------- ### Implement Custom Callbacks for Request Lifecycle Source: https://context7.com/ptrskay3/axum-prometheus/llms.txt Implement the `Callbacks` trait to create custom Tower middleware that hooks into different stages of a request's lifecycle. This example logs slow responses based on a configurable threshold. ```rust use axum_prometheus::lifecycle::{Callbacks, OnBodyChunk, FailedAt}; use bytes::Buf; use http::{HeaderMap, Request, Response}; use tower_http::classify::ClassifiedResponse; struct MyCallbacks { threshold_ms: u64, } impl Callbacks for MyCallbacks { // Data produced by `prepare` is passed into every subsequent hook type Data = std::time::Instant; fn prepare(&mut self, _request: &Request) -> Self::Data { std::time::Instant::now() } fn on_response( &mut self, response: &Response, _cls: ClassifiedResponse, data: &mut Self::Data, ) { let elapsed_ms = data.elapsed().as_millis() as u64; if elapsed_ms > self.threshold_ms { eprintln!( "Slow response: {} ms, status={}", elapsed_ms, response.status() ); } } fn on_failure( self, failed_at: FailedAt, _classification: FailureClass, data: &mut Self::Data, ) { eprintln!("Request failed at {:?} after {} ms", failed_at, data.elapsed().as_millis()); } } ``` -------------------------------- ### Instantiate Prometheus Middleware in Axum Source: https://github.com/ptrskay3/axum-prometheus/blob/master/README.md Instantiate the PrometheusMetricLayer and add it as middleware to your Axum router. The metrics endpoint must be manually defined. ```rust use std::{net::SocketAddr, time::Duration}; use axum::{routing::get, Router}; use axum_prometheus::PrometheusMetricLayer; #[tokio::main] async fn main() { let (prometheus_layer, metric_handle) = PrometheusMetricLayer::pair(); let app = Router::<()>::new() .route("/fast", get(|| async {{}})) .route( "/slow", get(|| async {{ tokio::time::sleep(Duration::from_secs(1)).await; }}) ) .route("/metrics", get(|| async move {{ metric_handle.render() }})) .layer(prometheus_layer); let listener = tokio::net::TcpListener::bind(SocketAddr::from(([127, 0, 0, 1], 3000))) .await .unwrap(); axum::serve(listener, app).await.unwrap(); } ``` -------------------------------- ### Add axum-prometheus to Cargo.toml Source: https://github.com/ptrskay3/axum-prometheus/blob/master/README.md Add the axum-prometheus crate to your project's dependencies in Cargo.toml. ```toml [dependencies] axum-prometheus = "0.10.0" ``` -------------------------------- ### Allow-list routes for metrics using allow patterns Source: https://context7.com/ptrskay3/axum-prometheus/llms.txt Use `with_allow_pattern` or `with_allow_patterns` to exclusively track requests matching specified patterns. All other requests are silently skipped. This is mutually exclusive with ignore patterns. ```rust use axum_prometheus::PrometheusMetricLayerBuilder; // Only track /api/* and /public/* routes let layer = PrometheusMetricLayerBuilder::new() .with_allow_patterns(&["/api/*path", "/public/*path"]) .build(); ``` -------------------------------- ### `MetricLayerBuilder::with_metrics_from_fn` Source: https://context7.com/ptrskay3/axum-prometheus/llms.txt Supply a custom Prometheus recorder using a closure. This provides full control over histogram bucket configuration and recorder settings before the layer is finalized. ```APIDOC ## `MetricLayerBuilder::with_metrics_from_fn` — Supply a custom Prometheus recorder Provides a closure that constructs and installs the Prometheus recorder, giving full control over histogram bucket configuration and recorder settings before the layer is finalized. ```rust use axum_prometheus::{ PrometheusMetricLayerBuilder, AXUM_HTTP_REQUESTS_DURATION_SECONDS, utils::SECONDS_DURATION_BUCKETS, }; use axum_prometheus::metrics_exporter_prometheus::{Matcher, PrometheusBuilder}; let (layer, handle) = PrometheusMetricLayerBuilder::new() .with_ignore_pattern("/healthz") .with_metrics_from_fn(|| { PrometheusBuilder::new() .set_buckets_for_metric( Matcher::Full(AXUM_HTTP_REQUESTS_DURATION_SECONDS.to_string()), // Custom buckets tuned for your latency profile &[0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1.0, 5.0], ) .unwrap() .install_recorder() .unwrap() }) .build_pair(); ``` ``` -------------------------------- ### Configure Endpoint Label Behavior with `EndpointLabel` Source: https://context7.com/ptrskay3/axum-prometheus/llms.txt Controls how the `endpoint` label is derived. Use `EndpointLabel::MatchedPathWithFallbackFn` for custom logic when the matched path is unavailable, such as in nested routers. ```rust use axum::{routing::get, Router}; use axum_prometheus::{EndpointLabel, PrometheusMetricLayerBuilder}; use std::net::SocketAddr; #[tokio::main] async fn main() { let (prometheus_layer, metric_handle) = PrometheusMetricLayerBuilder::new() // For nested routes where MatchedPath isn't available, append "_changed" to the path .with_endpoint_label_type(EndpointLabel::MatchedPathWithFallbackFn(|path| { format!("{path}_changed") })) .with_default_metrics() .build_pair(); let app = Router::new() .route("/foo/{bar}", get(|| async {{}})) .nest( "/baz", Router::new().route( "/qux/{a}", get(|| async {{ // Request to /baz/qux/2 appears as endpoint="/baz/qux/2_changed" }), ), ) .route("/metrics", get(|| async move {{ metric_handle.render() }})) .layer(prometheus_layer); let listener = tokio::net::TcpListener::bind(SocketAddr::from(([127, 0, 0, 1], 3000))) .await.unwrap(); axum::serve(listener, app).await.unwrap(); } ``` -------------------------------- ### Track Response Body Size with `enable_response_body_size` Source: https://context7.com/ptrskay3/axum-prometheus/llms.txt Enables an additional `axum_http_response_body_size` histogram that records the size of each response body in bytes. This feature has a small performance overhead due to body stream interception. ```rust use axum_prometheus::PrometheusMetricLayerBuilder; let (layer, handle) = PrometheusMetricLayerBuilder::new() .enable_response_body_size(true) .with_default_metrics() .build_pair(); // Additional metric exposed: // axum_http_response_body_size_bucket{method="GET",endpoint="/api/data",le="1024"} 5 // axum_http_response_body_size_sum{method="GET",endpoint="/api/data"} 51200 // axum_http_response_body_size_count{method="GET",endpoint="/api/data"} 5 ``` -------------------------------- ### `MetricLayerBuilder::enable_response_body_size` Source: https://context7.com/ptrskay3/axum-prometheus/llms.txt Enable tracking of response body size. This adds an `axum_http_response_body_size` histogram that records response body sizes in bytes, with a small performance overhead. ```APIDOC ## `MetricLayerBuilder::enable_response_body_size` — Track response body size Enables an additional `axum_http_response_body_size` histogram that records the size of each response body in bytes. Has a small performance overhead due to body stream interception. ```rust use axum_prometheus::PrometheusMetricLayerBuilder; let (layer, handle) = PrometheusMetricLayerBuilder::new() .enable_response_body_size(true) .with_default_metrics() .build_pair(); // Additional metric exposed: // axum_http_response_body_size_bucket{method="GET",endpoint="/api/data",le="1024"} 5 // axum_http_response_body_size_sum{method="GET",endpoint="/api/data"} 51200 // axum_http_response_body_size_count{method="GET",endpoint="/api/data"} 5 ``` ``` -------------------------------- ### Configure Metric Renaming with Cargo Config Source: https://github.com/ptrskay3/axum-prometheus/blob/master/README.md Set environment variables in .cargo/config.toml to rename default metrics. This is an alternative to using PrometheusMetricLayerBuilder::with_prefix. ```toml [env] AXUM_HTTP_REQUESTS_TOTAL = "my_app_requests_total" AXUM_HTTP_REQUESTS_DURATION_SECONDS = "my_app_requests_duration_seconds" AXUM_HTTP_REQUESTS_PENDING = "my_app_requests_pending" AXUM_HTTP_RESPONSE_BODY_SIZE = "my_app_response_body_size" ``` -------------------------------- ### Group parametric routes into a single label Source: https://context7.com/ptrskay3/axum-prometheus/llms.txt Use `with_group_patterns_as` to group multiple URI patterns under a single custom endpoint label. This prevents high-cardinality label explosion from parametric routes like `/users/1`, `/users/2`, etc. ```rust use axum_prometheus::PrometheusMetricLayerBuilder; let (layer, handle) = PrometheusMetricLayerBuilder::new() // /foo/bar and /foo/bar/baz will both appear as endpoint="/foo" .with_group_patterns_as("/foo", &["/foo/{bar}", "/foo/{bar}/{baz}"]) // all /auth/* routes collapsed to endpoint="/auth" .with_group_patterns_as("/auth", &["/auth/*path"]) .with_default_metrics() .build_pair(); // Result: requests to /foo/42 or /foo/42/extra are both reported as: // axum_http_requests_total{method="GET",endpoint="/foo",status="200"} N ``` -------------------------------- ### Configure Prometheus Recorder with Custom Buckets Source: https://context7.com/ptrskay3/axum-prometheus/llms.txt Configures the Prometheus recorder to use custom histogram buckets for the requests duration metric. Ensure the metric name matches the active name resolved at runtime. ```rust use axum_prometheus::utils::{ requests_total_name, requests_duration_name, requests_pending_name, response_body_size_name, SECONDS_DURATION_BUCKETS, }; use axum_prometheus::metrics_exporter_prometheus::{Matcher, PrometheusBuilder}; // SECONDS_DURATION_BUCKETS = [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0] let _ = PrometheusBuilder::new() .set_buckets_for_metric( // requests_duration_name() returns the active name, e.g. "myapp_http_requests_duration_seconds" // if with_prefix("myapp") was called, or "axum_http_requests_duration_seconds" otherwise. Matcher::Full(requests_duration_name().to_string()), SECONDS_DURATION_BUCKETS, ) .unwrap() .install_recorder() .unwrap(); // Runtime name resolution: println!("{}", requests_total_name()); // "axum_http_requests_total" (or custom prefix) println!("{}", requests_duration_name()); // "axum_http_requests_duration_seconds" println!("{}", requests_pending_name()); // "axum_http_requests_pending" println!("{}", response_body_size_name()); // "axum_http_response_body_size" ``` -------------------------------- ### Exclude routes from metrics using ignore patterns Source: https://context7.com/ptrskay3/axum-prometheus/llms.txt Use `with_ignore_pattern` or `with_ignore_patterns` to prevent specific URI path patterns from being recorded. These accept the same wildcard syntax as Axum's router and are mutually exclusive with allow patterns. ```rust use axum_prometheus::PrometheusMetricLayerBuilder; // Single pattern let layer = PrometheusMetricLayerBuilder::new() .with_ignore_pattern("/metrics") .build(); // Multiple patterns (equivalent to calling with_ignore_pattern repeatedly) let layer = PrometheusMetricLayerBuilder::new() .with_ignore_patterns(&["/metrics", "/healthz", "/internal/*path"]) .build(); ``` -------------------------------- ### Implement MakeDefaultHandle for StatsD Exporter Source: https://github.com/ptrskay3/axum-prometheus/blob/master/README.md Implement the `MakeDefaultHandle` trait for your custom recorder struct. This allows `axum-prometheus` to use your recorder. The `make_default_handle` method is where you set up and register your custom recorder. ```rust use metrics_exporter_statsd::StatsdBuilder; use axum_prometheus::{MakeDefaultHandle, GenericMetricLayer}; // The custom StatsD exporter struct. It may take fields as well. struct Recorder { port: u16 } // In order to use this with `axum_prometheus`, we must implement `MakeDefaultHandle`. impl MakeDefaultHandle for Recorder { // We don't need to return anything meaningful from here (unlike PrometheusHandle) // Let's just return an empty tuple. type Out = (); fn make_default_handle(self) -> Self::Out { // The regular setup for StatsD. Notice that `self` is passed in by value. let recorder = StatsdBuilder::from("127.0.0.1", self.port) .with_queue_size(5000) .with_buffer_size(1024) .build(Some("prefix")) .expect("Could not create StatsdRecorder"); metrics::set_boxed_recorder(Box::new(recorder)).unwrap(); } } fn main() { // Use `GenericMetricLayer` instead of `PrometheusMetricLayer`. // Generally `GenericMetricLayer::pair_from` is what you're looking for. // It lets you pass in a concrete initialized `Recorder`. let (metric_layer, _handle) = GenericMetricLayer::pair_from(Recorder { port: 8125 }); } ``` -------------------------------- ### Use GenericMetricLayer::pair with Default Recorder Source: https://github.com/ptrskay3/axum-prometheus/blob/master/README.md If your recorder struct implements the `Default` trait, you can use `GenericMetricLayer::pair` which will internally call `Recorder::default()` and then `make_default_handle`. ```rust use metrics_exporter_statsd::StatsdBuilder; use axum_prometheus::{MakeDefaultHandle, GenericMetricLayer}; #[derive(Default)] struct Recorder { port: u16 } impl MakeDefaultHandle for Recorder { /* .. same as before .. */ } fn main() { // This will internally call `Recorder::make_default_handle(Recorder::default)`. let (metric_layer, _handle) = GenericMetricLayer::<_, Recorder>::pair(); } ``` -------------------------------- ### `MetricLayerBuilder::with_endpoint_label_type` / `EndpointLabel` Source: https://context7.com/ptrskay3/axum-prometheus/llms.txt Configure how the `endpoint` label is derived for metrics. Options include using the matched route template, the exact URI, or a custom function for fallback scenarios. ```APIDOC ## `MetricLayerBuilder::with_endpoint_label_type` / `EndpointLabel` — Configure endpoint label behavior Controls how the `endpoint` label is derived. `EndpointLabel::MatchedPath` (default) uses Axum's matched route template; `EndpointLabel::Exact` uses the raw URI; `EndpointLabel::MatchedPathWithFallbackFn` applies a custom function when matched path is unavailable (e.g., nested routers). ```rust use axum::{routing::get, Router}; use axum_prometheus::{EndpointLabel, PrometheusMetricLayerBuilder}; use std::net::SocketAddr; #[tokio::main] async fn main() { let (prometheus_layer, metric_handle) = PrometheusMetricLayerBuilder::new() // For nested routes where MatchedPath isn't available, append "_changed" to the path .with_endpoint_label_type(EndpointLabel::MatchedPathWithFallbackFn(|path| { format!("{path}_changed") })) .with_default_metrics() .build_pair(); let app = Router::new() .route("/foo/{bar}", get(|| async {{}})) .nest( "/baz", Router::new().route( "/qux/{a}", get(|| async {{ // Request to /baz/qux/2 appears as endpoint="/baz/qux/2_changed" }), ), ) .route("/metrics", get(|| async move {{ metric_handle.render() }})) .layer(prometheus_layer); let listener = tokio::net::TcpListener::bind(SocketAddr::from(([127, 0, 0, 1], 3000))) .await.unwrap(); axum::serve(listener, app).await.unwrap(); } ``` ``` -------------------------------- ### Disable Default Features for Other Exporters Source: https://github.com/ptrskay3/axum-prometheus/blob/master/README.md To use a different metrics exporter, disable the default features for the `axum-prometheus` crate in your `Cargo.toml` file. ```toml axum-prometheus = { version = "0.10.0", default-features = false } ``` -------------------------------- ### Access Compile-Time Overridden Metric Name Constants Source: https://context7.com/ptrskay3/axum-prometheus/llms.txt After setting environment variables in `.cargo/config.toml`, these constants will resolve to the overridden values, allowing for compile-time renaming of metrics. ```rust // After setting env vars, the constants resolve to the overridden values: use axum_prometheus::{ AXUM_HTTP_REQUESTS_TOTAL, // "my_app_requests_total" AXUM_HTTP_REQUESTS_DURATION_SECONDS, // "my_app_requests_duration_seconds" AXUM_HTTP_REQUESTS_PENDING, // "my_app_requests_pending" AXUM_HTTP_RESPONSE_BODY_SIZE, // "my_app_response_body_size" }; ``` -------------------------------- ### `MetricLayerBuilder::with_prefix` Source: https://context7.com/ptrskay3/axum-prometheus/llms.txt Rename all metric names with a custom prefix. This option takes precedence over compile-time environment variables and can only be called once per process. ```APIDOC ## `MetricLayerBuilder::with_prefix` — Rename all metric names with a custom prefix Replaces the default `axum` prefix in all metric names with a custom string at runtime. Takes precedence over compile-time environment variables. Can only be called once per process. ```rust use axum_prometheus::PrometheusMetricLayerBuilder; // Metric names become: // myservice_http_requests_total // myservice_http_requests_pending // myservice_http_requests_duration_seconds // myservice_http_response_body_size (if body size enabled) let (layer, handle) = PrometheusMetricLayerBuilder::new() .with_prefix("myservice") .with_default_metrics() .build_pair(); ``` ``` -------------------------------- ### Rename Metrics with a Custom Prefix Source: https://context7.com/ptrskay3/axum-prometheus/llms.txt Replaces the default `axum` prefix in all metric names with a custom string at runtime. This option takes precedence over compile-time environment variables and can only be called once per process. ```rust use axum_prometheus::PrometheusMetricLayerBuilder; // Metric names become: // myservice_http_requests_total // myservice_http_requests_pending // myservice_http_requests_duration_seconds // myservice_http_response_body_size (if body size enabled) let (layer, handle) = PrometheusMetricLayerBuilder::new() .with_prefix("myservice") .with_default_metrics() .build_pair(); ``` -------------------------------- ### Override Default Metric Names at Compile Time Source: https://context7.com/ptrskay3/axum-prometheus/llms.txt Customize the default metric names by setting environment variables in your `.cargo/config.toml` file. These overrides are resolved at compile time. ```toml # .cargo/config.toml [env] AXUM_HTTP_REQUESTS_TOTAL = "my_app_requests_total" AXUM_HTTP_REQUESTS_DURATION_SECONDS = "my_app_requests_duration_seconds" AXUM_HTTP_REQUESTS_PENDING = "my_app_requests_pending" AXUM_HTTP_RESPONSE_BODY_SIZE = "my_app_response_body_size" ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.