From c9077ed944d57c85feb22049d26420f8c4472c41 Mon Sep 17 00:00:00 2001 From: DmitryAstafyev Date: Wed, 18 Mar 2026 21:19:54 +0100 Subject: [PATCH 01/10] feat(appender-tracing): add builder support for custom instrumentation scope (close #3415) --- opentelemetry-appender-tracing/CHANGELOG.md | 20 +++--- opentelemetry-appender-tracing/src/layer.rs | 73 ++++++++++++++++++--- 2 files changed, 76 insertions(+), 17 deletions(-) diff --git a/opentelemetry-appender-tracing/CHANGELOG.md b/opentelemetry-appender-tracing/CHANGELOG.md index 4b637c7eea..b78fa51b48 100644 --- a/opentelemetry-appender-tracing/CHANGELOG.md +++ b/opentelemetry-appender-tracing/CHANGELOG.md @@ -2,6 +2,10 @@ ## vNext +- Add `OpenTelemetryTracingBridgeBuilder::with_scope()` to configure the + OpenTelemetry `InstrumentationScope` used by the appender logger. + [3415](https://github.com/open-telemetry/opentelemetry-rust/issues/3415) + ## 0.32.0 Released 2026-May-08 @@ -75,14 +79,12 @@ Released 2025-May-23 - Updated `opentelemetry` dependency to version 0.30.0. - ## 0.29.1 Released 2025-Mar-24 - Bump `tracing-opentelemetry` to 0.30 - ## 0.29.0 Released 2025-Mar-21 @@ -123,16 +125,16 @@ Receivers (processors, exporters) are expected to use `LogRecord.target()` as scope name. This is already done in OTLP Exporters, so this change should be transparent to most users. -- Passes event name to the `event_enabled` method on the `Logger`. This allows +- Passes event name to the `event_enabled` method on the `Logger`. This allows implementations (SDK, processor, exporters) to leverage this additional information to determine if an event is enabled. - `u64`, `i128`, `u128` and `usize` values are stored as `opentelemetry::logs::AnyValue::Int` -when conversion is feasible. Otherwise stored as -`opentelemetry::logs::AnyValue::String`. This avoids unnecessary string -allocation when values can be represented in their original types. + when conversion is feasible. Otherwise stored as + `opentelemetry::logs::AnyValue::String`. This avoids unnecessary string + allocation when values can be represented in their original types. - Byte arrays are stored as `opentelemetry::logs::AnyValue::Bytes` instead -of string. + of string. - `Error` fields are reported using attribute named "exception.message". For example, the below will now report an attribute named "exception.message", instead of previously reporting the user provided attribute "error". @@ -144,7 +146,7 @@ of string. Released 2025-Feb-12 -- New *experimental* feature to use trace_id & span_id from spans created through the [tracing](https://crates.io/crates/tracing) crate (experimental_use_tracing_span_context) [#2438](https://github.com/open-telemetry/opentelemetry-rust/pull/2438) +- New _experimental_ feature to use trace_id & span_id from spans created through the [tracing](https://crates.io/crates/tracing) crate (experimental_use_tracing_span_context) [#2438](https://github.com/open-telemetry/opentelemetry-rust/pull/2438) ## 0.28.0 @@ -194,7 +196,7 @@ Released 2024-Sep-30 ### Added -- New experimental metadata attributes feature (experimental\_metadata\_attributes) [#1380](https://github.com/open-telemetry/opentelemetry-rust/pull/1380) +- New experimental metadata attributes feature (experimental_metadata_attributes) [#1380](https://github.com/open-telemetry/opentelemetry-rust/pull/1380) - Experimental new attributes for tracing metadata - Fixes the following for events emitted using log crate - Normalized metadata fields diff --git a/opentelemetry-appender-tracing/src/layer.rs b/opentelemetry-appender-tracing/src/layer.rs index 91f7d449a1..c0c65bc8ca 100644 --- a/opentelemetry-appender-tracing/src/layer.rs +++ b/opentelemetry-appender-tracing/src/layer.rs @@ -1,6 +1,6 @@ use opentelemetry::{ logs::{AnyValue, LogRecord, Logger, LoggerProvider, Severity}, - Key, + InstrumentationScope, Key, }; #[cfg(feature = "experimental_span_attributes")] use std::borrow::Cow; @@ -379,14 +379,15 @@ where Self::builder(provider).build() } - pub fn builder(provider: &P) -> OpenTelemetryTracingBridgeBuilder { + pub fn builder<'a>(provider: &'a P) -> OpenTelemetryTracingBridgeBuilder<'a, P, L> { OpenTelemetryTracingBridgeBuilder { // Using empty scope name. // The name/version of this library itself can be added // as a Scope attribute, once a semantic convention is // defined for the same. // See https://github.com/open-telemetry/semantic-conventions/issues/1550 - logger: provider.logger(""), + provider, + scope: None, _phantom: Default::default(), #[cfg(feature = "experimental_span_attributes")] span_attributes: None, @@ -394,18 +395,19 @@ where } } -pub struct OpenTelemetryTracingBridgeBuilder +pub struct OpenTelemetryTracingBridgeBuilder<'a, P, L> where P: LoggerProvider + Send + Sync, L: Logger + Send + Sync, { - logger: L, + provider: &'a P, + scope: Option, _phantom: std::marker::PhantomData

, #[cfg(feature = "experimental_span_attributes")] span_attributes: Option, } -impl OpenTelemetryTracingBridgeBuilder +impl<'a, P, L> OpenTelemetryTracingBridgeBuilder<'a, P, L> where P: LoggerProvider + Send + Sync, L: Logger + Send + Sync, @@ -432,9 +434,21 @@ where self } + /// Configures the OpenTelemetry `InstrumentationScope` used to create the + /// logger for this bridge. + /// + /// When not set, the bridge preserves the existing behavior and creates a + /// logger with an empty scope name. + pub fn with_scope(mut self, scope: InstrumentationScope) -> Self { + self.scope = Some(scope); + self + } + pub fn build(self) -> OpenTelemetryTracingBridge { OpenTelemetryTracingBridge { - logger: self.logger, + logger: self.scope.map(|scope| + self.provider.logger_with_scope(scope) + ).unwrap_or_else(||self.provider.logger("")), _phantom: self._phantom, #[cfg(feature = "experimental_span_attributes")] span_attributes: self.span_attributes, @@ -597,7 +611,7 @@ mod tests { use opentelemetry::trace::TracerProvider; use opentelemetry::trace::{TraceContextExt, TraceFlags, Tracer}; use opentelemetry::InstrumentationScope; - use opentelemetry::{logs::AnyValue, Key}; + use opentelemetry::{logs::AnyValue, Key, KeyValue}; use opentelemetry_sdk::error::{OTelSdkError, OTelSdkResult}; use opentelemetry_sdk::logs::{InMemoryLogExporter, LogProcessor}; use opentelemetry_sdk::logs::{SdkLogRecord, SdkLoggerProvider}; @@ -919,6 +933,49 @@ mod tests { } } + #[test] + fn tracing_appender_with_custom_scope() { + let exporter: InMemoryLogExporter = InMemoryLogExporter::default(); + let logger_provider = SdkLoggerProvider::builder() + .with_simple_exporter(exporter.clone()) + .build(); + + let scope = InstrumentationScope::builder("test.scope") + .with_version("1.2.3") + .with_schema_url("https://opentelemetry.io/schemas/1.0.0") + .with_attributes([KeyValue::new("scope-key", "scope-value")]) + .build(); + + let subscriber = tracing_subscriber::registry().with( + layer::OpenTelemetryTracingBridge::builder(&logger_provider) + .with_scope(scope) + .build(), + ); + let _guard = tracing::subscriber::set_default(subscriber); + + error!(name: "scoped-event", target: "my-system", event_id = 20); + assert!(logger_provider.force_flush().is_ok()); + + let exported_logs = exporter + .get_emitted_logs() + .expect("Logs are expected to be exported."); + assert_eq!(exported_logs.len(), 1); + let log = exported_logs + .first() + .expect("At least one log is expected to be present."); + + let instrumentation_scope = &log.instrumentation; + assert_eq!(instrumentation_scope.name(), "test.scope"); + assert_eq!(instrumentation_scope.version(), Some("1.2.3")); + assert_eq!( + instrumentation_scope.schema_url(), + Some("https://opentelemetry.io/schemas/1.0.0") + ); + assert!(instrumentation_scope + .attributes() + .eq([KeyValue::new("scope-key", "scope-value")].iter())); + } + #[test] #[ignore = "log tests set a global logger that cannot be unset and affects other tests"] fn tracing_appender_standalone_with_tracing_log() { From 4af4c46bdf650ed8d58f85785142ff11cb647ee8 Mon Sep 17 00:00:00 2001 From: DmitryAstafyev Date: Tue, 24 Mar 2026 07:33:07 +0100 Subject: [PATCH 02/10] refactor(appender-tracing): remove timelife from builder (close #3415) --- opentelemetry-appender-tracing/CHANGELOG.md | 2 +- opentelemetry-appender-tracing/src/layer.rs | 55 ++++++++++----------- 2 files changed, 28 insertions(+), 29 deletions(-) diff --git a/opentelemetry-appender-tracing/CHANGELOG.md b/opentelemetry-appender-tracing/CHANGELOG.md index b78fa51b48..9d42574af1 100644 --- a/opentelemetry-appender-tracing/CHANGELOG.md +++ b/opentelemetry-appender-tracing/CHANGELOG.md @@ -2,7 +2,7 @@ ## vNext -- Add `OpenTelemetryTracingBridgeBuilder::with_scope()` to configure the +- Add `OpenTelemetryTracingBridge::with_scope()` to configure the OpenTelemetry `InstrumentationScope` used by the appender logger. [3415](https://github.com/open-telemetry/opentelemetry-rust/issues/3415) diff --git a/opentelemetry-appender-tracing/src/layer.rs b/opentelemetry-appender-tracing/src/layer.rs index c0c65bc8ca..5059c0e4c7 100644 --- a/opentelemetry-appender-tracing/src/layer.rs +++ b/opentelemetry-appender-tracing/src/layer.rs @@ -376,18 +376,32 @@ where L: Logger + Send + Sync, { pub fn new(provider: &P) -> Self { - Self::builder(provider).build() + Self::builder(provider, None).build() } - pub fn builder<'a>(provider: &'a P) -> OpenTelemetryTracingBridgeBuilder<'a, P, L> { + /// Creates the bridge with a custom OpenTelemetry `InstrumentationScope`. + /// + /// Use this when you want emitted logs to carry a specific scope name, + /// version, schema URL, or scope attributes. + /// + /// For the default behavior (empty scope name), use [`Self::new`]. + pub fn with_scope(provider: &P, scope: InstrumentationScope) -> Self { + Self::builder(provider, Some(scope)).build() + } + + pub fn builder( + provider: &P, + scope: Option, + ) -> OpenTelemetryTracingBridgeBuilder { OpenTelemetryTracingBridgeBuilder { // Using empty scope name. // The name/version of this library itself can be added // as a Scope attribute, once a semantic convention is // defined for the same. // See https://github.com/open-telemetry/semantic-conventions/issues/1550 - provider, - scope: None, + logger: scope + .map(|scope| provider.logger_with_scope(scope)) + .unwrap_or_else(|| provider.logger("")), _phantom: Default::default(), #[cfg(feature = "experimental_span_attributes")] span_attributes: None, @@ -395,19 +409,18 @@ where } } -pub struct OpenTelemetryTracingBridgeBuilder<'a, P, L> +pub struct OpenTelemetryTracingBridgeBuilder where P: LoggerProvider + Send + Sync, L: Logger + Send + Sync, { - provider: &'a P, - scope: Option, + logger: L, _phantom: std::marker::PhantomData

, #[cfg(feature = "experimental_span_attributes")] span_attributes: Option, } -impl<'a, P, L> OpenTelemetryTracingBridgeBuilder<'a, P, L> +impl OpenTelemetryTracingBridgeBuilder where P: LoggerProvider + Send + Sync, L: Logger + Send + Sync, @@ -434,21 +447,9 @@ where self } - /// Configures the OpenTelemetry `InstrumentationScope` used to create the - /// logger for this bridge. - /// - /// When not set, the bridge preserves the existing behavior and creates a - /// logger with an empty scope name. - pub fn with_scope(mut self, scope: InstrumentationScope) -> Self { - self.scope = Some(scope); - self - } - pub fn build(self) -> OpenTelemetryTracingBridge { OpenTelemetryTracingBridge { - logger: self.scope.map(|scope| - self.provider.logger_with_scope(scope) - ).unwrap_or_else(||self.provider.logger("")), + logger: self.logger, _phantom: self._phantom, #[cfg(feature = "experimental_span_attributes")] span_attributes: self.span_attributes, @@ -947,9 +948,7 @@ mod tests { .build(); let subscriber = tracing_subscriber::registry().with( - layer::OpenTelemetryTracingBridge::builder(&logger_provider) - .with_scope(scope) - .build(), + layer::OpenTelemetryTracingBridge::with_scope(&logger_provider, scope), ); let _guard = tracing::subscriber::set_default(subscriber); @@ -1557,7 +1556,7 @@ mod tests { .with_simple_exporter(exporter.clone()) .build(); - let layer = layer::OpenTelemetryTracingBridge::builder(&provider) + let layer = layer::OpenTelemetryTracingBridge::builder(&provider, None) .with_tracing_span_attributes(TracingSpanAttributes::allowlist(["session.id"])) .build() .with_filter(tracing_subscriber::filter::filter_fn(|meta| { @@ -1594,7 +1593,7 @@ mod tests { .with_simple_exporter(exporter.clone()) .build(); - let layer = layer::OpenTelemetryTracingBridge::builder(&provider) + let layer = layer::OpenTelemetryTracingBridge::builder(&provider, None) .with_tracing_span_attributes(TracingSpanAttributes::allowlist(["session.id"])) .build() .with_filter(tracing_subscriber::filter::filter_fn(|meta| { @@ -1641,7 +1640,7 @@ mod tests { .with_simple_exporter(exporter.clone()) .build(); - let layer = layer::OpenTelemetryTracingBridge::builder(&provider) + let layer = layer::OpenTelemetryTracingBridge::builder(&provider, None) .with_tracing_span_attributes(TracingSpanAttributes::all()) .build() .with_filter(tracing_subscriber::filter::filter_fn(|meta| { @@ -1679,7 +1678,7 @@ mod tests { .with_simple_exporter(exporter.clone()) .build(); - let layer = layer::OpenTelemetryTracingBridge::builder(&provider) + let layer = layer::OpenTelemetryTracingBridge::builder(&provider, None) .with_tracing_span_attributes(TracingSpanAttributes::allowlist(["session.id"])) .build() .with_filter(tracing_subscriber::filter::filter_fn(|meta| { From db70dc02538e765cccd40f501cc5c3e40d9b0302 Mon Sep 17 00:00:00 2001 From: DmitryAstafyev Date: Wed, 25 Mar 2026 18:55:11 +0100 Subject: [PATCH 03/10] refactor(appender-tracing): add builder_with_scope and document OpenTelemetryTracingBridge API --- opentelemetry-appender-tracing/CHANGELOG.md | 5 ++- opentelemetry-appender-tracing/src/layer.rs | 50 ++++++++++++--------- 2 files changed, 33 insertions(+), 22 deletions(-) diff --git a/opentelemetry-appender-tracing/CHANGELOG.md b/opentelemetry-appender-tracing/CHANGELOG.md index 9d42574af1..22fcd653a2 100644 --- a/opentelemetry-appender-tracing/CHANGELOG.md +++ b/opentelemetry-appender-tracing/CHANGELOG.md @@ -2,8 +2,9 @@ ## vNext -- Add `OpenTelemetryTracingBridge::with_scope()` to configure the - OpenTelemetry `InstrumentationScope` used by the appender logger. +- Add custom `InstrumentationScope` support via + `OpenTelemetryTracingBridge::with_scope()` and + `OpenTelemetryTracingBridge::builder_with_scope()`. [3415](https://github.com/open-telemetry/opentelemetry-rust/issues/3415) ## 0.32.0 diff --git a/opentelemetry-appender-tracing/src/layer.rs b/opentelemetry-appender-tracing/src/layer.rs index 5059c0e4c7..54807aeeb2 100644 --- a/opentelemetry-appender-tracing/src/layer.rs +++ b/opentelemetry-appender-tracing/src/layer.rs @@ -375,33 +375,43 @@ where P: LoggerProvider + Send + Sync, L: Logger + Send + Sync, { + /// Creates a bridge using the default OpenTelemetry logger scope. + /// + /// The default scope uses an empty scope name for the appender logger. + /// Use [`Self::with_scope`] or [`Self::builder_with_scope`] to provide a + /// custom [`InstrumentationScope`]. pub fn new(provider: &P) -> Self { - Self::builder(provider, None).build() + Self::builder(provider).build() } - /// Creates the bridge with a custom OpenTelemetry `InstrumentationScope`. - /// - /// Use this when you want emitted logs to carry a specific scope name, - /// version, schema URL, or scope attributes. - /// - /// For the default behavior (empty scope name), use [`Self::new`]. + /// Creates the bridge with a custom OpenTelemetry [`InstrumentationScope`]. pub fn with_scope(provider: &P, scope: InstrumentationScope) -> Self { - Self::builder(provider, Some(scope)).build() + Self::builder_with_scope(provider, scope).build() } - pub fn builder( - provider: &P, - scope: Option, - ) -> OpenTelemetryTracingBridgeBuilder { + /// Creates a builder using the default OpenTelemetry logger scope. + pub fn builder(provider: &P) -> OpenTelemetryTracingBridgeBuilder { OpenTelemetryTracingBridgeBuilder { // Using empty scope name. // The name/version of this library itself can be added // as a Scope attribute, once a semantic convention is // defined for the same. // See https://github.com/open-telemetry/semantic-conventions/issues/1550 - logger: scope - .map(|scope| provider.logger_with_scope(scope)) - .unwrap_or_else(|| provider.logger("")), + logger: provider.logger(""), + _phantom: Default::default(), + #[cfg(feature = "experimental_span_attributes")] + span_attribute_allowlist: None, + } + } + + /// Creates a builder that uses a custom OpenTelemetry [`InstrumentationScope`] + /// for the appender logger. + pub fn builder_with_scope( + provider: &P, + scope: InstrumentationScope, + ) -> OpenTelemetryTracingBridgeBuilder { + OpenTelemetryTracingBridgeBuilder { + logger: provider.logger_with_scope(scope), _phantom: Default::default(), #[cfg(feature = "experimental_span_attributes")] span_attributes: None, @@ -948,7 +958,7 @@ mod tests { .build(); let subscriber = tracing_subscriber::registry().with( - layer::OpenTelemetryTracingBridge::with_scope(&logger_provider, scope), + layer::OpenTelemetryTracingBridge::builder_with_scope(&logger_provider, scope).build(), ); let _guard = tracing::subscriber::set_default(subscriber); @@ -1556,7 +1566,7 @@ mod tests { .with_simple_exporter(exporter.clone()) .build(); - let layer = layer::OpenTelemetryTracingBridge::builder(&provider, None) + let layer = layer::OpenTelemetryTracingBridge::builder(&provider) .with_tracing_span_attributes(TracingSpanAttributes::allowlist(["session.id"])) .build() .with_filter(tracing_subscriber::filter::filter_fn(|meta| { @@ -1593,7 +1603,7 @@ mod tests { .with_simple_exporter(exporter.clone()) .build(); - let layer = layer::OpenTelemetryTracingBridge::builder(&provider, None) + let layer = layer::OpenTelemetryTracingBridge::builder(&provider) .with_tracing_span_attributes(TracingSpanAttributes::allowlist(["session.id"])) .build() .with_filter(tracing_subscriber::filter::filter_fn(|meta| { @@ -1640,7 +1650,7 @@ mod tests { .with_simple_exporter(exporter.clone()) .build(); - let layer = layer::OpenTelemetryTracingBridge::builder(&provider, None) + let layer = layer::OpenTelemetryTracingBridge::builder(&provider) .with_tracing_span_attributes(TracingSpanAttributes::all()) .build() .with_filter(tracing_subscriber::filter::filter_fn(|meta| { @@ -1678,7 +1688,7 @@ mod tests { .with_simple_exporter(exporter.clone()) .build(); - let layer = layer::OpenTelemetryTracingBridge::builder(&provider, None) + let layer = layer::OpenTelemetryTracingBridge::builder(&provider) .with_tracing_span_attributes(TracingSpanAttributes::allowlist(["session.id"])) .build() .with_filter(tracing_subscriber::filter::filter_fn(|meta| { From 20fcd6c8ddf99b11a8b8e23ba9bb6b354c777cbd Mon Sep 17 00:00:00 2001 From: DmitryAstafyev Date: Wed, 25 Mar 2026 19:17:04 +0100 Subject: [PATCH 04/10] test(appender-tracing): cover both with_scope and builder_with_scope paths --- opentelemetry-appender-tracing/src/layer.rs | 69 +++++++++++++-------- 1 file changed, 42 insertions(+), 27 deletions(-) diff --git a/opentelemetry-appender-tracing/src/layer.rs b/opentelemetry-appender-tracing/src/layer.rs index 54807aeeb2..c6c166fb90 100644 --- a/opentelemetry-appender-tracing/src/layer.rs +++ b/opentelemetry-appender-tracing/src/layer.rs @@ -956,33 +956,48 @@ mod tests { .with_schema_url("https://opentelemetry.io/schemas/1.0.0") .with_attributes([KeyValue::new("scope-key", "scope-value")]) .build(); - - let subscriber = tracing_subscriber::registry().with( - layer::OpenTelemetryTracingBridge::builder_with_scope(&logger_provider, scope).build(), - ); - let _guard = tracing::subscriber::set_default(subscriber); - - error!(name: "scoped-event", target: "my-system", event_id = 20); - assert!(logger_provider.force_flush().is_ok()); - - let exported_logs = exporter - .get_emitted_logs() - .expect("Logs are expected to be exported."); - assert_eq!(exported_logs.len(), 1); - let log = exported_logs - .first() - .expect("At least one log is expected to be present."); - - let instrumentation_scope = &log.instrumentation; - assert_eq!(instrumentation_scope.name(), "test.scope"); - assert_eq!(instrumentation_scope.version(), Some("1.2.3")); - assert_eq!( - instrumentation_scope.schema_url(), - Some("https://opentelemetry.io/schemas/1.0.0") - ); - assert!(instrumentation_scope - .attributes() - .eq([KeyValue::new("scope-key", "scope-value")].iter())); + let subscribers = [ + tracing_subscriber::registry().with( + layer::OpenTelemetryTracingBridge::builder_with_scope( + &logger_provider, + scope.clone(), + ) + .build(), + ), + tracing_subscriber::registry().with(layer::OpenTelemetryTracingBridge::with_scope( + &logger_provider, + scope, + )), + ]; + + for subscriber in subscribers { + let _guard = tracing::subscriber::set_default(subscriber); + + error!(name: "scoped-event", target: "my-system", event_id = 20); + assert!(logger_provider.force_flush().is_ok()); + + let exported_logs = exporter + .get_emitted_logs() + .expect("Logs are expected to be exported."); + assert_eq!(exported_logs.len(), 1); + let log = exported_logs + .first() + .expect("At least one log is expected to be present."); + + let instrumentation_scope = &log.instrumentation; + assert_eq!(instrumentation_scope.name(), "test.scope"); + assert_eq!(instrumentation_scope.version(), Some("1.2.3")); + assert_eq!( + instrumentation_scope.schema_url(), + Some("https://opentelemetry.io/schemas/1.0.0") + ); + assert!(instrumentation_scope.attributes().eq([KeyValue::new( + "scope-key", + "scope-value" + )] + .iter())); + exporter.reset(); + } } #[test] From d4757643485c4f80ed7c899406ee45b187f176f6 Mon Sep 17 00:00:00 2001 From: DmitryAstafyev Date: Mon, 6 Apr 2026 10:47:40 +0200 Subject: [PATCH 05/10] refactor(appender-tracing): cleanup OpenTelemetryTracingBridge API --- opentelemetry-appender-tracing/CHANGELOG.md | 1 - opentelemetry-appender-tracing/src/layer.rs | 76 ++++++++------------- 2 files changed, 29 insertions(+), 48 deletions(-) diff --git a/opentelemetry-appender-tracing/CHANGELOG.md b/opentelemetry-appender-tracing/CHANGELOG.md index 22fcd653a2..2660851051 100644 --- a/opentelemetry-appender-tracing/CHANGELOG.md +++ b/opentelemetry-appender-tracing/CHANGELOG.md @@ -3,7 +3,6 @@ ## vNext - Add custom `InstrumentationScope` support via - `OpenTelemetryTracingBridge::with_scope()` and `OpenTelemetryTracingBridge::builder_with_scope()`. [3415](https://github.com/open-telemetry/opentelemetry-rust/issues/3415) diff --git a/opentelemetry-appender-tracing/src/layer.rs b/opentelemetry-appender-tracing/src/layer.rs index c6c166fb90..22f0529c51 100644 --- a/opentelemetry-appender-tracing/src/layer.rs +++ b/opentelemetry-appender-tracing/src/layer.rs @@ -378,17 +378,12 @@ where /// Creates a bridge using the default OpenTelemetry logger scope. /// /// The default scope uses an empty scope name for the appender logger. - /// Use [`Self::with_scope`] or [`Self::builder_with_scope`] to provide a + /// Use [`Self::builder_with_scope`] to provide a /// custom [`InstrumentationScope`]. pub fn new(provider: &P) -> Self { Self::builder(provider).build() } - /// Creates the bridge with a custom OpenTelemetry [`InstrumentationScope`]. - pub fn with_scope(provider: &P, scope: InstrumentationScope) -> Self { - Self::builder_with_scope(provider, scope).build() - } - /// Creates a builder using the default OpenTelemetry logger scope. pub fn builder(provider: &P) -> OpenTelemetryTracingBridgeBuilder { OpenTelemetryTracingBridgeBuilder { @@ -956,48 +951,35 @@ mod tests { .with_schema_url("https://opentelemetry.io/schemas/1.0.0") .with_attributes([KeyValue::new("scope-key", "scope-value")]) .build(); - let subscribers = [ - tracing_subscriber::registry().with( - layer::OpenTelemetryTracingBridge::builder_with_scope( - &logger_provider, - scope.clone(), - ) + let subscriber = tracing_subscriber::registry().with( + layer::OpenTelemetryTracingBridge::builder_with_scope(&logger_provider, scope.clone()) .build(), - ), - tracing_subscriber::registry().with(layer::OpenTelemetryTracingBridge::with_scope( - &logger_provider, - scope, - )), - ]; - - for subscriber in subscribers { - let _guard = tracing::subscriber::set_default(subscriber); - - error!(name: "scoped-event", target: "my-system", event_id = 20); - assert!(logger_provider.force_flush().is_ok()); - - let exported_logs = exporter - .get_emitted_logs() - .expect("Logs are expected to be exported."); - assert_eq!(exported_logs.len(), 1); - let log = exported_logs - .first() - .expect("At least one log is expected to be present."); - - let instrumentation_scope = &log.instrumentation; - assert_eq!(instrumentation_scope.name(), "test.scope"); - assert_eq!(instrumentation_scope.version(), Some("1.2.3")); - assert_eq!( - instrumentation_scope.schema_url(), - Some("https://opentelemetry.io/schemas/1.0.0") - ); - assert!(instrumentation_scope.attributes().eq([KeyValue::new( - "scope-key", - "scope-value" - )] - .iter())); - exporter.reset(); - } + ); + + let _guard = tracing::subscriber::set_default(subscriber); + + error!(name: "scoped-event", target: "my-system", event_id = 20); + assert!(logger_provider.force_flush().is_ok()); + + let exported_logs = exporter + .get_emitted_logs() + .expect("Logs are expected to be exported."); + assert_eq!(exported_logs.len(), 1); + let log = exported_logs + .first() + .expect("At least one log is expected to be present."); + + let instrumentation_scope = &log.instrumentation; + assert_eq!(instrumentation_scope.name(), "test.scope"); + assert_eq!(instrumentation_scope.version(), Some("1.2.3")); + assert_eq!( + instrumentation_scope.schema_url(), + Some("https://opentelemetry.io/schemas/1.0.0") + ); + assert!(instrumentation_scope + .attributes() + .eq([KeyValue::new("scope-key", "scope-value")].iter())); + exporter.reset(); } #[test] From 7db90f52b7ef80607b576ebf005a36ad26821ad0 Mon Sep 17 00:00:00 2001 From: DmitryAstafyev Date: Tue, 23 Jun 2026 15:54:32 +0200 Subject: [PATCH 06/10] fix(appender-tracing): fix rebase-on-master error --- opentelemetry-appender-tracing/src/layer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opentelemetry-appender-tracing/src/layer.rs b/opentelemetry-appender-tracing/src/layer.rs index 22f0529c51..5a46ba4d9d 100644 --- a/opentelemetry-appender-tracing/src/layer.rs +++ b/opentelemetry-appender-tracing/src/layer.rs @@ -395,7 +395,7 @@ where logger: provider.logger(""), _phantom: Default::default(), #[cfg(feature = "experimental_span_attributes")] - span_attribute_allowlist: None, + span_attributes: None, } } From 3fae4177e69b979b82655888e071887db85b9903 Mon Sep 17 00:00:00 2001 From: DmitryAstafyev Date: Tue, 23 Jun 2026 20:23:57 +0200 Subject: [PATCH 07/10] docs(appender-tracing): update changelog --- opentelemetry-appender-tracing/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opentelemetry-appender-tracing/CHANGELOG.md b/opentelemetry-appender-tracing/CHANGELOG.md index 2660851051..84f2e8c1ae 100644 --- a/opentelemetry-appender-tracing/CHANGELOG.md +++ b/opentelemetry-appender-tracing/CHANGELOG.md @@ -3,7 +3,7 @@ ## vNext - Add custom `InstrumentationScope` support via - `OpenTelemetryTracingBridge::builder_with_scope()`. + `OpenTelemetryTracingBridge::builder_with_scope(..)`. [3415](https://github.com/open-telemetry/opentelemetry-rust/issues/3415) ## 0.32.0 From 755d247bfc51e36d681923186e589d2a9dcb34a7 Mon Sep 17 00:00:00 2001 From: DmitryAstafyev Date: Thu, 25 Jun 2026 01:03:32 +0200 Subject: [PATCH 08/10] refactor(appender-tracing): rename method --- opentelemetry-appender-tracing/CHANGELOG.md | 2 +- opentelemetry-appender-tracing/src/layer.rs | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/opentelemetry-appender-tracing/CHANGELOG.md b/opentelemetry-appender-tracing/CHANGELOG.md index 84f2e8c1ae..399b05ca6a 100644 --- a/opentelemetry-appender-tracing/CHANGELOG.md +++ b/opentelemetry-appender-tracing/CHANGELOG.md @@ -3,7 +3,7 @@ ## vNext - Add custom `InstrumentationScope` support via - `OpenTelemetryTracingBridge::builder_with_scope(..)`. + `OpenTelemetryTracingBridge::builder_with_scope_attributes(..)`. [3415](https://github.com/open-telemetry/opentelemetry-rust/issues/3415) ## 0.32.0 diff --git a/opentelemetry-appender-tracing/src/layer.rs b/opentelemetry-appender-tracing/src/layer.rs index 5a46ba4d9d..6818237b4e 100644 --- a/opentelemetry-appender-tracing/src/layer.rs +++ b/opentelemetry-appender-tracing/src/layer.rs @@ -378,7 +378,7 @@ where /// Creates a bridge using the default OpenTelemetry logger scope. /// /// The default scope uses an empty scope name for the appender logger. - /// Use [`Self::builder_with_scope`] to provide a + /// Use [`Self::builder_with_scope_attributes`] to provide a /// custom [`InstrumentationScope`]. pub fn new(provider: &P) -> Self { Self::builder(provider).build() @@ -401,7 +401,7 @@ where /// Creates a builder that uses a custom OpenTelemetry [`InstrumentationScope`] /// for the appender logger. - pub fn builder_with_scope( + pub fn builder_with_scope_attributes( provider: &P, scope: InstrumentationScope, ) -> OpenTelemetryTracingBridgeBuilder { @@ -952,8 +952,11 @@ mod tests { .with_attributes([KeyValue::new("scope-key", "scope-value")]) .build(); let subscriber = tracing_subscriber::registry().with( - layer::OpenTelemetryTracingBridge::builder_with_scope(&logger_provider, scope.clone()) - .build(), + layer::OpenTelemetryTracingBridge::builder_with_scope_attributes( + &logger_provider, + scope.clone(), + ) + .build(), ); let _guard = tracing::subscriber::set_default(subscriber); From febb981664838c1fa57bde5e6834ff82893b4207 Mon Sep 17 00:00:00 2001 From: DmitryAstafyev Date: Thu, 25 Jun 2026 11:49:41 +0200 Subject: [PATCH 09/10] refactor(appender-tracing): narrowed down API --- opentelemetry-appender-tracing/CHANGELOG.md | 2 +- opentelemetry-appender-tracing/src/layer.rs | 32 ++++++++------------- 2 files changed, 13 insertions(+), 21 deletions(-) diff --git a/opentelemetry-appender-tracing/CHANGELOG.md b/opentelemetry-appender-tracing/CHANGELOG.md index 399b05ca6a..5cd0414b92 100644 --- a/opentelemetry-appender-tracing/CHANGELOG.md +++ b/opentelemetry-appender-tracing/CHANGELOG.md @@ -2,7 +2,7 @@ ## vNext -- Add custom `InstrumentationScope` support via +- Add custom instrumentation scope attributes support via `OpenTelemetryTracingBridge::builder_with_scope_attributes(..)`. [3415](https://github.com/open-telemetry/opentelemetry-rust/issues/3415) diff --git a/opentelemetry-appender-tracing/src/layer.rs b/opentelemetry-appender-tracing/src/layer.rs index 6818237b4e..fb5535473e 100644 --- a/opentelemetry-appender-tracing/src/layer.rs +++ b/opentelemetry-appender-tracing/src/layer.rs @@ -1,6 +1,6 @@ use opentelemetry::{ logs::{AnyValue, LogRecord, Logger, LoggerProvider, Severity}, - InstrumentationScope, Key, + InstrumentationScope, Key, KeyValue, }; #[cfg(feature = "experimental_span_attributes")] use std::borrow::Cow; @@ -379,7 +379,7 @@ where /// /// The default scope uses an empty scope name for the appender logger. /// Use [`Self::builder_with_scope_attributes`] to provide a - /// custom [`InstrumentationScope`]. + /// custom set of instrumentation scope attributes. pub fn new(provider: &P) -> Self { Self::builder(provider).build() } @@ -399,12 +399,15 @@ where } } - /// Creates a builder that uses a custom OpenTelemetry [`InstrumentationScope`] - /// for the appender logger. + /// Creates a builder that uses custom OpenTelemetry instrumentation scope + /// attributes for the appender logger. pub fn builder_with_scope_attributes( provider: &P, - scope: InstrumentationScope, + attributes: impl IntoIterator, ) -> OpenTelemetryTracingBridgeBuilder { + let scope = InstrumentationScope::builder("") + .with_attributes(attributes) + .build(); OpenTelemetryTracingBridgeBuilder { logger: provider.logger_with_scope(scope), _phantom: Default::default(), @@ -940,21 +943,16 @@ mod tests { } #[test] - fn tracing_appender_with_custom_scope() { + fn tracing_appender_with_custom_scope_attributes() { let exporter: InMemoryLogExporter = InMemoryLogExporter::default(); let logger_provider = SdkLoggerProvider::builder() .with_simple_exporter(exporter.clone()) .build(); - let scope = InstrumentationScope::builder("test.scope") - .with_version("1.2.3") - .with_schema_url("https://opentelemetry.io/schemas/1.0.0") - .with_attributes([KeyValue::new("scope-key", "scope-value")]) - .build(); let subscriber = tracing_subscriber::registry().with( layer::OpenTelemetryTracingBridge::builder_with_scope_attributes( &logger_provider, - scope.clone(), + [KeyValue::new("scope-key", "scope-value")], ) .build(), ); @@ -972,14 +970,8 @@ mod tests { .first() .expect("At least one log is expected to be present."); - let instrumentation_scope = &log.instrumentation; - assert_eq!(instrumentation_scope.name(), "test.scope"); - assert_eq!(instrumentation_scope.version(), Some("1.2.3")); - assert_eq!( - instrumentation_scope.schema_url(), - Some("https://opentelemetry.io/schemas/1.0.0") - ); - assert!(instrumentation_scope + assert!(log + .instrumentation .attributes() .eq([KeyValue::new("scope-key", "scope-value")].iter())); exporter.reset(); From 53d106f20ccedfa220fd7aa25573ae4834ee2ea5 Mon Sep 17 00:00:00 2001 From: DmitryAstafyev Date: Thu, 25 Jun 2026 12:50:32 +0200 Subject: [PATCH 10/10] docs(appender-tracing): remove accidental changelog formatting --- opentelemetry-appender-tracing/CHANGELOG.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/opentelemetry-appender-tracing/CHANGELOG.md b/opentelemetry-appender-tracing/CHANGELOG.md index 5cd0414b92..1b40e5b4db 100644 --- a/opentelemetry-appender-tracing/CHANGELOG.md +++ b/opentelemetry-appender-tracing/CHANGELOG.md @@ -79,12 +79,14 @@ Released 2025-May-23 - Updated `opentelemetry` dependency to version 0.30.0. + ## 0.29.1 Released 2025-Mar-24 - Bump `tracing-opentelemetry` to 0.30 + ## 0.29.0 Released 2025-Mar-21 @@ -125,16 +127,16 @@ Receivers (processors, exporters) are expected to use `LogRecord.target()` as scope name. This is already done in OTLP Exporters, so this change should be transparent to most users. -- Passes event name to the `event_enabled` method on the `Logger`. This allows +- Passes event name to the `event_enabled` method on the `Logger`. This allows implementations (SDK, processor, exporters) to leverage this additional information to determine if an event is enabled. - `u64`, `i128`, `u128` and `usize` values are stored as `opentelemetry::logs::AnyValue::Int` - when conversion is feasible. Otherwise stored as - `opentelemetry::logs::AnyValue::String`. This avoids unnecessary string - allocation when values can be represented in their original types. +when conversion is feasible. Otherwise stored as +`opentelemetry::logs::AnyValue::String`. This avoids unnecessary string +allocation when values can be represented in their original types. - Byte arrays are stored as `opentelemetry::logs::AnyValue::Bytes` instead - of string. +of string. - `Error` fields are reported using attribute named "exception.message". For example, the below will now report an attribute named "exception.message", instead of previously reporting the user provided attribute "error". @@ -146,7 +148,7 @@ transparent to most users. Released 2025-Feb-12 -- New _experimental_ feature to use trace_id & span_id from spans created through the [tracing](https://crates.io/crates/tracing) crate (experimental_use_tracing_span_context) [#2438](https://github.com/open-telemetry/opentelemetry-rust/pull/2438) +- New *experimental* feature to use trace_id & span_id from spans created through the [tracing](https://crates.io/crates/tracing) crate (experimental_use_tracing_span_context) [#2438](https://github.com/open-telemetry/opentelemetry-rust/pull/2438) ## 0.28.0 @@ -196,7 +198,7 @@ Released 2024-Sep-30 ### Added -- New experimental metadata attributes feature (experimental_metadata_attributes) [#1380](https://github.com/open-telemetry/opentelemetry-rust/pull/1380) +- New experimental metadata attributes feature (experimental\_metadata\_attributes) [#1380](https://github.com/open-telemetry/opentelemetry-rust/pull/1380) - Experimental new attributes for tracing metadata - Fixes the following for events emitted using log crate - Normalized metadata fields