diff --git a/opentelemetry-sdk/Cargo.toml b/opentelemetry-sdk/Cargo.toml index bf03c8d34a..39b5fddfa2 100644 --- a/opentelemetry-sdk/Cargo.toml +++ b/opentelemetry-sdk/Cargo.toml @@ -17,7 +17,6 @@ async-trait = { workspace = true, optional = true } futures-channel = "0.3" futures-executor = { workspace = true } futures-util = { workspace = true, features = ["std", "sink", "async-await-macro"] } -once_cell = { workspace = true } percent-encoding = { version = "2.0", optional = true } rand = { workspace = true, features = ["std", "std_rng","small_rng"], optional = true } glob = { version = "0.3.1", optional =true} diff --git a/opentelemetry-sdk/src/logs/log_emitter.rs b/opentelemetry-sdk/src/logs/log_emitter.rs index 9b426f1d31..a39152dbfd 100644 --- a/opentelemetry-sdk/src/logs/log_emitter.rs +++ b/opentelemetry-sdk/src/logs/log_emitter.rs @@ -11,20 +11,24 @@ use std::{ borrow::Cow, sync::{ atomic::{AtomicBool, Ordering}, - Arc, + Arc, OnceLock, }, }; -use once_cell::sync::Lazy; - // a no nop logger provider used as placeholder when the provider is shutdown -static NOOP_LOGGER_PROVIDER: Lazy = Lazy::new(|| LoggerProvider { - inner: Arc::new(LoggerProviderInner { - processors: Vec::new(), - resource: Resource::empty(), - is_shutdown: AtomicBool::new(true), - }), -}); +// TODO - replace it with LazyLock once it is stable +static NOOP_LOGGER_PROVIDER: OnceLock = OnceLock::new(); + +#[inline] +fn noop_logger_provider() -> &'static LoggerProvider { + NOOP_LOGGER_PROVIDER.get_or_init(|| LoggerProvider { + inner: Arc::new(LoggerProviderInner { + processors: Vec::new(), + resource: Resource::empty(), + is_shutdown: AtomicBool::new(true), + }), + }) +} #[derive(Debug, Clone)] /// Handles the creation and coordination of [`Logger`]s. @@ -55,7 +59,7 @@ impl opentelemetry::logs::LoggerProvider for LoggerProvider { fn logger_with_scope(&self, scope: InstrumentationScope) -> Self::Logger { // If the provider is shutdown, new logger will refer a no-op logger provider. if self.inner.is_shutdown.load(Ordering::Relaxed) { - return Logger::new(scope, NOOP_LOGGER_PROVIDER.clone()); + return Logger::new(scope, noop_logger_provider().clone()); } if scope.name().is_empty() { otel_info!(name: "LoggerNameEmpty", message = "Logger name is empty; consider providing a meaningful name. Logger will function normally and the provided name will be used as-is."); diff --git a/opentelemetry-sdk/src/metrics/internal/exponential_histogram.rs b/opentelemetry-sdk/src/metrics/internal/exponential_histogram.rs index c0d4263946..7975c1419e 100644 --- a/opentelemetry-sdk/src/metrics/internal/exponential_histogram.rs +++ b/opentelemetry-sdk/src/metrics/internal/exponential_histogram.rs @@ -1,7 +1,7 @@ use std::{f64::consts::LOG2_E, mem::replace, ops::DerefMut, sync::Mutex, time::SystemTime}; -use once_cell::sync::Lazy; use opentelemetry::{otel_debug, KeyValue}; +use std::sync::OnceLock; use crate::metrics::{ data::{self, Aggregation}, @@ -131,7 +131,7 @@ impl ExpoHistogramDataPoint { } return (exp - correction) >> -self.scale; } - (exp << self.scale) + (frac.ln() * SCALE_FACTORS[self.scale as usize]) as i32 - 1 + (exp << self.scale) + (frac.ln() * scale_factors()[self.scale as usize]) as i32 - 1 } } @@ -165,32 +165,38 @@ fn scale_change(max_size: i32, bin: i32, start_bin: i32, length: i32) -> u32 { count } -/// Constants used in calculating the logarithm index. -static SCALE_FACTORS: Lazy<[f64; 21]> = Lazy::new(|| { - [ - LOG2_E * 2f64.powi(0), - LOG2_E * 2f64.powi(1), - LOG2_E * 2f64.powi(2), - LOG2_E * 2f64.powi(3), - LOG2_E * 2f64.powi(4), - LOG2_E * 2f64.powi(5), - LOG2_E * 2f64.powi(6), - LOG2_E * 2f64.powi(7), - LOG2_E * 2f64.powi(8), - LOG2_E * 2f64.powi(9), - LOG2_E * 2f64.powi(10), - LOG2_E * 2f64.powi(11), - LOG2_E * 2f64.powi(12), - LOG2_E * 2f64.powi(13), - LOG2_E * 2f64.powi(14), - LOG2_E * 2f64.powi(15), - LOG2_E * 2f64.powi(16), - LOG2_E * 2f64.powi(17), - LOG2_E * 2f64.powi(18), - LOG2_E * 2f64.powi(19), - LOG2_E * 2f64.powi(20), - ] -}); +// TODO - replace it with LazyLock once it is stable +static SCALE_FACTORS: OnceLock<[f64; 21]> = OnceLock::new(); + +/// returns constants used in calculating the logarithm index. +#[inline] +fn scale_factors() -> &'static [f64; 21] { + SCALE_FACTORS.get_or_init(|| { + [ + LOG2_E * 2f64.powi(0), + LOG2_E * 2f64.powi(1), + LOG2_E * 2f64.powi(2), + LOG2_E * 2f64.powi(3), + LOG2_E * 2f64.powi(4), + LOG2_E * 2f64.powi(5), + LOG2_E * 2f64.powi(6), + LOG2_E * 2f64.powi(7), + LOG2_E * 2f64.powi(8), + LOG2_E * 2f64.powi(9), + LOG2_E * 2f64.powi(10), + LOG2_E * 2f64.powi(11), + LOG2_E * 2f64.powi(12), + LOG2_E * 2f64.powi(13), + LOG2_E * 2f64.powi(14), + LOG2_E * 2f64.powi(15), + LOG2_E * 2f64.powi(16), + LOG2_E * 2f64.powi(17), + LOG2_E * 2f64.powi(18), + LOG2_E * 2f64.powi(19), + LOG2_E * 2f64.powi(20), + ] + }) +} /// Breaks the number into a normalized fraction and a base-2 exponent. /// diff --git a/opentelemetry-sdk/src/metrics/internal/mod.rs b/opentelemetry-sdk/src/metrics/internal/mod.rs index fba67e07b4..1b5a6a4de5 100644 --- a/opentelemetry-sdk/src/metrics/internal/mod.rs +++ b/opentelemetry-sdk/src/metrics/internal/mod.rs @@ -15,11 +15,15 @@ use std::sync::{Arc, OnceLock, RwLock}; use aggregate::{is_under_cardinality_limit, STREAM_CARDINALITY_LIMIT}; pub(crate) use aggregate::{AggregateBuilder, ComputeAggregation, Measure}; pub(crate) use exponential_histogram::{EXPO_MAX_SCALE, EXPO_MIN_SCALE}; -use once_cell::sync::Lazy; use opentelemetry::{otel_warn, KeyValue}; -pub(crate) static STREAM_OVERFLOW_ATTRIBUTES: Lazy> = - Lazy::new(|| vec![KeyValue::new("otel.metric.overflow", "true")]); +// TODO Replace it with LazyLock once it is stable +pub(crate) static STREAM_OVERFLOW_ATTRIBUTES: OnceLock> = OnceLock::new(); + +#[inline] +fn stream_overflow_attributes() -> &'static Vec { + STREAM_OVERFLOW_ATTRIBUTES.get_or_init(|| vec![KeyValue::new("otel.metric.overflow", "true")]) +} pub(crate) trait Aggregator { /// A static configuration that is needed in order to initialize aggregator. @@ -134,12 +138,12 @@ where trackers.insert(sorted_attrs, new_tracker); self.count.fetch_add(1, Ordering::SeqCst); - } else if let Some(overflow_value) = trackers.get(STREAM_OVERFLOW_ATTRIBUTES.as_slice()) { + } else if let Some(overflow_value) = trackers.get(stream_overflow_attributes().as_slice()) { overflow_value.update(value); } else { let new_tracker = A::create(&self.config); new_tracker.update(value); - trackers.insert(STREAM_OVERFLOW_ATTRIBUTES.clone(), Arc::new(new_tracker)); + trackers.insert(stream_overflow_attributes().clone(), Arc::new(new_tracker)); otel_warn!( name: "ValueMap.measure", message = "Maximum data points for metric stream exceeded. Entry added to overflow. Subsequent overflows to same metric until next collect will not be logged." ); diff --git a/opentelemetry-sdk/src/propagation/baggage.rs b/opentelemetry-sdk/src/propagation/baggage.rs index 35567b4b4b..05d93e632f 100644 --- a/opentelemetry-sdk/src/propagation/baggage.rs +++ b/opentelemetry-sdk/src/propagation/baggage.rs @@ -1,4 +1,3 @@ -use once_cell::sync::Lazy; use opentelemetry::{ baggage::{BaggageExt, KeyValueMetadata}, otel_warn, @@ -7,10 +6,17 @@ use opentelemetry::{ }; use percent_encoding::{percent_decode_str, utf8_percent_encode, AsciiSet, CONTROLS}; use std::iter; +use std::sync::OnceLock; static BAGGAGE_HEADER: &str = "baggage"; const FRAGMENT: &AsciiSet = &CONTROLS.add(b' ').add(b'"').add(b';').add(b',').add(b'='); -static BAGGAGE_FIELDS: Lazy<[String; 1]> = Lazy::new(|| [BAGGAGE_HEADER.to_owned()]); + +// TODO Replace this with LazyLock once it is stable. +static BAGGAGE_FIELDS: OnceLock<[String; 1]> = OnceLock::new(); +#[inline] +fn baggage_fields() -> &'static [String; 1] { + BAGGAGE_FIELDS.get_or_init(|| [BAGGAGE_HEADER.to_owned()]) +} /// Propagates name-value pairs in [W3C Baggage] format. /// @@ -149,7 +155,7 @@ impl TextMapPropagator for BaggagePropagator { } fn fields(&self) -> FieldIter<'_> { - FieldIter::new(BAGGAGE_FIELDS.as_ref()) + FieldIter::new(baggage_fields()) } } diff --git a/opentelemetry-sdk/src/propagation/trace_context.rs b/opentelemetry-sdk/src/propagation/trace_context.rs index ced269c2d2..2a6d53ef04 100644 --- a/opentelemetry-sdk/src/propagation/trace_context.rs +++ b/opentelemetry-sdk/src/propagation/trace_context.rs @@ -1,21 +1,26 @@ //! # W3C Trace Context Propagator //! -use once_cell::sync::Lazy; use opentelemetry::{ propagation::{text_map_propagator::FieldIter, Extractor, Injector, TextMapPropagator}, trace::{SpanContext, SpanId, TraceContextExt, TraceFlags, TraceId, TraceState}, Context, }; use std::str::FromStr; +use std::sync::OnceLock; const SUPPORTED_VERSION: u8 = 0; const MAX_VERSION: u8 = 254; const TRACEPARENT_HEADER: &str = "traceparent"; const TRACESTATE_HEADER: &str = "tracestate"; -static TRACE_CONTEXT_HEADER_FIELDS: Lazy<[String; 2]> = - Lazy::new(|| [TRACEPARENT_HEADER.to_owned(), TRACESTATE_HEADER.to_owned()]); +// TODO Replace this with LazyLock once it is stable. +static TRACE_CONTEXT_HEADER_FIELDS: OnceLock<[String; 2]> = OnceLock::new(); + +fn trace_context_header_fields() -> &'static [String; 2] { + TRACE_CONTEXT_HEADER_FIELDS + .get_or_init(|| [TRACEPARENT_HEADER.to_owned(), TRACESTATE_HEADER.to_owned()]) +} /// Propagates `SpanContext`s in [W3C TraceContext] format under `traceparent` and `tracestate` header. /// @@ -146,7 +151,7 @@ impl TextMapPropagator for TraceContextPropagator { } fn fields(&self) -> FieldIter<'_> { - FieldIter::new(TRACE_CONTEXT_HEADER_FIELDS.as_ref()) + FieldIter::new(trace_context_header_fields()) } } diff --git a/opentelemetry-sdk/src/trace/provider.rs b/opentelemetry-sdk/src/trace/provider.rs index dcb8f55fd8..f8c65d59c9 100644 --- a/opentelemetry-sdk/src/trace/provider.rs +++ b/opentelemetry-sdk/src/trace/provider.rs @@ -68,32 +68,38 @@ use crate::trace::{ }; use crate::Resource; use crate::{export::trace::SpanExporter, trace::SpanProcessor}; -use once_cell::sync::{Lazy, OnceCell}; use opentelemetry::trace::TraceError; use opentelemetry::InstrumentationScope; use opentelemetry::{otel_debug, trace::TraceResult}; use std::borrow::Cow; use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::Arc; +use std::sync::{Arc, OnceLock}; use super::IdGenerator; -static PROVIDER_RESOURCE: OnceCell = OnceCell::new(); +static PROVIDER_RESOURCE: OnceLock = OnceLock::new(); // a no nop tracer provider used as placeholder when the provider is shutdown -static NOOP_TRACER_PROVIDER: Lazy = Lazy::new(|| TracerProvider { - inner: Arc::new(TracerProviderInner { - processors: Vec::new(), - config: Config { - // cannot use default here as the default resource is not empty - sampler: Box::new(Sampler::ParentBased(Box::new(Sampler::AlwaysOn))), - id_generator: Box::::default(), - span_limits: SpanLimits::default(), - resource: Cow::Owned(Resource::empty()), - }, - is_shutdown: AtomicBool::new(true), - }), -}); +// TODO Replace with LazyLock once it is stable +static NOOP_TRACER_PROVIDER: OnceLock = OnceLock::new(); +#[inline] +fn noop_tracer_provider() -> &'static TracerProvider { + NOOP_TRACER_PROVIDER.get_or_init(|| { + TracerProvider { + inner: Arc::new(TracerProviderInner { + processors: Vec::new(), + config: Config { + // cannot use default here as the default resource is not empty + sampler: Box::new(Sampler::ParentBased(Box::new(Sampler::AlwaysOn))), + id_generator: Box::::default(), + span_limits: SpanLimits::default(), + resource: Cow::Owned(Resource::empty()), + }, + is_shutdown: AtomicBool::new(true), + }), + } + }) +} /// TracerProvider inner type #[derive(Debug)] @@ -269,7 +275,7 @@ impl opentelemetry::trace::TracerProvider for TracerProvider { fn tracer_with_scope(&self, scope: InstrumentationScope) -> Self::Tracer { if self.inner.is_shutdown.load(Ordering::Relaxed) { - return Tracer::new(scope, NOOP_TRACER_PROVIDER.clone()); + return Tracer::new(scope, noop_tracer_provider().clone()); } Tracer::new(scope, self.clone()) } @@ -392,16 +398,13 @@ impl Builder { // For the uncommon case where there are multiple tracer providers with different resource // configurations, users can optionally provide their own borrowed static resource. if matches!(config.resource, Cow::Owned(_)) { - config.resource = match PROVIDER_RESOURCE.try_insert(config.resource.into_owned()) { - Ok(static_resource) => Cow::Borrowed(static_resource), - Err((prev, new)) => { - if prev == &new { - Cow::Borrowed(prev) - } else { - Cow::Owned(new) + config.resource = + match PROVIDER_RESOURCE.get_or_init(|| config.resource.clone().into_owned()) { + static_resource if *static_resource == *config.resource.as_ref() => { + Cow::Borrowed(static_resource) } - } - } + _ => config.resource, // Use the new resource if different + }; } // Create a new vector to hold the modified processors