rustic_rs/metrics/
opentelemetry.rs1use std::{collections::BTreeMap, time::Duration};
2
3use opentelemetry_otlp::{MetricExporter, Protocol, WithExportConfig};
4use opentelemetry_sdk::{
5 Resource,
6 metrics::{PeriodicReader, SdkMeterProvider},
7};
8
9use anyhow::Result;
10use opentelemetry::{KeyValue, metrics::MeterProvider};
11use reqwest::Url;
12
13use super::{Metric, MetricValue, MetricsExporter};
14
15pub struct OpentelemetryExporter {
16 pub endpoint: Url,
17 pub service_name: String,
18 pub labels: BTreeMap<String, String>,
19}
20
21impl MetricsExporter for OpentelemetryExporter {
22 fn push_metrics(&self, metrics: &[Metric]) -> Result<()> {
23 let exporter = MetricExporter::builder()
24 .with_http()
25 .with_protocol(Protocol::HttpBinary)
26 .with_endpoint(self.endpoint.to_string())
27 .build()?;
28
29 let reader = PeriodicReader::builder(exporter)
31 .with_interval(Duration::from_secs(u64::MAX))
32 .build();
33
34 let attributes = self
35 .labels
36 .iter()
37 .map(|(k, v)| KeyValue::new(k.clone(), v.clone()));
38
39 let resource = Resource::builder()
40 .with_service_name(self.service_name.clone())
41 .with_attributes(attributes)
42 .build();
43
44 let meter_provider = SdkMeterProvider::builder()
45 .with_reader(reader)
46 .with_resource(resource)
47 .build();
48
49 let meter = meter_provider.meter("rustic");
50
51 for metric in metrics {
52 match metric.value {
53 MetricValue::Int(value) => {
54 let gauge = &meter
55 .u64_gauge(metric.name)
56 .with_description(metric.description)
57 .build();
58
59 gauge.record(value, &[]);
60 }
61 MetricValue::Float(value) => {
62 let gauge = &meter
63 .f64_gauge(metric.name)
64 .with_description(metric.description)
65 .build();
66
67 gauge.record(value, &[]);
68 }
69 };
70 }
71
72 meter_provider.shutdown()?;
73 Ok(())
74 }
75}