Skip to content

Commit 01975a7

Browse files
committed
initial commit
1 parent af9d925 commit 01975a7

File tree

8 files changed

+75
-95
lines changed

8 files changed

+75
-95
lines changed

opentelemetry-sdk/benches/metrics_counter.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
|--------------------------------|-------------|
1010
| Counter_Add_Sorted | 172 ns |
1111
| Counter_Add_Unsorted | 183 ns |
12-
| Counter_Overflow | 898 ns |
12+
| Counter_Overflow | 562 ns |
1313
| ThreadLocal_Random_Generator_5 | 37 ns |
1414
*/
1515

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

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ pub(crate) use exponential_histogram::{EXPO_MAX_SCALE, EXPO_MIN_SCALE};
1818
use once_cell::sync::Lazy;
1919
use opentelemetry::{otel_warn, KeyValue};
2020

21-
use crate::metrics::AttributeSet;
22-
2321
pub(crate) static STREAM_OVERFLOW_ATTRIBUTES: Lazy<Vec<KeyValue>> =
2422
Lazy::new(|| vec![KeyValue::new("otel.metric.overflow", "true")]);
2523

@@ -95,7 +93,7 @@ where
9593
}
9694

9795
// Try to retrieve and update the tracker with the attributes sorted.
98-
let sorted_attrs = AttributeSet::from(attributes).into_vec();
96+
let sorted_attrs = sort_and_dedup(attributes);
9997
if let Some(tracker) = trackers.get(sorted_attrs.as_slice()) {
10098
tracker.update(value);
10199
return;
@@ -198,6 +196,16 @@ fn prepare_data<T>(data: &mut Vec<T>, list_len: usize) {
198196
}
199197
}
200198

199+
fn sort_and_dedup(attributes: &[KeyValue]) -> Vec<KeyValue> {
200+
// Use newly allocated vec here as incoming attributes are immutable so
201+
// cannot sort/de-dup in-place. TODO: This allocation can be avoided by
202+
// leveraging a ThreadLocal vec.
203+
let mut sorted = attributes.to_vec();
204+
sorted.sort_unstable_by(|a, b| a.key.cmp(&b.key));
205+
sorted.dedup_by(|a, b| a.key == b.key);
206+
sorted
207+
}
208+
201209
/// Marks a type that can have a value added and retrieved atomically. Required since
202210
/// different types have different backing atomic mechanisms
203211
pub(crate) trait AtomicTracker<T>: Sync + Send + 'static {

opentelemetry-sdk/src/metrics/mod.rs

Lines changed: 1 addition & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,7 @@ pub use view::*;
7777
// #[cfg(not(feature = "spec_unstable_metrics_views"))]
7878
// pub(crate) use view::*;
7979

80-
use std::collections::hash_map::DefaultHasher;
81-
use std::collections::HashSet;
82-
use std::hash::{Hash, Hasher};
83-
84-
use opentelemetry::KeyValue;
80+
use std::hash::Hash;
8581

8682
/// Defines the window that an aggregation was calculated over.
8783
#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, Hash)]
@@ -106,60 +102,6 @@ pub enum Temporality {
106102
LowMemory,
107103
}
108104

