From 71628d6b5901ef95124bf3ed429e96b68f736161 Mon Sep 17 00:00:00 2001 From: Julian Tescher Date: Fri, 9 Oct 2020 10:07:52 -0700 Subject: [PATCH] opentelemetry: Assign default ids if missing ## Motivation It is currently possible to create a span graph which includes a span that has both an invalid parent otel context _and_ a missing trace id by assigning an invalid extracted parent context to a non-root span. Constructing this particular graph will currently cause a panic. ## Solution Explicitly assign invalid trace / span ids when sampling using the otel SDK if the span builder does not contain these values. --- tracing-opentelemetry/src/tracer.rs | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/tracing-opentelemetry/src/tracer.rs b/tracing-opentelemetry/src/tracer.rs index d2ba4c59c6..7921df8fab 100644 --- a/tracing-opentelemetry/src/tracer.rs +++ b/tracing-opentelemetry/src/tracer.rs @@ -56,14 +56,18 @@ impl PreSampledTracer for api::NoopTracer { impl PreSampledTracer for sdk::Tracer { fn sampled_span_context(&self, builder: &mut api::SpanBuilder) -> api::SpanContext { - let span_id = builder.span_id.expect("Builders must have id"); + let span_id = builder + .span_id + .unwrap_or_else(|| self.provider().config().id_generator.new_span_id()); let (trace_id, trace_flags) = builder .parent_context .as_ref() .filter(|parent_context| parent_context.is_valid()) .map(|parent_context| (parent_context.trace_id(), parent_context.trace_flags())) .unwrap_or_else(|| { - let trace_id = builder.trace_id.expect("trace_id should exist"); + let trace_id = builder + .trace_id + .unwrap_or_else(|| self.provider().config().id_generator.new_trace_id()); // ensure sampling decision is recorded so all span contexts have consistent flags let sampling_decision = if let Some(result) = builder.sampling_result.as_ref() { @@ -111,3 +115,21 @@ impl PreSampledTracer for sdk::Tracer { self.provider().config().id_generator.new_span_id() } } + +#[cfg(test)] +mod tests { + use super::*; + use opentelemetry::api::{Provider, SpanBuilder}; + use opentelemetry::sdk; + + #[test] + fn assigns_default_ids_if_missing() { + let tracer = sdk::Provider::default().get_tracer("test"); + let mut builder = SpanBuilder::from_name("empty".to_string()); + builder.trace_id = None; + builder.span_id = None; + let span_context = tracer.sampled_span_context(&mut builder); + + assert!(span_context.is_valid()); + } +}