17 个不稳定版本 (6 个破坏性)

0.8.0 2024年2月10日
0.7.0 2023年7月21日
0.6.0 2022年2月25日
0.6.0-beta.32021年10月30日
0.1.2 2019年5月13日

#75 in Web 编程

Download history 5934/week @ 2024-03-14 5432/week @ 2024-03-21 5258/week @ 2024-03-28 6561/week @ 2024-04-04 6409/week @ 2024-04-11 7922/week @ 2024-04-18 6835/week @ 2024-04-25 6824/week @ 2024-05-02 6765/week @ 2024-05-09 7356/week @ 2024-05-16 6751/week @ 2024-05-23 7354/week @ 2024-05-30 7821/week @ 2024-06-06 7495/week @ 2024-06-13 7125/week @ 2024-06-20 6006/week @ 2024-06-27

每月29,942次下载
用于 7 crates

MIT 许可证

68KB
1K SLoC

actix-web-prom

CI Status docs.rs crates.io MIT licensed

actix-web 提供的 Prometheus 仪表。此中间件深受 sd2k/rocket_prometheus 的影响。我们跟踪相同的默认指标,并允许添加用户定义的指标。

默认情况下,跟踪两个指标(这假设命名空间为 actix_web_prom

  • actix_web_prom_http_requests_total(标签:端点、方法、状态):由 actix HttpServer 处理的 HTTP 请求总数。

  • actix_web_prom_http_requests_duration_seconds(标签:端点、方法、状态):由 actix HttpServer 处理的所有 HTTP 请求的请求持续时间。

用法

首先将 actix-web-prom 添加到您的 Cargo.toml

[dependencies]
actix-web-prom = "0.8.0"

然后实例化 Prometheus 中间件并将其传递给 .wrap()

use std::collections::HashMap;

use actix_web::{web, App, HttpResponse, HttpServer};
use actix_web_prom::{PrometheusMetrics, PrometheusMetricsBuilder};

async 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(())
}

使用上面的示例,以下几点值得注意

  • api 是指标命名空间
  • /metrics 将自动暴露(仅支持 GET 请求)并带有内容类型头 content-type: text/plain; version=0.0; charset=utf-8
  • Some(labels) 用于向指标添加固定标签;如果不需要额外的标签,则可以传递 None

调用/metrics端点将公开您的指标

$ curl https://127.0.0.1:8080/metrics
# HELP api_http_requests_duration_seconds HTTP request duration in seconds for all requests
# TYPE api_http_requests_duration_seconds histogram
api_http_requests_duration_seconds_bucket{endpoint="/metrics",label1="value1",method="GET",status="200",le="0.005"} 1
api_http_requests_duration_seconds_bucket{endpoint="/metrics",label1="value1",method="GET",status="200",le="0.01"} 1
api_http_requests_duration_seconds_bucket{endpoint="/metrics",label1="value1",method="GET",status="200",le="0.025"} 1
api_http_requests_duration_seconds_bucket{endpoint="/metrics",label1="value1",method="GET",status="200",le="0.05"} 1
api_http_requests_duration_seconds_bucket{endpoint="/metrics",label1="value1",method="GET",status="200",le="0.1"} 1
api_http_requests_duration_seconds_bucket{endpoint="/metrics",label1="value1",method="GET",status="200",le="0.25"} 1
api_http_requests_duration_seconds_bucket{endpoint="/metrics",label1="value1",method="GET",status="200",le="0.5"} 1
api_http_requests_duration_seconds_bucket{endpoint="/metrics",label1="value1",method="GET",status="200",le="1"} 1
api_http_requests_duration_seconds_bucket{endpoint="/metrics",label1="value1",method="GET",status="200",le="2.5"} 1
api_http_requests_duration_seconds_bucket{endpoint="/metrics",label1="value1",method="GET",status="200",le="5"} 1
api_http_requests_duration_seconds_bucket{endpoint="/metrics",label1="value1",method="GET",status="200",le="10"} 1
api_http_requests_duration_seconds_bucket{endpoint="/metrics",label1="value1",method="GET",status="200",le="+Inf"} 1
api_http_requests_duration_seconds_sum{endpoint="/metrics",label1="value1",method="GET",status="200"} 0.00003
api_http_requests_duration_seconds_count{endpoint="/metrics",label1="value1",method="GET",status="200"} 1
# HELP api_http_requests_total Total number of HTTP requests
# TYPE api_http_requests_total counter
api_http_requests_total{endpoint="/metrics",label1="value1",method="GET",status="200"} 1

特性

如果您启用此crate的process特性,将收集默认进程指标。默认进程指标

