Skip to content

Commit 303541f

Browse files
committed
chore: change OtelData to use an enum for different states
1 parent cbdb0bf commit 303541f

File tree

3 files changed

+179
-122
lines changed

3 files changed

+179
-122
lines changed

src/layer.rs

Lines changed: 92 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#[cfg(feature = "activate_context")]
22
use crate::stack::IdValueStack;
3-
use crate::OtelData;
3+
use crate::{OtelData, OtelDataState};
44
#[cfg(feature = "activate_context")]
55
use opentelemetry::ContextGuard;
66
use opentelemetry::{
@@ -9,12 +9,12 @@ use opentelemetry::{
99
};
1010
#[cfg(feature = "activate_context")]
1111
use std::cell::RefCell;
12-
use std::marker;
1312
use std::thread;
1413
#[cfg(not(all(target_arch = "wasm32", not(target_os = "wasi"))))]
1514
use std::time::Instant;
1615
use std::{any::TypeId, borrow::Cow};
1716
use std::{fmt, vec};
17+
use std::{marker, mem::take};
1818
use tracing_core::span::{self, Attributes, Id, Record};
1919
use tracing_core::{field, Event, Subscriber};
2020
#[cfg(feature = "tracing-log")]
@@ -165,16 +165,7 @@ struct SpanBuilderUpdates {
165165
}
166166

167167
impl SpanBuilderUpdates {
168-
fn update(self, span_builder: &mut Option<SpanBuilder>) -> Option<Self> {
169-
if let Some(builder) = span_builder.as_mut() {
170-
self.apply(builder);
171-
None
172-
} else {
173-
Some(self)
174-
}
175-
}
176-
177-
fn apply(self, span_builder: &mut SpanBuilder) {
168+
fn update(self, span_builder: &mut SpanBuilder) {
178169
let Self {
179170
name,
180171
span_kind,
@@ -970,15 +961,26 @@ where
970961
/// the context in the process.
971962
///
972963
fn start_cx(&self, otel_data: &mut OtelData) {
973-
if let Some(builder) = otel_data.builder.take() {
974-
let span = builder.start_with_context(&self.tracer, &otel_data.parent_cx);
975-
otel_data.parent_cx = otel_data.parent_cx.with_span(span);
964+
if let OtelDataState::Context { .. } = &otel_data.state {
965+
// If the context is already started, we do nothing.
966+
} else {
967+
match take(&mut otel_data.state) {
968+
OtelDataState::Builder { builder, parent_cx } => {
969+
let span = builder.start_with_context(&self.tracer, &parent_cx);
970+
let current_cx = parent_cx.with_span(span);
971+
otel_data.state = OtelDataState::Context { current_cx };
972+
}
973+
_ => (), // This should never happen.
974+
}
976975
}
977976
}
978977

979978
fn with_started_cx<U>(&self, otel_data: &mut OtelData, f: &dyn Fn(&OtelContext) -> U) -> U {
980979
self.start_cx(otel_data);
981-
f(&otel_data.parent_cx)
980+
match &otel_data.state {
981+
OtelDataState::Context { current_cx, .. } => f(current_cx),
982+
_ => panic!("OtelDataState should be a Context after starting it; this is a bug!"),
983+
}
982984
}
983985
}
984986

@@ -1071,12 +1073,10 @@ where
10711073
sem_conv_config: self.sem_conv_config,
10721074
});
10731075

1074-
let mut builder = Some(builder);
10751076
updates.update(&mut builder);
10761077
extensions.insert(OtelData {
1077-
builder,
1078-
parent_cx,
1079-
..Default::default()
1078+
state: OtelDataState::Builder { builder, parent_cx },
1079+
end_time: None,
10801080
});
10811081
}
10821082

@@ -1097,6 +1097,10 @@ where
10971097
GUARD_STACK.with(|stack| stack.borrow_mut().push(id.clone(), guard));
10981098
});
10991099
}
1100+
1101+
if !self.tracked_inactivity {
1102+
return;
1103+
}
11001104
}
11011105

