Skip to content

Commit

Permalink
Replace once_cell::Lazy with std::sync::OnceLock for global Initializ…
Browse files Browse the repository at this point in the history
…ation in otel-sdk crate (open-telemetry#2342)
  • Loading branch information
lalitb authored Nov 27, 2024
1 parent 8e6b479 commit fa6e6cd
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 78 deletions.
1 change: 0 additions & 1 deletion opentelemetry-sdk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down
26 changes: 15 additions & 11 deletions opentelemetry-sdk/src/logs/log_emitter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<LoggerProvider> = 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<LoggerProvider> = 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.
Expand Down Expand Up @@ -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.");
Expand Down
62 changes: 34 additions & 28 deletions opentelemetry-sdk/src/metrics/internal/exponential_histogram.rs
Original file line number Diff line number Diff line change
@@ -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},
Expand Down Expand Up @@ -131,7 +131,7 @@ impl<T: Number> ExpoHistogramDataPoint<T> {
}
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
}
}

Expand Down Expand Up @@ -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.
///
Expand Down
14 changes: 9 additions & 5 deletions opentelemetry-sdk/src/metrics/internal/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Vec<KeyValue>> =
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<Vec<KeyValue>> = OnceLock::new();

#[inline]
fn stream_overflow_attributes() -> &'static Vec<KeyValue> {
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.
Expand Down Expand Up @@ -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."
);
Expand Down
12 changes: 9 additions & 3 deletions opentelemetry-sdk/src/propagation/baggage.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use once_cell::sync::Lazy;
use opentelemetry::{
baggage::{BaggageExt, KeyValueMetadata},
otel_warn,
Expand All @@ -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.
///
Expand Down Expand Up @@ -149,7 +155,7 @@ impl TextMapPropagator for BaggagePropagator {
}

fn fields(&self) -> FieldIter<'_> {
FieldIter::new(BAGGAGE_FIELDS.as_ref())
FieldIter::new(baggage_fields())
}
}

Expand Down
13 changes: 9 additions & 4 deletions opentelemetry-sdk/src/propagation/trace_context.rs
Original file line number Diff line number Diff line change
@@ -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.
///
Expand Down Expand Up @@ -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())
}
}

Expand Down
55 changes: 29 additions & 26 deletions opentelemetry-sdk/src/trace/provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Resource> = OnceCell::new();
static PROVIDER_RESOURCE: OnceLock<Resource> = OnceLock::new();

// a no nop tracer provider used as placeholder when the provider is shutdown
static NOOP_TRACER_PROVIDER: Lazy<TracerProvider> = 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::<RandomIdGenerator>::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<TracerProvider> = 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::<RandomIdGenerator>::default(),
span_limits: SpanLimits::default(),
resource: Cow::Owned(Resource::empty()),
},
is_shutdown: AtomicBool::new(true),
}),
}
})
}

/// TracerProvider inner type
#[derive(Debug)]
Expand Down Expand Up @@ -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())
}
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit fa6e6cd

Please sign in to comment.