9个版本 (重大更改)

0.7.0 2024年5月30日
0.6.0 2023年12月25日
0.5.0 2023年9月6日
0.4.1 2023年4月25日
0.1.0 2020年4月11日

#44调试

Download history 357/week @ 2024-05-03 488/week @ 2024-05-10 626/week @ 2024-05-17 656/week @ 2024-05-24 961/week @ 2024-05-31 1200/week @ 2024-06-07 965/week @ 2024-06-14 899/week @ 2024-06-21 1203/week @ 2024-06-28 1302/week @ 2024-07-05 1186/week @ 2024-07-12 894/week @ 2024-07-19 1328/week @ 2024-07-26 1520/week @ 2024-08-02 1894/week @ 2024-08-09 2011/week @ 2024-08-16

每月下载 6,940
3 个crate中使用(通过metrics-dashboard

MIT/Apache

140KB
1.5K SLoC

metrics + prometheus = ❤️

crates.io Rust 1.72+ Unsafe Forbidden
CI Rust docs

API文档 | 变更日志

prometheus后端用于metrics crate.

动机

Rust在度量收集方面至少有两个生态系统

  • 一个是基于prometheus crate,专注于将度量数据发送到Prometheus(或其替代品,如VictoriaMetrics)。它提供了大量的Prometheus特定功能,并对度量数据进行严格验证,以满足Prometheus使用的格式。
  • 另一个是基于metrics crate,更为通用,针对更广泛的范围,而不仅仅是Prometheus。它提供了一个方便且易于使用的封装,允许以与通过log/tracing生态系统(甚至支持tracing::Span作为度量标签)处理日志和跟踪非常相似的方式与度量数据一起工作。

结果,一些crate使用prometheus crate来提供它们的指标,而另一些crate则使用metrics crate。此外,prometheusmetrics crate的设计差异很大,使得它们的组合成为一个非平凡的挑战。这个crate旨在弥合这一差距,允许在一个项目中结合prometheusmetrics生态系统。

替代方案

如果你没有义务直接处理prometheus crate或通过使用它的第三方crate,考虑使用metrics-exporter-prometheus crate,它为metrics界面提供了简单的Prometheus后端,而不引入整个prometheus crate的机制。

概述

这个crate提供了一个metrics::Recorder实现,允许通过metrics界面使用prometheus::Registry

它有3种口味,允许根据使用情况选择最小的性能开销

不支持任何prometheus指标,因为metrics包仅包含其中的一些。这是metrics包的指标如何映射到prometheus指标的方式。

当通过metrics外观指定任何标签时,使用prometheus::MetricVec类型。

为了满足metrics::Recorder的要求,在注册后可以随时更改指标描述(prometheus包不暗示并允许这样做),使用Describable包装器,允许arc-swap描述。

// By default `prometheus::default_registry()` is used.
let recorder = metrics_prometheus::install();

// Either use `metrics` crate interfaces.
metrics::counter!("count", "whose" => "mine", "kind" => "owned").increment(1);
metrics::counter!("count", "whose" => "mine", "kind" => "ref").increment(1);
metrics::counter!("count", "kind" => "owned", "whose" => "dummy").increment(1);

// Or construct and provide `prometheus` metrics directly.
recorder.register_metric(prometheus::Gauge::new("value", "help")?);

let report = prometheus::TextEncoder::new()
    .encode_to_string(&prometheus::default_registry().gather())?;
assert_eq!(
    report.trim(),
    r#"
## HELP count count
## TYPE count counter
count{kind="owned",whose="dummy"} 1
count{kind="owned",whose="mine"} 1
count{kind="ref",whose="mine"} 1
## HELP value help
## TYPE value gauge
value 0
    "#
    .trim(),
);

// Metrics can be described anytime after being registered in
// `prometheus::Registry`.
metrics::describe_counter!("count", "Example of counter.");
metrics::describe_gauge!("value", "Example of gauge.");

let report = prometheus::TextEncoder::new()
    .encode_to_string(&recorder.registry().gather())?;
assert_eq!(
    report.trim(),
    r#"
## HELP count Example of counter.
## TYPE count counter
count{kind="owned",whose="dummy"} 1
count{kind="owned",whose="mine"} 1
count{kind="ref",whose="mine"} 1
## HELP value Example of gauge.
## TYPE value gauge
value 0
    "#
    .trim(),
);

// Description can be changed multiple times and anytime.
metrics::describe_counter!("count", "Another description.");

// Even before a metric is registered in `prometheus::Registry`.
metrics::describe_counter!("another", "Yet another counter.");
metrics::counter!("another").increment(1);

let report = prometheus::TextEncoder::new()
    .encode_to_string(&recorder.registry().gather())?;
assert_eq!(
    report.trim(),
    r#"
## HELP another Yet another counter.
## TYPE another counter
another 1
## HELP count Another description.
## TYPE count counter
count{kind="owned",whose="dummy"} 1
count{kind="owned",whose="mine"} 1
count{kind="ref",whose="mine"} 1
## HELP value Example of gauge.
## TYPE value gauge
value 0
    "#
    .trim(),
);
# Ok::<_, prometheus::Error>(())

限制

由于 prometheus 包对指标格式进行了非常严格的验证,并非通过 metrics 门面表示的所有内容都可以放入 prometheus::Registry 中,否则会导致发出 prometheus::Error

  • 指标名称不能使用点进行命名空间(并且应遵循 Prometheus 格式)。

    metrics_prometheus::install();
    
    // panics: 'queries.count' is not a valid metric name
    metrics::counter!("queries.count").increment(1);
    
  • 相同的指标应始终使用相同的标签集。

    metrics_prometheus::install();
    
    metrics::counter!("count").increment(1);
    // panics: Inconsistent label cardinality, expect 0 label values, but got 1
    metrics::counter!("count", "whose" => "mine").increment(1);
    
    metrics_prometheus::install();
    
    metrics::counter!("count", "kind" => "owned").increment(1);
    // panics: label name kind missing in label map
    metrics::counter!("count", "whose" => "mine").increment(1);
    
    metrics_prometheus::install();
    
    metrics::counter!("count", "kind" => "owned").increment(1);
    // panics: Inconsistent label cardinality, expect 1 label values, but got 2
    metrics::counter!("count", "kind" => "ref", "whose" => "mine").increment(1);
    
  • 相同的名称不能用于不同类型的指标。

    metrics_prometheus::install();
    
    metrics::counter!("count").increment(1);
    // panics: Duplicate metrics collector registration attempted
    metrics::gauge!("count").increment(1.0);
    
  • 直接在 prometheus::Registry 中注册的任何指标,而不使用 metrics 或此包接口,将无法通过 metrics 门面使用,并会导致发出 prometheus::Error

    metrics_prometheus::install();
    
    prometheus::default_registry()
        .register(Box::new(prometheus::Gauge::new("value", "help")?))?;
    
    // panics: Duplicate metrics collector registration attempted
    metrics::gauge!("value").increment(4.5);
    # Ok::<_, prometheus::Error>(())
    
  • 不支持 metrics::Unit,因为 Prometheus 没有这个概念。通过 metrics 宏指定它们将不会产生任何效果。

prometheus::Error 处理

由于 metrics::Recorder 在其 API 中没有暴露任何错误,发出的 prometheus::Error 可以被转换为 panic,或者简单地静默忽略,返回一个无操作的指标(例如,参见 metrics::Counter::noop())。

这可以通过在构建 Recorder 时提供一个 failure::Strategy 来调整。

use metrics_prometheus::failure::strategy;

metrics_prometheus::Recorder::builder()
    .with_failure_strategy(strategy::NoOp)
    .build_and_install();

// `prometheus::Error` is ignored inside.
metrics::counter!("invalid.name").increment(1);

let stats = prometheus::default_registry().gather();
assert_eq!(stats.len(), 0);

默认的 failure::StrategyPanicInDebugNoOpInRelease。有关其他可用的 failure::Strategy,请参阅 failure::strategy 模块,或通过实现 failure::Strategy 特性来提供自己的一个。

许可协议

版权所有 © 2022-2024 Instrumentisto 团队,https://github.com/instrumentisto

根据您的选择,该项目受Apache License, Version 2.0MIT许可的许可。

除非您明确表示,否则您根据Apache-2.0许可提交给本项目以包含在内的任何贡献,都将按照上述方式双重许可,不附加任何额外条款或条件。

依赖项

约3–9MB
约74K SLoC