11021106
if let Some(timings) = extensions.get_mut::<Timings>() {
@@ -1145,8 +1149,15 @@ where
11451149
});
11461150
let mut extensions = span.extensions_mut();
11471151
if let Some(otel_data) = extensions.get_mut::<OtelData>() {
1148-
if let Some(updates) = updates.update(&mut otel_data.builder) {
1149-
updates.update_span(&otel_data.parent_cx.span());
1152+
match &mut otel_data.state {
1153+
OtelDataState::Builder { builder, .. } => {
1154+
// If the builder is present, then update it.
1155+
updates.update(builder);
1156+
}
1157+
OtelDataState::Context { current_cx, .. } => {
1158+
// If the Context has been created, then update the span.
1159+
updates.update_span(&current_cx.span());
1160+
}
11501161
}
11511162
}
11521163
}
@@ -1168,14 +1179,17 @@ where
11681179
.expect("Missing otel data span extensions");
11691180
let follows_context =
11701181
self.with_started_cx(follows_data, &|cx| cx.span().span_context().clone());
1171-
if let Some(builder) = data.builder.as_mut() {
1172-
if let Some(ref mut links) = builder.links {
1173-
links.push(otel::Link::with_context(follows_context));
1174-
} else {
1175-
builder.links = Some(vec![otel::Link::with_context(follows_context)]);
1182+
match &mut data.state {
1183+
OtelDataState::Builder { builder, .. } => {
1184+
if let Some(ref mut links) = builder.links {
1185+
links.push(otel::Link::with_context(follows_context));
1186+
} else {
1187+
builder.links = Some(vec![otel::Link::with_context(follows_context)]);
1188+
}
1189+
}
1190+
OtelDataState::Context { current_cx, .. } => {
1191+
current_cx.span().add_link(follows_context, vec![]);
11761192
}
1177-
} else {
1178-
data.parent_cx.span().add_link(follows_context, vec![]);
11791193
}
11801194
}
11811195
}
@@ -1280,33 +1294,36 @@ where
12801294
}
12811295
}
12821296

1283-
if let Some(builder) = otel_data.builder.as_mut() {
1284-
if builder.status == otel::Status::Unset
1285-
&& *meta.level() == tracing_core::Level::ERROR
1286-
{
1287-
builder.status = otel::Status::error("");
1288-
}
1289-
if let Some(builder_updates) = builder_updates {
1290-
builder_updates.apply(builder);
1297+
match &mut otel_data.state {
1298+
OtelDataState::Builder { builder, .. } => {
1299+
if builder.status == otel::Status::Unset
1300+
&& *meta.level() == tracing_core::Level::ERROR
1301+
{
1302+
builder.status = otel::Status::error("");
1303+
}
1304+
if let Some(builder_updates) = builder_updates {
1305+
builder_updates.update(builder);
1306+
}
1307+
if let Some(ref mut events) = builder.events {
1308+
events.push(otel_event);
1309+
} else {
1310+
builder.events = Some(vec![otel_event]);
1311+
}
12911312
}
1292-
if let Some(ref mut events) = builder.events {
1293-
events.push(otel_event);
1294-
} else {
1295-
builder.events = Some(vec![otel_event]);
1296-
}
1297-
} else {
1298-
let span = otel_data.parent_cx.span();
1299-
// TODO:ban fix this with accessor in SpanRef that can check the span status
1300-
if *meta.level() == tracing_core::Level::ERROR {
1301-
span.set_status(otel::Status::error(""));
1313+
OtelDataState::Context { current_cx, .. } => {
1314+
let span = current_cx.span();
1315+
// TODO:ban fix this with accessor in SpanRef that can check the span status
1316+
if *meta.level() == tracing_core::Level::ERROR {
1317+
span.set_status(otel::Status::error(""));
1318+
}
1319+
if let Some(builder_updates) = builder_updates {
1320+
builder_updates.update_span(&span);
1321+
}
1322+
span.add_event(otel_event.name, otel_event.attributes);
13021323
}
1303-
if let Some(builder_updates) = builder_updates {
1304-
builder_updates.update_span(&span);
1305-
}
1306-
span.add_event(otel_event.name, otel_event.attributes);
13071324
}
1308-
}
1309-
};
1325+
};
1326+
}
13101327
}
13111328

