diff --git a/opentelemetry-jaeger/src/lib.rs b/opentelemetry-jaeger/src/lib.rs index c62516b98a..12fc34e3ab 100644 --- a/opentelemetry-jaeger/src/lib.rs +++ b/opentelemetry-jaeger/src/lib.rs @@ -332,14 +332,14 @@ impl Into for api::Event { impl Into for Arc { /// Convert spans to jaeger thrift span for exporting. fn into(self) -> jaeger::Span { - let trace_id = self.context.trace_id(); + let trace_id = self.context.trace_id().to_u128(); let trace_id_high = (trace_id >> 64) as i64; let trace_id_low = trace_id as i64; jaeger::Span { trace_id_low, trace_id_high, - span_id: self.context.span_id() as i64, - parent_span_id: self.parent_span_id as i64, + span_id: self.context.span_id().to_u64() as i64, + parent_span_id: self.parent_span_id.to_u64() as i64, operation_name: self.name.clone(), references: links_to_references(&self.links), flags: self.context.trace_flags() as i32, diff --git a/src/api/mod.rs b/src/api/mod.rs index b8e6660f62..0a60d2d61a 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -36,7 +36,7 @@ pub use trace::{ provider::Provider, sampler::{Sampler, SamplingDecision, SamplingResult}, span::{Span, SpanKind, SpanStatus}, - span_context::{SpanContext, TRACE_FLAGS_UNUSED, TRACE_FLAG_SAMPLED}, + span_context::{SpanContext, SpanId, TraceId, TRACE_FLAGS_UNUSED, TRACE_FLAG_SAMPLED}, span_processor::SpanProcessor, trace_context_propagator::TraceContextPropagator, tracer::{Tracer, TracerGenerics}, diff --git a/src/api/propagation/binary_propagator.rs b/src/api/propagation/binary_propagator.rs index 7b827a8ad3..fbd3f0f966 100644 --- a/src/api/propagation/binary_propagator.rs +++ b/src/api/propagation/binary_propagator.rs @@ -36,10 +36,9 @@ impl BinaryFormat for BinaryPropagator { if !context.is_valid() { return res; } - - res[2..18].copy_from_slice(&context.trace_id().to_be_bytes()); + res[2..18].copy_from_slice(&context.trace_id().to_u128().to_be_bytes()); res[18] = 1; - res[19..27].copy_from_slice(&context.span_id().to_be_bytes()); + res[19..27].copy_from_slice(&context.span_id().to_u64().to_be_bytes()); res[27] = 2; res[28] = context.trace_flags(); @@ -69,7 +68,12 @@ impl BinaryFormat for BinaryPropagator { trace_flags = b[1] } - let span_context = api::SpanContext::new(trace_id, span_id, trace_flags, true); + let span_context = api::SpanContext::new( + api::TraceId::from_u128(trace_id), + api::SpanId::from_u64(span_id), + trace_flags, + true, + ); if span_context.is_valid() { span_context @@ -88,13 +92,17 @@ mod test { fn to_bytes_data() -> Vec<(api::SpanContext, [u8; 29])> { vec![ // Context with sampled - (api::SpanContext::new(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736, 0x00f0_67aa_0ba9_02b7, 1, true), [ + (api::SpanContext::new( + api::TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), + api::SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 1, true), [ 0x00, 0x00, 0x4b, 0xf9, 0x2f, 0x35, 0x77, 0xb3, 0x4d, 0xa6, 0xa3, 0xce, 0x92, 0x9d, 0x0e, 0x0e, 0x47, 0x36, 0x01, 0x00, 0xf0, 0x67, 0xaa, 0x0b, 0xa9, 0x02, 0xb7, 0x02, 0x01, ]), // Context without sampled - (api::SpanContext::new(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736, 0x00f0_67aa_0ba9_02b7, 0, true), [ + (api::SpanContext::new( + api::TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), + api::SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 0, true), [ 0x00, 0x00, 0x4b, 0xf9, 0x2f, 0x35, 0x77, 0xb3, 0x4d, 0xa6, 0xa3, 0xce, 0x92, 0x9d, 0x0e, 0x0e, 0x47, 0x36, 0x01, 0x00, 0xf0, 0x67, 0xaa, 0x0b, 0xa9, 0x02, 0xb7, 0x02, 0x00, @@ -108,19 +116,19 @@ mod test { fn from_bytes_data() -> Vec<(api::SpanContext, Vec)> { vec![ // Future version of the proto - (api::SpanContext::new(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736, 0x00f0_67aa_0ba9_02b7, 1, true), vec![ + (api::SpanContext::new(api::TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), api::SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 1, true), vec![ 0x02, 0x00, 0x4b, 0xf9, 0x2f, 0x35, 0x77, 0xb3, 0x4d, 0xa6, 0xa3, 0xce, 0x92, 0x9d, 0x0e, 0x0e, 0x47, 0x36, 0x01, 0x00, 0xf0, 0x67, 0xaa, 0x0b, 0xa9, 0x02, 0xb7, 0x02, 0x01, ]), // current version with sampled - (api::SpanContext::new(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736, 0x00f0_67aa_0ba9_02b7, 1, true), vec![ + (api::SpanContext::new(api::TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), api::SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 1, true), vec![ 0x02, 0x00, 0x4b, 0xf9, 0x2f, 0x35, 0x77, 0xb3, 0x4d, 0xa6, 0xa3, 0xce, 0x92, 0x9d, 0x0e, 0x0e, 0x47, 0x36, 0x01, 0x00, 0xf0, 0x67, 0xaa, 0x0b, 0xa9, 0x02, 0xb7, 0x02, 0x01, ]), // valid context without option - (api::SpanContext::new(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736, 0x00f0_67aa_0ba9_02b7, 0, true), vec![ + (api::SpanContext::new(api::TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), api::SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 0, true), vec![ 0x00, 0x00, 0x4b, 0xf9, 0x2f, 0x35, 0x77, 0xb3, 0x4d, 0xa6, 0xa3, 0xce, 0x92, 0x9d, 0x0e, 0x0e, 0x47, 0x36, 0x01, 0x00, 0xf0, 0x67, 0xaa, 0x0b, 0xa9, 0x02, 0xb7, ]), diff --git a/src/api/propagation/noop.rs b/src/api/propagation/noop.rs index 80d9058639..007c000df8 100644 --- a/src/api/propagation/noop.rs +++ b/src/api/propagation/noop.rs @@ -16,7 +16,7 @@ impl api::HttpTextFormat for NoopTextFormat { /// Always returns invalid span contexts fn extract(&self, _carrier: &dyn api::Carrier) -> api::SpanContext { - api::SpanContext::new(0, 0, 0, false) + api::SpanContext::new(api::TraceId::invalid(), api::SpanId::invalid(), 0, false) } } @@ -31,6 +31,6 @@ impl api::BinaryFormat for NoopBinaryFormat { /// Always returns invalid span contexts fn from_bytes(&self, _bytes: Vec) -> api::SpanContext { - api::SpanContext::new(0, 0, 0, false) + api::SpanContext::new(api::TraceId::invalid(), api::SpanId::invalid(), 0, false) } } diff --git a/src/api/trace/b3_propagator.rs b/src/api/trace/b3_propagator.rs index 85b7e44c34..0d1c864a0e 100644 --- a/src/api/trace/b3_propagator.rs +++ b/src/api/trace/b3_propagator.rs @@ -35,13 +35,13 @@ impl B3Propagator { } /// Extract trace id from hex encoded &str value. - fn extract_trace_id(&self, trace_id: &str) -> Result { - u128::from_str_radix(trace_id, 16) + fn extract_trace_id(&self, trace_id: &str) -> Result { + u128::from_str_radix(trace_id, 16).map(api::TraceId::from_u128) } /// Extract span id from hex encoded &str value. - fn extract_span_id(&self, span_id: &str) -> Result { - u64::from_str_radix(span_id, 16) + fn extract_span_id(&self, span_id: &str) -> Result { + u64::from_str_radix(span_id, 16).map(api::SpanId::from_u64) } /// Extract sampled state from encoded &str value @@ -136,14 +136,20 @@ impl api::HttpTextFormat for B3Propagator { B3_SINGLE_HEADER, format!( "{:032x}-{:016x}-{:01}", - context.trace_id(), - context.span_id(), + context.trace_id().to_u128(), + context.span_id().to_u64(), sampled ), ); } else { - carrier.set(B3_TRACE_ID_HEADER, format!("{:032x}", context.trace_id())); - carrier.set(B3_SPAN_ID_HEADER, format!("{:016x}", context.span_id())); + carrier.set( + B3_TRACE_ID_HEADER, + format!("{:032x}", context.trace_id().to_u128()), + ); + carrier.set( + B3_SPAN_ID_HEADER, + format!("{:016x}", context.span_id().to_u64()), + ); let sampled = if context.is_sampled() { "1" } else { "0" }; carrier.set(B3_SAMPLED_HEADER, sampled.to_string()) @@ -169,17 +175,18 @@ impl api::HttpTextFormat for B3Propagator { #[cfg(test)] mod test { use super::*; + use crate::api::trace::span_context::{SpanId, TraceId}; use crate::api::HttpTextFormat; use std::collections::HashMap; #[rustfmt::skip] fn single_header_extract_data() -> Vec<(&'static str, api::SpanContext)> { vec![ - ("4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7", api::SpanContext::new(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736, 0x00f0_67aa_0ba9_02b7, 0, true)), - ("4bf92f3577b34da6a3ce929d0e0e4736-f067aa0ba902b7-0", api::SpanContext::new(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736, 0x00f0_67aa_0ba9_02b7, 0, true)), - ("4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-1", api::SpanContext::new(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736, 0x00f0_67aa_0ba9_02b7, 1, true)), - ("4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-d", api::SpanContext::new(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736, 0x00f0_67aa_0ba9_02b7, 1, true)), - ("4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-1-00000000000000cd", api::SpanContext::new(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736, 0x00f0_67aa_0ba9_02b7, 1, true)), + ("4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7", api::SpanContext::new(TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 0, true)), + ("4bf92f3577b34da6a3ce929d0e0e4736-f067aa0ba902b7-0", api::SpanContext::new(TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 0, true)), + ("4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-1", api::SpanContext::new(TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 1, true)), + ("4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-d", api::SpanContext::new(TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 1, true)), + ("4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-1-00000000000000cd", api::SpanContext::new(TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 1, true)), ("0", api::SpanContext::empty_context()), ] } @@ -188,13 +195,12 @@ mod test { #[allow(clippy::type_complexity)] fn multi_header_extract_data() -> Vec<((Option<&'static str>, Option<&'static str>, Option<&'static str>, Option<&'static str>, Option<&'static str>), api::SpanContext)> { vec![ - ((Some("4bf92f3577b34da6a3ce929d0e0e4736"), Some("00f067aa0ba902b7"), None, None, None), api::SpanContext::new(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736, 0x00f0_67aa_0ba9_02b7, 0, true)), - ((Some("4bf92f3577b34da6a3ce929d0e0e4736"), Some("00f067aa0ba902b7"), Some("0"), None, None), api::SpanContext::new(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736, 0x00f0_67aa_0ba9_02b7, 0, true)), - ((Some("4bf92f3577b34da6a3ce929d0e0e4736"), Some("00f067aa0ba902b7"), Some("1"), None, None), api::SpanContext::new(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736, 0x00f0_67aa_0ba9_02b7, 1, true)), - ((Some("4bf92f3577b34da6a3ce929d0e0e4736"), Some("00f067aa0ba902b7"), Some("true"), None, None), api::SpanContext::new(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736, 0x00f0_67aa_0ba9_02b7, 1, true)), - ((Some("4bf92f3577b34da6a3ce929d0e0e4736"), Some("00f067aa0ba902b7"), None, Some("1"), None), api::SpanContext::new(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736, 0x00f0_67aa_0ba9_02b7, 1, true)), - ((Some("4bf92f3577b34da6a3ce929d0e0e4736"), Some("00f067aa0ba902b7"), Some("0"), Some("1"), None), api::SpanContext::new(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736, 0x00f0_67aa_0ba9_02b7, 1, true)), - ((Some("4bf92f3577b34da6a3ce929d0e0e4736"), Some("00f067aa0ba902b7"), Some("1"), None, Some("00f067aa0ba90200")), api::SpanContext::new(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736, 0x00f0_67aa_0ba9_02b7, 1, true)), + ((Some("4bf92f3577b34da6a3ce929d0e0e4736"), Some("00f067aa0ba902b7"), None, None, None), api::SpanContext::new(TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 0, true)), + ((Some("4bf92f3577b34da6a3ce929d0e0e4736"), Some("00f067aa0ba902b7"), Some("0"), None, None), api::SpanContext::new(TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 0, true)), + ((Some("4bf92f3577b34da6a3ce929d0e0e4736"), Some("00f067aa0ba902b7"), Some("1"), None, None), api::SpanContext::new(TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 1, true)), + ((Some("4bf92f3577b34da6a3ce929d0e0e4736"), Some("00f067aa0ba902b7"), Some("true"), None, None), api::SpanContext::new(TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 1, true)), + ((Some("4bf92f3577b34da6a3ce929d0e0e4736"), Some("00f067aa0ba902b7"), None, Some("1"), None), api::SpanContext::new(TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 1, true)), + ((Some("4bf92f3577b34da6a3ce929d0e0e4736"), Some("00f067aa0ba902b7"), Some("1"), None, Some("00f067aa0ba90200")), api::SpanContext::new(TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 1, true)), ((None, None, Some("0"), None, None), api::SpanContext::empty_context()), ] } @@ -202,18 +208,18 @@ mod test { #[rustfmt::skip] fn single_header_inject_data() -> Vec<(&'static str, api::SpanContext)> { vec![ - ("4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-1", api::SpanContext::new(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736, 0x00f0_67aa_0ba9_02b7, 1, true)), - ("4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-0", api::SpanContext::new(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736, 0x00f0_67aa_0ba9_02b7, 0, true)), - ("4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-1", api::SpanContext::new(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736, 0x00f0_67aa_0ba9_02b7, 0xff, true)), + ("4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-1", api::SpanContext::new(TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 1, true)), + ("4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-0", api::SpanContext::new(TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 0, true)), + ("4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-1", api::SpanContext::new(TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 0xff, true)), ] } #[rustfmt::skip] fn multi_header_inject_data() -> Vec<(&'static str, &'static str, &'static str, api::SpanContext)> { vec![ - ("4bf92f3577b34da6a3ce929d0e0e4736", "00f067aa0ba902b7", "1", api::SpanContext::new(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736, 0x00f0_67aa_0ba9_02b7, 1, true)), - ("4bf92f3577b34da6a3ce929d0e0e4736", "00f067aa0ba902b7", "0", api::SpanContext::new(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736, 0x00f0_67aa_0ba9_02b7, 0, true)), - ("4bf92f3577b34da6a3ce929d0e0e4736", "00f067aa0ba902b7", "1", api::SpanContext::new(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736, 0x00f0_67aa_0ba9_02b7, 0xff, true)), + ("4bf92f3577b34da6a3ce929d0e0e4736", "00f067aa0ba902b7", "1", api::SpanContext::new(TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 1, true)), + ("4bf92f3577b34da6a3ce929d0e0e4736", "00f067aa0ba902b7", "0", api::SpanContext::new(TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 0, true)), + ("4bf92f3577b34da6a3ce929d0e0e4736", "00f067aa0ba902b7", "1", api::SpanContext::new(TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 0xff, true)), ] } diff --git a/src/api/trace/noop.rs b/src/api/trace/noop.rs index 5c97a65285..03782ca76c 100644 --- a/src/api/trace/noop.rs +++ b/src/api/trace/noop.rs @@ -36,7 +36,12 @@ impl NoopSpan { /// Creates a new `NoopSpan` instance. pub fn new() -> Self { NoopSpan { - span_context: api::SpanContext::new(0, 0, 0, false), + span_context: api::SpanContext::new( + api::TraceId::invalid(), + api::SpanId::invalid(), + 0, + false, + ), } } } @@ -126,7 +131,7 @@ impl api::Tracer for NoopTracer { } /// Ignores active span state. - fn mark_span_as_inactive(&self, _span_id: u64) { + fn mark_span_as_inactive(&self, _span_id: api::SpanId) { // Noop } diff --git a/src/api/trace/sampler.rs b/src/api/trace/sampler.rs index 9665b1475f..8fc1e25b85 100644 --- a/src/api/trace/sampler.rs +++ b/src/api/trace/sampler.rs @@ -48,8 +48,8 @@ pub trait Sampler: Send + Sync + std::fmt::Debug { fn should_sample( &self, parent_context: Option<&api::SpanContext>, - trace_id: u128, - span_id: u64, + trace_id: api::TraceId, + span_id: api::SpanId, name: &str, span_kind: &api::SpanKind, attributes: &[api::KeyValue], diff --git a/src/api/trace/span_context.rs b/src/api/trace/span_context.rs index 38c8ae888c..f1d10439d7 100644 --- a/src/api/trace/span_context.rs +++ b/src/api/trace/span_context.rs @@ -22,12 +22,58 @@ pub const TRACE_FLAG_SAMPLED: u8 = TRACE_FLAGS_BIT_MASK_SAMPLED; /// Useful for extracting trace context pub const TRACE_FLAGS_UNUSED: u8 = TRACE_FLAGS_BIT_MASK_UNUSED; +/// TraceId is an 16-byte value which uniquely identifies a given trace +/// The actual `u128` value is wrapped in a tuple struct in order to leverage the newtype pattern +#[cfg_attr(feature = "serialize", derive(Deserialize, Serialize))] +#[derive(Clone, Debug, PartialEq, Eq, Copy, Hash)] +pub struct TraceId(u128); + +impl TraceId { + /// Construct a new invalid (zero-valued) TraceId + pub fn invalid() -> Self { + TraceId(0) + } + + /// Convert from u128 to TraceId + pub fn from_u128(item: u128) -> Self { + TraceId(item) + } + + /// Convert from TraceId to u128 + pub fn to_u128(self) -> u128 { + self.0 + } +} + +/// SpanId is an 8-byte value which uniquely identifies a given span within a trace +/// The actual `u64` value is wrapped in a tuple struct in order to leverage the newtype pattern +#[cfg_attr(feature = "serialize", derive(Deserialize, Serialize))] +#[derive(Clone, Debug, PartialEq, Eq, Copy, Hash)] +pub struct SpanId(u64); + +impl SpanId { + /// Construct a new invalid (zero-valued) SpanId + pub fn invalid() -> Self { + SpanId(0) + } + + /// Convert from u64 to SpanId + pub fn from_u64(item: u64) -> Self { + SpanId(item) + } + + /// Convert from SpanId to u64 + pub fn to_u64(self) -> u64 { + self.0 + } +} + /// Immutable portion of a `Span` which can be serialized and propagated. #[cfg_attr(feature = "serialize", derive(Deserialize, Serialize))] #[derive(Clone, Debug, PartialEq)] pub struct SpanContext { - trace_id: u128, - span_id: u64, + trace_id: TraceId, + span_id: SpanId, trace_flags: u8, is_remote: bool, } @@ -35,11 +81,11 @@ pub struct SpanContext { impl SpanContext { /// Create an invalid empty span context pub fn empty_context() -> Self { - SpanContext::new(0, 0, 0, false) + SpanContext::new(TraceId::invalid(), SpanId::invalid(), 0, false) } /// Construct a new `SpanContext` - pub fn new(trace_id: u128, span_id: u64, trace_flags: u8, is_remote: bool) -> Self { + pub fn new(trace_id: TraceId, span_id: SpanId, trace_flags: u8, is_remote: bool) -> Self { SpanContext { trace_id, span_id, @@ -49,12 +95,12 @@ impl SpanContext { } /// A valid trace identifier is a non-zero `u128`. - pub fn trace_id(&self) -> u128 { + pub fn trace_id(&self) -> TraceId { self.trace_id } /// A valid span identifier is a non-zero `u64`. - pub fn span_id(&self) -> u64 { + pub fn span_id(&self) -> SpanId { self.span_id } @@ -67,7 +113,7 @@ impl SpanContext { /// Returns a bool flag which is true if the `SpanContext` has a valid (non-zero) `trace_id` /// and a valid (non-zero) `span_id`. pub fn is_valid(&self) -> bool { - self.trace_id != 0 && self.span_id != 0 + self.trace_id.0 != 0 && self.span_id.0 != 0 } /// Returns true if the `SpanContext` was propagated from a remote parent. diff --git a/src/api/trace/trace_context_propagator.rs b/src/api/trace/trace_context_propagator.rs index 180cd663e5..784164f92f 100644 --- a/src/api/trace/trace_context_propagator.rs +++ b/src/api/trace/trace_context_propagator.rs @@ -51,10 +51,14 @@ impl TraceContextPropagator { } // Parse trace id section - let trace_id = u128::from_str_radix(parts[1], 16).map_err(|_| ())?; + let trace_id = u128::from_str_radix(parts[1], 16) + .map_err(|_| ()) + .map(api::TraceId::from_u128)?; // Parse span id section - let span_id = u64::from_str_radix(parts[2], 16).map_err(|_| ())?; + let span_id = u64::from_str_radix(parts[2], 16) + .map_err(|_| ()) + .map(api::SpanId::from_u64)?; // Parse trace flags section let opts = u8::from_str_radix(parts[3], 16).map_err(|_| ())?; @@ -86,8 +90,8 @@ impl api::HttpTextFormat for TraceContextPropagator { let header_value = format!( "{:02x}-{:032x}-{:016x}-{:02x}", SUPPORTED_VERSION, - context.trace_id(), - context.span_id(), + context.trace_id().to_u128(), + context.span_id().to_u64(), context.trace_flags() & api::TRACE_FLAG_SAMPLED ); carrier.set(TRACEPARENT_HEADER, header_value) @@ -107,29 +111,28 @@ impl api::HttpTextFormat for TraceContextPropagator { #[cfg(test)] mod test { use super::*; - use crate::api::{Carrier, HttpTextFormat}; use std::collections::HashMap; #[rustfmt::skip] fn extract_data() -> Vec<(&'static str, api::SpanContext)> { vec![ - ("00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00", api::SpanContext::new(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736, 0x00f0_67aa_0ba9_02b7, 0, true)), - ("00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01", api::SpanContext::new(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736, 0x00f0_67aa_0ba9_02b7, 1, true)), - ("02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01", api::SpanContext::new(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736, 0x00f0_67aa_0ba9_02b7, 1, true)), - ("02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-09", api::SpanContext::new(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736, 0x00f0_67aa_0ba9_02b7, 1, true)), - ("02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-08", api::SpanContext::new(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736, 0x00f0_67aa_0ba9_02b7, 0, true)), - ("02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-09-XYZxsf09", api::SpanContext::new(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736, 0x00f0_67aa_0ba9_02b7, 1, true)), - ("00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01-", api::SpanContext::new(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736, 0x00f0_67aa_0ba9_02b7, 1, true)), - ("01-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-09-", api::SpanContext::new(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736, 0x00f0_67aa_0ba9_02b7, 1, true)), + ("00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00", api::SpanContext::new(api::TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), api::SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 0, true)), + ("00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01", api::SpanContext::new(api::TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), api::SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 1, true)), + ("02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01", api::SpanContext::new(api::TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), api::SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 1, true)), + ("02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-09", api::SpanContext::new(api::TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), api::SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 1, true)), + ("02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-08", api::SpanContext::new(api::TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), api::SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 0, true)), + ("02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-09-XYZxsf09", api::SpanContext::new(api::TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), api::SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 1, true)), + ("00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01-", api::SpanContext::new(api::TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), api::SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 1, true)), + ("01-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-09-", api::SpanContext::new(api::TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), api::SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 1, true)), ] } #[rustfmt::skip] fn inject_data() -> Vec<(&'static str, api::SpanContext)> { vec![ - ("00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01", api::SpanContext::new(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736, 0x00f0_67aa_0ba9_02b7, 1, true)), - ("00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00", api::SpanContext::new(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736, 0x00f0_67aa_0ba9_02b7, 0, true)), - ("00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01", api::SpanContext::new(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736, 0x00f0_67aa_0ba9_02b7, 0xff, true)), + ("00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01", api::SpanContext::new(api::TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), api::SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 1, true)), + ("00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00", api::SpanContext::new(api::TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), api::SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 0, true)), + ("00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01", api::SpanContext::new(api::TraceId::from_u128(0x4bf9_2f35_77b3_4da6_a3ce_929d_0e0e_4736), api::SpanId::from_u64(0x00f0_67aa_0ba9_02b7), 0xff, true)), ("", api::SpanContext::empty_context()), ] } diff --git a/src/api/trace/tracer.rs b/src/api/trace/tracer.rs index 6d9c546eab..d7a9f9b4b6 100644 --- a/src/api/trace/tracer.rs +++ b/src/api/trace/tracer.rs @@ -88,7 +88,7 @@ pub trait Tracer: Send + Sync { /// together or you can end up retaining references to the currently active `Span`. /// If you do not want to manage active state of `Span`s manually, use the `with_span` /// API defined for all `Tracer`s via `TracerGenerics` - fn mark_span_as_inactive(&self, span_id: u64); + fn mark_span_as_inactive(&self, span_id: api::SpanId); /// Clone a span created by this tracer. fn clone_span(&self, span: &Self::Span) -> Self::Span; diff --git a/src/exporter/trace/mod.rs b/src/exporter/trace/mod.rs index 39dfc2c89f..5c5723e565 100644 --- a/src/exporter/trace/mod.rs +++ b/src/exporter/trace/mod.rs @@ -65,7 +65,7 @@ pub struct SpanData { /// Exportable `SpanContext` pub context: api::SpanContext, /// Span parent id - pub parent_span_id: u64, + pub parent_span_id: api::SpanId, /// Span kind pub span_kind: api::SpanKind, /// Span name @@ -96,7 +96,12 @@ mod tests { let trace_flags = 0; let remote = false; - let context = api::SpanContext::new(trace_id, span_id, trace_flags, remote); + let context = api::SpanContext::new( + api::TraceId::from_u128(trace_id), + api::SpanId::from_u64(span_id), + trace_flags, + remote, + ); let parent_span_id = 1; let span_kind = api::SpanKind::Client; @@ -113,7 +118,7 @@ mod tests { let span_data = SpanData { context, - parent_span_id, + parent_span_id: api::SpanId::from_u64(parent_span_id), span_kind, name, start_time, diff --git a/src/global.rs b/src/global.rs index c02fc3b7d5..270d479f60 100644 --- a/src/global.rs +++ b/src/global.rs @@ -77,7 +77,7 @@ pub trait GenericTracer: Send + Sync { fn mark_span_as_active_boxed(&self, span: &dyn api::Span); /// Marks the current span as inactive - fn mark_span_as_inactive_boxed(&self, span_id: u64); + fn mark_span_as_inactive_boxed(&self, span_id: api::SpanId); /// Clone span fn clone_span_boxed(&self, span: &dyn api::Span) -> Box; @@ -108,7 +108,7 @@ impl GenericTracer for Box> { } /// Mark span as inactive. - fn mark_span_as_inactive_boxed(&self, span_id: u64) { + fn mark_span_as_inactive_boxed(&self, span_id: api::SpanId) { self.mark_span_as_inactive(span_id) } @@ -147,7 +147,7 @@ impl Tracer for dyn GenericTracer { } /// Marks a given `Span` as inactive. - fn mark_span_as_inactive(&self, span_id: u64) { + fn mark_span_as_inactive(&self, span_id: api::SpanId) { self.mark_span_as_inactive_boxed(span_id) } @@ -188,7 +188,7 @@ impl api::Tracer for BoxedTracer { } /// Mark a given `Span` as inactive. - fn mark_span_as_inactive(&self, span_id: u64) { + fn mark_span_as_inactive(&self, span_id: api::SpanId) { self.0.mark_span_as_inactive(span_id) } diff --git a/src/sdk/trace/sampler.rs b/src/sdk/trace/sampler.rs index e1ab85c901..3983e0ca76 100644 --- a/src/sdk/trace/sampler.rs +++ b/src/sdk/trace/sampler.rs @@ -22,8 +22,8 @@ impl api::Sampler for Sampler { fn should_sample( &self, parent_context: Option<&api::SpanContext>, - _trace_id: u128, - _span_id: u64, + _trace_id: api::TraceId, + _span_id: api::SpanId, _name: &str, _span_kind: &api::SpanKind, _attributes: &[api::KeyValue], diff --git a/src/sdk/trace/span.rs b/src/sdk/trace/span.rs index 313985516b..d2a1204678 100644 --- a/src/sdk/trace/span.rs +++ b/src/sdk/trace/span.rs @@ -17,7 +17,7 @@ use std::time::SystemTime; /// Single operation within a trace. #[derive(Clone, Debug)] pub struct Span { - id: u64, + id: api::SpanId, inner: Arc, } @@ -30,7 +30,7 @@ struct SpanInner { impl Span { pub(crate) fn new( - id: u64, + id: api::SpanId, data: Option, tracer: sdk::Tracer, ) -> Self { @@ -44,7 +44,7 @@ impl Span { } /// Return span id - pub(crate) fn id(&self) -> u64 { + pub(crate) fn id(&self) -> api::SpanId { self.id } @@ -87,7 +87,9 @@ impl api::Span for Span { /// Returns the `SpanContext` for the given `Span`. fn get_context(&self) -> api::SpanContext { self.with_data(|data| data.context.clone()) - .unwrap_or_else(|| api::SpanContext::new(0, 0, 0, false)) + .unwrap_or_else(|| { + api::SpanContext::new(api::TraceId::invalid(), api::SpanId::invalid(), 0, false) + }) } /// Returns true if this `Span` is recording information like events with the `add_event` diff --git a/src/sdk/trace/tracer.rs b/src/sdk/trace/tracer.rs index 666a19e9e1..cc3ba54fd3 100644 --- a/src/sdk/trace/tracer.rs +++ b/src/sdk/trace/tracer.rs @@ -7,7 +7,7 @@ //! and exposes methods for creating and activating new `Spans`. //! //! Docs: https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/api-tracing.md#tracer -use crate::api::Span; +use crate::api::trace::span::Span; use crate::sdk; use crate::{api, exporter}; use std::cell::RefCell; @@ -47,8 +47,8 @@ impl Tracer { fn make_sampling_decision( &self, parent_context: Option<&api::SpanContext>, - trace_id: u128, - span_id: u64, + trace_id: api::TraceId, + span_id: api::SpanId, name: &str, span_kind: &api::SpanKind, attributes: &[api::KeyValue], @@ -98,7 +98,7 @@ impl api::Tracer for Tracer { /// Returns a span with an inactive `SpanContext`. Used by functions that /// need to return a default span like `get_active_span` if no span is present. fn invalid(&self) -> Self::Span { - sdk::Span::new(0, None, self.clone()) + sdk::Span::new(api::SpanId::invalid(), None, self.clone()) } /// Starts a new `Span`. @@ -110,7 +110,7 @@ impl api::Tracer for Tracer { /// spans in the trace. fn start(&self, name: &str, parent_span: Option) -> Self::Span { let config = self.provider.config(); - let span_id: u64 = rand::random(); + let span_id = api::SpanId::from_u64(rand::random::()); // TODO allow the following to be set when starting span let span_kind = api::SpanKind::Internal; @@ -131,7 +131,13 @@ impl api::Tracer for Tracer { ctx.trace_flags(), ) }) - .unwrap_or((true, rand::random(), 0, false, 0)); + .unwrap_or(( + true, + api::TraceId::from_u128(rand::random::()), + api::SpanId::invalid(), + false, + 0, + )); // Make new sampling decision or use parent sampling decision let sampling_decision = if no_parent || remote_parent { @@ -199,7 +205,7 @@ impl api::Tracer for Tracer { } /// Mark a given `Span` as inactive. - fn mark_span_as_inactive(&self, span_id: u64) { + fn mark_span_as_inactive(&self, span_id: api::SpanId) { CURRENT_SPANS.with(|spans| { spans.borrow_mut().pop(span_id); }) @@ -220,7 +226,7 @@ struct ContextId { /// A stack of `Span`s that can be used to track active `Span`s per thread. pub(crate) struct SpanStack { stack: Vec, - ids: HashSet, + ids: HashSet, } impl SpanStack { @@ -242,7 +248,7 @@ impl SpanStack { } /// Pop a `Span` from the stack - fn pop(&mut self, expected_id: u64) -> Option { + fn pop(&mut self, expected_id: api::SpanId) -> Option { if self.stack.last()?.span.id() == expected_id { let ContextId { span, duplicate } = self.stack.pop()?; if !duplicate {