use once_cell::sync::Lazy;
pub use prometheus::{
self, core::MetricVec, core::MetricVecBuilder, exponential_buckets, linear_buckets, Counter,
Encoder, Gauge, GaugeVec, Histogram, HistogramOpts, HistogramVec, IntCounter, IntCounterVec,
IntGauge, IntGaugeVec, Opts, Result, TextEncoder,
};
use std::collections::HashSet;
pub fn gather() -> Vec<prometheus::proto::MetricFamily> {
prometheus::gather()
}
pub fn try_create_int_counter(name: &str, help: &str) -> Result<IntCounter> {
check_metric_unc_prefix(name)?;
let opts = Opts::new(name, help);
let counter = IntCounter::with_opts(opts)?;
prometheus::register(Box::new(counter.clone()))?;
Ok(counter)
}
pub fn try_create_int_counter_vec(
name: &str,
help: &str,
labels: &[&str],
) -> Result<IntCounterVec> {
check_metric_unc_prefix(name)?;
let opts = Opts::new(name, help);
let counter = IntCounterVec::new(opts, labels)?;
prometheus::register(Box::new(counter.clone()))?;
Ok(counter)
}
pub fn try_create_counter(name: &str, help: &str) -> Result<Counter> {
check_metric_unc_prefix(name)?;
let opts = Opts::new(name, help);
let counter = Counter::with_opts(opts)?;
prometheus::register(Box::new(counter.clone()))?;
Ok(counter)
}
pub fn try_create_int_gauge(name: &str, help: &str) -> Result<IntGauge> {
check_metric_unc_prefix(name)?;
let opts = Opts::new(name, help);
let gauge = IntGauge::with_opts(opts)?;
prometheus::register(Box::new(gauge.clone()))?;
Ok(gauge)
}
pub fn try_create_int_gauge_vec(name: &str, help: &str, labels: &[&str]) -> Result<IntGaugeVec> {
check_metric_unc_prefix(name)?;
let opts = Opts::new(name, help);
let gauge = IntGaugeVec::new(opts, labels)?;
prometheus::register(Box::new(gauge.clone()))?;
Ok(gauge)
}
pub fn try_create_gauge(name: &str, help: &str) -> Result<Gauge> {
check_metric_unc_prefix(name)?;
let opts = Opts::new(name, help);
let gauge = Gauge::with_opts(opts)?;
prometheus::register(Box::new(gauge.clone()))?;
Ok(gauge)
}
pub fn try_create_gauge_vec(name: &str, help: &str, labels: &[&str]) -> Result<GaugeVec> {
check_metric_unc_prefix(name)?;
let opts = Opts::new(name, help);
let gauge = GaugeVec::new(opts, labels)?;
prometheus::register(Box::new(gauge.clone()))?;
Ok(gauge)
}
pub fn try_create_histogram(name: &str, help: &str) -> Result<Histogram> {
check_metric_unc_prefix(name)?;
let opts = HistogramOpts::new(name, help);
let histogram = Histogram::with_opts(opts)?;
prometheus::register(Box::new(histogram.clone()))?;
Ok(histogram)
}
pub fn try_create_histogram_with_buckets(
name: &str,
help: &str,
buckets: Vec<f64>,
) -> Result<Histogram> {
check_metric_unc_prefix(name)?;
let opts = HistogramOpts::new(name, help).buckets(buckets);
let histogram = Histogram::with_opts(opts)?;
prometheus::register(Box::new(histogram.clone()))?;
Ok(histogram)
}
pub fn try_create_histogram_vec(
name: &str,
help: &str,
labels: &[&str],
buckets: Option<Vec<f64>>,
) -> Result<HistogramVec> {
check_metric_unc_prefix(name)?;
let mut opts = HistogramOpts::new(name, help);
if let Some(buckets) = buckets {
opts = opts.buckets(buckets);
}
let histogram = HistogramVec::new(opts, labels)?;
prometheus::register(Box::new(histogram.clone()))?;
Ok(histogram)
}
pub fn processing_time_buckets() -> Vec<f64> {
let mut buckets = vec![0.01, 0.025, 0.05, 0.1, 0.25, 0.5];
buckets.extend_from_slice(&exponential_buckets(1.0, 1.3, 12).unwrap());
buckets
}
static EXCEPTIONS: Lazy<HashSet<&str>> = Lazy::new(|| {
HashSet::from([
"flat_storage_cached_changes_num_items",
"flat_storage_cached_changes_size",
"flat_storage_cached_deltas",
"flat_storage_creation_fetched_state_items",
"flat_storage_creation_fetched_state_parts",
"flat_storage_creation_remaining_state_parts",
"flat_storage_creation_status",
"flat_storage_creation_threads_used",
"flat_storage_distance_to_head",
"flat_storage_head_height",
"flat_storage_hops_to_head",
])
});
fn check_metric_unc_prefix(name: &str) -> Result<()> {
if name.starts_with("unc_") || EXCEPTIONS.contains(name) {
Ok(())
} else {
Err(prometheus::Error::Msg(format!(
"Metrics are expected to start with 'unc_', got {}",
name
)))
}
}
#[cfg(test)]
mod tests {
use crate::metrics::check_metric_unc_prefix;
#[test]
fn test_unc_prefix() {
assert!(check_metric_unc_prefix("unc_abc").is_ok());
assert!(check_metric_unc_prefix("flat_storage_head_height").is_ok());
assert!(check_metric_unc_prefix("unc").is_err());
assert!(check_metric_unc_prefix("abc").is_err());
}
}