109-
/// A unique set of attributes that can be used as instrument identifiers.
110-
///
111-
/// This must implement [Hash], [PartialEq], and [Eq] so it may be used as
112-
/// HashMap keys and other de-duplication methods.
113-
#[derive(Clone, Default, Debug, PartialEq, Eq)]
114-
pub(crate) struct AttributeSet(Vec<KeyValue>, u64);
115-
116-
impl From<&[KeyValue]> for AttributeSet {
117-
fn from(values: &[KeyValue]) -> Self {
118-
let mut seen_keys = HashSet::with_capacity(values.len());
119-
let vec = values
120-
.iter()
121-
.rev()
122-
.filter_map(|kv| {
123-
if seen_keys.insert(kv.key.clone()) {
124-
Some(kv.clone())
125-
} else {
126-
None
127-
}
128-
})
129-
.collect::<Vec<_>>();
130-
131-
AttributeSet::new(vec)
132-
}
133-
}
134-
135-
fn calculate_hash(values: &[KeyValue]) -> u64 {
136-
let mut hasher = DefaultHasher::new();
137-
values.iter().fold(&mut hasher, |mut hasher, item| {
138-
item.hash(&mut hasher);
139-
hasher
140-
});
141-
hasher.finish()
142-
}
143-
144-
impl AttributeSet {
145-
fn new(mut values: Vec<KeyValue>) -> Self {
146-
values.sort_unstable_by(|a, b| a.key.cmp(&b.key));
147-
let hash = calculate_hash(&values);
148-
AttributeSet(values, hash)
149-
}
150-
151-
/// Returns the underlying Vec of KeyValue pairs
152-
pub(crate) fn into_vec(self) -> Vec<KeyValue> {
153-
self.0
154-
}
155-
}
156-
157-
impl Hash for AttributeSet {
158-
fn hash<H: Hasher>(&self, state: &mut H) {
159-
state.write_u64(self.1)
160-
}
161-
}
162-
163105
#[cfg(all(test, feature = "testing"))]
164106
mod tests {
165107
use self::data::{DataPoint, HistogramDataPoint, ScopeMetrics};

opentelemetry/Cargo.toml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,8 @@ all-features = true
2121
rustdoc-args = ["--cfg", "docsrs"]
2222

2323
[dependencies]
24-
futures-core = { workspace = true }
25-
futures-sink = "0.3"
26-
once_cell = { workspace = true }
24+
futures-core = { workspace = true, optional = true }
25+
futures-sink = { version = "0.3", optional = true }
2726
pin-project-lite = { workspace = true, optional = true }
2827
thiserror = { workspace = true }
2928
tracing = {workspace = true, optional = true} # optional for opentelemetry internal logging
@@ -33,7 +32,7 @@ js-sys = "0.3.63"
3332

3433
[features]
3534
default = ["trace", "metrics", "logs"]
36-
trace = ["pin-project-lite"]
35+
trace = ["pin-project-lite", "futures-sink", "futures-core"]
3736
metrics = []
3837
testing = ["trace", "metrics"]
3938
logs = []

opentelemetry/src/baggage.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,22 @@
1515
//!
1616
//! [W3C Baggage]: https://w3c.github.io/baggage
1717
use crate::{Context, Key, KeyValue, Value};
18-
use once_cell::sync::Lazy;
1918
use std::collections::{hash_map, HashMap};
2019
use std::fmt;
20+
use std::sync::OnceLock;
2121

22-
static DEFAULT_BAGGAGE: Lazy<Baggage> = Lazy::new(Baggage::default);
22+
static DEFAULT_BAGGAGE: OnceLock<Baggage> = OnceLock::new();
2323

2424
const MAX_KEY_VALUE_PAIRS: usize = 180;
2525
const MAX_BYTES_FOR_ONE_PAIR: usize = 4096;
2626
const MAX_LEN_OF_ALL_PAIRS: usize = 8192;
2727

28+
/// Returns the default baggage, ensuring it is initialized only once.
29+
#[inline]
30+
fn get_default_baggage() -> &'static Baggage {
31+
DEFAULT_BAGGAGE.get_or_init(Baggage::default)
32+
}
33+
2834
/// A set of name/value pairs describing user-defined properties.
2935
///
3036
/// ### Baggage Names
@@ -399,7 +405,7 @@ impl BaggageExt for Context {
399405
}
400406

401407
fn baggage(&self) -> &Baggage {
402-
self.get::<Baggage>().unwrap_or(&DEFAULT_BAGGAGE)
408+
self.get::<Baggage>().unwrap_or(get_default_baggage())
403409
}
404410
}
405411

opentelemetry/src/global/metrics.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,35 @@
11
use crate::metrics::{self, Meter, MeterProvider};
22
use crate::InstrumentationScope;
3-
use once_cell::sync::Lazy;
4-
use std::sync::{Arc, RwLock};
3+
use std::sync::{Arc, OnceLock, RwLock};
54

65
type GlobalMeterProvider = Arc<dyn MeterProvider + Send + Sync>;
76

