Skip to content

Commit fda011c

Browse files
committed
layer: refactor visitors to not require SpanBuilder
1 parent 101dc89 commit fda011c

File tree

1 file changed

+100
-53
lines changed

1 file changed

+100
-53
lines changed

src/layer.rs

Lines changed: 100 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
use crate::{OtelData, PreSampledTracer};
22
use once_cell::unsync;
33
use opentelemetry::{
4-
trace::{self as otel, noop, TraceContextExt},
4+
trace::{self as otel, noop, SpanBuilder, SpanKind, Status, TraceContextExt},
55
Context as OtelContext, Key, KeyValue, StringValue, Value,
66
};
7-
use std::any::TypeId;
87
use std::fmt;
98
use std::marker;
109
use std::thread;
1110
#[cfg(not(target_arch = "wasm32"))]
1211
use std::time::Instant;
12+
use std::{any::TypeId, borrow::Cow};
1313
use tracing_core::span::{self, Attributes, Id, Record};
1414
use tracing_core::{field, Event, Subscriber};
1515
#[cfg(feature = "tracing-log")]
@@ -117,9 +117,45 @@ fn str_to_status(s: &str) -> otel::Status {
117117
}
118118
}
119119

120+
#[derive(Default)]
121+
struct SpanBuilderUpdates {
122+
name: Option<Cow<'static, str>>,
123+
span_kind: Option<SpanKind>,
124+
status: Option<Status>,
125+
attributes: Option<Vec<KeyValue>>,
126+
}
127+
128+
impl SpanBuilderUpdates {
129+
fn update(self, span_builder: &mut SpanBuilder) {
130+
let Self {
131+
name,
132+
span_kind,
133+
status,
134+
attributes,
135+
} = self;
136+
137+
if let Some(name) = name {
138+
span_builder.name = name;
139+
}
140+
if let Some(span_kind) = span_kind {
141+
span_builder.span_kind = Some(span_kind);
142+
}
143+
if let Some(status) = status {
144+
span_builder.status = status;
145+
}
146+
if let Some(attributes) = attributes {
147+
if let Some(builder_attributes) = &mut span_builder.attributes {
148+
builder_attributes.extend(attributes);
149+
} else {
150+
span_builder.attributes = Some(attributes);
151+
}
152+
}
153+
}
154+
}
155+
120156
struct SpanEventVisitor<'a, 'b> {
121157
event_builder: &'a mut otel::Event,
122-
span_builder: Option<&'b mut otel::SpanBuilder>,
158+
span_builder_updates: &'b mut Option<SpanBuilderUpdates>,
123159
sem_conv_config: SemConvConfig,
124160
}
125161

