opentelemetry/global/
metrics.rs

1use crate::metrics::{self, Meter, MeterProvider};
2use crate::KeyValue;
3use core::fmt;
4use once_cell::sync::Lazy;
5use std::{
6    borrow::Cow,
7    sync::{Arc, RwLock},
8};
9
10/// The global `MeterProvider` singleton.
11static GLOBAL_METER_PROVIDER: Lazy<RwLock<GlobalMeterProvider>> = Lazy::new(|| {
12    RwLock::new(GlobalMeterProvider::new(
13        metrics::noop::NoopMeterProvider::new(),
14    ))
15});
16
17/// Allows a specific [MeterProvider] to be used generically by the
18/// [GlobalMeterProvider] by mirroring the interface and boxing the return types.
19pub trait ObjectSafeMeterProvider {
20    /// Creates a versioned named meter instance that is a trait object through the underlying
21    /// [MeterProvider].
22    fn versioned_meter_cow(
23        &self,
24        name: Cow<'static, str>,
25        version: Option<Cow<'static, str>>,
26        schema_url: Option<Cow<'static, str>>,
27        attributes: Option<Vec<KeyValue>>,
28    ) -> Meter;
29}
30
31impl<P> ObjectSafeMeterProvider for P
32where
33    P: MeterProvider,
34{
35    /// Return a versioned boxed tracer
36    fn versioned_meter_cow(
37        &self,
38        name: Cow<'static, str>,
39        version: Option<Cow<'static, str>>,
40        schema_url: Option<Cow<'static, str>>,
41        attributes: Option<Vec<KeyValue>>,
42    ) -> Meter {
43        self.versioned_meter(name, version, schema_url, attributes)
44    }
45}
46
47/// Represents the globally configured [`MeterProvider`] instance for this
48/// application.
49#[derive(Clone)]
50pub struct GlobalMeterProvider {
51    provider: Arc<dyn ObjectSafeMeterProvider + Send + Sync>,
52}
53
54impl fmt::Debug for GlobalMeterProvider {
55    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56        f.debug_struct("GlobalMeterProvider").finish()
57    }
58}
59
60impl MeterProvider for GlobalMeterProvider {
61    fn versioned_meter(
62        &self,
63        name: impl Into<Cow<'static, str>>,
64        version: Option<impl Into<Cow<'static, str>>>,
65        schema_url: Option<impl Into<Cow<'static, str>>>,
66        attributes: Option<Vec<KeyValue>>,
67    ) -> Meter {
68        self.provider.versioned_meter_cow(
69            name.into(),
70            version.map(Into::into),
71            schema_url.map(Into::into),
72            attributes,
73        )
74    }
75}
76
77impl GlobalMeterProvider {
78    /// Create a new global meter provider
79    pub fn new<P>(provider: P) -> Self
80    where
81        P: MeterProvider + Send + Sync + 'static,
82    {
83        GlobalMeterProvider {
84            provider: Arc::new(provider),
85        }
86    }
87}
88
89/// Sets the given [`MeterProvider`] instance as the current global meter
90/// provider.
91pub fn set_meter_provider<P>(new_provider: P)
92where
93    P: metrics::MeterProvider + Send + Sync + 'static,
94{
95    let mut global_provider = GLOBAL_METER_PROVIDER
96        .write()
97        .expect("GLOBAL_METER_PROVIDER RwLock poisoned");
98    *global_provider = GlobalMeterProvider::new(new_provider);
99}
100
101/// Returns an instance of the currently configured global [`MeterProvider`]
102/// through [`GlobalMeterProvider`].
103pub fn meter_provider() -> GlobalMeterProvider {
104    GLOBAL_METER_PROVIDER
105        .read()
106        .expect("GLOBAL_METER_PROVIDER RwLock poisoned")
107        .clone()
108}
109
110/// Creates a named [`Meter`] via the configured [`GlobalMeterProvider`].
111///
112/// If the name is an empty string, the provider will use a default name.
113///
114/// This is a more convenient way of expressing `global::meter_provider().meter(name)`.
115pub fn meter(name: impl Into<Cow<'static, str>>) -> Meter {
116    meter_provider().meter(name.into())
117}
118
119/// Creates a [`Meter`] with the name, version and schema url.
120///
121/// - name SHOULD uniquely identify the instrumentation scope, such as the instrumentation library (e.g. io.opentelemetry.contrib.mongodb), package, module or class name.
122/// - version specifies the version of the instrumentation scope if the scope has a version
123/// - schema url specifies the Schema URL that should be recorded in the emitted telemetry.
124///
125/// This is a convenient way of `global::meter_provider().versioned_meter(...)`
126///
127/// # Example
128///
129/// ```
130/// use opentelemetry::global::meter_with_version;
131/// use opentelemetry::KeyValue;
132///
133/// let meter = meter_with_version(
134///     "io.opentelemetry",
135///     Some("0.17"),
136///     Some("https://opentelemetry.io/schemas/1.2.0"),
137///     Some(vec![KeyValue::new("key", "value")]),
138/// );
139/// ```
140pub fn meter_with_version(
141    name: impl Into<Cow<'static, str>>,
142    version: Option<impl Into<Cow<'static, str>>>,
143    schema_url: Option<impl Into<Cow<'static, str>>>,
144    attributes: Option<Vec<KeyValue>>,
145) -> Meter {
146    meter_provider().versioned_meter(
147        name.into(),
148        version.map(Into::into),
149        schema_url.map(Into::into),
150        attributes,
151    )
152}