87
/// The global `MeterProvider` singleton.
9-
static GLOBAL_METER_PROVIDER: Lazy<RwLock<GlobalMeterProvider>> =
10-
Lazy::new(|| RwLock::new(Arc::new(crate::metrics::noop::NoopMeterProvider::new())));
8+
static GLOBAL_METER_PROVIDER: OnceLock<RwLock<GlobalMeterProvider>> = OnceLock::new();
9+
10+
#[inline]
11+
fn global_meter_provider() -> &'static RwLock<GlobalMeterProvider> {
12+
GLOBAL_METER_PROVIDER
13+
.get_or_init(|| RwLock::new(Arc::new(crate::metrics::noop::NoopMeterProvider::new())))
14+
}
1115

1216
/// Sets the given [`MeterProvider`] instance as the current global meter
1317
/// provider.
1418
pub fn set_meter_provider<P>(new_provider: P)
1519
where
1620
P: metrics::MeterProvider + Send + Sync + 'static,
1721
{
18-
let mut global_provider = GLOBAL_METER_PROVIDER
22+
let global_provider = global_meter_provider();
23+
let mut global_provider = global_provider
1924
.write()
2025
.expect("GLOBAL_METER_PROVIDER RwLock poisoned");
2126
*global_provider = Arc::new(new_provider);
2227
}
2328

2429
/// Returns an instance of the currently configured global [`MeterProvider`].
2530
pub fn meter_provider() -> GlobalMeterProvider {
26-
GLOBAL_METER_PROVIDER
31+
let global_provider = global_meter_provider();
32+
global_provider
2733
.read()
2834
.expect("GLOBAL_METER_PROVIDER RwLock poisoned")
2935
.clone()
Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,30 @@
11
use crate::propagation::TextMapPropagator;
22
use crate::trace::noop::NoopTextMapPropagator;
3-
use once_cell::sync::Lazy;
4-
use std::sync::RwLock;
3+
use std::sync::{OnceLock, RwLock};
54

65
/// The current global `TextMapPropagator` propagator.
7-
static GLOBAL_TEXT_MAP_PROPAGATOR: Lazy<RwLock<Box<dyn TextMapPropagator + Send + Sync>>> =
8-
Lazy::new(|| RwLock::new(Box::new(NoopTextMapPropagator::new())));
6+
static GLOBAL_TEXT_MAP_PROPAGATOR: OnceLock<RwLock<Box<dyn TextMapPropagator + Send + Sync>>> =
7+
OnceLock::new();
98

109
/// The global default `TextMapPropagator` propagator.
11-
static DEFAULT_TEXT_MAP_PROPAGATOR: Lazy<NoopTextMapPropagator> =
12-
Lazy::new(NoopTextMapPropagator::new);
10+
static DEFAULT_TEXT_MAP_PROPAGATOR: OnceLock<NoopTextMapPropagator> = OnceLock::new();
11+
12+
/// Ensures the `GLOBAL_TEXT_MAP_PROPAGATOR` is initialized with a `NoopTextMapPropagator`.
13+
#[inline]
14+
fn init_global_text_map_propagator() -> &'static RwLock<Box<dyn TextMapPropagator + Send + Sync>> {
15+
GLOBAL_TEXT_MAP_PROPAGATOR.get_or_init(|| RwLock::new(Box::new(NoopTextMapPropagator::new())))
16+
}
17+
18+
/// Ensures the `DEFAULT_TEXT_MAP_PROPAGATOR` is initialized.
19+
#[inline]
20+
fn init_default_text_map_propagator() -> &'static NoopTextMapPropagator {
21+
DEFAULT_TEXT_MAP_PROPAGATOR.get_or_init(NoopTextMapPropagator::new)
22+
}
1323