13121329
/// Exports an OpenTelemetry [`Span`] on close.
@@ -1325,12 +1342,7 @@ where
13251342
(extensions.remove::<OtelData>(), timings)
13261343
};
13271344

1328-
if let Some(OtelData {
1329-
builder,
1330-
parent_cx,
1331-
end_time,
1332-
}) = otel_data
1333-
{
1345+
if let Some(OtelData { state, end_time }) = otel_data {
13341346
// Append busy/idle timings when enabled.
13351347
let timings = timings.map(|timings| {
13361348
let busy_ns = Key::new("busy_ns");
@@ -1342,24 +1354,28 @@ where
13421354
]
13431355
});
13441356

1345-
if let Some(builder) = builder {
1346-
// Don't create the context here just to get a SpanRef since it's costly
1347-
let mut span = builder.start_with_context(&self.tracer, &parent_cx);
1348-
if let Some(timings) = timings {
1349-
span.set_attributes(timings)
1350-
};
1351-
if let Some(end_time) = end_time {
1352-
span.end_with_timestamp(end_time);
1353-
} else {
1354-
span.end();
1357+
match state {
1358+
OtelDataState::Builder { builder, parent_cx } => {
1359+
// Don't create the context here just to get a SpanRef since it's costly
1360+
let mut span = builder.start_with_context(&self.tracer, &parent_cx);
1361+
if let Some(timings) = timings {
1362+
span.set_attributes(timings)
1363+
};
1364+
if let Some(end_time) = end_time {
1365+
span.end_with_timestamp(end_time);
1366+
} else {
1367+
span.end();
1368+
}
13551369
}
1356-
} else {
1357-
let span = parent_cx.span();
1358-
if let Some(timings) = timings {
1359-
span.set_attributes(timings)
1360-
};
1361-
end_time.map_or_else(|| span.end(), |end_time| span.end_with_timestamp(end_time));
1362-
};
1370+
OtelDataState::Context { current_cx } => {
1371+
let span = current_cx.span();
1372+
if let Some(timings) = timings {
1373+
span.set_attributes(timings)
1374+
};
1375+
end_time
1376+
.map_or_else(|| span.end(), |end_time| span.end_with_timestamp(end_time));
1377+
}
1378+
}
13631379
}
13641380
}
13651381

src/lib.rs

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -130,15 +130,33 @@ pub use metrics::MetricsLayer;
130130
pub use span_ext::OpenTelemetrySpanExt;
131131

132132
/// Per-span OpenTelemetry data tracked by this crate.
133-
#[derive(Debug, Clone, Default)]
134-
struct OtelData {
135-
/// The parent otel `Context` for the current tracing span.
136-
pub parent_cx: opentelemetry::Context,
133+
#[derive(Debug)]
134+
pub(crate) struct OtelData {
135+
/// The state of the OtelData, which can either be a builder or a context.
136+
state: OtelDataState,
137+
/// The end time of the span if it has been exited.
138+
end_time: Option<SystemTime>,
139+
}
137140

138-
/// The otel span data recorded during the current tracing span.
139-
pub builder: Option<opentelemetry::trace::SpanBuilder>,
141+
/// The state of the OpenTelemetry data for a span.
142+
#[derive(Debug)]
143+
#[allow(clippy::large_enum_variant)]
144+
pub(crate) enum OtelDataState {
145+
/// The span is being built, with a parent context and a builder.
146+
Builder {
147+
parent_cx: opentelemetry::Context,
148+
builder: opentelemetry::trace::SpanBuilder,
149+
},
150+
/// The span has been started or accessed and is now in a context.
151+
Context { current_cx: opentelemetry::Context },
152+
}
140153

141-
end_time: Option<SystemTime>,
154+
impl Default for OtelDataState {
155+
fn default() -> Self {
156+
OtelDataState::Context {
157+
current_cx: opentelemetry::Context::default(),
158+
}
159+
}
142160
}
143161

144162
pub(crate) mod time {

0 commit comments

Comments
 (0)