Skip to content

Commit 5ed1240

Browse files
committed
feat: Replace OnceLock + helper function patterns with LazyLock
Resolves 6 TODO comments in opentelemetry-sdk that were waiting for LazyLock stabilization (stable since Rust 1.80). Each OnceLock paired with a getter function is now a single LazyLock static declaration. Signed-off-by: Bryant Biggs <bryantbiggs@gmail.com>
1 parent 4d7ce7f commit 5ed1240

6 files changed

Lines changed: 65 additions & 99 deletions

File tree

opentelemetry-sdk/src/logs/logger_provider.rs

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,17 @@ use std::{
88
borrow::Cow,
99
sync::{
1010
atomic::{AtomicBool, Ordering},
11-
Arc, OnceLock,
11+
Arc, LazyLock,
1212
},
1313
};
1414

15-
// a no nop logger provider used as placeholder when the provider is shutdown
16-
// TODO - replace it with LazyLock once it is stable
17-
static NOOP_LOGGER_PROVIDER: OnceLock<SdkLoggerProvider> = OnceLock::new();
18-
19-
#[inline]
20-
fn noop_logger_provider() -> &'static SdkLoggerProvider {
21-
NOOP_LOGGER_PROVIDER.get_or_init(|| SdkLoggerProvider {
22-
inner: Arc::new(LoggerProviderInner {
23-
processors: Vec::new(),
24-
is_shutdown: AtomicBool::new(true),
25-
}),
26-
})
27-
}
15+
// a no-op logger provider used as placeholder when the provider is shutdown
16+
static NOOP_LOGGER_PROVIDER: LazyLock<SdkLoggerProvider> = LazyLock::new(|| SdkLoggerProvider {
17+
inner: Arc::new(LoggerProviderInner {
18+
processors: Vec::new(),
19+
is_shutdown: AtomicBool::new(true),
20+
}),
21+
});
2822

2923
#[derive(Debug, Clone)]
3024
/// Handles the creation and coordination of [`Logger`]s.
@@ -59,7 +53,7 @@ impl opentelemetry::logs::LoggerProvider for SdkLoggerProvider {
5953
name: "LoggerProvider.NoOpLoggerReturned",
6054
logger_name = scope.name(),
6155
);
62-
return SdkLogger::new(scope, noop_logger_provider().clone());
56+
return SdkLogger::new(scope, NOOP_LOGGER_PROVIDER.clone());
6357
}
6458
if scope.name().is_empty() {
6559
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.");

opentelemetry-sdk/src/metrics/internal/exponential_histogram.rs

Lines changed: 28 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::{f64::consts::LOG2_E, mem::replace, ops::DerefMut, sync::Mutex};
22

33
use opentelemetry::{otel_debug, KeyValue};
4-
use std::sync::OnceLock;
4+
use std::sync::LazyLock;
55

66
use crate::metrics::{
77
data::{self, AggregatedMetrics, MetricData},
@@ -134,7 +134,7 @@ impl<T: Number> ExpoHistogramDataPoint<T> {
134134
}
135135
return (exp - correction) >> -self.scale;
136136
}
137-
(exp << self.scale) + (frac.ln() * scale_factors()[self.scale as usize]) as i32 - 1
137+
(exp << self.scale) + (frac.ln() * SCALE_FACTORS[self.scale as usize]) as i32 - 1
138138
}
139139
}
140140

@@ -168,38 +168,32 @@ fn scale_change(max_size: i32, bin: i32, start_bin: i32, length: i32) -> u32 {
168168
count
169169
}
170170

171-
// TODO - replace it with LazyLock once it is stable
172-
static SCALE_FACTORS: OnceLock<[f64; 21]> = OnceLock::new();
173-
174-
/// returns constants used in calculating the logarithm index.
175-
#[inline]
176-
fn scale_factors() -> &'static [f64; 21] {
177-
SCALE_FACTORS.get_or_init(|| {
178-
[
179-
LOG2_E * 2f64.powi(0),
180-
LOG2_E * 2f64.powi(1),
181-
LOG2_E * 2f64.powi(2),
182-
LOG2_E * 2f64.powi(3),
183-
LOG2_E * 2f64.powi(4),
184-
LOG2_E * 2f64.powi(5),
185-
LOG2_E * 2f64.powi(6),
186-
LOG2_E * 2f64.powi(7),
187-
LOG2_E * 2f64.powi(8),
188-
LOG2_E * 2f64.powi(9),
189-
LOG2_E * 2f64.powi(10),
190-
LOG2_E * 2f64.powi(11),
191-
LOG2_E * 2f64.powi(12),
192-
LOG2_E * 2f64.powi(13),
193-
LOG2_E * 2f64.powi(14),
194-
LOG2_E * 2f64.powi(15),
195-
LOG2_E * 2f64.powi(16),
196-
LOG2_E * 2f64.powi(17),
197-
LOG2_E * 2f64.powi(18),
198-
LOG2_E * 2f64.powi(19),
199-
LOG2_E * 2f64.powi(20),
200-
]
201-
})
202-
}
171+
/// Constants used in calculating the logarithm index.
172+
static SCALE_FACTORS: LazyLock<[f64; 21]> = LazyLock::new(|| {
173+
[
174+
LOG2_E * 2f64.powi(0),
175+
LOG2_E * 2f64.powi(1),
176+
LOG2_E * 2f64.powi(2),
177+
LOG2_E * 2f64.powi(3),
178+
LOG2_E * 2f64.powi(4),
179+
LOG2_E * 2f64.powi(5),
180+
LOG2_E * 2f64.powi(6),
181+
LOG2_E * 2f64.powi(7),
182+
LOG2_E * 2f64.powi(8),
183+
LOG2_E * 2f64.powi(9),
184+
LOG2_E * 2f64.powi(10),
185+
LOG2_E * 2f64.powi(11),
186+
LOG2_E * 2f64.powi(12),
187+
LOG2_E * 2f64.powi(13),
188+
LOG2_E * 2f64.powi(14),
189+
LOG2_E * 2f64.powi(15),
190+
LOG2_E * 2f64.powi(16),
191+
LOG2_E * 2f64.powi(17),
192+
LOG2_E * 2f64.powi(18),
193+
LOG2_E * 2f64.powi(19),
194+
LOG2_E * 2f64.powi(20),
195+
]
196+
});
203197

