opentelemetry/metrics/instruments/
mod.rs

1use crate::metrics::{Meter, MetricsError, Result};
2use crate::KeyValue;
3use core::fmt;
4use std::any::Any;
5use std::borrow::Cow;
6use std::marker;
7use std::sync::Arc;
8
9use super::InstrumentProvider;
10
11pub(super) mod counter;
12pub(super) mod gauge;
13pub(super) mod histogram;
14pub(super) mod up_down_counter;
15
16/// An SDK implemented instrument that records measurements via callback.
17pub trait AsyncInstrument<T>: Send + Sync {
18    /// Observes the state of the instrument.
19    ///
20    /// It is only valid to call this within a callback.
21    fn observe(&self, measurement: T, attributes: &[KeyValue]);
22
23    /// Used for SDKs to downcast instruments in callbacks.
24    fn as_any(&self) -> Arc<dyn Any>;
25}
26
27/// Configuration for building a sync instrument.
28pub struct InstrumentBuilder<'a, T> {
29    instrument_provider: &'a dyn InstrumentProvider,
30    name: Cow<'static, str>,
31    description: Option<Cow<'static, str>>,
32    unit: Option<Cow<'static, str>>,
33    _marker: marker::PhantomData<T>,
34}
35
36impl<'a, T> InstrumentBuilder<'a, T>
37where
38    T: TryFrom<Self, Error = MetricsError>,
39{
40    /// Create a new instrument builder
41    pub(crate) fn new(meter: &'a Meter, name: Cow<'static, str>) -> Self {
42        InstrumentBuilder {
43            instrument_provider: meter.instrument_provider.as_ref(),
44            name,
45            description: None,
46            unit: None,
47            _marker: marker::PhantomData,
48        }
49    }
50
51    /// Set the description for this instrument
52    pub fn with_description<S: Into<Cow<'static, str>>>(mut self, description: S) -> Self {
53        self.description = Some(description.into());
54        self
55    }
56
57    /// Set the unit for this instrument.
58    ///
59    /// Unit is case sensitive(`kb` is not the same as `kB`).
60    ///
61    /// Unit must be:
62    /// - ASCII string
63    /// - No longer than 63 characters
64    pub fn with_unit<S: Into<Cow<'static, str>>>(mut self, unit: S) -> Self {
65        self.unit = Some(unit.into());
66        self
67    }
68
69    /// Validate the instrument configuration and creates a new instrument.
70    pub fn try_init(self) -> Result<T> {
71        T::try_from(self)
72    }
73
74    /// Creates a new instrument.
75    ///
76    /// Validate the instrument configuration and crates a new instrument.
77    ///
78    /// # Panics
79    ///
80    /// Panics if the instrument cannot be created. Use
81    /// [`try_init`](InstrumentBuilder::try_init) if you want to handle errors.
82    pub fn init(self) -> T {
83        T::try_from(self).unwrap()
84    }
85}
86
87impl<T> fmt::Debug for InstrumentBuilder<'_, T> {
88    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89        f.debug_struct("InstrumentBuilder")
90            .field("name", &self.name)
91            .field("description", &self.description)
92            .field("unit", &self.unit)
93            .field("kind", &std::any::type_name::<T>())
94            .finish()
95    }
96}
97
98/// A function registered with a [Meter] that makes observations for the
99/// instruments it is registered with.
100///
101/// The async instrument parameter is used to record measurement observations
102/// for these instruments.
103///
104/// The function needs to complete in a finite amount of time.
105pub type Callback<T> = Box<dyn Fn(&dyn AsyncInstrument<T>) + Send + Sync>;
106
107/// Configuration for building an async instrument.
108pub struct AsyncInstrumentBuilder<'a, I, M>
109where
110    I: AsyncInstrument<M>,
111{
112    meter: &'a Meter,
113    name: Cow<'static, str>,
114    description: Option<Cow<'static, str>>,
115    unit: Option<Cow<'static, str>>,
116    _inst: marker::PhantomData<I>,
117    callbacks: Vec<Callback<M>>,
118}
119
120impl<'a, I, M> AsyncInstrumentBuilder<'a, I, M>
121where
122    I: TryFrom<Self, Error = MetricsError>,
123    I: AsyncInstrument<M>,
124{
125    /// Create a new instrument builder
126    pub(crate) fn new(meter: &'a Meter, name: Cow<'static, str>) -> Self {
127        AsyncInstrumentBuilder {
128            meter,
129            name,
130            description: None,
131            unit: None,
132            _inst: marker::PhantomData,
133            callbacks: Vec::new(),
134        }
135    }
136
137    /// Set the description for this instrument
138    pub fn with_description<S: Into<Cow<'static, str>>>(mut self, description: S) -> Self {
139        self.description = Some(description.into());
140        self
141    }
142
143    /// Set the unit for this instrument.
144    ///
145    /// Unit is case sensitive(`kb` is not the same as `kB`).
146    ///
147    /// Unit must be:
148    /// - ASCII string
149    /// - No longer than 63 characters
150    pub fn with_unit<S: Into<Cow<'static, str>>>(mut self, unit: S) -> Self {
151        self.unit = Some(unit.into());
152        self
153    }
154
155    /// Set the callback to be called for this instrument.
156    pub fn with_callback<F>(mut self, callback: F) -> Self
157    where
158        F: Fn(&dyn AsyncInstrument<M>) + Send + Sync + 'static,
159    {
160        self.callbacks.push(Box::new(callback));
161        self
162    }
163
164    /// Validate the instrument configuration and creates a new instrument.
165    pub fn try_init(self) -> Result<I> {
166        I::try_from(self)
167    }
168
169    /// Creates a new instrument.
170    ///
171    /// Validate the instrument configuration and creates a new instrument.
172    ///
173    /// # Panics
174    ///
175    /// Panics if the instrument cannot be created. Use
176    /// [`try_init`](InstrumentBuilder::try_init) if you want to handle errors.
177    pub fn init(self) -> I {
178        I::try_from(self).unwrap()
179    }
180}
181
182impl<I, M> fmt::Debug for AsyncInstrumentBuilder<'_, I, M>
183where
184    I: AsyncInstrument<M>,
185{
186    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
187        f.debug_struct("InstrumentBuilder")
188            .field("name", &self.name)
189            .field("description", &self.description)
190            .field("unit", &self.unit)
191            .field("kind", &std::any::type_name::<I>())
192            .field("callbacks_len", &self.callbacks.len())
193            .finish()
194    }
195}