use std::sync::Arc;
use opentelemetry::metrics::{Counter, Gauge, Histogram, Meter, MeterProvider, UpDownCounter};
use opentelemetry_sdk::{
Resource,
metrics::{PeriodicReader, SdkMeterProvider},
};
use crate::{
config::OtelConfig,
error::{OtelError, OtelResult},
};
#[derive(Clone)]
pub struct Metrics {
provider: Arc<SdkMeterProvider>,
meter: Meter,
}
impl Metrics {
pub(crate) fn new(config: &OtelConfig, resource: Resource) -> OtelResult<Self> {
let metrics_config = config
.metrics
.as_ref()
.ok_or_else(|| OtelError::config("metrics not configured"))?;
let exporter = crate::transport::build_metric_exporter(&config.exporter)?;
let reader = PeriodicReader::builder(exporter)
.with_interval(metrics_config.export_interval)
.build();
let provider = SdkMeterProvider::builder()
.with_resource(resource)
.with_reader(reader)
.build();
let meter = provider.meter("otel-rs");
Ok(Self {
provider: Arc::new(provider),
meter,
})
}
pub const fn meter(&self) -> &Meter {
&self.meter
}
pub fn counter(&self, name: &'static str) -> Counter<u64> {
self.meter.u64_counter(name).build()
}
pub fn f64_counter(&self, name: &'static str) -> Counter<f64> {
self.meter.f64_counter(name).build()
}
pub fn histogram(&self, name: &'static str) -> Histogram<f64> {
self.meter.f64_histogram(name).build()
}
pub fn gauge(&self, name: &'static str) -> Gauge<u64> {
self.meter.u64_gauge(name).build()
}
pub fn f64_gauge(&self, name: &'static str) -> Gauge<f64> {
self.meter.f64_gauge(name).build()
}
pub fn up_down_counter(&self, name: &'static str) -> UpDownCounter<i64> {
self.meter.i64_up_down_counter(name).build()
}
pub fn shutdown(&self) -> OtelResult<()> {
self.provider
.shutdown()
.map_err(|e| OtelError::MetricsShutdown(e.to_string()))
}
}