204198
/// Breaks the number into a normalized fraction and a base-2 exponent.
205199
///

opentelemetry-sdk/src/metrics/internal/mod.rs

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use std::ops::{Add, AddAssign, DerefMut, Sub};
1515
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
1616
#[cfg(target_has_atomic = "64")]
1717
use std::sync::atomic::{AtomicI64, AtomicU64};
18-
use std::sync::{Arc, OnceLock, RwLock};
18+
use std::sync::{Arc, LazyLock, OnceLock, RwLock};
1919

2020
pub(crate) use aggregate::{AggregateBuilder, AggregateFns, ComputeAggregation, Measure};
2121
pub(crate) use exponential_histogram::{EXPO_MAX_SCALE, EXPO_MIN_SCALE};
@@ -24,13 +24,8 @@ use opentelemetry::{otel_warn, KeyValue};
2424
use super::data::{AggregatedMetrics, MetricData};
2525
use super::pipeline::DEFAULT_CARDINALITY_LIMIT;
2626

27-
// TODO Replace it with LazyLock once it is stable
28-
pub(crate) static STREAM_OVERFLOW_ATTRIBUTES: OnceLock<Vec<KeyValue>> = OnceLock::new();
29-
30-
#[inline]
31-
fn stream_overflow_attributes() -> &'static Vec<KeyValue> {
32-
STREAM_OVERFLOW_ATTRIBUTES.get_or_init(|| vec![KeyValue::new("otel.metric.overflow", true)])
33-
}
27+
pub(crate) static STREAM_OVERFLOW_ATTRIBUTES: LazyLock<Vec<KeyValue>> =
28+
LazyLock::new(|| vec![KeyValue::new("otel.metric.overflow", true)]);
3429

3530
pub(crate) trait Aggregator {
3631
/// A static configuration that is needed in order to initialize aggregator.
@@ -157,12 +152,12 @@ where
157152
trackers.insert(sorted_attrs, new_tracker);
158153

159154
self.count.fetch_add(1, Ordering::SeqCst);
160-
} else if let Some(overflow_value) = trackers.get(stream_overflow_attributes().as_slice()) {
155+
} else if let Some(overflow_value) = trackers.get(STREAM_OVERFLOW_ATTRIBUTES.as_slice()) {
161156
overflow_value.update(value);
162157
} else {
163158
let new_tracker = A::create(&self.config);
164159
new_tracker.update(value);
165-
trackers.insert(stream_overflow_attributes().clone(), Arc::new(new_tracker));
160+
trackers.insert(STREAM_OVERFLOW_ATTRIBUTES.clone(), Arc::new(new_tracker));
166161
}
167162
}
168163

opentelemetry-sdk/src/propagation/baggage.rs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,12 @@ use opentelemetry::{
66
};
77
use percent_encoding::{percent_decode_str, utf8_percent_encode, AsciiSet, CONTROLS};
88
use std::iter;
9-
use std::sync::OnceLock;
9+
use std::sync::LazyLock;
1010

1111
static BAGGAGE_HEADER: &str = "baggage";
1212
const FRAGMENT: &AsciiSet = &CONTROLS.add(b' ').add(b'"').add(b';').add(b',').add(b'=');
1313

14-
// TODO Replace this with LazyLock once it is stable.
15-
static BAGGAGE_FIELDS: OnceLock<[String; 1]> = OnceLock::new();
16-
#[inline]
17-
fn baggage_fields() -> &'static [String; 1] {
18-
BAGGAGE_FIELDS.get_or_init(|| [BAGGAGE_HEADER.to_owned()])
19-
}
14+
static BAGGAGE_FIELDS: LazyLock<[String; 1]> = LazyLock::new(|| [BAGGAGE_HEADER.to_owned()]);
2015

2116
/// Propagates name-value pairs in [W3C Baggage] format.
2217
///
@@ -158,7 +153,7 @@ impl TextMapPropagator for BaggagePropagator {
158153
}
159154

