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