diff --git a/opentelemetry/src/api/trace/context.rs b/opentelemetry/src/api/trace/context.rs index 56980d5909..351020b4cb 100644 --- a/opentelemetry/src/api/trace/context.rs +++ b/opentelemetry/src/api/trace/context.rs @@ -33,11 +33,11 @@ pub trait TraceContextExt { /// }; /// /// // returns a reference to an empty span by default - /// assert_eq!(Context::current().span().span_context(), SpanContext::empty_context()); + /// assert_eq!(Context::current().span().span_context(), &SpanContext::empty_context()); /// /// sdktrace::TracerProvider::default().get_tracer("my-component", None).in_span("my-span", |cx| { /// // Returns a reference to the current span if set - /// assert_ne!(cx.span().span_context(), SpanContext::empty_context()); + /// assert_ne!(cx.span().span_context(), &SpanContext::empty_context()); /// }); /// ``` fn span(&self) -> &dyn crate::trace::Span; diff --git a/opentelemetry/src/api/trace/noop.rs b/opentelemetry/src/api/trace/noop.rs index 368d09ebd7..675e6fe29b 100644 --- a/opentelemetry/src/api/trace/noop.rs +++ b/opentelemetry/src/api/trace/noop.rs @@ -78,8 +78,8 @@ impl trace::Span for NoopSpan { } /// Returns an invalid `SpanContext`. - fn span_context(&self) -> trace::SpanContext { - self.span_context.clone() + fn span_context(&self) -> &trace::SpanContext { + &self.span_context } /// Returns false, signifying that this span is never recording. @@ -131,7 +131,7 @@ impl trace::Tracer for NoopTracer { /// Starts a new `NoopSpan` in a given context. /// - /// If the context contains a valid span context, it is progagated. + /// If the context contains a valid span context, it is propagated. fn start_from_context(&self, name: &str, cx: &Context) -> Self::Span { let builder = self.span_builder(name); self.build_with_context(builder, cx) @@ -144,13 +144,17 @@ impl trace::Tracer for NoopTracer { /// Builds a `NoopSpan` from a `SpanBuilder`. /// - /// If the span builder or context contains a valid span context, it is progagated. + /// If the span builder or context contains a valid span context, it is propagated. fn build_with_context(&self, mut builder: trace::SpanBuilder, cx: &Context) -> Self::Span { let parent_span_context = builder .parent_context .take() - .or_else(|| Some(cx.span().span_context()).filter(|cx| cx.is_valid())) - .or_else(|| cx.remote_span_context().cloned()) + .or_else(|| { + Some(cx.span().span_context()) + .filter(|sc| sc.is_valid()) + .cloned() + }) + .or_else(|| cx.remote_span_context().filter(|sc| sc.is_valid()).cloned()) .filter(|cx| cx.is_valid()); if let Some(span_context) = parent_span_context { trace::NoopSpan { span_context } diff --git a/opentelemetry/src/api/trace/span.rs b/opentelemetry/src/api/trace/span.rs index 0a2d17c12d..5f45bf487f 100644 --- a/opentelemetry/src/api/trace/span.rs +++ b/opentelemetry/src/api/trace/span.rs @@ -87,7 +87,7 @@ pub trait Span: fmt::Debug + 'static + Send + Sync { /// Returns the `SpanContext` for the given `Span`. The returned value may be used even after /// the `Span is finished. The returned value MUST be the same for the entire `Span` lifetime. - fn span_context(&self) -> SpanContext; + fn span_context(&self) -> &SpanContext; /// Returns true if this `Span` is recording information like events with the `add_event` /// operation, attributes using `set_attributes`, status with `set_status`, etc. diff --git a/opentelemetry/src/api/trace/span_processor.rs b/opentelemetry/src/api/trace/span_processor.rs index 707783378a..4ac960162c 100644 --- a/opentelemetry/src/api/trace/span_processor.rs +++ b/opentelemetry/src/api/trace/span_processor.rs @@ -35,11 +35,12 @@ //! [`TracerProvider`]: ../provider/trait.TracerProvider.html use crate::exporter::trace::SpanData; +use crate::{trace::Span, Context}; /// `SpanProcessor`s allow finished spans to be processed. pub trait SpanProcessor: Send + Sync + std::fmt::Debug { /// `on_start` method is invoked when a `Span` is started. - fn on_start(&self, span: &SpanData); + fn on_start(&self, span: &dyn Span, cx: &Context); /// `on_end` method is invoked when a `Span` is ended. fn on_end(&self, span: SpanData); /// Shutdown is invoked when SDK shuts down. Use this call to cleanup any diff --git a/opentelemetry/src/api/trace/tracer.rs b/opentelemetry/src/api/trace/tracer.rs index 7397c0bcc5..a52084d40b 100644 --- a/opentelemetry/src/api/trace/tracer.rs +++ b/opentelemetry/src/api/trace/tracer.rs @@ -41,7 +41,7 @@ use std::time::SystemTime; /// /// let parent = tracer.start("foo"); /// let child = tracer.span_builder("bar") -/// .with_parent(parent.span_context()) +/// .with_parent(parent.span_context().clone()) /// .start(&tracer); /// /// // ... diff --git a/opentelemetry/src/global/trace.rs b/opentelemetry/src/global/trace.rs index 544e0aadd6..319ebaa1ea 100644 --- a/opentelemetry/src/global/trace.rs +++ b/opentelemetry/src/global/trace.rs @@ -30,7 +30,7 @@ impl trace::Span for BoxedSpan { } /// Returns the `SpanContext` for the given `Span`. - fn span_context(&self) -> trace::SpanContext { + fn span_context(&self) -> &trace::SpanContext { self.0.span_context() } diff --git a/opentelemetry/src/sdk/propagation/aws.rs b/opentelemetry/src/sdk/propagation/aws.rs index 07bf9b9313..e04936a54b 100644 --- a/opentelemetry/src/sdk/propagation/aws.rs +++ b/opentelemetry/src/sdk/propagation/aws.rs @@ -107,7 +107,7 @@ impl XrayPropagator { impl TextMapPropagator for XrayPropagator { fn inject_context(&self, cx: &Context, injector: &mut dyn Injector) { - let span_context: SpanContext = cx.span().span_context(); + let span_context = cx.span().span_context(); if span_context.is_valid() { let xray_trace_id: XrayTraceId = span_context.trace_id().into(); diff --git a/opentelemetry/src/sdk/trace/span.rs b/opentelemetry/src/sdk/trace/span.rs index e89b973b0c..d4563c2cbb 100644 --- a/opentelemetry/src/sdk/trace/span.rs +++ b/opentelemetry/src/sdk/trace/span.rs @@ -8,51 +8,68 @@ //! start time is set to the current time on span creation. After the `Span` is created, it //! is possible to change its name, set its `Attributes`, and add `Links` and `Events`. //! These cannot be changed after the `Span`'s end time has been set. -use crate::trace::{Event, SpanContext, SpanId, StatusCode, TraceId, TraceState}; -use crate::{exporter::trace::SpanData, sdk, KeyValue}; +use crate::trace::{Event, SpanContext, SpanId, StatusCode}; +use crate::{api, exporter, sdk, KeyValue}; use std::sync::{Arc, Mutex}; use std::time::SystemTime; /// Single operation within a trace. #[derive(Clone, Debug)] pub struct Span { - id: SpanId, inner: Arc, } /// Inner data, processed and exported on drop #[derive(Debug)] struct SpanInner { + span_context: SpanContext, data: Option>>, tracer: sdk::trace::Tracer, } +#[derive(Clone, Debug, PartialEq)] +pub(crate) struct SpanData { + /// Span parent id + pub(crate) parent_span_id: SpanId, + /// Span kind + pub(crate) span_kind: api::trace::SpanKind, + /// Span name + pub(crate) name: String, + /// Span start time + pub(crate) start_time: SystemTime, + /// Span end time + pub(crate) end_time: SystemTime, + /// Span attributes + pub(crate) attributes: sdk::trace::EvictedHashMap, + /// Span Message events + pub(crate) message_events: sdk::trace::EvictedQueue, + /// Span Links + pub(crate) links: sdk::trace::EvictedQueue, + /// Span status code + pub(crate) status_code: api::trace::StatusCode, + /// Span status message + pub(crate) status_message: String, + /// Resource contains attributes representing an entity that produced this span. + pub(crate) resource: Arc, +} + impl Span { - pub(crate) fn new(id: SpanId, data: Option, tracer: sdk::trace::Tracer) -> Self { + pub(crate) fn new( + span_context: api::trace::SpanContext, + data: Option, + tracer: sdk::trace::Tracer, + ) -> Self { Span { - id, inner: Arc::new(SpanInner { + span_context, data: data.map(|data| Mutex::new(Some(data))), tracer, }), } } - /// Operate on reference to span inner + /// Operate on a mutable reference to span data fn with_data(&self, f: F) -> Option - where - F: FnOnce(&SpanData) -> T, - { - self.inner.data.as_ref().and_then(|inner| { - inner - .lock() - .ok() - .and_then(|span_data| span_data.as_ref().map(f)) - }) - } - - /// Operate on mutable reference to span inner - fn with_data_mut(&self, f: F) -> Option where F: FnOnce(&mut SpanData) -> T, { @@ -77,24 +94,15 @@ impl crate::trace::Span for Span { timestamp: SystemTime, attributes: Vec, ) { - self.with_data_mut(|data| { + self.with_data(|data| { data.message_events .push_back(Event::new(name, timestamp, attributes)) }); } /// Returns the `SpanContext` for the given `Span`. - fn span_context(&self) -> SpanContext { - self.with_data(|data| data.span_context.clone()) - .unwrap_or_else(|| { - SpanContext::new( - TraceId::invalid(), - SpanId::invalid(), - 0, - false, - TraceState::default(), - ) - }) + fn span_context(&self) -> &SpanContext { + &self.inner.span_context } /// Returns true if this `Span` is recording information like events with the `add_event` @@ -109,7 +117,7 @@ impl crate::trace::Span for Span { /// attributes"](https://github.com/open-telemetry/opentelemetry-specification/tree/v0.5.0/specification/trace/semantic_conventions/README.md) /// that have prescribed semantic meanings. fn set_attribute(&self, attribute: KeyValue) { - self.with_data_mut(|data| { + self.with_data(|data| { data.attributes.insert(attribute); }); } @@ -117,7 +125,7 @@ impl crate::trace::Span for Span { /// Sets the status of the `Span`. If used, this will override the default `Span` /// status, which is `Unset`. fn set_status(&self, code: StatusCode, message: String) { - self.with_data_mut(|data| { + self.with_data(|data| { data.status_code = code; data.status_message = message }); @@ -125,14 +133,14 @@ impl crate::trace::Span for Span { /// Updates the `Span`'s name. fn update_name(&self, new_name: String) { - self.with_data_mut(|data| { + self.with_data(|data| { data.name = new_name; }); } /// Finishes the span with given timestamp. fn end_with_timestamp(&self, timestamp: SystemTime) { - self.with_data_mut(|data| { + self.with_data(|data| { data.end_time = timestamp; }); } @@ -161,7 +169,11 @@ impl Drop for SpanInner { }; if let Some(span_data) = span_data { - processor.on_end(span_data); + processor.on_end(build_export_data( + span_data, + self.span_context.clone(), + &self.tracer, + )); } } } @@ -170,6 +182,28 @@ impl Drop for SpanInner { } } +fn build_export_data( + data: SpanData, + span_context: SpanContext, + tracer: &sdk::trace::Tracer, +) -> exporter::trace::SpanData { + exporter::trace::SpanData { + span_context, + parent_span_id: data.parent_span_id, + span_kind: data.span_kind, + name: data.name, + start_time: data.start_time, + end_time: data.end_time, + attributes: data.attributes, + message_events: data.message_events, + links: data.links, + status_code: data.status_code, + status_message: data.status_message, + resource: data.resource, + instrumentation_lib: tracer.instrumentation_library().clone(), + } +} + #[cfg(test)] mod tests { use super::*; @@ -181,13 +215,6 @@ mod tests { let config = provider.config(); let tracer = provider.get_tracer("opentelemetry", Some(env!("CARGO_PKG_VERSION"))); let data = SpanData { - span_context: SpanContext::new( - TraceId::from_u128(0), - SpanId::from_u64(0), - api::trace::TRACE_FLAG_NOT_SAMPLED, - false, - TraceState::default(), - ), parent_span_id: SpanId::from_u64(0), span_kind: api::trace::SpanKind::Internal, name: "opentelemetry".to_string(), @@ -199,27 +226,26 @@ mod tests { status_code: StatusCode::Unset, status_message: "".to_string(), resource: config.resource.clone(), - instrumentation_lib: *tracer.instrumentation_library(), }; (tracer, data) } fn create_span() -> Span { let (tracer, data) = init(); - Span::new(SpanId::from_u64(0), Some(data), tracer) + Span::new(SpanContext::empty_context(), Some(data), tracer) } #[test] fn create_span_without_data() { let (tracer, _) = init(); - let span = Span::new(SpanId::from_u64(0), None, tracer); + let span = Span::new(SpanContext::empty_context(), None, tracer); span.with_data(|_data| panic!("there are data")); } #[test] - fn create_span_with_data() { + fn create_span_with_data_mut() { let (tracer, data) = init(); - let span = Span::new(SpanId::from_u64(0), Some(data.clone()), tracer); + let span = Span::new(SpanContext::empty_context(), Some(data.clone()), tracer); span.with_data(|d| assert_eq!(*d, data)); } diff --git a/opentelemetry/src/sdk/trace/span_processor.rs b/opentelemetry/src/sdk/trace/span_processor.rs index 9739331b38..175281a440 100644 --- a/opentelemetry/src/sdk/trace/span_processor.rs +++ b/opentelemetry/src/sdk/trace/span_processor.rs @@ -1,6 +1,7 @@ use crate::{ exporter::trace::{SpanData, SpanExporter}, - trace::SpanProcessor, + trace::{Span, SpanProcessor}, + Context, }; use futures::{channel::mpsc, executor, future::BoxFuture, Future, FutureExt, Stream, StreamExt}; use std::fmt; @@ -57,7 +58,7 @@ impl SimpleSpanProcessor { } impl SpanProcessor for SimpleSpanProcessor { - fn on_start(&self, _span: &SpanData) { + fn on_start(&self, _span: &dyn Span, _cx: &Context) { // Ignored } @@ -126,7 +127,7 @@ impl fmt::Debug for BatchSpanProcessor { } impl SpanProcessor for BatchSpanProcessor { - fn on_start(&self, _span: &SpanData) { + fn on_start(&self, _span: &dyn Span, _cx: &Context) { // Ignored } diff --git a/opentelemetry/src/sdk/trace/tracer.rs b/opentelemetry/src/sdk/trace/tracer.rs index cb271917a7..c9957674b5 100644 --- a/opentelemetry/src/sdk/trace/tracer.rs +++ b/opentelemetry/src/sdk/trace/tracer.rs @@ -7,12 +7,19 @@ //! 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::sdk; +use crate::sdk::{ + trace::{ + provider::{TracerProvider, TracerProviderInner}, + span::{Span, SpanData}, + EvictedHashMap, EvictedQueue, SamplingDecision, SamplingResult, + }, + InstrumentationLibrary, +}; use crate::trace::{ Link, SpanBuilder, SpanContext, SpanId, SpanKind, StatusCode, TraceContextExt, TraceId, TraceState, TRACE_FLAG_SAMPLED, }; -use crate::{exporter, Context, KeyValue}; +use crate::{Context, KeyValue}; use std::fmt; use std::sync::Weak; use std::time::SystemTime; @@ -20,8 +27,8 @@ use std::time::SystemTime; /// `Tracer` implementation to create and manage spans #[derive(Clone)] pub struct Tracer { - instrumentation_lib: sdk::InstrumentationLibrary, - provider: Weak, + instrumentation_lib: InstrumentationLibrary, + provider: Weak, } impl fmt::Debug for Tracer { @@ -38,8 +45,8 @@ impl fmt::Debug for Tracer { impl Tracer { /// Create a new tracer (used internally by `TracerProvider`s). pub(crate) fn new( - instrumentation_lib: sdk::InstrumentationLibrary, - provider: Weak, + instrumentation_lib: InstrumentationLibrary, + provider: Weak, ) -> Self { Tracer { instrumentation_lib, @@ -48,12 +55,12 @@ impl Tracer { } /// TracerProvider associated with this tracer. - pub fn provider(&self) -> Option { - self.provider.upgrade().map(sdk::trace::TracerProvider::new) + pub fn provider(&self) -> Option { + self.provider.upgrade().map(TracerProvider::new) } /// instrumentation library information of this tracer. - pub fn instrumentation_library(&self) -> &sdk::InstrumentationLibrary { + pub fn instrumentation_library(&self) -> &InstrumentationLibrary { &self.instrumentation_lib } @@ -78,24 +85,24 @@ impl Tracer { fn process_sampling_result( &self, - sampling_result: sdk::trace::SamplingResult, + sampling_result: SamplingResult, parent_context: Option<&SpanContext>, ) -> Option<(u8, Vec, TraceState)> { match sampling_result { - sdk::trace::SamplingResult { - decision: sdk::trace::SamplingDecision::Drop, + SamplingResult { + decision: SamplingDecision::Drop, .. } => None, - sdk::trace::SamplingResult { - decision: sdk::trace::SamplingDecision::RecordOnly, + SamplingResult { + decision: SamplingDecision::RecordOnly, attributes, trace_state, } => { let trace_flags = parent_context.map(|ctx| ctx.trace_flags()).unwrap_or(0); Some((trace_flags & !TRACE_FLAG_SAMPLED, attributes, trace_state)) } - sdk::trace::SamplingResult { - decision: sdk::trace::SamplingDecision::RecordAndSample, + SamplingResult { + decision: SamplingDecision::RecordAndSample, attributes, trace_state, } => { @@ -108,12 +115,12 @@ impl Tracer { impl crate::trace::Tracer for Tracer { /// This implementation of `Tracer` produces `sdk::Span` instances. - type Span = sdk::trace::Span; + type Span = Span; /// 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::trace::Span::new(SpanId::invalid(), None, self.clone()) + Span::new(SpanContext::empty_context(), None, self.clone()) } /// Starts a new `Span` in a given context. @@ -146,7 +153,7 @@ impl crate::trace::Tracer for Tracer { fn build_with_context(&self, mut builder: SpanBuilder, cx: &Context) -> Self::Span { let provider = self.provider(); if provider.is_none() { - return sdk::trace::Span::new(SpanId::invalid(), None, self.clone()); + return Span::new(SpanContext::empty_context(), None, self.clone()); } let provider = provider.unwrap(); @@ -159,12 +166,14 @@ impl crate::trace::Tracer for Tracer { let span_kind = builder.span_kind.take().unwrap_or(SpanKind::Internal); let mut attribute_options = builder.attributes.take().unwrap_or_else(Vec::new); let mut link_options = builder.links.take().unwrap_or_else(Vec::new); + let mut flags = 0; + let mut span_trace_state = Default::default(); let parent_span_context = builder .parent_context - .take() + .as_ref() .or_else(|| Some(cx.span().span_context()).filter(|cx| cx.is_valid())) - .or_else(|| cx.remote_span_context().cloned()) + .or_else(|| cx.remote_span_context()) .filter(|cx| cx.is_valid()); // Build context for sampling decision let (no_parent, trace_id, parent_span_id, remote_parent, parent_trace_flags) = @@ -195,10 +204,10 @@ impl crate::trace::Tracer for Tracer { // * There is no parent or a remote parent, in which case make decision now // * There is a local parent, in which case defer to the parent's decision let sampling_decision = if let Some(sampling_result) = builder.sampling_result.take() { - self.process_sampling_result(sampling_result, parent_span_context.as_ref()) + self.process_sampling_result(sampling_result, parent_span_context) } else if no_parent || remote_parent { self.make_sampling_decision( - parent_span_context.as_ref(), + parent_span_context, trace_id, &builder.name, &span_kind, @@ -219,17 +228,19 @@ impl crate::trace::Tracer for Tracer { }; // Build optional inner context, `None` if not recording. - let inner = sampling_decision.map(move |(trace_flags, mut extra_attrs, trace_state)| { + let inner = sampling_decision.map(|(trace_flags, mut extra_attrs, trace_state)| { + flags = trace_flags; + span_trace_state = trace_state; attribute_options.append(&mut extra_attrs); - let mut attributes = sdk::trace::EvictedHashMap::new(config.max_attributes_per_span); + let mut attributes = EvictedHashMap::new(config.max_attributes_per_span); for attribute in attribute_options { attributes.insert(attribute); } - let mut links = sdk::trace::EvictedQueue::new(config.max_links_per_span); + let mut links = EvictedQueue::new(config.max_links_per_span); links.append_vec(&mut link_options); let start_time = builder.start_time.unwrap_or_else(SystemTime::now); let end_time = builder.end_time.unwrap_or(start_time); - let mut message_events = sdk::trace::EvictedQueue::new(config.max_events_per_span); + let mut message_events = EvictedQueue::new(config.max_events_per_span); if let Some(mut events) = builder.message_events { message_events.append_vec(&mut events); } @@ -237,8 +248,7 @@ impl crate::trace::Tracer for Tracer { let status_message = builder.status_message.unwrap_or_else(String::new); let resource = config.resource.clone(); - exporter::trace::SpanData { - span_context: SpanContext::new(trace_id, span_id, trace_flags, false, trace_state), + SpanData { parent_span_id, span_kind, name: builder.name, @@ -250,18 +260,18 @@ impl crate::trace::Tracer for Tracer { status_code, status_message, resource, - instrumentation_lib: self.instrumentation_lib, } }); + let span_context = SpanContext::new(trace_id, span_id, flags, false, span_trace_state); + let span = Span::new(span_context, inner, self.clone()); + // Call `on_start` for all processors - if let Some(inner) = inner.as_ref().cloned() { - for processor in provider.span_processors() { - processor.on_start(&inner) - } + for processor in provider.span_processors() { + processor.on_start(&span, cx) } - sdk::trace::Span::new(span_id, inner, self.clone()) + span } } diff --git a/opentelemetry/src/testing/trace.rs b/opentelemetry/src/testing/trace.rs index 40c970ba03..14cfcb6cb7 100644 --- a/opentelemetry/src/testing/trace.rs +++ b/opentelemetry/src/testing/trace.rs @@ -14,8 +14,8 @@ impl Span for TestSpan { _attributes: Vec, ) { } - fn span_context(&self) -> SpanContext { - self.0.clone() + fn span_context(&self) -> &SpanContext { + &self.0 } fn is_recording(&self) -> bool { false