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
use crate::metrics::{self, Meter, MeterProvider};
use crate::KeyValue;
use core::fmt;
use once_cell::sync::Lazy;
use std::{
borrow::Cow,
sync::{Arc, RwLock},
};
/// The global `MeterProvider` singleton.
static GLOBAL_METER_PROVIDER: Lazy<RwLock<GlobalMeterProvider>> = Lazy::new(|| {
RwLock::new(GlobalMeterProvider::new(
metrics::noop::NoopMeterProvider::new(),
))
});
/// Allows a specific [MeterProvider] to be used generically by the
/// [GlobalMeterProvider] by mirroring the interface and boxing the return types.
pub trait ObjectSafeMeterProvider {
/// Creates a versioned named meter instance that is a trait object through the underlying
/// [MeterProvider].
fn versioned_meter_cow(
&self,
name: Cow<'static, str>,
version: Option<Cow<'static, str>>,
schema_url: Option<Cow<'static, str>>,
attributes: Option<Vec<KeyValue>>,
) -> Meter;
}
impl<P> ObjectSafeMeterProvider for P
where
P: MeterProvider,
{
/// Return a versioned boxed tracer
fn versioned_meter_cow(
&self,
name: Cow<'static, str>,
version: Option<Cow<'static, str>>,
schema_url: Option<Cow<'static, str>>,
attributes: Option<Vec<KeyValue>>,
) -> Meter {
self.versioned_meter(name, version, schema_url, attributes)
}
}
/// Represents the globally configured [`MeterProvider`] instance for this
/// application.
#[derive(Clone)]
pub struct GlobalMeterProvider {
provider: Arc<dyn ObjectSafeMeterProvider + Send + Sync>,
}
impl fmt::Debug for GlobalMeterProvider {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("GlobalMeterProvider").finish()
}
}
impl MeterProvider for GlobalMeterProvider {
fn versioned_meter(
&self,
name: impl Into<Cow<'static, str>>,
version: Option<impl Into<Cow<'static, str>>>,
schema_url: Option<impl Into<Cow<'static, str>>>,
attributes: Option<Vec<KeyValue>>,
) -> Meter {
self.provider.versioned_meter_cow(
name.into(),
version.map(Into::into),
schema_url.map(Into::into),
attributes,
)
}
}
impl GlobalMeterProvider {
/// Create a new global meter provider
pub fn new<P>(provider: P) -> Self
where
P: MeterProvider + Send + Sync + 'static,
{
GlobalMeterProvider {
provider: Arc::new(provider),
}
}
}
/// Sets the given [`MeterProvider`] instance as the current global meter
/// provider.
pub fn set_meter_provider<P>(new_provider: P)
where
P: metrics::MeterProvider + Send + Sync + 'static,
{
let mut global_provider = GLOBAL_METER_PROVIDER
.write()
.expect("GLOBAL_METER_PROVIDER RwLock poisoned");
*global_provider = GlobalMeterProvider::new(new_provider);
}
/// Returns an instance of the currently configured global [`MeterProvider`]
/// through [`GlobalMeterProvider`].
pub fn meter_provider() -> GlobalMeterProvider {
GLOBAL_METER_PROVIDER
.read()
.expect("GLOBAL_METER_PROVIDER RwLock poisoned")
.clone()
}
/// Creates a named [`Meter`] via the configured [`GlobalMeterProvider`].
///
/// If the name is an empty string, the provider will use a default name.
///
/// This is a more convenient way of expressing `global::meter_provider().meter(name)`.
pub fn meter(name: impl Into<Cow<'static, str>>) -> Meter {
meter_provider().meter(name.into())
}
/// Creates a [`Meter`] with the name, version and schema url.
///
/// - name SHOULD uniquely identify the instrumentation scope, such as the instrumentation library (e.g. io.opentelemetry.contrib.mongodb), package, module or class name.
/// - version specifies the version of the instrumentation scope if the scope has a version
/// - schema url specifies the Schema URL that should be recorded in the emitted telemetry.
///
/// This is a convenient way of `global::meter_provider().versioned_meter(...)`
///
/// # Example
///
/// ```
/// use opentelemetry::global::meter_with_version;
/// use opentelemetry::KeyValue;
///
/// let meter = meter_with_version(
/// "io.opentelemetry",
/// Some("0.17"),
/// Some("https://opentelemetry.io/schemas/1.2.0"),
/// Some(vec![KeyValue::new("key", "value")]),
/// );
/// ```
pub fn meter_with_version(
name: impl Into<Cow<'static, str>>,
version: Option<impl Into<Cow<'static, str>>>,
schema_url: Option<impl Into<Cow<'static, str>>>,
attributes: Option<Vec<KeyValue>>,
) -> Meter {
meter_provider().versioned_meter(
name.into(),
version.map(Into::into),
schema_url.map(Into::into),
attributes,
)
}