Expand description

Prometheus instrumentation for actix-web. This middleware is inspired by and forked from actix-web-prom. By default three metrics are tracked (this assumes the namespace actix_web_prometheus):

  • actix_web_prometheus_incoming_requests (labels: endpoint, method, status): the total number of HTTP requests handled by the actix HttpServer.
  • actix_web_prometheus_response_code (labels: endpoint, method, statuscode, type): Response codes of all HTTP requests handled by the actix HttpServer.
  • actix_web_prometheus_response_time (labels: endpoint, method, status): Total the request duration of all HTTP requests handled by the actix HttpServer.

Usage

First add actix-web-prom to your Cargo.toml:

[dependencies]
actix-web-prometheus = "0.1.0-beta.8"

You then instantiate the prometheus middleware and pass it to .wrap():

use std::collections::HashMap;
use actix_web::{web, App, HttpResponse, HttpServer};
use actix_web_prometheus::{PrometheusMetrics, PrometheusMetricsBuilder};
fn health() -> HttpResponse {
    HttpResponse::Ok().finish()
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
    let mut labels = HashMap::new();
    labels.insert("label1".to_string(), "value1".to_string());
    let prometheus = PrometheusMetricsBuilder::new("api")
        .endpoint("/metrics")
        .const_labels(labels)
        .build()
        .unwrap();
        HttpServer::new(move || {
            App::new()
                .wrap(prometheus.clone())
                .service(web::resource("/health").to(health))
        })
        .bind("127.0.0.1:8080")?
        .run()
        .await?;
    Ok(())
}

Using the above as an example, a few things are worth mentioning:

  • api is the metrics namespace
  • /metrics will be auto exposed (GET requests only) with Content-Type header content-type: text/plain; version=0.0.4; charset=utf-8
  • Some(labels) is used to add fixed labels to the metrics; None can be passed instead if no additional labels are necessary. A call to the /metrics endpoint will expose your metrics:
$ curl http://localhost:8080/metrics
actix_web_prometheus_incoming_requests{endpoint="/metrics",method="GET",status="200"} 23
actix_web_prometheus_response_code{endpoint="/metrics",method="GET",statuscode="200",type="200"} 23
actix_web_prometheus_response_time_bucket{endpoint="/metrics",method="GET",status="200",le="0.005"} 23
actix_web_prometheus_response_time_bucket{endpoint="/metrics",method="GET",status="200",le="0.01"} 23
actix_web_prometheus_response_time_bucket{endpoint="/metrics",method="GET",status="200",le="0.025"} 23
actix_web_prometheus_response_time_bucket{endpoint="/metrics",method="GET",status="200",le="0.05"} 23
actix_web_prometheus_response_time_bucket{endpoint="/metrics",method="GET",status="200",le="0.1"} 23
actix_web_prometheus_response_time_bucket{endpoint="/metrics",method="GET",status="200",le="0.25"} 23
actix_web_prometheus_response_time_bucket{endpoint="/metrics",method="GET",status="200",le="0.5"} 23
actix_web_prometheus_response_time_bucket{endpoint="/metrics",method="GET",status="200",le="1"} 23
actix_web_prometheus_response_time_bucket{endpoint="/metrics",method="GET",status="200",le="2.5"} 23
actix_web_prometheus_response_time_bucket{endpoint="/metrics",method="GET",status="200",le="5"} 23
actix_web_prometheus_response_time_bucket{endpoint="/metrics",method="GET",status="200",le="10"} 23
actix_web_prometheus_response_time_bucket{endpoint="/metrics",method="GET",status="200",le="+Inf"} 23
actix_web_prometheus_response_time_sum{endpoint="/metrics",method="GET",status="200"} 0.00410981
actix_web_prometheus_response_time_count{endpoint="/metrics",method="GET",status="200"} 23

Features

If you enable process feature of this crate, default process metrics will also be collected. Default process metrics

process_cpu_seconds_total 0.22
process_max_fds 1048576
process_open_fds 78
process_resident_memory_bytes 17526784
process_start_time_seconds 1628105774.92
process_virtual_memory_bytes 1893163008

Custom metrics

You instantiate PrometheusMetrics and then use its .registry to register your custom metric (in this case, we use a IntCounterVec). Then you can pass this counter through .data() to have it available within the resource responder.

use actix_web::{web, App, HttpResponse, HttpServer};
use actix_web_prometheus::{PrometheusMetrics, PrometheusMetricsBuilder};
use prometheus::{opts, IntCounterVec};
fn health(counter: web::Data<IntCounterVec>) -> HttpResponse {
    counter.with_label_values(&["endpoint", "method", "status"]).inc();
    HttpResponse::Ok().finish()
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
    let prometheus = PrometheusMetricsBuilder::new("api")
        .endpoint("/metrics")
        .build()
        .unwrap();
    let counter_opts = opts!("counter", "some random counter").namespace("api");
    let counter = IntCounterVec::new(counter_opts, &["endpoint", "method", "status"]).unwrap();
    prometheus
        .registry
        .register(Box::new(counter.clone()))
        .unwrap();
        HttpServer::new(move || {
            App::new()
                .wrap(prometheus.clone())
                .app_data(web::Data::new(counter.clone()))
                .service(web::resource("/health").to(health))
        })
        .bind("127.0.0.1:8080")?
        .run()
        .await?;
    Ok(())
}

Re-exports

pub use error::Error;

Modules

Module which defines error which can happen within this crate

Structs

Builder to create new PrometheusMetrics struct.HistogramVec