From 2367e71ff40acde3cac06d39d3780d1ca4983abf Mon Sep 17 00:00:00 2001 From: Brian Rogers Date: Sat, 3 Jul 2021 09:33:59 -0700 Subject: [PATCH] Support updated OT 0.14 / tracing-OT 0.13 crate versions (#23) * Support updated OT 0.14 / tracing-OT 0.12 crate versions Add support for opentelemetry 0.14 and tracing-opentelemetry 0.13. Make corresponding changes to the features, docs, and examples. Due to the use of two different versions of the same packages, some reorganization had to be done for the internal modules. Addresses issue #22. * Re-export versioned set_otel_parent `fn`s for use in macro --- Cargo.toml | 9 +++++--- README.md | 11 +++++----- examples/opentelemetry/Cargo.toml | 8 +++---- src/lib.rs | 16 ++++++++------ src/otel.rs | 21 ------------------ src/otel_0_13.rs | 36 +++++++++++++++++++++++++++++++ src/otel_0_14.rs | 36 +++++++++++++++++++++++++++++++ src/root_span_macro.rs | 31 +++++++++++--------------- 8 files changed, 109 insertions(+), 59 deletions(-) delete mode 100644 src/otel.rs create mode 100644 src/otel_0_13.rs create mode 100644 src/otel_0_14.rs diff --git a/Cargo.toml b/Cargo.toml index 4ee8b3573..65d1bd5e4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,8 @@ categories = ["asynchronous", "web-programming"] [features] default = ["opentelemetry_0_13", "emit_event_on_error"] -opentelemetry_0_13 = ["opentelemetry", "tracing-opentelemetry"] +opentelemetry_0_13 = ["opentelemetry_0_13_pkg", "tracing-opentelemetry_0_12_pkg"] +opentelemetry_0_14 = ["opentelemetry_0_14_pkg", "tracing-opentelemetry_0_13_pkg"] emit_event_on_error = [] [dependencies] @@ -31,8 +32,10 @@ tracing = "0.1.19" tracing-futures = "0.2.4" futures = "0.3.5" uuid = { version = "0.8.1", features = ["v4"] } -opentelemetry = { version = "0.13", optional = true } -tracing-opentelemetry = { version = "0.12", optional = true } +opentelemetry_0_13_pkg = { package = "opentelemetry", version = "0.13", optional = true } +opentelemetry_0_14_pkg = { package = "opentelemetry", version = "0.14", optional = true } +tracing-opentelemetry_0_12_pkg = { package = "tracing-opentelemetry",version = "0.12", optional = true } +tracing-opentelemetry_0_13_pkg = { package = "tracing-opentelemetry", version = "0.13", optional = true } [dev-dependencies] tracing-subscriber = { version = "0.2.12", features = ["registry", "env-filter"] } diff --git a/README.md b/README.md index be53f1913..ea780cc9d 100644 --- a/README.md +++ b/README.md @@ -40,12 +40,11 @@ tracing = "0.1" actix-web = "4.0.0-beta.7" ``` -`tracing-actix-web` exposes two feature flags: +`tracing-actix-web` exposes three feature flags: -- `opentelemetry_0_13`: attach [OpenTelemetry](https://github.com/open-telemetry/opentelemetry-rust)'s context to the root span; -- `emit_event_on_error`: emit a [`tracing`] event when request processing fails with an error. - -They are both enabled by default. +- `opentelemetry_0_13`: attach [OpenTelemetry](https://github.com/open-telemetry/opentelemetry-rust)'s context to the root span using OTEL 0.13 (enabled by default). +- `opentelemetry_0_14`: same as above but using OTEL 0.14. +- `emit_event_on_error`: emit a [`tracing`] event when request processing fails with an error (enabled by default). `tracing-actix-web` will release `0.4.0`, going out of beta, as soon as `actix-web` releases a stable `4.0.0`. @@ -242,7 +241,7 @@ async fn index(request_id: RequestId) -> String { `tracing-actix-web` follows [OpenTelemetry's semantic convention](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/overview.md#spancontext) for field names. -Furthermore, if you have not disabled the `opentelemetry_0_13` feature flag, `tracing-actix-web` automatically +Furthermore, if you have not disabled the `opentelemetry_0_13` or `opentelemetry_0_14` feature flags, `tracing-actix-web` automatically performs trace propagation according to the OpenTelemetry standard. It tries to extract the OpenTelemetry context out of the headers of incoming requests and, when it finds one, it sets it as the remote context for the current root span. diff --git a/examples/opentelemetry/Cargo.toml b/examples/opentelemetry/Cargo.toml index 8ac0b3cca..c7ad9f97c 100644 --- a/examples/opentelemetry/Cargo.toml +++ b/examples/opentelemetry/Cargo.toml @@ -9,9 +9,9 @@ license = "MIT/Apache-2.0" [dependencies] actix-web = "=4.0.0-beta.7" tracing = "0.1.19" -opentelemetry = { version = "0.13", features = ["rt-tokio-current-thread"] } -opentelemetry-jaeger = { version = "0.12", features = ["tokio"] } -tracing-opentelemetry = { version = "0.12" } +opentelemetry = { version = "0.14", features = ["rt-tokio-current-thread"] } +opentelemetry-jaeger = { version = "0.13", features = ["tokio"] } +tracing-opentelemetry = { version = "0.13" } tracing-subscriber = { version = "0.2.12", features = ["registry", "env-filter"] } tracing-bunyan-formatter = "0.1.6" -tracing-actix-web = { path = "../.." } +tracing-actix-web = { path = "../..", features = ["opentelemetry_0_14"] } diff --git a/src/lib.rs b/src/lib.rs index fa8d572f5..15e552a38 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,12 +13,11 @@ //! actix-web = "4.0.0-beta.7" //! ``` //! -//! `tracing-actix-web` exposes two feature flags: +//! `tracing-actix-web` exposes three feature flags: //! -//! - `opentelemetry_0_13`: attach [OpenTelemetry](https://github.com/open-telemetry/opentelemetry-rust)'s context to the root span; -//! - `emit_event_on_error`: emit a [`tracing`] event when request processing fails with an error. -//! -//! They are both enabled by default. +//! - `opentelemetry_0_13`: attach [OpenTelemetry](https://github.com/open-telemetry/opentelemetry-rust)'s context to the root span using OTEL 0.13 (enabled by default). +//! - `opentelemetry_0_14`: same as above but using OTEL 0.14. +//! - `emit_event_on_error`: emit a [`tracing`] event when request processing fails with an error (enabled by default). //! //! `tracing-actix-web` will release `0.4.0`, going out of beta, as soon as `actix-web` releases a stable `4.0.0`. //! @@ -215,7 +214,7 @@ //! //! `tracing-actix-web` follows [OpenTelemetry's semantic convention](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/overview.md#spancontext) //! for field names. -//! Furthermore, if you have not disabled the `opentelemetry_0_13` feature flag, `tracing-actix-web` automatically +//! Furthermore, if you have not disabled the `opentelemetry_0_13` or `opentelemetry_0_14` feature flags, `tracing-actix-web` automatically //! performs trace propagation according to the OpenTelemetry standard. //! It tries to extract the OpenTelemetry context out of the headers of incoming requests and, when it finds one, it sets //! it as the remote context for the current root span. @@ -245,4 +244,7 @@ pub use root_span_builder::{DefaultRootSpanBuilder, RootSpanBuilder}; pub mod root_span_macro; #[cfg(feature = "opentelemetry_0_13")] -mod otel; +mod otel_0_13; + +#[cfg(feature = "opentelemetry_0_14")] +mod otel_0_14; diff --git a/src/otel.rs b/src/otel.rs deleted file mode 100644 index 8c9a67142..000000000 --- a/src/otel.rs +++ /dev/null @@ -1,21 +0,0 @@ -use opentelemetry::propagation::Extractor; - -pub(crate) struct RequestHeaderCarrier<'a> { - headers: &'a actix_web::http::HeaderMap, -} - -impl<'a> RequestHeaderCarrier<'a> { - pub(crate) fn new(headers: &'a actix_web::http::HeaderMap) -> Self { - RequestHeaderCarrier { headers } - } -} - -impl<'a> Extractor for RequestHeaderCarrier<'a> { - fn get(&self, key: &str) -> Option<&str> { - self.headers.get(key).and_then(|v| v.to_str().ok()) - } - - fn keys(&self) -> Vec<&str> { - self.headers.keys().map(|header| header.as_str()).collect() - } -} diff --git a/src/otel_0_13.rs b/src/otel_0_13.rs new file mode 100644 index 000000000..37fbf03c8 --- /dev/null +++ b/src/otel_0_13.rs @@ -0,0 +1,36 @@ +use actix_web::dev::ServiceRequest; +use opentelemetry_0_13_pkg::propagation::Extractor; + +pub(crate) struct RequestHeaderCarrier<'a> { + headers: &'a actix_web::http::HeaderMap, +} + +impl<'a> RequestHeaderCarrier<'a> { + pub(crate) fn new(headers: &'a actix_web::http::HeaderMap) -> Self { + RequestHeaderCarrier { headers } + } +} + +impl<'a> Extractor for RequestHeaderCarrier<'a> { + fn get(&self, key: &str) -> Option<&str> { + self.headers.get(key).and_then(|v| v.to_str().ok()) + } + + fn keys(&self) -> Vec<&str> { + self.headers.keys().map(|header| header.as_str()).collect() + } +} + +pub(crate) fn set_otel_parent(req: &ServiceRequest, span: &tracing::Span) { + use opentelemetry_0_13_pkg::trace::TraceContextExt as _; + use tracing_opentelemetry_0_12_pkg::OpenTelemetrySpanExt as _; + + let parent_context = opentelemetry_0_13_pkg::global::get_text_map_propagator(|propagator| { + propagator.extract(&crate::otel_0_13::RequestHeaderCarrier::new(req.headers())) + }); + span.set_parent(parent_context); + // If we have a remote parent span, this will be the parent's trace identifier. + // If not, it will be the newly generated trace identifier with this request as root span. + let trace_id = span.context().span().span_context().trace_id().to_hex(); + span.record("trace_id", &tracing::field::display(trace_id)); +} diff --git a/src/otel_0_14.rs b/src/otel_0_14.rs new file mode 100644 index 000000000..40698c912 --- /dev/null +++ b/src/otel_0_14.rs @@ -0,0 +1,36 @@ +use actix_web::dev::ServiceRequest; +use opentelemetry_0_14_pkg::propagation::Extractor; + +pub(crate) struct RequestHeaderCarrier<'a> { + headers: &'a actix_web::http::HeaderMap, +} + +impl<'a> RequestHeaderCarrier<'a> { + pub(crate) fn new(headers: &'a actix_web::http::HeaderMap) -> Self { + RequestHeaderCarrier { headers } + } +} + +impl<'a> Extractor for RequestHeaderCarrier<'a> { + fn get(&self, key: &str) -> Option<&str> { + self.headers.get(key).and_then(|v| v.to_str().ok()) + } + + fn keys(&self) -> Vec<&str> { + self.headers.keys().map(|header| header.as_str()).collect() + } +} + +pub(crate) fn set_otel_parent(req: &ServiceRequest, span: &tracing::Span) { + use opentelemetry_0_14_pkg::trace::TraceContextExt as _; + use tracing_opentelemetry_0_13_pkg::OpenTelemetrySpanExt as _; + + let parent_context = opentelemetry_0_14_pkg::global::get_text_map_propagator(|propagator| { + propagator.extract(&crate::otel_0_14::RequestHeaderCarrier::new(req.headers())) + }); + span.set_parent(parent_context); + // If we have a remote parent span, this will be the parent's trace identifier. + // If not, it will be the newly generated trace identifier with this request as root span. + let trace_id = span.context().span().span_context().trace_id().to_hex(); + span.record("trace_id", &tracing::field::display(trace_id)); +} diff --git a/src/root_span_macro.rs b/src/root_span_macro.rs index 2b4ee67b0..9902725b4 100644 --- a/src/root_span_macro.rs +++ b/src/root_span_macro.rs @@ -97,7 +97,12 @@ macro_rules! root_span { ); std::mem::drop(connection_info); - $crate::root_span_macro::private::set_otel_parent(&$request, &span); + #[cfg(feature = "opentelemetry_0_13")] + $crate::root_span_macro::private::set_otel_parent_0_13(&$request, &span); + + #[cfg(feature = "opentelemetry_0_14")] + $crate::root_span_macro::private::set_otel_parent_0_14(&$request, &span); + span } }; @@ -116,26 +121,16 @@ pub mod private { pub use tracing; - #[cfg(not(feature = "opentelemetry_0_13"))] - #[doc(hidden)] - pub fn set_otel_parent(_req: &ServiceRequest, _span: &tracing::Span) { - // No-op if the OpenTelemetry feature is not active - } - #[cfg(feature = "opentelemetry_0_13")] #[doc(hidden)] - pub fn set_otel_parent(req: &ServiceRequest, span: &tracing::Span) { - use opentelemetry::trace::TraceContextExt as _; - use tracing_opentelemetry::OpenTelemetrySpanExt as _; + pub fn set_otel_parent_0_13(req: &ServiceRequest, span: &tracing::Span) { + crate::otel_0_13::set_otel_parent(req, span); + } - let parent_context = opentelemetry::global::get_text_map_propagator(|propagator| { - propagator.extract(&crate::otel::RequestHeaderCarrier::new(req.headers())) - }); - span.set_parent(parent_context); - // If we have a remote parent span, this will be the parent's trace identifier. - // If not, it will be the newly generated trace identifier with this request as root span. - let trace_id = span.context().span().span_context().trace_id().to_hex(); - span.record("trace_id", &tracing::field::display(trace_id)); + #[cfg(feature = "opentelemetry_0_14")] + #[doc(hidden)] + pub fn set_otel_parent_0_14(req: &ServiceRequest, span: &tracing::Span) { + crate::otel_0_14::set_otel_parent(req, span); } #[doc(hidden)]