# HELP process_cpu_seconds_total Total user and system CPU time spent in seconds.
# TYPE process_cpu_seconds_total counter
process_cpu_seconds_total 0.22
# HELP process_max_fds Maximum number of open file descriptors.
# TYPE process_max_fds gauge
process_max_fds 1048576
# HELP process_open_fds Number of open file descriptors.
# TYPE process_open_fds gauge
process_open_fds 78
# HELP process_resident_memory_bytes Resident memory size in bytes.
# TYPE process_resident_memory_bytes gauge
process_resident_memory_bytes 17526784
# HELP process_start_time_seconds Start time of the process since unix epoch in seconds.
# TYPE process_start_time_seconds gauge
process_start_time_seconds 1628105774.92
# HELP process_virtual_memory_bytes Virtual memory size in bytes.
# TYPE process_virtual_memory_bytes gauge
process_virtual_memory_bytes 1893163008

自定义指标

您实例化PrometheusMetrics,然后使用其.registry来注册您的自定义指标(在这种情况下,我们使用一个IntCounterVec)。

然后您可以通过.data()将此计数器传递,使其在资源响应者中可用。

use actix_web::{web, App, HttpResponse, HttpServer};
use actix_web_prom::{PrometheusMetrics, PrometheusMetricsBuilder};
use prometheus::{opts, IntCounterVec};

async 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())
                .data(counter.clone())
                .service(web::resource("/health").to(health))
        })
        .bind("127.0.0.1:8080")?
        .run()
        .await?;
    Ok(())
}

自定义Registry

一些应用程序可能拥有多个actix_web::HttpServer。如果是这种情况,您可能想要使用自己的注册表

use actix_web::{web, App, HttpResponse, HttpServer};
use actix_web_prom::{PrometheusMetrics, PrometheusMetricsBuilder};
use actix_web::rt::System;
use prometheus::Registry;
use std::thread;

async fn public_handler() -> HttpResponse {
    HttpResponse::Ok().body("Everyone can see it!")
}

async fn private_handler() -> HttpResponse {
    HttpResponse::Ok().body("This can be hidden behind a firewall")
}

fn main() -> std::io::Result<()> {
    let shared_registry = Registry::new();

    let private_metrics = PrometheusMetricsBuilder::new("private_api")
        .registry(shared_registry.clone())
        .endpoint("/metrics")
        .build()
        // It is safe to unwrap when __no other app has the same namespace__
        .unwrap();

    let public_metrics = PrometheusMetricsBuilder::new("public_api")
        .registry(shared_registry.clone())
        // Metrics should not be available from the outside
        // so no endpoint is registered
        .build()
        .unwrap();

    let private_thread = thread::spawn(move || {
        let mut sys = System::new();
        let srv = HttpServer::new(move || {
            App::new()
                .wrap(private_metrics.clone())
                .service(web::resource("/test").to(private_handler))
        })
        .bind("127.0.0.1:8081")
        .unwrap()
        .run();
        sys.block_on(srv).unwrap();
    });

    let public_thread = thread::spawn(|| {
        let mut sys = System::new();
        let srv = HttpServer::new(move || {
            App::new()
                .wrap(public_metrics.clone())
                .service(web::resource("/test").to(public_handler))
        })
        .bind("127.0.0.1:8082")
        .unwrap()
        .run();
        sys.block_on(srv).unwrap();
    });

    private_thread.join().unwrap();
    public_thread.join().unwrap();
    Ok(())
}

可配置路由模式基数

假设您的应用程序中有一个路由,可以按语言和slug获取帖子GET /posts/{language}/{slug}。默认情况下,actix-web-prom将提供带有标签endpoint设置为模式/posts/{language}/{slug}的整个路由的指标。这很好,但是您无法区分语言间的指标(因为它们的集合有限)。Actix-web-prom可以配置为允许某些路由参数具有更高的基数。

为此,您需要添加一个中间件来传递一些扩展数据,特别是包含您希望保持基数的参数列表的MetricsConfig结构。

use actix_web::dev::Service;
use actix_web::HttpMessage;
use actix_web_prom::MetricsConfig;

web::resource("/posts/{language}/{slug}")
    .wrap_fn(|req, srv| {
        req.extensions_mut().insert::<MetricsConfig>(
            MetricsConfig { cardinality_keep_params: vec!["language".to_string()] }
        );
        srv.call(req)
    })
    .route(web::get().to(handler));

请参阅完整示例with_cardinality_on_params.rs

可配置指标名称

如果您想重命名默认指标,可以使用ActixMetricsConfiguration来实现。

use actix_web_prom::{PrometheusMetricsBuilder, ActixMetricsConfiguration};

PrometheusMetricsBuilder::new("api")
    .endpoint("/metrics")
    .metrics_configuration(
        ActixMetricsConfiguration::default()
        .http_requests_duration_seconds_name("my_http_request_duration"),
    )
    .build()
    .unwrap();

请参阅完整示例configuring_default_metrics.rs

依赖项

~17–30MB
~549K SLoC