@@ -186,9 +222,10 @@ impl<'a, 'b> field::Visit for SpanEventVisitor<'a, 'b> {
186222
// In both cases, an event with an empty name and with an error attribute is created.
187223
"error" if self.event_builder.name.is_empty() => {
188224
if self.sem_conv_config.error_events_to_status {
189-
if let Some(span) = &mut self.span_builder {
190-
span.status = otel::Status::error(format!("{:?}", value));
191-
}
225+
self.span_builder_updates
226+
.get_or_insert_with(SpanBuilderUpdates::default)
227+
.status
228+
.replace(otel::Status::error(format!("{:?}", value)));
192229
}
193230
if self.sem_conv_config.error_events_to_exceptions {
194231
self.event_builder.name = EVENT_EXCEPTION_NAME.into();
@@ -225,9 +262,10 @@ impl<'a, 'b> field::Visit for SpanEventVisitor<'a, 'b> {
225262
// In both cases, an event with an empty name and with an error attribute is created.
226263
"error" if self.event_builder.name.is_empty() => {
227264
if self.sem_conv_config.error_events_to_status {
228-
if let Some(span) = &mut self.span_builder {
229-
span.status = otel::Status::error(format!("{:?}", value));
230-
}
265+
self.span_builder_updates
266+
.get_or_insert_with(SpanBuilderUpdates::default)
267+
.status
268+
.replace(otel::Status::error(format!("{:?}", value)));
231269
}
232270
if self.sem_conv_config.error_events_to_exceptions {
233271
self.event_builder.name = EVENT_EXCEPTION_NAME.into();
@@ -288,25 +326,27 @@ impl<'a, 'b> field::Visit for SpanEventVisitor<'a, 'b> {
288326
}
289327

290328
if self.sem_conv_config.error_records_to_exceptions {
291-
if let Some(span) = &mut self.span_builder {
292-
if let Some(attrs) = span.attributes.as_mut() {
293-
attrs.push(KeyValue::new(
294-
FIELD_EXCEPTION_MESSAGE,
295-
Value::String(error_msg.clone().into()),
296-
));
329+
let attributes = self
330+
.span_builder_updates
331+
.get_or_insert_with(SpanBuilderUpdates::default)
332+
.attributes
333+
.get_or_insert_with(Vec::new);
297334

298-
// NOTE: This is actually not the stacktrace of the exception. This is
299-
// the "source chain". It represents the heirarchy of errors from the
300-
// app level to the lowest level such as IO. It does not represent all
301-
// of the callsites in the code that led to the error happening.
302-
// `std::error::Error::backtrace` is a nightly-only API and cannot be
303-
// used here until the feature is stabilized.
304-
attrs.push(KeyValue::new(
305-
FIELD_EXCEPTION_STACKTRACE,
306-
Value::Array(chain.clone().into()),
307-
));
308-
}
309-
}
335+
attributes.push(KeyValue::new(
336+
FIELD_EXCEPTION_MESSAGE,
337+
Value::String(error_msg.clone().into()),
338+
));
339+
340+
// NOTE: This is actually not the stacktrace of the exception. This is
341+
// the "source chain". It represents the heirarchy of errors from the
342+
// app level to the lowest level such as IO. It does not represent all
343+
// of the callsites in the code that led to the error happening.
344+
// `std::error::Error::backtrace` is a nightly-only API and cannot be
345+
// used here until the feature is stabilized.
346+
attributes.push(KeyValue::new(
347+
FIELD_EXCEPTION_STACKTRACE,
348+
Value::Array(chain.clone().into()),
349+
));
310350
}
311351

312352
self.event_builder
@@ -354,16 +394,16 @@ struct SemConvConfig {
354394
}
355395

356396
struct SpanAttributeVisitor<'a> {
357-
span_builder: &'a mut otel::SpanBuilder,
397+
span_builder_updates: &'a mut SpanBuilderUpdates,
358398
sem_conv_config: SemConvConfig,
359399
}
360400

361401
impl<'a> SpanAttributeVisitor<'a> {
362402
fn record(&mut self, attribute: KeyValue) {
363-
debug_assert!(self.span_builder.attributes.is_some());
364-
if let Some(v) = self.span_builder.attributes.as_mut() {
365-
v.push(KeyValue::new(attribute.key, attribute.value));
366-
}
403+
self.span_builder_updates
404+
.attributes
405+
.get_or_insert_with(Vec::new)
406+
.push(KeyValue::new(attribute.key, attribute.value));
367407
}
368408
}
369409

@@ -394,11 +434,11 @@ impl<'a> field::Visit for SpanAttributeVisitor<'a> {
394434
/// [`Span`]: opentelemetry::trace::Span
395435
fn record_str(&mut self, field: &field::Field, value: &str) {
396436
match field.name() {
397-
SPAN_NAME_FIELD => self.span_builder.name = value.to_string().into(),
398-
SPAN_KIND_FIELD => self.span_builder.span_kind = str_to_span_kind(value),
399-
SPAN_STATUS_CODE_FIELD => self.span_builder.status = str_to_status(value),
437+
SPAN_NAME_FIELD => self.span_builder_updates.name = Some(value.to_string().into()),
438+
SPAN_KIND_FIELD => self.span_builder_updates.span_kind = str_to_span_kind(value),
439+
SPAN_STATUS_CODE_FIELD => self.span_builder_updates.status = Some(str_to_status(value)),
400440
SPAN_STATUS_MESSAGE_FIELD => {
401-
self.span_builder.status = otel::Status::error(value.to_string())
441+
self.span_builder_updates.status = Some(otel::Status::error(value.to_string()))
402442
}
403443
_ => self.record(KeyValue::new(field.name(), value.to_string())),
404444
}
@@ -410,15 +450,15 @@ impl<'a> field::Visit for SpanAttributeVisitor<'a> {
410450
/// [`Span`]: opentelemetry::trace::Span
411451
fn record_debug(&mut self, field: &field::Field, value: &dyn fmt::Debug) {
412452
match field.name() {
413-
SPAN_NAME_FIELD => self.span_builder.name = format!("{:?}", value).into(),
453+
SPAN_NAME_FIELD => self.span_builder_updates.name = Some(format!("{:?}", value).into()),
414454
SPAN_KIND_FIELD => {
415-
self.span_builder.span_kind = str_to_span_kind(&format!("{:?}", value))
455+
self.span_builder_updates.span_kind = str_to_span_kind(&format!("{:?}", value))
416456
}
417457
SPAN_STATUS_CODE_FIELD => {
418-
self.span_builder.status = str_to_status(&format!("{:?}", value))
458+
self.span_builder_updates.status = Some(str_to_status(&format!("{:?}", value)))
419459
}
420460
SPAN_STATUS_MESSAGE_FIELD => {
421-
self.span_builder.status = otel::Status::error(format!("{:?}", value))
461+
self.span_builder_updates.status = Some(otel::Status::error(format!("{:?}", value)))
422462
}
423463
_ => self.record(Key::new(field.name()).string(format!("{:?}", value))),
424464
}
@@ -904,10 +944,13 @@ where
904944
}
905945
}
906946

947+
let mut updates = SpanBuilderUpdates::default();
907948
attrs.record(&mut SpanAttributeVisitor {
908-
span_builder: &mut builder,
949+
span_builder_updates: &mut updates,
909950
sem_conv_config: self.sem_conv_config,
910951
});
952+
953+
updates.update(&mut builder);
911954
extensions.insert(OtelData { builder, parent_cx });
912955
}
913956

@@ -946,12 +989,14 @@ where
946989
/// [`attributes`]: opentelemetry::trace::SpanBuilder::attributes
947990
fn on_record(&self, id: &Id, values: &Record<'_>, ctx: Context<'_, S>) {
948991
let span = ctx.span(id).expect("Span not found, this is a bug");
992+
let mut updates = SpanBuilderUpdates::default();
993+
values.record(&mut SpanAttributeVisitor {
994+
span_builder_updates: &mut updates,
995+
sem_conv_config: self.sem_conv_config,
996+
});
949997
let mut extensions = span.extensions_mut();
950998
if let Some(data) = extensions.get_mut::<OtelData>() {
951-
values.record(&mut SpanAttributeVisitor {
952-
span_builder: &mut data.builder,
953-
sem_conv_config: self.sem_conv_config,
954-
});
999+
updates.update(&mut data.builder);
9551000
}
9561001
}
9571002

@@ -1023,24 +1068,24 @@ where
10231068
#[cfg(not(feature = "tracing-log"))]
10241069
let target = target.string(meta.target());
10251070

1026-
// Move out extension data to not hold the extensions lock across the event.record() call, which could result in a deadlock
1027-
let mut otel_data = span.extensions_mut().remove::<OtelData>();
1028-
let span_builder = otel_data.as_mut().map(|data| &mut data.builder);
1029-
10301071
let mut otel_event = otel::Event::new(
10311072
String::new(),
10321073
crate::time::now(),
10331074
vec![Key::new("level").string(meta.level().as_str()), target],
10341075
0,
10351076
);
10361077

1078+
let mut builder_updates = None;
10371079
event.record(&mut SpanEventVisitor {
10381080
event_builder: &mut otel_event,
1039-
span_builder,
1081+
span_builder_updates: &mut builder_updates,
10401082
sem_conv_config: self.sem_conv_config,
10411083
});
10421084

1043-
if let Some(mut otel_data) = otel_data {
1085+
let mut extensions = span.extensions_mut();
1086+
let otel_data = extensions.get_mut::<OtelData>();
1087+
1088+
if let Some(otel_data) = otel_data {
10441089
let builder = &mut otel_data.builder;
10451090

10461091
if builder.status == otel::Status::Unset
@@ -1049,6 +1094,10 @@ where
10491094
builder.status = otel::Status::error("")
10501095
}
10511096

1097+
if let Some(builder_updates) = builder_updates {
1098+
builder_updates.update(builder);
1099+
}
1100+
10521101
if self.location {
10531102
#[cfg(not(feature = "tracing-log"))]
10541103
let normalized_meta: Option<tracing_core::Metadata<'_>> = None;
@@ -1085,8 +1134,6 @@ where
10851134
} else {
10861135
builder.events = Some(vec![otel_event]);
10871136
}
1088-
1089-
span.extensions_mut().replace(otel_data);
10901137
}
10911138
};
10921139
}

0 commit comments

Comments
 (0)