160155
fn fields(&self) -> FieldIter<'_> {
161-
FieldIter::new(baggage_fields())
156+
FieldIter::new(&*BAGGAGE_FIELDS)
162157
}
163158
}
164159

opentelemetry-sdk/src/propagation/trace_context.rs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,15 @@ use opentelemetry::{
77
Context,
88
};
99
use std::str::FromStr;
10-
use std::sync::OnceLock;
10+
use std::sync::LazyLock;
1111

1212
const SUPPORTED_VERSION: u8 = 0;
1313
const MAX_VERSION: u8 = 254;
1414
const TRACEPARENT_HEADER: &str = "traceparent";
1515
const TRACESTATE_HEADER: &str = "tracestate";
1616

17-
// TODO Replace this with LazyLock once it is stable.
18-
static TRACE_CONTEXT_HEADER_FIELDS: OnceLock<[String; 2]> = OnceLock::new();
19-
20-
fn trace_context_header_fields() -> &'static [String; 2] {
21-
TRACE_CONTEXT_HEADER_FIELDS
22-
.get_or_init(|| [TRACEPARENT_HEADER.to_owned(), TRACESTATE_HEADER.to_owned()])
23-
}
17+
static TRACE_CONTEXT_HEADER_FIELDS: LazyLock<[String; 2]> =
18+
LazyLock::new(|| [TRACEPARENT_HEADER.to_owned(), TRACESTATE_HEADER.to_owned()]);
2419

2520
/// Propagates `SpanContext`s in [W3C TraceContext] format under `traceparent` and `tracestate` header.
2621
///
@@ -151,7 +146,7 @@ impl TextMapPropagator for TraceContextPropagator {
151146
}
152147

153148
fn fields(&self) -> FieldIter<'_> {
154-
FieldIter::new(trace_context_header_fields())
149+
FieldIter::new(&*TRACE_CONTEXT_HEADER_FIELDS)
155150
}
156151
}
157152

opentelemetry-sdk/src/trace/provider.rs

Lines changed: 16 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -74,32 +74,25 @@ use opentelemetry::otel_debug;
7474
use opentelemetry::{otel_info, InstrumentationScope};
7575
use std::borrow::Cow;
7676
use std::sync::atomic::{AtomicBool, Ordering};
77-
use std::sync::{Arc, OnceLock};
77+
use std::sync::{Arc, LazyLock, OnceLock};
7878
use std::time::Duration;
7979

8080
static PROVIDER_RESOURCE: OnceLock<Resource> = OnceLock::new();
8181

82-
// a no nop tracer provider used as placeholder when the provider is shutdown
83-
// TODO Replace with LazyLock once it is stable
84-
static NOOP_TRACER_PROVIDER: OnceLock<SdkTracerProvider> = OnceLock::new();
85-
#[inline]
86-
fn noop_tracer_provider() -> &'static SdkTracerProvider {
87-
NOOP_TRACER_PROVIDER.get_or_init(|| {
88-
SdkTracerProvider {
89-
inner: Arc::new(TracerProviderInner {
90-
processors: Vec::new(),
91-
config: Config {
92-
// cannot use default here as the default resource is not empty
93-
sampler: Box::new(Sampler::ParentBased(Box::new(Sampler::AlwaysOn))),
94-
id_generator: Box::<RandomIdGenerator>::default(),
95-
span_limits: SpanLimits::default(),
96-
resource: Cow::Owned(Resource::empty()),
97-
},
98-
is_shutdown: AtomicBool::new(true),
99-
}),
100-
}
101-
})
102-
}
82+
// a no-op tracer provider used as placeholder when the provider is shutdown
83+
static NOOP_TRACER_PROVIDER: LazyLock<SdkTracerProvider> = LazyLock::new(|| SdkTracerProvider {
84+
inner: Arc::new(TracerProviderInner {
85+
processors: Vec::new(),
86+
config: Config {
87+
// cannot use default here as the default resource is not empty
88+
sampler: Box::new(Sampler::ParentBased(Box::new(Sampler::AlwaysOn))),
89+
id_generator: Box::<RandomIdGenerator>::default(),
90+
span_limits: SpanLimits::default(),
91+
resource: Cow::Owned(Resource::empty()),
92+
},
93+
is_shutdown: AtomicBool::new(true),
94+
}),
95+
});
10396

10497
/// TracerProvider inner type
10598
#[derive(Debug)]
@@ -286,7 +279,7 @@ impl opentelemetry::trace::TracerProvider for SdkTracerProvider {
286279

287280
fn tracer_with_scope(&self, scope: InstrumentationScope) -> Self::Tracer {
288281
if self.inner.is_shutdown.load(Ordering::Relaxed) {
289-
return SdkTracer::new(scope, noop_tracer_provider().clone());
282+
return SdkTracer::new(scope, NOOP_TRACER_PROVIDER.clone());
290283
}
291284
if scope.name().is_empty() {
292285
otel_info!(name: "TracerNameEmpty", message = "Tracer name is empty; consider providing a meaningful name. Tracer will function normally and the provided name will be used as-is.");

0 commit comments

Comments
 (0)