diff --git a/examples/aws-xray/src/server.rs b/examples/aws-xray/src/server.rs index 9cfa3ca218..ec1a0f18d1 100644 --- a/examples/aws-xray/src/server.rs +++ b/examples/aws-xray/src/server.rs @@ -22,7 +22,7 @@ async fn handle(req: Request) -> Result, Infallible> { .to_str() .unwrap(); - let span = global::tracer("example/server").start_with_context("hello", parent_context); + let mut span = global::tracer("example/server").start_with_context("hello", parent_context); span.add_event(format!("Handling - {}", x_amzn_trace_id), Vec::new()); Ok(Response::new( diff --git a/examples/datadog/src/main.rs b/examples/datadog/src/main.rs index 5c649bc88d..aa94451036 100644 --- a/examples/datadog/src/main.rs +++ b/examples/datadog/src/main.rs @@ -10,7 +10,7 @@ use std::time::Duration; fn bar() { let tracer = global::tracer("component-bar"); - let span = tracer.start("bar"); + let mut span = tracer.start("bar"); span.set_attribute(Key::new("span.type").string("sql")); span.set_attribute(Key::new("sql.query").string("SELECT * FROM table")); thread::sleep(Duration::from_millis(6)); diff --git a/examples/grpc/src/server.rs b/examples/grpc/src/server.rs index 440a3a7472..2a487dcc82 100644 --- a/examples/grpc/src/server.rs +++ b/examples/grpc/src/server.rs @@ -47,7 +47,7 @@ impl Greeter for MyGreeter { ) -> Result, Status> { let parent_cx = global::get_text_map_propagator(|prop| prop.extract(&MetadataMap(request.metadata()))); - let span = global::tracer("greeter").start_with_context("Processing reply", parent_cx); + let mut span = global::tracer("greeter").start_with_context("Processing reply", parent_cx); span.set_attribute(KeyValue::new("request", format!("{:?}", request))); // Return an instance of type HelloReply diff --git a/examples/http/src/server.rs b/examples/http/src/server.rs index c230ded0ae..3e9eea3d85 100644 --- a/examples/http/src/server.rs +++ b/examples/http/src/server.rs @@ -16,7 +16,7 @@ async fn handle(req: Request) -> Result, Infallible> { let parent_cx = global::get_text_map_propagator(|propagator| { propagator.extract(&HeaderExtractor(req.headers())) }); - let span = global::tracer("example/server").start_with_context("hello", parent_cx); + let mut span = global::tracer("example/server").start_with_context("hello", parent_cx); span.add_event("handling this...".to_string(), Vec::new()); Ok(Response::new("Hello, World!".into())) diff --git a/examples/zipkin/src/main.rs b/examples/zipkin/src/main.rs index dc4a646208..6b9720083e 100644 --- a/examples/zipkin/src/main.rs +++ b/examples/zipkin/src/main.rs @@ -6,7 +6,7 @@ use std::time::Duration; fn bar() { let tracer = global::tracer("component-bar"); - let span = tracer.start("bar"); + let mut span = tracer.start("bar"); thread::sleep(Duration::from_millis(6)); span.end() } diff --git a/opentelemetry-aws/src/lib.rs b/opentelemetry-aws/src/lib.rs index ce721cdafc..7c13ca55fb 100644 --- a/opentelemetry-aws/src/lib.rs +++ b/opentelemetry-aws/src/lib.rs @@ -146,7 +146,8 @@ pub mod trace { impl TextMapPropagator for XrayPropagator { fn inject_context(&self, cx: &Context, injector: &mut dyn Injector) { - let span_context = cx.span().span_context(); + let span = cx.span(); + let span_context = span.span_context(); if span_context.is_valid() { let xray_trace_id: XrayTraceId = span_context.trace_id().into(); diff --git a/opentelemetry-datadog/src/lib.rs b/opentelemetry-datadog/src/lib.rs index 43367deabf..4454e870cb 100644 --- a/opentelemetry-datadog/src/lib.rs +++ b/opentelemetry-datadog/src/lib.rs @@ -260,7 +260,8 @@ mod propagator { impl TextMapPropagator for DatadogPropagator { fn inject_context(&self, cx: &Context, injector: &mut dyn Injector) { - let span_context = cx.span().span_context(); + let span = cx.span(); + let span_context = span.span_context(); if span_context.is_valid() { injector.set( DATADOG_TRACE_ID_HEADER, diff --git a/opentelemetry-jaeger/src/lib.rs b/opentelemetry-jaeger/src/lib.rs index 196a77a693..a4ee5984bc 100644 --- a/opentelemetry-jaeger/src/lib.rs +++ b/opentelemetry-jaeger/src/lib.rs @@ -331,7 +331,8 @@ mod propagator { impl TextMapPropagator for Propagator { fn inject_context(&self, cx: &Context, injector: &mut dyn Injector) { - let span_context = cx.span().span_context(); + let span = cx.span(); + let span_context = span.span_context(); if span_context.is_valid() { let flag: u8 = if span_context.is_sampled() { if span_context.is_debug() { diff --git a/opentelemetry-otlp/tests/smoke.rs b/opentelemetry-otlp/tests/smoke.rs index 04dfdac08a..eadfb035ae 100644 --- a/opentelemetry-otlp/tests/smoke.rs +++ b/opentelemetry-otlp/tests/smoke.rs @@ -74,7 +74,7 @@ async fn smoke_tracer() { .expect("failed to install"); println!("Sending span..."); - let span = tracer + let mut span = tracer .span_builder("my-test-span") .with_kind(SpanKind::Server) .start(&tracer); diff --git a/opentelemetry-zipkin/src/propagator/mod.rs b/opentelemetry-zipkin/src/propagator/mod.rs index 9a3f2158c3..b8ae070529 100644 --- a/opentelemetry-zipkin/src/propagator/mod.rs +++ b/opentelemetry-zipkin/src/propagator/mod.rs @@ -211,7 +211,8 @@ impl TextMapPropagator for Propagator { /// Properly encodes the values of the `Context`'s `SpanContext` and injects /// them into the `Injector`. fn inject_context(&self, context: &Context, injector: &mut dyn Injector) { - let span_context = context.span().span_context(); + let span = context.span(); + let span_context = span.span_context(); if span_context.is_valid() { if self.inject_encoding.support(&B3Encoding::SingleHeader) { let mut value = format!( diff --git a/opentelemetry/benches/trace.rs b/opentelemetry/benches/trace.rs index 42347340c7..c5f4e9f52e 100644 --- a/opentelemetry/benches/trace.rs +++ b/opentelemetry/benches/trace.rs @@ -27,7 +27,7 @@ fn criterion_benchmark(c: &mut Criterion) { trace_benchmark_group(c, "start-end-span", |tracer| tracer.start("foo").end()); trace_benchmark_group(c, "start-end-span-4-attrs", |tracer| { - let span = tracer.start("foo"); + let mut span = tracer.start("foo"); span.set_attribute(Key::new("key1").bool(false)); span.set_attribute(Key::new("key2").string("hello")); span.set_attribute(Key::new("key4").f64(123.456)); @@ -35,7 +35,7 @@ fn criterion_benchmark(c: &mut Criterion) { }); trace_benchmark_group(c, "start-end-span-8-attrs", |tracer| { - let span = tracer.start("foo"); + let mut span = tracer.start("foo"); span.set_attribute(Key::new("key1").bool(false)); span.set_attribute(Key::new("key2").string("hello")); span.set_attribute(Key::new("key4").f64(123.456)); @@ -46,7 +46,7 @@ fn criterion_benchmark(c: &mut Criterion) { }); trace_benchmark_group(c, "start-end-span-all-attr-types", |tracer| { - let span = tracer.start("foo"); + let mut span = tracer.start("foo"); span.set_attribute(Key::new("key1").bool(false)); span.set_attribute(Key::new("key2").string("hello")); span.set_attribute(Key::new("key3").i64(123)); @@ -55,7 +55,7 @@ fn criterion_benchmark(c: &mut Criterion) { }); trace_benchmark_group(c, "start-end-span-all-attr-types-2x", |tracer| { - let span = tracer.start("foo"); + let mut span = tracer.start("foo"); span.set_attribute(Key::new("key1").bool(false)); span.set_attribute(Key::new("key2").string("hello")); span.set_attribute(Key::new("key3").i64(123)); diff --git a/opentelemetry/src/global/trace.rs b/opentelemetry/src/global/trace.rs index 1d09cde3a2..4ff11b42b0 100644 --- a/opentelemetry/src/global/trace.rs +++ b/opentelemetry/src/global/trace.rs @@ -21,7 +21,7 @@ impl trace::Span for BoxedSpan { /// keys"](https://github.com/open-telemetry/opentelemetry-specification/tree/v0.5.0/specification/trace/semantic_conventions/README.md) /// which have prescribed semantic meanings. fn add_event_with_timestamp( - &self, + &mut self, name: String, timestamp: SystemTime, attributes: Vec, @@ -45,23 +45,23 @@ impl trace::Span for BoxedSpan { /// Note that the OpenTelemetry project documents certain ["standard /// 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) { + fn set_attribute(&mut self, attribute: KeyValue) { self.0.set_attribute(attribute) } /// Sets the status of the `Span`. If used, this will override the default `Span` /// status, which is `Unset`. - fn set_status(&self, code: trace::StatusCode, message: String) { + fn set_status(&mut self, code: trace::StatusCode, message: String) { self.0.set_status(code, message) } /// Updates the `Span`'s name. - fn update_name(&self, new_name: String) { + fn update_name(&mut self, new_name: String) { self.0.update_name(new_name) } /// Finishes the span with given timestamp. - fn end_with_timestamp(&self, timestamp: SystemTime) { + fn end_with_timestamp(&mut self, timestamp: SystemTime) { self.0.end_with_timestamp(timestamp); } } @@ -128,7 +128,7 @@ pub trait GenericTracer: fmt::Debug + 'static { impl GenericTracer for T where - S: trace::Span + Send + Sync, + S: trace::Span + Send + Sync + 'static, T: trace::Tracer, { /// Create a new invalid span for use in cases where there are no active spans. @@ -165,7 +165,7 @@ pub trait GenericTracerProvider: fmt::Debug + 'static { impl GenericTracerProvider for P where - S: trace::Span + Send + Sync, + S: trace::Span + Send + Sync + 'static, T: trace::Tracer + Send + Sync, P: trace::TracerProvider, { @@ -193,7 +193,7 @@ impl GlobalTracerProvider { /// Create a new GlobalTracerProvider instance from a struct that implements `TracerProvider`. fn new(provider: P) -> Self where - S: trace::Span + Send + Sync, + S: trace::Span + Send + Sync + 'static, T: trace::Tracer + Send + Sync, P: trace::TracerProvider + Send + Sync, { @@ -258,7 +258,7 @@ pub fn tracer_with_version(name: &'static str, version: &'static str) -> BoxedTr /// [`TracerProvider`]: crate::trace::TracerProvider pub fn set_tracer_provider(new_provider: P) -> GlobalTracerProvider where - S: trace::Span + Send + Sync, + S: trace::Span + Send + Sync + 'static, T: trace::Tracer + Send + Sync, P: trace::TracerProvider + Send + Sync, { diff --git a/opentelemetry/src/sdk/propagation/composite.rs b/opentelemetry/src/sdk/propagation/composite.rs index 9c292191ed..e4fdce6aa2 100644 --- a/opentelemetry/src/sdk/propagation/composite.rs +++ b/opentelemetry/src/sdk/propagation/composite.rs @@ -138,14 +138,15 @@ mod tests { impl TextMapPropagator for TestPropagator { fn inject_context(&self, cx: &Context, injector: &mut dyn Injector) { - let span = cx.span().span_context(); + let span = cx.span(); + let span_context = span.span_context(); injector.set( "testheader", format!( "{}-{}-{}", - span.trace_id().to_u128(), - span.span_id().to_u64(), - span.trace_flags() + span_context.trace_id().to_u128(), + span_context.span_id().to_u64(), + span_context.trace_flags() ), ) } diff --git a/opentelemetry/src/sdk/propagation/trace_context.rs b/opentelemetry/src/sdk/propagation/trace_context.rs index 9904638c1e..c00c75c83c 100644 --- a/opentelemetry/src/sdk/propagation/trace_context.rs +++ b/opentelemetry/src/sdk/propagation/trace_context.rs @@ -117,7 +117,8 @@ impl TextMapPropagator for TraceContextPropagator { /// Properly encodes the values of the `SpanContext` and injects them /// into the `Injector`. fn inject_context(&self, cx: &Context, injector: &mut dyn Injector) { - let span_context = cx.span().span_context(); + let span = cx.span(); + let span_context = span.span_context(); if span_context.is_valid() { let header_value = format!( "{:02x}-{:032x}-{:016x}-{:02x}", diff --git a/opentelemetry/src/sdk/trace/sampler.rs b/opentelemetry/src/sdk/trace/sampler.rs index 5242dbf2cd..c05c79d320 100644 --- a/opentelemetry/src/sdk/trace/sampler.rs +++ b/opentelemetry/src/sdk/trace/sampler.rs @@ -119,7 +119,8 @@ impl ShouldSample for Sampler { .should_sample(parent_context, trace_id, name, span_kind, attributes, links) .decision, |ctx| { - let parent_span_context = ctx.span().span_context(); + let span = ctx.span(); + let parent_span_context = span.span_context(); if parent_span_context.is_sampled() { SamplingDecision::RecordAndSample } else { diff --git a/opentelemetry/src/sdk/trace/span.rs b/opentelemetry/src/sdk/trace/span.rs index f8eec586b1..866f1780e2 100644 --- a/opentelemetry/src/sdk/trace/span.rs +++ b/opentelemetry/src/sdk/trace/span.rs @@ -10,20 +10,14 @@ //! These cannot be changed after the `Span`'s end time has been set. use crate::trace::{Event, SpanContext, SpanId, SpanKind, StatusCode}; use crate::{sdk, trace, KeyValue}; -use std::sync::{Arc, Mutex}; +use std::sync::Arc; use std::time::SystemTime; /// Single operation within a trace. -#[derive(Clone, Debug)] -pub struct Span { - inner: Arc, -} - -/// Inner data, processed and exported on end #[derive(Debug)] -struct SpanInner { +pub struct Span { span_context: SpanContext, - data: Option>>, + data: Option, tracer: sdk::trace::Tracer, } @@ -49,8 +43,6 @@ pub(crate) struct SpanData { pub(crate) status_code: 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 { @@ -60,25 +52,18 @@ impl Span { tracer: sdk::trace::Tracer, ) -> Self { Span { - inner: Arc::new(SpanInner { - span_context, - data: data.map(|data| Mutex::new(Some(data))), - tracer, - }), + span_context, + data, + tracer, } } /// Operate on a mutable reference to span data - fn with_data(&self, f: F) -> Option + fn with_data(&mut self, f: F) -> Option where F: FnOnce(&mut SpanData) -> T, { - self.inner.data.as_ref().and_then(|inner| { - inner - .lock() - .ok() - .and_then(|mut span_data| span_data.as_mut().map(f)) - }) + self.data.as_mut().map(f) } } @@ -89,7 +74,7 @@ impl crate::trace::Span for Span { /// keys"](https://github.com/open-telemetry/opentelemetry-specification/tree/v0.5.0/specification/trace/semantic_conventions/README.md) /// which have prescribed semantic meanings. fn add_event_with_timestamp( - &self, + &mut self, name: String, timestamp: SystemTime, attributes: Vec, @@ -102,19 +87,14 @@ impl crate::trace::Span for Span { /// Returns the `SpanContext` for the given `Span`. fn span_context(&self) -> &SpanContext { - &self.inner.span_context + &self.span_context } /// Returns true if this `Span` is recording information like events with the `add_event` /// operation, attributes using `set_attributes`, status with `set_status`, etc. /// Always returns false after span `end`. fn is_recording(&self) -> bool { - if let Some(data) = &self.inner.data { - if let Ok(span_data) = data.lock() { - return span_data.is_some(); - } - } - false + self.data.is_some() } /// Sets a single `Attribute` where the attribute properties are passed as arguments. @@ -122,7 +102,7 @@ impl crate::trace::Span for Span { /// Note that the OpenTelemetry project documents certain ["standard /// 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) { + fn set_attribute(&mut self, attribute: KeyValue) { self.with_data(|data| { data.attributes.insert(attribute); }); @@ -130,7 +110,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`. `message` MUST be ignored when the status is `OK` or `Unset` - fn set_status(&self, code: StatusCode, message: String) { + fn set_status(&mut self, code: StatusCode, message: String) { self.with_data(|data| { if code == StatusCode::Error { data.status_message = message; @@ -140,50 +120,49 @@ impl crate::trace::Span for Span { } /// Updates the `Span`'s name. - fn update_name(&self, new_name: String) { + fn update_name(&mut self, new_name: String) { self.with_data(|data| { data.name = new_name; }); } /// Finishes the span with given timestamp. - fn end_with_timestamp(&self, timestamp: SystemTime) { - self.inner.ensure_ended_and_exported(Some(timestamp)); + fn end_with_timestamp(&mut self, timestamp: SystemTime) { + self.ensure_ended_and_exported(Some(timestamp)); } } -impl SpanInner { - fn ensure_ended_and_exported(&self, timestamp: Option) { - if let Some(data) = &self.data { - if let Ok(mut span_data) = data.lock().map(|mut data| data.take()) { - // Ensure end time is set via explicit end or implicitly on drop - if let Some(span_data) = span_data.as_mut() { - if let Some(timestamp) = timestamp { - span_data.end_time = timestamp; - } else if span_data.end_time == span_data.start_time { - span_data.end_time = crate::time::now(); - } - } +impl Span { + fn ensure_ended_and_exported(&mut self, timestamp: Option) { + if let Some(mut data) = self.data.take() { + // Ensure end time is set via explicit end or implicitly on drop + if let Some(timestamp) = timestamp { + data.end_time = timestamp; + } else if data.end_time == data.start_time { + data.end_time = crate::time::now(); + } - // Notify each span processor that the span has ended - if let Some(provider) = self.tracer.provider() { - let mut processors = provider.span_processors().iter().peekable(); - while let Some(processor) = processors.next() { - let span_data = if processors.peek().is_none() { - // last loop or single processor/exporter, move data - span_data.take() - } else { - // clone so each exporter gets owned data - span_data.clone() - }; - - if let Some(span_data) = span_data { - processor.on_end(build_export_data( - span_data, - self.span_context.clone(), - &self.tracer, - )); - } + // Notify each span processor that the span has ended + if let Some(provider) = self.tracer.provider() { + let mut processors = provider.span_processors().iter().peekable(); + let resource = provider.config().resource.clone(); + let mut span_data = Some((data, resource)); + while let Some(processor) = processors.next() { + let span_data = if processors.peek().is_none() { + // last loop or single processor/exporter, move data + span_data.take() + } else { + // clone so each exporter gets owned data + span_data.clone() + }; + + if let Some((span_data, resource)) = span_data { + processor.on_end(build_export_data( + span_data, + self.span_context.clone(), + resource, + &self.tracer, + )); } } } @@ -191,7 +170,7 @@ impl SpanInner { } } -impl Drop for SpanInner { +impl Drop for Span { /// Report span on inner drop fn drop(&mut self) { self.ensure_ended_and_exported(None); @@ -201,6 +180,7 @@ impl Drop for SpanInner { fn build_export_data( data: SpanData, span_context: SpanContext, + resource: Arc, tracer: &sdk::trace::Tracer, ) -> sdk::export::trace::SpanData { sdk::export::trace::SpanData { @@ -215,7 +195,7 @@ fn build_export_data( links: data.links, status_code: data.status_code, status_message: data.status_message, - resource: data.resource, + resource, instrumentation_lib: *tracer.instrumentation_library(), } } @@ -241,7 +221,6 @@ mod tests { links: sdk::trace::EvictedQueue::new(config.max_links_per_span), status_code: StatusCode::Unset, status_message: "".to_string(), - resource: config.resource.clone(), }; (tracer, data) } @@ -254,20 +233,20 @@ mod tests { #[test] fn create_span_without_data() { let (tracer, _) = init(); - let span = Span::new(SpanContext::empty_context(), None, tracer); + let mut span = Span::new(SpanContext::empty_context(), None, tracer); span.with_data(|_data| panic!("there are data")); } #[test] fn create_span_with_data_mut() { let (tracer, data) = init(); - let span = Span::new(SpanContext::empty_context(), Some(data.clone()), tracer); + let mut span = Span::new(SpanContext::empty_context(), Some(data.clone()), tracer); span.with_data(|d| assert_eq!(*d, data)); } #[test] fn add_event() { - let span = create_span(); + let mut span = create_span(); let name = "some_event".to_string(); let attributes = vec![KeyValue::new("k", "v")]; span.add_event(name.clone(), attributes.clone()); @@ -283,7 +262,7 @@ mod tests { #[test] fn add_event_with_timestamp() { - let span = create_span(); + let mut span = create_span(); let name = "some_event".to_string(); let attributes = vec![KeyValue::new("k", "v")]; let timestamp = crate::time::now(); @@ -301,7 +280,7 @@ mod tests { #[test] fn record_exception() { - let span = create_span(); + let mut span = create_span(); let err = std::io::Error::from(std::io::ErrorKind::Other); span.record_exception(&err); span.with_data(|data| { @@ -319,7 +298,7 @@ mod tests { #[test] fn record_exception_with_stacktrace() { - let span = create_span(); + let mut span = create_span(); let err = std::io::Error::from(std::io::ErrorKind::Other); let stacktrace = "stacktrace...".to_string(); span.record_exception_with_stacktrace(&err, stacktrace.clone()); @@ -341,7 +320,7 @@ mod tests { #[test] fn set_attribute() { - let span = create_span(); + let mut span = create_span(); let attributes = KeyValue::new("k", "v"); span.set_attribute(attributes.clone()); span.with_data(|data| { @@ -356,7 +335,7 @@ mod tests { #[test] fn set_status() { { - let span = create_span(); + let mut span = create_span(); let status = StatusCode::Ok; let message = "OK".to_string(); span.set_status(status, message); @@ -366,7 +345,7 @@ mod tests { }); } { - let span = create_span(); + let mut span = create_span(); let status = StatusCode::Unset; let message = "OK".to_string(); span.set_status(status, message); @@ -376,7 +355,7 @@ mod tests { }); } { - let span = create_span(); + let mut span = create_span(); let status = StatusCode::Error; let message = "Error".to_string(); span.set_status(status, message); @@ -389,7 +368,7 @@ mod tests { #[test] fn update_name() { - let span = create_span(); + let mut span = create_span(); let name = "new_name".to_string(); span.update_name(name.clone()); span.with_data(|data| { @@ -399,13 +378,13 @@ mod tests { #[test] fn end() { - let span = create_span(); + let mut span = create_span(); span.end(); } #[test] fn end_with_timestamp() { - let span = create_span(); + let mut span = create_span(); let timestamp = crate::time::now(); span.end_with_timestamp(timestamp); span.with_data(|data| assert_eq!(data.end_time, timestamp)); @@ -413,21 +392,14 @@ mod tests { #[test] fn allows_to_get_span_context_after_end() { - let span = create_span(); + let mut span = create_span(); span.end(); assert_eq!(span.span_context(), &SpanContext::empty_context()); } - #[test] - fn allows_to_get_span_context_after_clone_drop() { - let span = create_span(); - drop(span.clone()); - assert_eq!(span.span_context(), &SpanContext::empty_context()); - } - #[test] fn end_only_once() { - let span = create_span(); + let mut span = create_span(); let timestamp = crate::time::now(); span.end_with_timestamp(timestamp); span.end_with_timestamp(timestamp.checked_add(Duration::from_secs(10)).unwrap()); @@ -436,7 +408,7 @@ mod tests { #[test] fn noop_after_end() { - let span = create_span(); + let mut span = create_span(); let initial = span.with_data(|data| data.clone()).unwrap(); span.end(); span.add_event("some_event".to_string(), vec![KeyValue::new("k", "v")]); @@ -468,7 +440,7 @@ mod tests { #[test] fn is_recording_false_after_end() { - let span = create_span(); + let mut span = create_span(); span.end(); assert!(!span.is_recording()); } diff --git a/opentelemetry/src/sdk/trace/tracer.rs b/opentelemetry/src/sdk/trace/tracer.rs index 29d29fa4dc..f9369d5813 100644 --- a/opentelemetry/src/sdk/trace/tracer.rs +++ b/opentelemetry/src/sdk/trace/tracer.rs @@ -11,7 +11,7 @@ use crate::sdk::{ trace::{ provider::{TracerProvider, TracerProviderInner}, span::{Span, SpanData}, - EvictedHashMap, EvictedQueue, SamplingDecision, SamplingResult, + Config, EvictedHashMap, EvictedQueue, SamplingDecision, SamplingResult, }, InstrumentationLibrary, }; @@ -73,11 +73,9 @@ impl Tracer { span_kind: &SpanKind, attributes: &[KeyValue], links: &[Link], + config: &Config, ) -> Option<(u8, Vec, TraceState)> { - let provider = self.provider()?; - let sampler = &provider.config().default_sampler; - - let sampling_result = sampler.should_sample( + let sampling_result = config.default_sampler.should_sample( Some(parent_cx), trace_id, name, @@ -192,11 +190,13 @@ impl crate::trace::Tracer for Tracer { _ => cx, } }; + let span = parent_cx.span(); let parent_span_context = if parent_cx.has_active_span() { - Some(parent_cx.span().span_context()) + Some(span.span_context()) } else { None }; + // Build context for sampling decision let (no_parent, trace_id, parent_span_id, remote_parent, parent_trace_flags) = parent_span_context @@ -235,6 +235,7 @@ impl crate::trace::Tracer for Tracer { &span_kind, &attribute_options, link_options.as_deref().unwrap_or(&[]), + provider.config(), ) } else { // has parent that is local: use parent if sampled, or don't record. @@ -270,8 +271,7 @@ impl crate::trace::Tracer for Tracer { message_events.append_vec(&mut events); } let status_code = builder.status_code.unwrap_or(StatusCode::Unset); - let status_message = builder.status_message.unwrap_or_else(String::new); - let resource = config.resource.clone(); + let status_message = builder.status_message.unwrap_or_default(); SpanData { parent_span_id, @@ -284,7 +284,6 @@ impl crate::trace::Tracer for Tracer { links, status_code, status_message, - resource, } }); diff --git a/opentelemetry/src/testing/trace.rs b/opentelemetry/src/testing/trace.rs index b6f4caa83a..6f2f3ebd89 100644 --- a/opentelemetry/src/testing/trace.rs +++ b/opentelemetry/src/testing/trace.rs @@ -19,7 +19,7 @@ pub struct TestSpan(pub SpanContext); impl Span for TestSpan { fn add_event_with_timestamp( - &self, + &mut self, _name: String, _timestamp: std::time::SystemTime, _attributes: Vec, @@ -31,10 +31,10 @@ impl Span for TestSpan { fn is_recording(&self) -> bool { false } - fn set_attribute(&self, _attribute: KeyValue) {} - fn set_status(&self, _code: StatusCode, _message: String) {} - fn update_name(&self, _new_name: String) {} - fn end_with_timestamp(&self, _timestamp: std::time::SystemTime) {} + fn set_attribute(&mut self, _attribute: KeyValue) {} + fn set_status(&mut self, _code: StatusCode, _message: String) {} + fn update_name(&mut self, _new_name: String) {} + fn end_with_timestamp(&mut self, _timestamp: std::time::SystemTime) {} } pub fn new_test_export_span_data() -> SpanData { diff --git a/opentelemetry/src/trace/context.rs b/opentelemetry/src/trace/context.rs index 05932ca263..93bb2ade1a 100644 --- a/opentelemetry/src/trace/context.rs +++ b/opentelemetry/src/trace/context.rs @@ -1,10 +1,110 @@ //! Context extensions for tracing -use crate::{Context, ContextGuard}; +use crate::{global, trace::SpanContext, Context, ContextGuard, KeyValue}; +use std::error::Error; +use std::sync::Mutex; + lazy_static::lazy_static! { - static ref NOOP_SPAN: crate::trace::NoopSpan = crate::trace::NoopSpan::new(); + static ref NOOP_SPAN: SynchronizedSpan = SynchronizedSpan { + span_context: SpanContext::empty_context(), + inner: None, + }; +} + +/// A reference to the currently active span in this context. +#[derive(Debug)] +pub struct SpanRef<'a>(&'a SynchronizedSpan); + +#[derive(Debug)] +struct SynchronizedSpan { + /// Immutable span context + span_context: SpanContext, + /// Mutable span inner that requires synchronization + inner: Option>>, +} + +impl SpanRef<'_> { + fn with_inner_mut(&self, f: F) { + if let Some(ref inner) = self.0.inner { + match inner.lock() { + Ok(mut locked) => f(&mut *locked), + Err(err) => global::handle_error(err), + } + } + } } -struct Span(Box); +impl SpanRef<'_> { + /// An API to record events in the context of a given `Span`. + pub fn add_event(&self, name: String, attributes: Vec) { + self.with_inner_mut(|inner| inner.add_event(name, attributes)) + } + + /// Convenience method to record an exception/error as an `Event` + pub fn record_exception(&self, err: &dyn Error) { + self.with_inner_mut(|inner| inner.record_exception(err)) + } + + /// Convenience method to record a exception/error as an `Event` with custom stacktrace + pub fn record_exception_with_stacktrace(&self, err: &dyn Error, stacktrace: String) { + self.with_inner_mut(|inner| inner.record_exception_with_stacktrace(err, stacktrace)) + } + + /// An API to record events at a specific time in the context of a given `Span`. + pub fn add_event_with_timestamp( + &self, + name: String, + timestamp: std::time::SystemTime, + attributes: Vec, + ) { + self.with_inner_mut(move |inner| { + inner.add_event_with_timestamp(name, timestamp, attributes) + }) + } + + /// Returns the `SpanContext` for the given `Span`. + pub fn span_context(&self) -> &SpanContext { + &self.0.span_context + } + + /// Returns true if this `Span` is recording information like events with the `add_event` + /// operation, attributes using `set_attributes`, status with `set_status`, etc. + pub fn is_recording(&self) -> bool { + self.0 + .inner + .as_ref() + .and_then(|inner| inner.lock().ok().map(|active| active.is_recording())) + .unwrap_or(false) + } + + /// An API to set a single `Attribute` where the attribute properties are passed + /// as arguments. To avoid extra allocations some implementations may offer a separate API for + /// each of the possible value types. + pub fn set_attribute(&self, attribute: crate::KeyValue) { + self.with_inner_mut(move |inner| inner.set_attribute(attribute)) + } + + /// Sets the status of the `Span`. If used, this will override the default `Span` + /// status, which is `Unset`. `message` MUST be ignored when the status is `OK` or `Unset` + pub fn set_status(&self, code: super::StatusCode, message: String) { + self.with_inner_mut(move |inner| inner.set_status(code, message)) + } + + /// Updates the `Span`'s name. After this update, any sampling behavior based on the + /// name will depend on the implementation. + pub fn update_name(&self, new_name: String) { + self.with_inner_mut(move |inner| inner.update_name(new_name)) + } + + /// Finishes the `Span`. + pub fn end(&self) { + self.end_with_timestamp(crate::time::now()); + } + + /// Finishes the `Span` with given timestamp + pub fn end_with_timestamp(&self, timestamp: std::time::SystemTime) { + self.with_inner_mut(move |inner| inner.end_with_timestamp(timestamp)) + } +} struct RemoteSpanContext(crate::trace::SpanContext); @@ -13,12 +113,12 @@ pub trait TraceContextExt { /// Returns a clone of the current context with the included span. /// /// This is useful for building tracers. - fn current_with_span(span: T) -> Self; + fn current_with_span(span: T) -> Self; /// Returns a clone of this context with the included span. /// /// This is useful for building tracers. - fn with_span(&self, span: T) -> Self; + fn with_span(&self, span: T) -> Self; /// Returns a reference to this context's span, or the default no-op span if /// none has been set. @@ -40,7 +140,7 @@ pub trait TraceContextExt { /// assert_ne!(cx.span().span_context(), &SpanContext::empty_context()); /// }); /// ``` - fn span(&self) -> &dyn crate::trace::Span; + fn span(&self) -> SpanRef<'_>; /// Used to see if a span has been marked as active /// @@ -60,24 +160,30 @@ pub trait TraceContextExt { } impl TraceContextExt for Context { - fn current_with_span(span: T) -> Self { - Context::current_with_value(Span(Box::new(span))) + fn current_with_span(span: T) -> Self { + Context::current_with_value(SynchronizedSpan { + span_context: span.span_context().clone(), + inner: Some(Box::new(Mutex::new(span))), + }) } - fn with_span(&self, span: T) -> Self { - self.with_value(Span(Box::new(span))) + fn with_span(&self, span: T) -> Self { + self.with_value(SynchronizedSpan { + span_context: span.span_context().clone(), + inner: Some(Box::new(Mutex::new(span))), + }) } - fn span(&self) -> &dyn crate::trace::Span { - if let Some(span) = self.get::() { - span.0.as_ref() + fn span(&self) -> SpanRef<'_> { + if let Some(span) = self.get::() { + SpanRef(span) } else { - &*NOOP_SPAN + SpanRef(&*NOOP_SPAN) } } fn has_active_span(&self) -> bool { - self.get::().is_some() + self.get::().is_some() } fn with_remote_span_context(&self, span_context: crate::trace::SpanContext) -> Self { @@ -121,7 +227,7 @@ impl TraceContextExt for Context { /// } /// ``` #[must_use = "Dropping the guard detaches the context."] -pub fn mark_span_as_active(span: T) -> ContextGuard { +pub fn mark_span_as_active(span: T) -> ContextGuard { let cx = Context::current_with_span(span); cx.attach() } @@ -151,7 +257,7 @@ pub fn mark_span_as_active(span: T) -> Cont /// ``` pub fn get_active_span(f: F) -> T where - F: FnOnce(&dyn crate::trace::Span) -> T, + F: FnOnce(SpanRef<'_>) -> T, { f(Context::current().span()) } diff --git a/opentelemetry/src/trace/noop.rs b/opentelemetry/src/trace/noop.rs index 7b2dad3540..e2ee5d0949 100644 --- a/opentelemetry/src/trace/noop.rs +++ b/opentelemetry/src/trace/noop.rs @@ -63,13 +63,13 @@ impl NoopSpan { impl trace::Span for NoopSpan { /// Ignores all events - fn add_event(&self, _name: String, _attributes: Vec) { + fn add_event(&mut self, _name: String, _attributes: Vec) { // Ignore } /// Ignores all events with timestamps fn add_event_with_timestamp( - &self, + &mut self, _name: String, _timestamp: SystemTime, _attributes: Vec, @@ -88,22 +88,22 @@ impl trace::Span for NoopSpan { } /// Ignores all attributes - fn set_attribute(&self, _attribute: KeyValue) { + fn set_attribute(&mut self, _attribute: KeyValue) { // Ignored } /// Ignores status - fn set_status(&self, _code: trace::StatusCode, _message: String) { + fn set_status(&mut self, _code: trace::StatusCode, _message: String) { // Ignored } /// Ignores name updates - fn update_name(&self, _new_name: String) { + fn update_name(&mut self, _new_name: String) { // Ignored } /// Ignores `Span` endings - fn end_with_timestamp(&self, _timestamp: SystemTime) { + fn end_with_timestamp(&mut self, _timestamp: SystemTime) { // Ignored } } diff --git a/opentelemetry/src/trace/span.rs b/opentelemetry/src/trace/span.rs index f7033edc29..2ba22e67e2 100644 --- a/opentelemetry/src/trace/span.rs +++ b/opentelemetry/src/trace/span.rs @@ -23,7 +23,7 @@ use std::fmt; use std::time::SystemTime; /// Interface for a single operation within a trace. -pub trait Span: fmt::Debug + 'static + Send + Sync { +pub trait Span: fmt::Debug { /// An API to record events in the context of a given `Span`. /// /// Events have a time associated with the moment when they are @@ -35,7 +35,7 @@ pub trait Span: fmt::Debug + 'static + Send + Sync { /// Note that the OpenTelemetry project documents certain ["standard event names and /// keys"](https://github.com/open-telemetry/opentelemetry-specification/tree/v0.5.0/specification/trace/semantic_conventions/README.md) /// which have prescribed semantic meanings. - fn add_event(&self, name: String, attributes: Vec) { + fn add_event(&mut self, name: String, attributes: Vec) { self.add_event_with_timestamp(name, crate::time::now(), attributes) } @@ -52,7 +52,7 @@ pub trait Span: fmt::Debug + 'static + Send + Sync { /// /// Users can custom the exception message by overriding the `fmt::Display` trait's `fmt` method /// for the error. - fn record_exception(&self, err: &dyn Error) { + fn record_exception(&mut self, err: &dyn Error) { let attributes = vec![KeyValue::new("exception.message", err.to_string())]; self.add_event("exception".to_string(), attributes); @@ -61,7 +61,7 @@ pub trait Span: fmt::Debug + 'static + Send + Sync { /// Convenience method to record a exception/error as an `Event` with custom stacktrace /// /// See `Span:record_exception` method for more details. - fn record_exception_with_stacktrace(&self, err: &dyn Error, stacktrace: String) { + fn record_exception_with_stacktrace(&mut self, err: &dyn Error, stacktrace: String) { let attributes = vec![ KeyValue::new("exception.message", err.to_string()), KeyValue::new("exception.stacktrace", stacktrace), @@ -79,7 +79,7 @@ pub trait Span: fmt::Debug + 'static + Send + Sync { /// keys"](https://github.com/open-telemetry/opentelemetry-specification/tree/v0.5.0/specification/trace/semantic_conventions/README.md) /// which have prescribed semantic meanings. fn add_event_with_timestamp( - &self, + &mut self, name: String, timestamp: SystemTime, attributes: Vec, @@ -120,14 +120,14 @@ pub trait Span: fmt::Debug + 'static + Send + Sync { /// Note that the OpenTelemetry project documents certain ["standard /// 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); + fn set_attribute(&mut self, attribute: KeyValue); /// Sets the status of the `Span`. If used, this will override the default `Span` /// status, which is `Unset`. `message` MUST be ignored when the status is `OK` or `Unset` /// /// Only the value of the last call will be recorded, and implementations are free /// to ignore previous calls. - fn set_status(&self, code: StatusCode, message: String); + fn set_status(&mut self, code: StatusCode, message: String); /// Updates the `Span`'s name. After this update, any sampling behavior based on the /// name will depend on the implementation. @@ -141,7 +141,7 @@ pub trait Span: fmt::Debug + 'static + Send + Sync { /// regular property. It emphasizes that this operation signifies a /// major change for a `Span` and may lead to re-calculation of sampling or /// filtering decisions made previously depending on the implementation. - fn update_name(&self, new_name: String); + fn update_name(&mut self, new_name: String); /// Finishes the `Span`. /// @@ -153,7 +153,7 @@ pub trait Span: fmt::Debug + 'static + Send + Sync { /// still be running and can be ended later. /// /// This API MUST be non-blocking. - fn end(&self) { + fn end(&mut self) { self.end_with_timestamp(crate::time::now()); } @@ -162,7 +162,7 @@ pub trait Span: fmt::Debug + 'static + Send + Sync { /// For more details, refer to [`Span::end`] /// /// [`Span::end`]: Span::end() - fn end_with_timestamp(&self, timestamp: SystemTime); + fn end_with_timestamp(&mut self, timestamp: SystemTime); } /// `SpanKind` describes the relationship between the Span, its parents, diff --git a/opentelemetry/src/trace/tracer.rs b/opentelemetry/src/trace/tracer.rs index fb685c217e..065606f4d1 100644 --- a/opentelemetry/src/trace/tracer.rs +++ b/opentelemetry/src/trace/tracer.rs @@ -1,5 +1,5 @@ -use crate::sdk; use crate::{ + sdk, trace::{Event, Link, Span, SpanId, SpanKind, StatusCode, TraceContextExt, TraceId}, Context, KeyValue, }; @@ -40,7 +40,7 @@ use std::time::SystemTime; /// /// let parent = tracer.start("foo"); /// let parent_cx = Context::current_with_span(parent); -/// let child = tracer.span_builder("bar") +/// let mut child = tracer.span_builder("bar") /// .with_parent_context(parent_cx.clone()) /// .start(&tracer); /// @@ -158,7 +158,7 @@ use std::time::SystemTime; /// [`Context`]: crate::Context pub trait Tracer: fmt::Debug + 'static { /// The `Span` type used by this `Tracer`. - type Span: Span; + type Span: Span + Send + Sync; /// Returns a span with an invalid `SpanContext`. Used by functions that /// need to return a default span like `get_active_span` if no span is present.