Skip to main content

metrics_exporter_otel/
lib.rs

1#![doc = include_str!("../README.md")]
2#![cfg_attr(docsrs, feature(doc_cfg), deny(rustdoc::broken_intra_doc_links))]
3#![deny(missing_docs)]
4
5mod instruments;
6mod metadata;
7mod storage;
8/// FIXME this module is for temporary patch of [metrics]
9mod metrics_ext;
10
11use crate::metadata::MetricMetadata;
12use crate::storage::OtelMetricStorage;
13use metrics::{Counter, Gauge, Histogram, Key, KeyName, Recorder, SharedString, Unit};
14use metrics_util::registry::Registry;
15use metrics_util::MetricKind;
16use opentelemetry::metrics::Meter;
17use std::sync::Arc;
18
19/// A [`Recorder`] that exports metrics to OpenTelemetry.
20///
21/// Clone is shallow; Clones share the same underlying data.
22///
23/// ```rust,no_run
24/// use opentelemetry::metrics::MeterProvider;
25/// use metrics_exporter_otel::OpenTelemetryRecorder;
26/// use opentelemetry_sdk::metrics::SdkMeterProvider;
27///
28/// let provider = SdkMeterProvider::default();
29/// let meter = provider.meter("my_app");
30/// let recorder = OpenTelemetryRecorder::new(meter);
31///
32/// metrics::set_global_recorder(recorder).expect("failed to install recorder");
33/// ```
34#[derive(Clone)]
35pub struct OpenTelemetryRecorder {
36    registry: Arc<Registry<Key, OtelMetricStorage>>,
37    metadata: MetricMetadata,
38}
39
40impl OpenTelemetryRecorder {
41    /// Creates a new OpenTelemetry recorder with the given meter.
42    pub fn new(meter: Meter) -> Self {
43        let metadata = MetricMetadata::new();
44        let storage = OtelMetricStorage::new(meter, metadata.clone());
45        Self { registry: Arc::new(Registry::new(storage)), metadata }
46    }
47
48    /// Sets custom bucket boundaries for a histogram metric.
49    ///
50    /// Must be called before the histogram is first created. Boundaries cannot be
51    /// changed after a histogram has been created.
52    pub fn set_histogram_bounds(&self, key: &KeyName, bounds: Vec<f64>) {
53        self.metadata.set_histogram_bounds(key.clone(), bounds);
54    }
55
56    /// Gets a description entry for testing purposes.
57    #[cfg(test)]
58    pub fn get_description(
59        &self,
60        key_name: KeyName,
61        metric_kind: MetricKind,
62    ) -> Option<crate::metadata::MetricDescription> {
63        self.metadata.get_description(&key_name, metric_kind)
64    }
65}
66
67impl Recorder for OpenTelemetryRecorder {
68    fn describe_counter(&self, key_name: KeyName, unit: Option<Unit>, description: SharedString) {
69        self.metadata.set_description(key_name, MetricKind::Counter, unit, description);
70    }
71
72    fn describe_gauge(&self, key_name: KeyName, unit: Option<Unit>, description: SharedString) {
73        self.metadata.set_description(key_name, MetricKind::Gauge, unit, description);
74    }
75
76    fn describe_histogram(&self, key_name: KeyName, unit: Option<Unit>, description: SharedString) {
77        self.metadata.set_description(key_name, MetricKind::Histogram, unit, description);
78    }
79
80    fn register_counter(&self, key: &Key, _metadata: &metrics::Metadata<'_>) -> Counter {
81        self.registry.get_or_create_counter(key, |c| Counter::from_arc(c.clone()))
82    }
83
84    fn register_gauge(&self, key: &Key, _metadata: &metrics::Metadata<'_>) -> Gauge {
85        self.registry.get_or_create_gauge(key, |g| Gauge::from_arc(g.clone()))
86    }
87
88    fn register_histogram(&self, key: &Key, _metadata: &metrics::Metadata<'_>) -> Histogram {
89        self.registry.get_or_create_histogram(key, |h| Histogram::from_arc(h.clone()))
90    }
91}