diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 97f5f37b..235d37d3 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -52,5 +52,5 @@ inferno = "0.10.0" tempdir = "0.3.7" # opentelemetry example -opentelemetry = { version = "0.8", default-features = false, features = ["trace"] } -opentelemetry-jaeger = "0.7" +opentelemetry = { version = "0.10", default-features = false, features = ["trace"] } +opentelemetry-jaeger = "0.9" diff --git a/examples/examples/opentelemetry-remote-context.rs b/examples/examples/opentelemetry-remote-context.rs index d3af423d..b05b7fcf 100644 --- a/examples/examples/opentelemetry-remote-context.rs +++ b/examples/examples/opentelemetry-remote-context.rs @@ -1,13 +1,14 @@ -use opentelemetry::{api, api::HttpTextFormat}; +use opentelemetry::sdk::propagation::B3Propagator; +use opentelemetry::{global, Context}; use std::collections::HashMap; use tracing::span; use tracing_opentelemetry::OpenTelemetrySpanExt; use tracing_subscriber::layer::SubscriberExt; use tracing_subscriber::Registry; -fn make_request(_cx: api::Context) { +fn make_request(_cx: Context) { // perform external request after injecting context - // e.g. if there are request headers that impl `opentelemetry::api::Carrier` + // e.g. if there are request headers that impl `opentelemetry::propagation::Injector` // then `propagator.inject_context(cx, request.headers_mut())` } @@ -22,14 +23,15 @@ fn build_example_carrier() -> HashMap { } fn main() { + // Set a format for propagating context. This MUST be provided, as the default is a no-op. + global::set_text_map_propagator(B3Propagator::new()); let subscriber = Registry::default().with(tracing_opentelemetry::layer()); - // Propagator can be swapped with trace context propagator binary propagator, etc. - let propagator = api::B3Propagator::new(); - tracing::subscriber::with_default(subscriber, || { - // Extract from request headers, or any type that impls `opentelemetry::api::Carrier` - let parent_context = propagator.extract(&build_example_carrier()); + // Extract context from request headers + let parent_context = global::get_text_map_propagator(|propagator| { + propagator.extract(&build_example_carrier()) + }); // Generate tracing span as usual let app_root = span!(tracing::Level::INFO, "app_start"); diff --git a/examples/examples/opentelemetry.rs b/examples/examples/opentelemetry.rs index 33f645c9..b7e522ef 100644 --- a/examples/examples/opentelemetry.rs +++ b/examples/examples/opentelemetry.rs @@ -1,6 +1,4 @@ -use opentelemetry::api::Provider; -use opentelemetry::sdk; -use std::{thread, time::Duration}; +use std::{error::Error, thread, time::Duration}; use tracing::{span, trace, warn}; use tracing_attributes::instrument; use tracing_subscriber::prelude::*; @@ -16,34 +14,15 @@ fn expensive_work() -> &'static str { "success" } -fn init_tracer() -> Result<(), Box> { - let exporter = opentelemetry_jaeger::Exporter::builder() - .with_agent_endpoint("127.0.0.1:6831".parse().unwrap()) - .with_process(opentelemetry_jaeger::Process { - service_name: "report_example".to_string(), - tags: Vec::new(), - }) - .init()?; - let provider = sdk::Provider::builder() - .with_simple_exporter(exporter) - .with_config(sdk::Config { - default_sampler: Box::new(sdk::Sampler::AlwaysOn), - ..Default::default() - }) - .build(); - let tracer = provider.get_tracer("tracing"); - +fn main() -> Result<(), Box> { + let (tracer, _uninstall) = opentelemetry_jaeger::new_pipeline() + .with_service_name("report_example") + .install()?; let opentelemetry = tracing_opentelemetry::layer().with_tracer(tracer); tracing_subscriber::registry() .with(opentelemetry) .try_init()?; - Ok(()) -} - -fn main() -> Result<(), Box> { - init_tracer()?; - let root = span!(tracing::Level::INFO, "app_start", work_units = 2); let _enter = root.enter(); diff --git a/tracing-opentelemetry/Cargo.toml b/tracing-opentelemetry/Cargo.toml index 572f57d0..a5868e7b 100644 --- a/tracing-opentelemetry/Cargo.toml +++ b/tracing-opentelemetry/Cargo.toml @@ -22,12 +22,11 @@ edition = "2018" default = ["tracing-log"] [dependencies] -opentelemetry = { version = "0.8", default-features = false, features = ["trace"] } -rand = "0.7" +opentelemetry = { version = "0.10", default-features = false, features = ["trace"] } tracing = { path = "../tracing", version = "0.1" } tracing-core = { path = "../tracing-core", version = "0.1" } tracing-subscriber = { path = "../tracing-subscriber", version = "0.2", default-features = false, features = ["registry"] } tracing-log = { path = "../tracing-log", version = "0.1", default-features = false, optional = true } [dev-dependencies] -opentelemetry-jaeger = "0.7" +opentelemetry-jaeger = "0.9" diff --git a/tracing-opentelemetry/README.md b/tracing-opentelemetry/README.md index f804766a..6aecc166 100644 --- a/tracing-opentelemetry/README.md +++ b/tracing-opentelemetry/README.md @@ -59,22 +59,25 @@ The crate provides the following types: ### Basic Usage ```rust -use opentelemetry::{api::Provider, sdk}; +use opentelemetry::exporter::trace::stdout; use tracing::{error, span}; use tracing_subscriber::layer::SubscriberExt; use tracing_subscriber::Registry; fn main() { - // Create a new tracer - let tracer = sdk::Provider::default().get_tracer("component_name"); + // Install a new OpenTelemetry trace pipeline + let (tracer, _uninstall) = stdout::new_pipeline().install(); - // Create a new OpenTelemetry tracing layer + // Create a tracing layer with the configured tracer let telemetry = tracing_opentelemetry::layer().with_tracer(tracer); + // Use the tracing subscriber `Registry`, or any other subscriber + // that impls `LookupSpan` let subscriber = Registry::default().with(telemetry); // Trace executed code tracing::subscriber::with_default(subscriber, || { + // Spans will be sent to the configured OpenTelemetry exporter let root = span!(tracing::Level::TRACE, "app_start", work_units = 2); let _enter = root.enter(); diff --git a/tracing-opentelemetry/src/layer.rs b/tracing-opentelemetry/src/layer.rs index 85000b7b..81f32709 100644 --- a/tracing-opentelemetry/src/layer.rs +++ b/tracing-opentelemetry/src/layer.rs @@ -1,5 +1,5 @@ use crate::PreSampledTracer; -use opentelemetry::api::{self, Context as OtelContext, TraceContextExt}; +use opentelemetry::{trace as otel, trace::TraceContextExt, Context as OtelContext, Key, KeyValue}; use std::any::TypeId; use std::fmt; use std::marker; @@ -27,12 +27,12 @@ pub struct OpenTelemetryLayer { _registry: marker::PhantomData, } -impl Default for OpenTelemetryLayer +impl Default for OpenTelemetryLayer where S: Subscriber + for<'span> LookupSpan<'span>, { fn default() -> Self { - OpenTelemetryLayer::new(api::NoopTracer {}) + OpenTelemetryLayer::new(otel::NoopTracer::new()) } } @@ -51,7 +51,7 @@ where /// let subscriber = Registry::default().with(tracing_opentelemetry::layer()); /// # drop(subscriber); /// ``` -pub fn layer() -> OpenTelemetryLayer +pub fn layer() -> OpenTelemetryLayer where S: Subscriber + for<'span> LookupSpan<'span>, { @@ -67,7 +67,7 @@ pub(crate) struct WithContext( fn( &tracing::Dispatch, &span::Id, - f: &mut dyn FnMut(&mut api::SpanBuilder, &dyn PreSampledTracer), + f: &mut dyn FnMut(&mut otel::SpanBuilder, &dyn PreSampledTracer), ), ); @@ -78,34 +78,34 @@ impl WithContext { &self, dispatch: &'a tracing::Dispatch, id: &span::Id, - mut f: impl FnMut(&mut api::SpanBuilder, &dyn PreSampledTracer), + mut f: impl FnMut(&mut otel::SpanBuilder, &dyn PreSampledTracer), ) { (self.0)(dispatch, id, &mut f) } } -fn str_to_span_kind(s: &str) -> Option { +fn str_to_span_kind(s: &str) -> Option { if s.eq_ignore_ascii_case("SERVER") { - Some(api::SpanKind::Server) + Some(otel::SpanKind::Server) } else if s.eq_ignore_ascii_case("CLIENT") { - Some(api::SpanKind::Client) + Some(otel::SpanKind::Client) } else if s.eq_ignore_ascii_case("PRODUCER") { - Some(api::SpanKind::Producer) + Some(otel::SpanKind::Producer) } else if s.eq_ignore_ascii_case("CONSUMER") { - Some(api::SpanKind::Consumer) + Some(otel::SpanKind::Consumer) } else if s.eq_ignore_ascii_case("INTERNAL") { - Some(api::SpanKind::Internal) + Some(otel::SpanKind::Internal) } else { None } } -struct SpanEventVisitor<'a>(&'a mut api::Event); +struct SpanEventVisitor<'a>(&'a mut otel::Event); impl<'a> field::Visit for SpanEventVisitor<'a> { /// Record events on the underlying OpenTelemetry [`Span`] from `bool` values. /// - /// [`Span`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/span/trait.Span.html + /// [`Span`]: opentelemetry::trace::Span fn record_bool(&mut self, field: &field::Field, value: bool) { match field.name() { "message" => self.0.name = value.to_string(), @@ -113,14 +113,14 @@ impl<'a> field::Visit for SpanEventVisitor<'a> { #[cfg(feature = "tracing-log")] name if name.starts_with("log.") => (), name => { - self.0.attributes.push(api::KeyValue::new(name, value)); + self.0.attributes.push(KeyValue::new(name, value)); } } } /// Record events on the underlying OpenTelemetry [`Span`] from `i64` values. /// - /// [`Span`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/span/trait.Span.html + /// [`Span`]: opentelemetry::trace::Span fn record_i64(&mut self, field: &field::Field, value: i64) { match field.name() { "message" => self.0.name = value.to_string(), @@ -128,29 +128,14 @@ impl<'a> field::Visit for SpanEventVisitor<'a> { #[cfg(feature = "tracing-log")] name if name.starts_with("log.") => (), name => { - self.0.attributes.push(api::KeyValue::new(name, value)); - } - } - } - - /// Record events on the underlying OpenTelemetry [`Span`] from `u64` values. - /// - /// [`Span`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/span/trait.Span.html - fn record_u64(&mut self, field: &field::Field, value: u64) { - match field.name() { - "message" => self.0.name = value.to_string(), - // Skip fields that are actually log metadata that have already been handled - #[cfg(feature = "tracing-log")] - name if name.starts_with("log.") => (), - name => { - self.0.attributes.push(api::KeyValue::new(name, value)); + self.0.attributes.push(KeyValue::new(name, value)); } } } /// Record events on the underlying OpenTelemetry [`Span`] from `&str` values. /// - /// [`Span`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/span/trait.Span.html + /// [`Span`]: opentelemetry::trace::Span fn record_str(&mut self, field: &field::Field, value: &str) { match field.name() { "message" => self.0.name = value.to_string(), @@ -158,7 +143,9 @@ impl<'a> field::Visit for SpanEventVisitor<'a> { #[cfg(feature = "tracing-log")] name if name.starts_with("log.") => (), name => { - self.0.attributes.push(api::KeyValue::new(name, value)); + self.0 + .attributes + .push(KeyValue::new(name, value.to_string())); } } } @@ -166,7 +153,7 @@ impl<'a> field::Visit for SpanEventVisitor<'a> { /// Record events on the underlying OpenTelemetry [`Span`] from values that /// implement Debug. /// - /// [`Span`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/span/trait.Span.html + /// [`Span`]: opentelemetry::trace::Span fn record_debug(&mut self, field: &field::Field, value: &dyn fmt::Debug) { match field.name() { "message" => self.0.name = format!("{:?}", value), @@ -176,20 +163,20 @@ impl<'a> field::Visit for SpanEventVisitor<'a> { name => { self.0 .attributes - .push(api::KeyValue::new(name, format!("{:?}", value))); + .push(KeyValue::new(name, format!("{:?}", value))); } } } } -struct SpanAttributeVisitor<'a>(&'a mut api::SpanBuilder); +struct SpanAttributeVisitor<'a>(&'a mut otel::SpanBuilder); impl<'a> field::Visit for SpanAttributeVisitor<'a> { /// Set attributes on the underlying OpenTelemetry [`Span`] from `bool` values. /// - /// [`Span`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/span/trait.Span.html + /// [`Span`]: opentelemetry::trace::Span fn record_bool(&mut self, field: &field::Field, value: bool) { - let attribute = api::KeyValue::new(field.name(), value); + let attribute = KeyValue::new(field.name(), value); if let Some(attributes) = &mut self.0.attributes { attributes.push(attribute); } else { @@ -199,21 +186,9 @@ impl<'a> field::Visit for SpanAttributeVisitor<'a> { /// Set attributes on the underlying OpenTelemetry [`Span`] from `i64` values. /// - /// [`Span`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/span/trait.Span.html + /// [`Span`]: opentelemetry::trace::Span fn record_i64(&mut self, field: &field::Field, value: i64) { - let attribute = api::KeyValue::new(field.name(), value); - if let Some(attributes) = &mut self.0.attributes { - attributes.push(attribute); - } else { - self.0.attributes = Some(vec![attribute]); - } - } - - /// Set attributes on the underlying OpenTelemetry [`Span`] from `u64` values. - /// - /// [`Span`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/span/trait.Span.html - fn record_u64(&mut self, field: &field::Field, value: u64) { - let attribute = api::KeyValue::new(field.name(), value); + let attribute = KeyValue::new(field.name(), value); if let Some(attributes) = &mut self.0.attributes { attributes.push(attribute); } else { @@ -223,14 +198,14 @@ impl<'a> field::Visit for SpanAttributeVisitor<'a> { /// Set attributes on the underlying OpenTelemetry [`Span`] from `&str` values. /// - /// [`Span`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/span/trait.Span.html + /// [`Span`]: opentelemetry::trace::Span fn record_str(&mut self, field: &field::Field, value: &str) { if field.name() == SPAN_NAME_FIELD { self.0.name = value.to_string(); } else if field.name() == SPAN_KIND_FIELD { self.0.span_kind = str_to_span_kind(value); } else { - let attribute = api::KeyValue::new(field.name(), value); + let attribute = KeyValue::new(field.name(), value.to_string()); if let Some(attributes) = &mut self.0.attributes { attributes.push(attribute); } else { @@ -242,14 +217,14 @@ impl<'a> field::Visit for SpanAttributeVisitor<'a> { /// Set attributes on the underlying OpenTelemetry [`Span`] from values that /// implement Debug. /// - /// [`Span`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/span/trait.Span.html + /// [`Span`]: opentelemetry::trace::Span fn record_debug(&mut self, field: &field::Field, value: &dyn fmt::Debug) { if field.name() == SPAN_NAME_FIELD { self.0.name = format!("{:?}", value); } else if field.name() == SPAN_KIND_FIELD { self.0.span_kind = str_to_span_kind(&format!("{:?}", value)); } else { - let attribute = api::Key::new(field.name()).string(format!("{:?}", value)); + let attribute = Key::new(field.name()).string(format!("{:?}", value)); if let Some(attributes) = &mut self.0.attributes { attributes.push(attribute); } else { @@ -262,42 +237,25 @@ impl<'a> field::Visit for SpanAttributeVisitor<'a> { impl OpenTelemetryLayer where S: Subscriber + for<'span> LookupSpan<'span>, - T: api::Tracer + PreSampledTracer + 'static, + T: otel::Tracer + PreSampledTracer + 'static, { /// Set the [`Tracer`] that this layer will use to produce and track /// OpenTelemetry [`Span`]s. /// - /// [`Tracer`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/tracer/trait.Tracer.html - /// [`Span`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/span/trait.Span.html + /// [`Tracer`]: opentelemetry::trace::Tracer + /// [`Span`]: opentelemetry::trace::Span /// /// # Examples /// - /// ```rust,no_run - /// use opentelemetry::{api::Provider, sdk}; + /// ```no_run /// use tracing_opentelemetry::OpenTelemetryLayer; /// use tracing_subscriber::layer::SubscriberExt; /// use tracing_subscriber::Registry; /// - /// // Create a jaeger exporter for a `trace-demo` service. - /// let exporter = opentelemetry_jaeger::Exporter::builder() - /// .with_agent_endpoint("127.0.0.1:6831".parse().unwrap()) - /// .with_process(opentelemetry_jaeger::Process { - /// service_name: "trace_demo".to_string(), - /// tags: Vec::new(), - /// }) - /// .init().expect("Error initializing Jaeger exporter"); - /// - /// // Build a provider from the jaeger exporter that always samples. - /// let provider = sdk::Provider::builder() - /// .with_simple_exporter(exporter) - /// .with_config(sdk::Config { - /// default_sampler: Box::new(sdk::Sampler::AlwaysOn), - /// ..Default::default() - /// }) - /// .build(); - /// - /// // Get a tracer from the provider for a component - /// let tracer = provider.get_tracer("component-name"); + /// // Create a jaeger exporter pipeline for a `trace_demo` service. + /// let (tracer, _uninstall) = opentelemetry_jaeger::new_pipeline() + /// .with_service_name("trace_demo") + /// .install().expect("Error initializing Jaeger exporter"); /// /// // Create a layer with the configured tracer /// let otel_layer = OpenTelemetryLayer::new(tracer); @@ -318,49 +276,31 @@ where /// Set the [`Tracer`] that this layer will use to produce and track /// OpenTelemetry [`Span`]s. /// - /// [`Tracer`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/tracer/trait.Tracer.html - /// [`Span`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/span/trait.Span.html + /// [`Tracer`]: opentelemetry::trace::Tracer + /// [`Span`]: opentelemetry::trace::Span /// /// # Examples /// - /// ```rust,no_run - /// use opentelemetry::{api::Provider, sdk}; + /// ```no_run /// use tracing_subscriber::layer::SubscriberExt; /// use tracing_subscriber::Registry; /// - /// // Create a jaeger exporter for a `trace-demo` service. - /// let exporter = opentelemetry_jaeger::Exporter::builder() - /// .with_agent_endpoint("127.0.0.1:6831".parse().unwrap()) - /// .with_process(opentelemetry_jaeger::Process { - /// service_name: "trace_demo".to_string(), - /// tags: Vec::new(), - /// }) - /// .init().expect("Error initializing Jaeger exporter"); - /// - /// // Build a provider from the jaeger exporter that always samples. - /// let provider = sdk::Provider::builder() - /// .with_simple_exporter(exporter) - /// .with_config(sdk::Config { - /// default_sampler: Box::new(sdk::Sampler::AlwaysOn), - /// ..Default::default() - /// }) - /// .build(); - /// - /// // Get a tracer from the provider for a component - /// let tracer = provider.get_tracer("component-name"); + /// // Create a jaeger exporter pipeline for a `trace_demo` service. + /// let (tracer, _uninstall) = opentelemetry_jaeger::new_pipeline() + /// .with_service_name("trace_demo") + /// .install().expect("Error initializing Jaeger exporter"); /// /// // Create a layer with the configured tracer /// let otel_layer = tracing_opentelemetry::layer().with_tracer(tracer); /// /// // Use the tracing subscriber `Registry`, or any other subscriber /// // that impls `LookupSpan` - /// let subscriber = Registry::default() - /// .with(otel_layer); + /// let subscriber = Registry::default().with(otel_layer); /// # drop(subscriber); /// ``` pub fn with_tracer(self, tracer: Tracer) -> OpenTelemetryLayer where - Tracer: api::Tracer + PreSampledTracer + 'static, + Tracer: otel::Tracer + PreSampledTracer + 'static, { OpenTelemetryLayer { tracer, @@ -373,27 +313,27 @@ where /// tracing [`span`] through the [`Registry`]. This [`SpanContext`] /// links spans to their parent for proper hierarchical visualization. /// - /// [`SpanContext`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/span_context/struct.SpanContext.html - /// [`span`]: https://docs.rs/tracing/latest/tracing/struct.Span.html - /// [`Registry`]: https://docs.rs/tracing-subscriber/latest/tracing_subscriber/struct.Registry.html + /// [`SpanContext`]: opentelemetry::trace::SpanContext + /// [`span`]: tracing::Span + /// [`Registry`]: tracing_subscriber::Registry fn parent_span_context( &self, attrs: &Attributes<'_>, ctx: &Context<'_, S>, - ) -> Option { + ) -> Option { // If a span is specified, it _should_ exist in the underlying `Registry`. if let Some(parent) = attrs.parent() { let span = ctx.span(parent).expect("Span not found, this is a bug"); let mut extensions = span.extensions_mut(); extensions - .get_mut::() + .get_mut::() .map(|builder| self.tracer.sampled_span_context(builder)) // Else if the span is inferred from context, look up any available current span. } else if attrs.is_contextual() { ctx.lookup_current().and_then(|span| { let mut extensions = span.extensions_mut(); extensions - .get_mut::() + .get_mut::() .map(|builder| self.tracer.sampled_span_context(builder)) }) // Explicit root spans should have no parent context. @@ -405,7 +345,7 @@ where fn get_context( dispatch: &tracing::Dispatch, id: &span::Id, - f: &mut dyn FnMut(&mut api::SpanBuilder, &dyn PreSampledTracer), + f: &mut dyn FnMut(&mut otel::SpanBuilder, &dyn PreSampledTracer), ) { let subscriber = dispatch .downcast_ref::() @@ -418,7 +358,7 @@ where .expect("layer should downcast to expected type; this is a bug!"); let mut extensions = span.extensions_mut(); - if let Some(builder) = extensions.get_mut::() { + if let Some(builder) = extensions.get_mut::() { f(builder, &layer.tracer); } } @@ -427,12 +367,12 @@ where impl Layer for OpenTelemetryLayer where S: Subscriber + for<'span> LookupSpan<'span>, - T: api::Tracer + PreSampledTracer + 'static, + T: otel::Tracer + PreSampledTracer + 'static, { /// Creates an [OpenTelemetry `Span`] for the corresponding [tracing `Span`]. /// - /// [OpenTelemetry `Span`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/span/trait.Span.html - /// [tracing `Span`]: https://docs.rs/tracing/latest/tracing/struct.Span.html + /// [OpenTelemetry `Span`]: opentelemetry::trace::Span + /// [tracing `Span`]: tracing::Span fn new_span(&self, attrs: &Attributes<'_>, id: &span::Id, ctx: Context<'_, S>) { let span = ctx.span(id).expect("Span not found, this is a bug"); let mut extensions = span.extensions_mut(); @@ -449,7 +389,8 @@ where // Ensure trace id exists so children are matched properly. if builder.parent_context.is_none() { - let existing_otel_span_context = OtelContext::current().span().span_context(); + let cx = OtelContext::current(); + let existing_otel_span_context = cx.span().span_context(); if existing_otel_span_context.is_valid() { builder.trace_id = Some(existing_otel_span_context.trace_id()); } else { @@ -463,11 +404,11 @@ where /// Record OpenTelemetry [`attributes`] for the given values. /// - /// [`attributes`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/tracer/struct.SpanBuilder.html#structfield.attributes + /// [`attributes`]: opentelemetry::trace::SpanBuilder::attributes fn on_record(&self, id: &Id, values: &Record<'_>, ctx: Context<'_, S>) { let span = ctx.span(id).expect("Span not found, this is a bug"); let mut extensions = span.extensions_mut(); - if let Some(builder) = extensions.get_mut::() { + if let Some(builder) = extensions.get_mut::() { values.record(&mut SpanAttributeVisitor(builder)); } } @@ -476,7 +417,7 @@ where let span = ctx.span(id).expect("Span not found, this is a bug"); let mut extensions = span.extensions_mut(); let builder = extensions - .get_mut::() + .get_mut::() .expect("Missing SpanBuilder span extensions"); let follows_span = ctx @@ -484,11 +425,11 @@ where .expect("Span to follow not found, this is a bug"); let mut follows_extensions = follows_span.extensions_mut(); let follows_builder = follows_extensions - .get_mut::() + .get_mut::() .expect("Missing SpanBuilder span extensions"); let follows_context = self.tracer.sampled_span_context(follows_builder); - let follows_link = api::Link::new(follows_context, Vec::new()); + let follows_link = otel::Link::new(follows_context, Vec::new()); if let Some(ref mut links) = builder.links { links.push(follows_link); } else { @@ -499,11 +440,11 @@ where /// Records OpenTelemetry [`Event`] data on event. /// /// Note: an [`ERROR`]-level event will also set the OpenTelemetry span status code to - /// [`Unknown`], signaling that an error has occurred. + /// [`Error`], signaling that an error has occurred. /// - /// [`Event`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/event/struct.Event.html - /// [`ERROR`]: https://docs.rs/tracing/latest/tracing/struct.Level.html#associatedconstant.ERROR - /// [`Unknown`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/span/enum.StatusCode.html#variant.Unknown + /// [`Event`]: opentelemetry::trace::Event + /// [`ERROR`]: tracing::Level::ERROR + /// [`Error`]: opentelemetry::trace::StatusCode::Error fn on_event(&self, event: &Event<'_>, ctx: Context<'_, S>) { // Ignore events that are not in the context of a span if let Some(span) = ctx.lookup_current() { @@ -515,20 +456,20 @@ where let meta = normalized_meta.as_ref().unwrap_or_else(|| event.metadata()); #[cfg(not(feature = "tracing-log"))] let meta = event.metadata(); - let mut otel_event = api::Event::new( + let mut otel_event = otel::Event::new( String::new(), SystemTime::now(), vec![ - api::Key::new("level").string(meta.level().to_string()), - api::Key::new("target").string(meta.target()), + Key::new("level").string(meta.level().to_string()), + Key::new("target").string(meta.target().to_string()), ], ); event.record(&mut SpanEventVisitor(&mut otel_event)); let mut extensions = span.extensions_mut(); - if let Some(builder) = extensions.get_mut::() { + if let Some(builder) = extensions.get_mut::() { if builder.status_code.is_none() && *meta.level() == tracing_core::Level::ERROR { - builder.status_code = Some(api::StatusCode::Unknown); + builder.status_code = Some(otel::StatusCode::Error); } if let Some(ref mut events) = builder.message_events { @@ -542,11 +483,11 @@ where /// Exports an OpenTelemetry [`Span`] on close. /// - /// [`Span`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/span/trait.Span.html + /// [`Span`]: opentelemetry::trace::Span fn on_close(&self, id: span::Id, ctx: Context<'_, S>) { let span = ctx.span(&id).expect("Span not found, this is a bug"); let mut extensions = span.extensions_mut(); - if let Some(builder) = extensions.remove::() { + if let Some(builder) = extensions.remove::() { // Assign end time, build and start span, drop span to export builder.with_end_time(SystemTime::now()).start(&self.tracer); } @@ -568,57 +509,55 @@ where #[cfg(test)] mod tests { use super::*; - use opentelemetry::api; - use opentelemetry::api::TraceContextExt; use std::sync::{Arc, Mutex}; use std::time::SystemTime; use tracing_subscriber::prelude::*; #[derive(Debug, Clone)] - struct TestTracer(Arc>>); - impl api::Tracer for TestTracer { - type Span = api::NoopSpan; + struct TestTracer(Arc>>); + impl otel::Tracer for TestTracer { + type Span = otel::NoopSpan; fn invalid(&self) -> Self::Span { - api::NoopSpan::new() + otel::NoopSpan::new() } - fn start_from_context(&self, _name: &str, _context: &api::Context) -> Self::Span { + fn start_from_context(&self, _name: &str, _context: &OtelContext) -> Self::Span { self.invalid() } - fn span_builder(&self, name: &str) -> api::SpanBuilder { - api::SpanBuilder::from_name(name.to_string()) + fn span_builder(&self, name: &str) -> otel::SpanBuilder { + otel::SpanBuilder::from_name(name.to_string()) } - fn build_with_context(&self, builder: api::SpanBuilder, _cx: &api::Context) -> Self::Span { + fn build_with_context(&self, builder: otel::SpanBuilder, _cx: &OtelContext) -> Self::Span { *self.0.lock().unwrap() = Some(builder); self.invalid() } } impl PreSampledTracer for TestTracer { - fn sampled_span_context(&self, _builder: &mut api::SpanBuilder) -> api::SpanContext { - api::SpanContext::empty_context() + fn sampled_span_context(&self, _builder: &mut otel::SpanBuilder) -> otel::SpanContext { + otel::SpanContext::empty_context() } - fn new_trace_id(&self) -> api::TraceId { - api::TraceId::invalid() + fn new_trace_id(&self) -> otel::TraceId { + otel::TraceId::invalid() } - fn new_span_id(&self) -> api::SpanId { - api::SpanId::invalid() + fn new_span_id(&self) -> otel::SpanId { + otel::SpanId::invalid() } } #[derive(Debug, Clone)] - struct TestSpan(api::SpanContext); - impl api::Span for TestSpan { - fn add_event_with_timestamp(&self, _: String, _: SystemTime, _: Vec) {} - fn span_context(&self) -> api::SpanContext { - self.0.clone() + struct TestSpan(otel::SpanContext); + impl otel::Span for TestSpan { + fn add_event_with_timestamp(&self, _: String, _: SystemTime, _: Vec) {} + fn span_context(&self) -> &otel::SpanContext { + &self.0 } fn is_recording(&self) -> bool { false } - fn set_attribute(&self, _attribute: api::KeyValue) {} - fn set_status(&self, _code: api::StatusCode, _message: String) {} + fn set_attribute(&self, _attribute: KeyValue) {} + fn set_status(&self, _code: otel::StatusCode, _message: String) {} fn update_name(&self, _new_name: String) {} - fn end(&self) {} + fn end_with_timestamp(&self, _timestamp: SystemTime) {} } #[test] @@ -645,19 +584,20 @@ mod tests { }); let recorded_kind = tracer.0.lock().unwrap().as_ref().unwrap().span_kind.clone(); - assert_eq!(recorded_kind, Some(api::SpanKind::Server)) + assert_eq!(recorded_kind, Some(otel::SpanKind::Server)) } #[test] fn trace_id_from_existing_context() { let tracer = TestTracer(Arc::new(Mutex::new(None))); let subscriber = tracing_subscriber::registry().with(layer().with_tracer(tracer.clone())); - let trace_id = api::TraceId::from_u128(42); - let existing_cx = api::Context::current_with_span(TestSpan(api::SpanContext::new( + let trace_id = otel::TraceId::from_u128(42); + let existing_cx = OtelContext::current_with_span(TestSpan(otel::SpanContext::new( trace_id, - api::SpanId::from_u64(1), + otel::SpanId::from_u64(1), 0, false, + Default::default(), ))); let _g = existing_cx.attach(); diff --git a/tracing-opentelemetry/src/lib.rs b/tracing-opentelemetry/src/lib.rs index 0c7d74ba..efa25736 100644 --- a/tracing-opentelemetry/src/lib.rs +++ b/tracing-opentelemetry/src/lib.rs @@ -43,25 +43,27 @@ //! ### Stability Status //! //! The OpenTelemetry specification is currently in beta so some breaking -//! may still occur on the path to 1.0. You can follow the changes via the -//! [spec repository] to track progress toward stabilization. +//! changes may still occur on the path to 1.0. You can follow the changes via +//! the [spec repository] to track progress toward stabilization. //! //! [spec repository]: https://github.com/open-telemetry/opentelemetry-specification //! //! ## Examples //! //! ``` -//! use opentelemetry::{api::Provider, sdk}; +//! use opentelemetry::exporter::trace::stdout; //! use tracing::{error, span}; //! use tracing_subscriber::layer::SubscriberExt; //! use tracing_subscriber::Registry; //! -//! // Create a new tracer -//! let tracer = sdk::Provider::default().get_tracer("service_name"); +//! // Create a new OpenTelemetry pipeline +//! let (tracer, _uninstall) = stdout::new_pipeline().install(); //! -//! // Create a new OpenTelemetry tracing layer +//! // Create a tracing layer with the configured tracer //! let telemetry = tracing_opentelemetry::layer().with_tracer(tracer); //! +//! // Use the tracing subscriber `Registry`, or any other subscriber +//! // that impls `LookupSpan` //! let subscriber = Registry::default().with(telemetry); //! //! // Trace executed code diff --git a/tracing-opentelemetry/src/span_ext.rs b/tracing-opentelemetry/src/span_ext.rs index c0da7aef..031bb30b 100644 --- a/tracing-opentelemetry/src/span_ext.rs +++ b/tracing-opentelemetry/src/span_ext.rs @@ -1,32 +1,33 @@ use crate::layer::WithContext; -use opentelemetry::api; -use opentelemetry::api::TraceContextExt; +use opentelemetry::{trace as otel, trace::TraceContextExt, Context, KeyValue}; +use std::time::SystemTime; /// Utility functions to allow tracing [`Span`]s to accept and return /// [OpenTelemetry] [`Context`]s. /// /// [`Span`]: https://docs.rs/tracing/latest/tracing/struct.Span.html /// [OpenTelemetry]: https://opentelemetry.io -/// [`Context`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/context/struct.Context.html +/// [`Context`]: opentelemetry::Context pub trait OpenTelemetrySpanExt { /// Associates `self` with a given OpenTelemetry trace, using the provided /// parent [`Context`]. /// - /// [`Context`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/context/struct.Context.html + /// [`Context`]: opentelemetry::Context /// /// # Examples /// /// ```rust - /// use opentelemetry::api::{self, HttpTextFormat, TraceContextExt}; + /// use opentelemetry::{propagation::TextMapPropagator, trace::TraceContextExt}; + /// use opentelemetry::sdk::propagation::B3Propagator; /// use tracing_opentelemetry::OpenTelemetrySpanExt; /// use std::collections::HashMap; /// use tracing::Span; /// - /// // Example carrier, could be a framework header map that impls `api::Carrier`. + /// // Example carrier, could be a framework header map that impls otel's `Extract`. /// let mut carrier = HashMap::new(); /// - /// // Propagator can be swapped with trace context propagator binary propagator, etc. - /// let propagator = api::B3Propagator::new(); + /// // Propagator can be swapped with trace context propagator, binary propagator, etc. + /// let propagator = B3Propagator::new(); /// /// // Extract otel parent context via the chosen propagator /// let parent_context = propagator.extract(&carrier); @@ -40,22 +41,22 @@ pub trait OpenTelemetrySpanExt { /// // Or if the current span has been created elsewhere: /// Span::current().set_parent(&parent_context); /// ``` - fn set_parent(&self, span_context: &api::Context); + fn set_parent(&self, cx: &Context); /// Extracts an OpenTelemetry [`Context`] from `self`. /// - /// [`Context`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/context/struct.Context.html + /// [`Context`]: opentelemetry::Context /// /// # Examples /// /// ```rust - /// use opentelemetry::api; + /// use opentelemetry::Context; /// use tracing_opentelemetry::OpenTelemetrySpanExt; /// use tracing::Span; /// - /// fn make_request(cx: api::Context) { + /// fn make_request(cx: Context) { /// // perform external request after injecting context - /// // e.g. if there are request headers that impl `opentelemetry::api::Carrier` + /// // e.g. if the request's headers impl `opentelemetry::propagation::Injector` /// // then `propagator.inject_context(cx, request.headers_mut())` /// } /// @@ -69,21 +70,21 @@ pub trait OpenTelemetrySpanExt { /// // Or if the current span has been created elsewhere: /// make_request(Span::current().context()) /// ``` - fn context(&self) -> api::Context; + fn context(&self) -> Context; } impl OpenTelemetrySpanExt for tracing::Span { - fn set_parent(&self, parent_context: &api::Context) { + fn set_parent(&self, cx: &Context) { self.with_subscriber(move |(id, subscriber)| { if let Some(get_context) = subscriber.downcast_ref::() { get_context.with_context(subscriber, id, move |builder, _tracer| { - builder.parent_context = parent_context.remote_span_context().cloned() + builder.parent_context = cx.remote_span_context().cloned() }); } }); } - fn context(&self) -> api::Context { + fn context(&self) -> Context { let mut span_context = None; self.with_subscriber(|(id, subscriber)| { if let Some(get_context) = subscriber.downcast_ref::() { @@ -93,20 +94,21 @@ impl OpenTelemetrySpanExt for tracing::Span { } }); - let compat_span = CompatSpan(span_context.unwrap_or_else(api::SpanContext::empty_context)); - api::Context::current_with_span(compat_span) + let span_context = span_context.unwrap_or_else(otel::SpanContext::empty_context); + let compat_span = CompatSpan(span_context); + Context::current_with_span(compat_span) } } /// A compatibility wrapper for an injectable OpenTelemetry span context. #[derive(Debug)] -struct CompatSpan(api::SpanContext); -impl api::Span for CompatSpan { +struct CompatSpan(otel::SpanContext); +impl otel::Span for CompatSpan { fn add_event_with_timestamp( &self, _name: String, _timestamp: std::time::SystemTime, - _attributes: Vec, + _attributes: Vec, ) { #[cfg(debug_assertions)] panic!( @@ -115,11 +117,11 @@ impl api::Span for CompatSpan { } /// This method is used by OpenTelemetry propagators to inject span context - /// information into [`Carrier`]s. + /// information into [`Injector`]s. /// - /// [`Carrier`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/context/propagation/trait.Carrier.html - fn span_context(&self) -> api::SpanContext { - self.0.clone() + /// [`Injector`]: opentelemetry::propagation::Injector + fn span_context(&self) -> &otel::SpanContext { + &self.0 } fn is_recording(&self) -> bool { @@ -130,12 +132,12 @@ impl api::Span for CompatSpan { false } - fn set_attribute(&self, _attribute: api::KeyValue) { + fn set_attribute(&self, _attribute: KeyValue) { #[cfg(debug_assertions)] panic!("OpenTelemetry and tracing APIs cannot be mixed, use `tracing::span!` macro or `span.record()` instead."); } - fn set_status(&self, _code: api::StatusCode, _message: String) { + fn set_status(&self, _code: otel::StatusCode, _message: String) { #[cfg(debug_assertions)] panic!("OpenTelemetry and tracing APIs cannot be mixed, use `tracing::span!` macro or `span.record()` instead."); } @@ -145,7 +147,7 @@ impl api::Span for CompatSpan { panic!("OpenTelemetry and tracing APIs cannot be mixed, span names are not mutable."); } - fn end(&self) { + fn end_with_timestamp(&self, _timestamp: SystemTime) { #[cfg(debug_assertions)] panic!("OpenTelemetry and tracing APIs cannot be mixed, span end times are set when the underlying tracing span closes."); } diff --git a/tracing-opentelemetry/src/tracer.rs b/tracing-opentelemetry/src/tracer.rs index 7921df8f..dacf748d 100644 --- a/tracing-opentelemetry/src/tracer.rs +++ b/tracing-opentelemetry/src/tracer.rs @@ -1,4 +1,5 @@ -use opentelemetry::{api, sdk}; +use opentelemetry::sdk::trace::{SamplingDecision, Tracer}; +use opentelemetry::trace as otel; /// An interface for authors of OpenTelemetry SDKs to build pre-sampled tracers. /// @@ -20,67 +21,71 @@ use opentelemetry::{api, sdk}; /// See the [`OpenTelemetrySpanExt::set_parent`] and /// [`OpenTelemetrySpanExt::context`] methods for example usage. /// -/// [`Tracer`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/tracer/trait.Tracer.html -/// [`SpanBuilder`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/tracer/struct.SpanBuilder.html -/// [`SpanContext`]: https://docs.rs/opentelemetry/latest/opentelemetry/api/trace/span_context/struct.SpanContext.html -/// [`PreSampledTracer::sampled_span_context`]: trait.PreSampledTracer.html#tymethod.sampled_span_context -/// [`OpenTelemetrySpanExt::set_parent`]: trait.OpenTelemetrySpanExt.html#tymethod.set_parent -/// [`OpenTelemetrySpanExt::context`]: trait.OpenTelemetrySpanExt.html#tymethod.context +/// [`Tracer`]: opentelemetry::trace::Tracer +/// [`SpanBuilder`]: opentelemetry::trace::SpanBuilder +/// [`SpanContext`]: opentelemetry::trace::SpanContext +/// [`PreSampledTracer::sampled_span_context`]: crate::PreSampledTracer::sampled_span_context +/// [`OpenTelemetrySpanExt::set_parent`]: crate::OpenTelemetrySpanExt::set_parent +/// [`OpenTelemetrySpanExt::context`]: crate::OpenTelemetrySpanExt::context pub trait PreSampledTracer { /// Produce a pre-sampled span context for the given span builder. - fn sampled_span_context(&self, builder: &mut api::SpanBuilder) -> api::SpanContext; + fn sampled_span_context(&self, builder: &mut otel::SpanBuilder) -> otel::SpanContext; /// Generate a new trace id. - fn new_trace_id(&self) -> api::TraceId; + fn new_trace_id(&self) -> otel::TraceId; /// Generate a new span id. - fn new_span_id(&self) -> api::SpanId; + fn new_span_id(&self) -> otel::SpanId; } -impl PreSampledTracer for api::NoopTracer { - fn sampled_span_context(&self, builder: &mut api::SpanBuilder) -> api::SpanContext { +impl PreSampledTracer for otel::NoopTracer { + fn sampled_span_context(&self, builder: &mut otel::SpanBuilder) -> otel::SpanContext { builder .parent_context .clone() - .unwrap_or_else(api::SpanContext::empty_context) + .unwrap_or_else(otel::SpanContext::empty_context) } - fn new_trace_id(&self) -> api::TraceId { - api::TraceId::invalid() + fn new_trace_id(&self) -> otel::TraceId { + otel::TraceId::invalid() } - fn new_span_id(&self) -> api::SpanId { - api::SpanId::invalid() + fn new_span_id(&self) -> otel::SpanId { + otel::SpanId::invalid() } } -impl PreSampledTracer for sdk::Tracer { - fn sampled_span_context(&self, builder: &mut api::SpanBuilder) -> api::SpanContext { - let span_id = builder - .span_id - .unwrap_or_else(|| self.provider().config().id_generator.new_span_id()); +impl PreSampledTracer for Tracer { + fn sampled_span_context(&self, builder: &mut otel::SpanBuilder) -> otel::SpanContext { + let span_id = builder.span_id.unwrap_or_else(|| { + self.provider() + .map(|provider| provider.config().id_generator.new_span_id()) + .unwrap_or_else(otel::SpanId::invalid) + }); let (trace_id, trace_flags) = builder .parent_context .as_ref() .filter(|parent_context| parent_context.is_valid()) .map(|parent_context| (parent_context.trace_id(), parent_context.trace_flags())) .unwrap_or_else(|| { - let trace_id = builder - .trace_id - .unwrap_or_else(|| self.provider().config().id_generator.new_trace_id()); + let trace_id = builder.trace_id.unwrap_or_else(|| { + self.provider() + .map(|provider| provider.config().id_generator.new_trace_id()) + .unwrap_or_else(otel::TraceId::invalid) + }); // ensure sampling decision is recorded so all span contexts have consistent flags let sampling_decision = if let Some(result) = builder.sampling_result.as_ref() { result.decision.clone() - } else { - let mut result = self.provider().config().default_sampler.should_sample( + } else if let Some(provider) = self.provider().as_ref() { + let mut result = provider.config().default_sampler.should_sample( builder.parent_context.as_ref(), trace_id, &builder.name, builder .span_kind .as_ref() - .unwrap_or(&api::SpanKind::Internal), + .unwrap_or(&otel::SpanKind::Internal), builder.attributes.as_ref().unwrap_or(&Vec::new()), builder.links.as_ref().unwrap_or(&Vec::new()), ); @@ -93,10 +98,12 @@ impl PreSampledTracer for sdk::Tracer { } result.decision + } else { + SamplingDecision::Drop }; - let trace_flags = if sampling_decision == sdk::SamplingDecision::RecordAndSampled { - api::TRACE_FLAG_SAMPLED + let trace_flags = if sampling_decision == SamplingDecision::RecordAndSample { + otel::TRACE_FLAG_SAMPLED } else { 0 }; @@ -104,27 +111,32 @@ impl PreSampledTracer for sdk::Tracer { (trace_id, trace_flags) }); - api::SpanContext::new(trace_id, span_id, trace_flags, false) + otel::SpanContext::new(trace_id, span_id, trace_flags, false, Default::default()) } - fn new_trace_id(&self) -> api::TraceId { - self.provider().config().id_generator.new_trace_id() + fn new_trace_id(&self) -> otel::TraceId { + self.provider() + .map(|provider| provider.config().id_generator.new_trace_id()) + .unwrap_or_else(otel::TraceId::invalid) } - fn new_span_id(&self) -> api::SpanId { - self.provider().config().id_generator.new_span_id() + fn new_span_id(&self) -> otel::SpanId { + self.provider() + .map(|provider| provider.config().id_generator.new_span_id()) + .unwrap_or_else(otel::SpanId::invalid) } } #[cfg(test)] mod tests { use super::*; - use opentelemetry::api::{Provider, SpanBuilder}; use opentelemetry::sdk; + use opentelemetry::trace::{SpanBuilder, TracerProvider}; #[test] fn assigns_default_ids_if_missing() { - let tracer = sdk::Provider::default().get_tracer("test"); + let provider = sdk::trace::TracerProvider::default(); + let tracer = provider.get_tracer("test", None); let mut builder = SpanBuilder::from_name("empty".to_string()); builder.trace_id = None; builder.span_id = None;