diff --git a/Cargo.toml b/Cargo.toml index a5879076b..ce8e38f85 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ categories = ["asynchronous", "web-programming"] default = ["opentelemetry_0_14", "emit_event_on_error"] opentelemetry_0_13 = ["opentelemetry_0_13_pkg", "tracing-opentelemetry_0_12_pkg"] opentelemetry_0_14 = ["opentelemetry_0_14_pkg", "tracing-opentelemetry_0_13_pkg"] +opentelemetry_0_15 = ["opentelemetry_0_15_pkg", "tracing-opentelemetry_0_14_pkg"] emit_event_on_error = [] [dependencies] @@ -32,8 +33,10 @@ futures = "0.3.5" uuid = { version = "0.8.1", features = ["v4"] } opentelemetry_0_13_pkg = { package = "opentelemetry", version = "0.13", optional = true } opentelemetry_0_14_pkg = { package = "opentelemetry", version = "0.14", optional = true } +opentelemetry_0_15_pkg = { package = "opentelemetry", version = "0.15", 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 } +tracing-opentelemetry_0_14_pkg = { package = "tracing-opentelemetry",version = "0.14", optional = true } [dev-dependencies] tracing-subscriber = { version = "0.2.12", features = ["registry", "env-filter"] } diff --git a/README.md b/README.md index 441d6e5cc..de9027cc4 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,7 @@ actix-web = "4.0.0-beta.7" - `opentelemetry_0_13`: attach [OpenTelemetry](https://github.com/open-telemetry/opentelemetry-rust)'s context to the root span using OTEL 0.13. - `opentelemetry_0_14`: same as above but using OTEL 0.14 (enabled by default). +- `opentelemetry_0_15`: same as above but using OTEL 0.15 - `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`. diff --git a/src/lib.rs b/src/lib.rs index 715895d6c..cdd20bc14 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,6 +17,7 @@ //! //! - `opentelemetry_0_13`: attach [OpenTelemetry](https://github.com/open-telemetry/opentelemetry-rust)'s context to the root span using OTEL 0.13; //! - `opentelemetry_0_14`: same as above but using OTEL 0.14 (enabled by default); +//! - `opentelemetry_0_15`: same as above but using OTEL 0.15 //! - `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`. @@ -214,7 +215,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` or `opentelemetry_0_14` feature flags, `tracing-actix-web` automatically +//! Furthermore, if you have not disabled the `opentelemetry_0_13` or `opentelemetry_0_14` or `opentelemetry_0_15` 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. @@ -248,3 +249,6 @@ mod otel_0_13; #[cfg(feature = "opentelemetry_0_14")] mod otel_0_14; + +#[cfg(feature = "opentelemetry_0_15")] +mod otel_0_15; \ No newline at end of file diff --git a/src/otel_0_15.rs b/src/otel_0_15.rs new file mode 100644 index 000000000..ee98d5a70 --- /dev/null +++ b/src/otel_0_15.rs @@ -0,0 +1,36 @@ +use actix_web::dev::ServiceRequest; +use opentelemetry_0_15_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_15_pkg::trace::TraceContextExt as _; + use tracing_opentelemetry_0_14_pkg::OpenTelemetrySpanExt as _; + + let parent_context = opentelemetry_0_15_pkg::global::get_text_map_propagator(|propagator| { + propagator.extract(&crate::otel_0_15::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 9902725b4..39a714941 100644 --- a/src/root_span_macro.rs +++ b/src/root_span_macro.rs @@ -103,6 +103,9 @@ macro_rules! root_span { #[cfg(feature = "opentelemetry_0_14")] $crate::root_span_macro::private::set_otel_parent_0_14(&$request, &span); + #[cfg(feature = "opentelemetry_0_15")] + $crate::root_span_macro::private::set_otel_parent_0_15(&$request, &span); + span } }; @@ -133,6 +136,12 @@ pub mod private { crate::otel_0_14::set_otel_parent(req, span); } + #[cfg(feature = "opentelemetry_0_15")] + #[doc(hidden)] + pub fn set_otel_parent_0_15(req: &ServiceRequest, span: &tracing::Span) { + crate::otel_0_15::set_otel_parent(req, span); + } + #[doc(hidden)] #[inline] pub fn http_method_str(method: &Method) -> Cow<'static, str> {