Skip to main content

iroh_metrics/
lib.rs

1//! Metrics library for iroh
2
3#![deny(missing_docs, rustdoc::broken_intra_doc_links)]
4#![cfg_attr(iroh_docsrs, feature(doc_cfg))]
5
6pub use self::{
7    base::*,
8    family::{Family, FamilyEncoder, FamilyItem},
9    labels::*,
10    metrics::*,
11    registry::*,
12};
13
14mod base;
15pub mod encoding;
16mod family;
17pub mod iterable;
18mod labels;
19mod metrics;
20mod registry;
21#[cfg(feature = "service")]
22pub mod service;
23#[cfg(feature = "static_core")]
24pub mod static_core;
25
26/// Derives [`EncodeLabelSet`] for a struct.
27///
28/// Each field becomes a label with the field name as the key.
29/// Use `#[label(name = "custom")]` to customize the label key.
30/// Use `#[label(skip)]` to exclude a field from the label set.
31/// Use `#[label(rename_all = "...")]` on the struct to rename all fields by
32/// case rule. Supported rules: `snake_case`, `camelCase`, `PascalCase`,
33/// `SCREAMING_SNAKE_CASE`, `kebab-case`, `lowercase`, `UPPERCASE`.
34///
35/// Field types must implement [`EncodeLabelValue`]. Out of the box this
36/// covers `String`, `&'static str`, the integer types, and `bool`.
37///
38/// The struct must also derive `Clone`, `Hash`, `PartialEq`, and `Eq`.
39/// To use the label set with [`Family`], also derive `PartialOrd` and `Ord`
40/// (the encoder produces output sorted by label set).
41///
42/// # Example
43///
44/// ```
45/// use iroh_metrics::EncodeLabelSet;
46///
47/// #[derive(Clone, Hash, PartialEq, Eq, EncodeLabelSet)]
48/// #[label(rename_all = "kebab-case")]
49/// struct HttpLabels {
50///     method: String,
51///     #[label(name = "status_code")]
52///     status: u16,
53/// }
54/// ```
55pub use iroh_metrics_derive::EncodeLabelSet;
56/// Derives [`EncodeLabelValue`] for an enum with only unit variants.
57///
58/// Each variant becomes a string label; default casing is `snake_case`.
59/// Use `#[label(rename_all = "...")]` on the enum or `#[label(name = "...")]`
60/// on a variant to customize. See [`macro@EncodeLabelSet`] for the list of
61/// supported `rename_all` values.
62pub use iroh_metrics_derive::EncodeLabelValue;
63/// Derives [`MetricsGroup`] and [`Iterable`].
64///
65/// This derive macro only works on structs with named fields.
66///
67/// It will generate a [`Default`] impl which expects all fields to be of a type
68/// that has a public `new` method taking a single `&'static str` argument.
69/// The [`Default::default`] method will call each field's `new` method with the
70/// first line of the field's doc comment as argument. Alternatively, you can override
71/// the value passed to `new` by setting a `#[metrics(help = "my help")]`
72/// attribute on the field.
73///
74/// It will also generate a [`MetricsGroup`] impl. By default, the struct's name,
75/// converted to `camel_case` will be used as the return value of the [`MetricsGroup::name`]
76/// method. The name can be customized by setting a `#[metrics(name = "my-name")]` attribute.
77///
78/// It will also generate a [`Iterable`] impl. Fields with the `Family<_, _>`
79/// type are routed through [`Iterable::family_field_ref`] instead of
80/// [`Iterable::metric_field_ref`]. Detection inspects the last segment of
81/// the field type, so `iroh_metrics::Family<L, M>` is recognized but a type
82/// alias is not — annotate the field with `#[metrics(family)]` in that case.
83///
84/// [`Iterable`]: iterable::Iterable
85/// [`Iterable::metric_field_ref`]: iterable::Iterable::metric_field_ref
86/// [`Iterable::family_field_ref`]: iterable::Iterable::family_field_ref
87pub use iroh_metrics_derive::MetricsGroup;
88/// Derives [`MetricsGroupSet`] for a struct.
89///
90/// All fields of the struct must be public and have a type of `Arc<SomeType>`,
91/// where `SomeType` implements `MetricsGroup`.
92pub use iroh_metrics_derive::MetricsGroupSet;
93
94// This lets us use the derive metrics in the lib tests within this crate.
95extern crate self as iroh_metrics;
96
97use std::collections::HashMap;
98
99/// Potential errors from this library.
100#[n0_error::stack_error(derive, add_meta, from_sources, std_sources)]
101#[non_exhaustive]
102#[allow(missing_docs)]
103pub enum Error {
104    /// Indicates that the metrics have not been enabled.
105    #[error("Metrics not enabled")]
106    NoMetrics,
107    /// Writing the metrics to the output buffer failed.
108    #[error(transparent)]
109    Fmt { source: std::fmt::Error },
110    /// Any IO related error.
111    #[error(transparent)]
112    IO { source: std::io::Error },
113}
114
115/// Parses Prometheus metrics from a string.
116pub fn parse_prometheus_metrics(data: &str) -> HashMap<String, f64> {
117    let mut metrics = HashMap::new();
118    for line in data.lines() {
119        if line.starts_with('#') {
120            continue;
121        }
122        let parts: Vec<&str> = line.split_whitespace().collect();
123        if parts.len() < 2 {
124            continue;
125        }
126        let metric = parts[0];
127        let value = parts[1].parse::<f64>();
128        if value.is_err() {
129            continue;
130        }
131        metrics.insert(metric.to_string(), value.unwrap());
132    }
133    metrics
134}