1424
/// Sets the given [`TextMapPropagator`] propagator as the current global propagator.
1525
pub fn set_text_map_propagator<P: TextMapPropagator + Send + Sync + 'static>(propagator: P) {
16-
let _lock = GLOBAL_TEXT_MAP_PROPAGATOR
26+
let global_propagator = init_global_text_map_propagator();
27+
let _lock = global_propagator
1728
.write()
1829
.map(|mut global_propagator| *global_propagator = Box::new(propagator));
1930
}
@@ -23,8 +34,12 @@ pub fn get_text_map_propagator<T, F>(mut f: F) -> T
2334
where
2435
F: FnMut(&dyn TextMapPropagator) -> T,
2536
{
26-
GLOBAL_TEXT_MAP_PROPAGATOR
37+
let global_propagator = init_global_text_map_propagator();
38+
global_propagator
2739
.read()
2840
.map(|propagator| f(&**propagator))
29-
.unwrap_or_else(|_| f(&*DEFAULT_TEXT_MAP_PROPAGATOR as &dyn TextMapPropagator))
41+
.unwrap_or_else(|_| {
42+
let default_propagator = init_default_text_map_propagator();
43+
f(default_propagator as &dyn TextMapPropagator)
44+
})
3045
}

opentelemetry/src/global/trace.rs

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
use crate::trace::{noop::NoopTracerProvider, SpanContext, Status};
22
use crate::InstrumentationScope;
33
use crate::{trace, trace::TracerProvider, Context, KeyValue};
4-
use once_cell::sync::Lazy;
54
use std::borrow::Cow;
65
use std::fmt;
76
use std::mem;
8-
use std::sync::{Arc, RwLock};
7+
use std::sync::{Arc, OnceLock, RwLock};
98
use std::time::SystemTime;
109

1110
/// Allows a specific [`crate::trace::Span`] to be used generically by [`BoxedSpan`]
@@ -360,19 +359,22 @@ impl trace::TracerProvider for GlobalTracerProvider {
360359
}
361360

362361
/// The global `Tracer` provider singleton.
363-
static GLOBAL_TRACER_PROVIDER: Lazy<RwLock<GlobalTracerProvider>> = Lazy::new(|| {
364-
RwLock::new(GlobalTracerProvider::new(
365-
trace::noop::NoopTracerProvider::new(),
366-
))
367-
});
362+
static GLOBAL_TRACER_PROVIDER: OnceLock<RwLock<GlobalTracerProvider>> = OnceLock::new();
363+
364+
#[inline]
365+
fn global_tracer_provider() -> &'static RwLock<GlobalTracerProvider> {
366+
GLOBAL_TRACER_PROVIDER
367+
.get_or_init(|| RwLock::new(GlobalTracerProvider::new(NoopTracerProvider::new())))
368+
}
368369

369370
/// Returns an instance of the currently configured global [`TracerProvider`] through
370371
/// [`GlobalTracerProvider`].
371372
///
372373
/// [`TracerProvider`]: crate::trace::TracerProvider
373374
/// [`GlobalTracerProvider`]: crate::global::GlobalTracerProvider
374375
pub fn tracer_provider() -> GlobalTracerProvider {
375-
GLOBAL_TRACER_PROVIDER
376+
let global_provider = global_tracer_provider();
377+
global_provider
376378
.read()
377379
.expect("GLOBAL_TRACER_PROVIDER RwLock poisoned")
378380
.clone()
@@ -428,7 +430,8 @@ where
428430
T: trace::Tracer<Span = S> + Send + Sync + 'static,
429431
P: trace::TracerProvider<Tracer = T> + Send + Sync + 'static,
430432
{
431-
let mut tracer_provider = GLOBAL_TRACER_PROVIDER
433+
let global_provider = global_tracer_provider();
434+
let mut tracer_provider = global_provider
432435
.write()
433436
.expect("GLOBAL_TRACER_PROVIDER RwLock poisoned");
434437
mem::replace(
@@ -440,7 +443,8 @@ where
440443
/// Shut down the current tracer provider. This will invoke the shutdown method on all span processors.
441444
/// span processors should export remaining spans before return
442445
pub fn shutdown_tracer_provider() {
443-
let mut tracer_provider = GLOBAL_TRACER_PROVIDER
446+
let global_provider = global_tracer_provider();
447+
let mut tracer_provider = global_provider
444448
.write()
445449
.expect("GLOBAL_TRACER_PROVIDER RwLock poisoned");
446450

0 commit comments

Comments
 (0)