feat: ability to link other spans in span context
This can be used when aggregating from multiple parent spans, e.g. when we want to implement #1473.pull/24376/head
parent
c31bcbced5
commit
173f9aefcf
|
@ -51,6 +51,11 @@ pub struct SpanContext {
|
|||
|
||||
pub span_id: SpanId,
|
||||
|
||||
/// Link to other spans, can be cross-trace if this span aggregates multiple spans.
|
||||
///
|
||||
/// See <https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/overview.md#links-between-spans>.
|
||||
pub links: Vec<(TraceId, SpanId)>,
|
||||
|
||||
pub collector: Option<Arc<dyn TraceCollector>>,
|
||||
}
|
||||
|
||||
|
@ -67,6 +72,7 @@ impl SpanContext {
|
|||
trace_id: TraceId(NonZeroU128::new(trace_id).unwrap()),
|
||||
parent_span_id: None,
|
||||
span_id: SpanId(NonZeroU64::new(span_id).unwrap()),
|
||||
links: Vec::with_capacity(0),
|
||||
collector: Some(collector),
|
||||
}
|
||||
}
|
||||
|
@ -79,6 +85,7 @@ impl SpanContext {
|
|||
trace_id: self.trace_id,
|
||||
span_id: SpanId::gen(),
|
||||
collector: self.collector.clone(),
|
||||
links: Vec::with_capacity(0),
|
||||
parent_span_id: Some(self.span_id),
|
||||
},
|
||||
start: None,
|
||||
|
|
|
@ -236,9 +236,14 @@ mod tests {
|
|||
trace_id: TraceId::new(43434).unwrap(),
|
||||
parent_span_id: None,
|
||||
span_id: SpanId::new(3495993).unwrap(),
|
||||
links: vec![],
|
||||
collector: None,
|
||||
};
|
||||
let mut span = ctx.child("foo");
|
||||
span.ctx.links = vec![
|
||||
(TraceId::new(12).unwrap(), SpanId::new(123).unwrap()),
|
||||
(TraceId::new(45).unwrap(), SpanId::new(456).unwrap()),
|
||||
];
|
||||
span.status = SpanStatus::Ok;
|
||||
span.events = vec![SpanEvent {
|
||||
time: Utc.timestamp_nanos(200000),
|
||||
|
@ -283,6 +288,14 @@ mod tests {
|
|||
span.ctx.parent_span_id.unwrap().get() as i64
|
||||
);
|
||||
|
||||
// test links
|
||||
let b1_s0_refs = b1_s0.references.as_ref().unwrap();
|
||||
assert_eq!(b1_s0_refs.len(), 2);
|
||||
let b1_s0_r0 = &b1_s0_refs[0];
|
||||
let b1_s0_r1 = &b1_s0_refs[1];
|
||||
assert_eq!(b1_s0_r0.span_id, span.ctx.links[0].1.get() as i64);
|
||||
assert_eq!(b1_s0_r1.span_id, span.ctx.links[1].1.get() as i64);
|
||||
|
||||
// microseconds not nanoseconds
|
||||
assert_eq!(b1_s0.start_time, 100);
|
||||
assert_eq!(b1_s0.duration, 200);
|
||||
|
|
|
@ -1,12 +1,21 @@
|
|||
/// Contains the conversion logic from a `trace::span::Span` to `thrift::jaeger::Span`
|
||||
use crate::thrift::jaeger;
|
||||
use trace::span::{MetaValue, Span, SpanEvent, SpanStatus};
|
||||
use crate::thrift::jaeger::{self, SpanRef};
|
||||
use trace::{
|
||||
ctx::TraceId,
|
||||
span::{MetaValue, Span, SpanEvent, SpanStatus},
|
||||
};
|
||||
|
||||
/// Split [`TraceId`] into high and low part.
|
||||
fn split_trace_id(trace_id: TraceId) -> (i64, i64) {
|
||||
let trace_id = trace_id.get();
|
||||
let trace_id_high = (trace_id >> 64) as i64;
|
||||
let trace_id_low = trace_id as i64;
|
||||
(trace_id_high, trace_id_low)
|
||||
}
|
||||
|
||||
impl From<Span> for jaeger::Span {
|
||||
fn from(mut s: Span) -> Self {
|
||||
let trace_id = s.ctx.trace_id.get();
|
||||
let trace_id_high = (trace_id >> 64) as i64;
|
||||
let trace_id_low = trace_id as i64;
|
||||
let (trace_id_high, trace_id_low) = split_trace_id(s.ctx.trace_id);
|
||||
|
||||
// A parent span id of 0 indicates no parent span ID (span IDs are non-zero)
|
||||
let parent_span_id = s.ctx.parent_span_id.map(|id| id.get()).unwrap_or_default() as i64;
|
||||
|
@ -51,13 +60,34 @@ impl From<Span> for jaeger::Span {
|
|||
false => Some(s.events.into_iter().map(Into::into).collect()),
|
||||
};
|
||||
|
||||
let references = if s.ctx.links.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(
|
||||
s.ctx
|
||||
.links
|
||||
.into_iter()
|
||||
.map(|(trace_id, span_id)| {
|
||||
// https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk_exporters/jaeger.md#links
|
||||
let (trace_id_high, trace_id_low) = split_trace_id(trace_id);
|
||||
SpanRef {
|
||||
ref_type: jaeger::SpanRefType::FollowsFrom,
|
||||
trace_id_high,
|
||||
trace_id_low,
|
||||
span_id: span_id.get() as i64,
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
};
|
||||
|
||||
Self {
|
||||
trace_id_low,
|
||||
trace_id_high,
|
||||
span_id: s.ctx.span_id.get() as i64,
|
||||
parent_span_id,
|
||||
operation_name: s.name.to_string(),
|
||||
references: None,
|
||||
references,
|
||||
flags: 0,
|
||||
start_time,
|
||||
duration,
|
||||
|
|
|
@ -154,10 +154,14 @@ fn decode_b3(
|
|||
return Ok(None);
|
||||
}
|
||||
|
||||
// Links cannot be specified via the HTTP header
|
||||
let links = Vec::with_capacity(0);
|
||||
|
||||
Ok(Some(SpanContext {
|
||||
trace_id: required_header(headers, B3_TRACE_ID_HEADER, parse_trace)?,
|
||||
parent_span_id: parsed_header(headers, B3_PARENT_SPAN_ID_HEADER, parse_span)?,
|
||||
span_id: required_header(headers, B3_SPAN_ID_HEADER, parse_span)?,
|
||||
links,
|
||||
collector: Some(Arc::clone(collector)),
|
||||
}))
|
||||
}
|
||||
|
@ -211,10 +215,14 @@ fn decode_jaeger(
|
|||
return Ok(None);
|
||||
}
|
||||
|
||||
// Links cannot be specified via the HTTP header
|
||||
let links = Vec::with_capacity(0);
|
||||
|
||||
Ok(Some(SpanContext {
|
||||
trace_id: decoded.trace_id,
|
||||
parent_span_id: decoded.parent_span_id,
|
||||
span_id: decoded.span_id,
|
||||
links,
|
||||
collector: Some(Arc::clone(collector)),
|
||||
}))
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue