use gauge::{Gauge, ObservableGauge};
use crate::metrics::Meter;
use crate::KeyValue;
use core::fmt;
use std::borrow::Cow;
use std::marker;
use super::{
Counter, Histogram, InstrumentProvider, ObservableCounter, ObservableUpDownCounter,
UpDownCounter,
};
pub(super) mod counter;
pub(super) mod gauge;
pub(super) mod histogram;
pub(super) mod up_down_counter;
pub trait AsyncInstrument<T>: Send + Sync {
fn observe(&self, measurement: T, attributes: &[KeyValue]);
}
pub trait SyncInstrument<T>: Send + Sync {
fn measure(&self, measurement: T, attributes: &[KeyValue]);
}
#[non_exhaustive] pub struct HistogramBuilder<'a, T> {
pub instrument_provider: &'a dyn InstrumentProvider,
pub name: Cow<'static, str>,
pub description: Option<Cow<'static, str>>,
pub unit: Option<Cow<'static, str>>,
pub boundaries: Option<Vec<f64>>,
_marker: marker::PhantomData<T>,
}
impl<'a, T> HistogramBuilder<'a, T> {
pub(crate) fn new(meter: &'a Meter, name: Cow<'static, str>) -> Self {
HistogramBuilder {
instrument_provider: meter.instrument_provider.as_ref(),
name,
description: None,
unit: None,
boundaries: None,
_marker: marker::PhantomData,
}
}
pub fn with_description<S: Into<Cow<'static, str>>>(mut self, description: S) -> Self {
self.description = Some(description.into());
self
}
pub fn with_unit<S: Into<Cow<'static, str>>>(mut self, unit: S) -> Self {
self.unit = Some(unit.into());
self
}
pub fn with_boundaries(mut self, boundaries: Vec<f64>) -> Self {
self.boundaries = Some(boundaries);
self
}
}
impl<'a> HistogramBuilder<'a, Histogram<f64>> {
pub fn build(self) -> Histogram<f64> {
self.instrument_provider.f64_histogram(self)
}
}
impl<'a> HistogramBuilder<'a, Histogram<u64>> {
pub fn build(self) -> Histogram<u64> {
self.instrument_provider.u64_histogram(self)
}
}
#[non_exhaustive] pub struct InstrumentBuilder<'a, T> {
pub instrument_provider: &'a dyn InstrumentProvider,
pub name: Cow<'static, str>,
pub description: Option<Cow<'static, str>>,
pub unit: Option<Cow<'static, str>>,
_marker: marker::PhantomData<T>,
}
impl<'a, T> InstrumentBuilder<'a, T> {
pub(crate) fn new(meter: &'a Meter, name: Cow<'static, str>) -> Self {
InstrumentBuilder {
instrument_provider: meter.instrument_provider.as_ref(),
name,
description: None,
unit: None,
_marker: marker::PhantomData,
}
}
pub fn with_description<S: Into<Cow<'static, str>>>(mut self, description: S) -> Self {
self.description = Some(description.into());
self
}
pub fn with_unit<S: Into<Cow<'static, str>>>(mut self, unit: S) -> Self {
self.unit = Some(unit.into());
self
}
}
macro_rules! build_instrument {
($name:ident, $inst:ty) => {
impl<'a> InstrumentBuilder<'a, $inst> {
#[doc = concat!("Validates the instrument configuration and creates a new `", stringify!($inst), "`.")]
pub fn build(self) -> $inst {
self.instrument_provider.$name(self)
}
}
};
}
build_instrument!(u64_counter, Counter<u64>);
build_instrument!(f64_counter, Counter<f64>);
build_instrument!(u64_gauge, Gauge<u64>);
build_instrument!(f64_gauge, Gauge<f64>);
build_instrument!(i64_gauge, Gauge<i64>);
build_instrument!(i64_up_down_counter, UpDownCounter<i64>);
build_instrument!(f64_up_down_counter, UpDownCounter<f64>);
impl<T> fmt::Debug for InstrumentBuilder<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("InstrumentBuilder")
.field("name", &self.name)
.field("description", &self.description)
.field("unit", &self.unit)
.field("kind", &std::any::type_name::<T>())
.finish()
}
}
impl<T> fmt::Debug for HistogramBuilder<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("HistogramBuilder")
.field("name", &self.name)
.field("description", &self.description)
.field("unit", &self.unit)
.field("boundaries", &self.boundaries)
.field(
"kind",
&format!("Histogram<{}>", &std::any::type_name::<T>()),
)
.finish()
}
}
pub type Callback<T> = Box<dyn Fn(&dyn AsyncInstrument<T>) + Send + Sync>;
#[non_exhaustive] pub struct AsyncInstrumentBuilder<'a, I, M> {
pub instrument_provider: &'a dyn InstrumentProvider,
pub name: Cow<'static, str>,
pub description: Option<Cow<'static, str>>,
pub unit: Option<Cow<'static, str>>,
pub callbacks: Vec<Callback<M>>,
_inst: marker::PhantomData<I>,
}
impl<'a, I, M> AsyncInstrumentBuilder<'a, I, M> {
pub(crate) fn new(meter: &'a Meter, name: Cow<'static, str>) -> Self {
AsyncInstrumentBuilder {
instrument_provider: meter.instrument_provider.as_ref(),
name,
description: None,
unit: None,
_inst: marker::PhantomData,
callbacks: Vec::new(),
}
}
pub fn with_description<S: Into<Cow<'static, str>>>(mut self, description: S) -> Self {
self.description = Some(description.into());
self
}
pub fn with_unit<S: Into<Cow<'static, str>>>(mut self, unit: S) -> Self {
self.unit = Some(unit.into());
self
}
pub fn with_callback<F>(mut self, callback: F) -> Self
where
F: Fn(&dyn AsyncInstrument<M>) + Send + Sync + 'static,
{
self.callbacks.push(Box::new(callback));
self
}
}
macro_rules! build_async_instrument {
($name:ident, $inst:ty, $measurement:ty) => {
impl<'a> AsyncInstrumentBuilder<'a, $inst, $measurement> {
#[doc = concat!("Validates the instrument configuration and creates a new `", stringify!($inst), "`.")]
pub fn build(self) -> $inst {
self.instrument_provider.$name(self)
}
}
};
}
build_async_instrument!(u64_observable_counter, ObservableCounter<u64>, u64);
build_async_instrument!(f64_observable_counter, ObservableCounter<f64>, f64);
build_async_instrument!(u64_observable_gauge, ObservableGauge<u64>, u64);
build_async_instrument!(f64_observable_gauge, ObservableGauge<f64>, f64);
build_async_instrument!(i64_observable_gauge, ObservableGauge<i64>, i64);
build_async_instrument!(
i64_observable_up_down_counter,
ObservableUpDownCounter<i64>,
i64
);
build_async_instrument!(
f64_observable_up_down_counter,
ObservableUpDownCounter<f64>,
f64
);
impl<I, M> fmt::Debug for AsyncInstrumentBuilder<'_, I, M>
where
I: AsyncInstrument<M>,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("InstrumentBuilder")
.field("name", &self.name)
.field("description", &self.description)
.field("unit", &self.unit)
.field("kind", &std::any::type_name::<I>())
.field("callbacks_len", &self.callbacks.len())
.finish()
}
}