From 96359fca5d1b96a911510e0c10002af2752f867c Mon Sep 17 00:00:00 2001 From: Luca Muscat Date: Wed, 17 Sep 2025 23:21:54 +0200 Subject: [PATCH 1/2] fix: Suppress telemetry emitted inside of `BatchLogProcessor::emit` --- .../test_no_stack_overflow_after_shutdown.rs | 23 +++++++++++++++++++ .../src/logs/batch_log_processor.rs | 2 ++ 2 files changed, 25 insertions(+) create mode 100644 opentelemetry-appender-tracing/tests/test_no_stack_overflow_after_shutdown.rs diff --git a/opentelemetry-appender-tracing/tests/test_no_stack_overflow_after_shutdown.rs b/opentelemetry-appender-tracing/tests/test_no_stack_overflow_after_shutdown.rs new file mode 100644 index 0000000000..1e7cf207b6 --- /dev/null +++ b/opentelemetry-appender-tracing/tests/test_no_stack_overflow_after_shutdown.rs @@ -0,0 +1,23 @@ +use opentelemetry_appender_tracing::layer; +use opentelemetry_sdk::logs::SdkLoggerProvider; +use tracing::info; +use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; + +#[test] +fn test_logging_after_shutdown_does_not_cause_telemetry_induced_telemetry() { + //! Reproduces [#3161](https://github.com/open-telemetry/opentelemetry-rust/issues/3161) + let exporter = opentelemetry_stdout::LogExporter::default(); + let provider: SdkLoggerProvider = SdkLoggerProvider::builder() + .with_batch_exporter(exporter) + .build(); + + let otel_layer = layer::OpenTelemetryTracingBridge::new(&provider); + + tracing_subscriber::registry().with(otel_layer).init(); + + provider.shutdown().unwrap(); + + // If logging causes telemetry-induced-telemetry after shutting down the provider, then a stack + // overflow may occur. + info!("Don't crash") +} diff --git a/opentelemetry-sdk/src/logs/batch_log_processor.rs b/opentelemetry-sdk/src/logs/batch_log_processor.rs index d104a0a221..0fd87595da 100644 --- a/opentelemetry-sdk/src/logs/batch_log_processor.rs +++ b/opentelemetry-sdk/src/logs/batch_log_processor.rs @@ -151,6 +151,8 @@ impl Debug for BatchLogProcessor { impl LogProcessor for BatchLogProcessor { fn emit(&self, record: &mut SdkLogRecord, instrumentation: &InstrumentationScope) { + let _guard = Context::enter_telemetry_suppressed_scope(); + let result = self .logs_sender .try_send(Box::new((record.clone(), instrumentation.clone()))); From 72e02aa4f355bc35095991f0c8583c7bcf67974e Mon Sep 17 00:00:00 2001 From: Luca Muscat Date: Thu, 18 Sep 2025 19:34:58 +0200 Subject: [PATCH 2/2] fix: Move telemetry suppression inside of the disconnected branch to avoid the added overhead of suppressing telemetry in the happy path --- opentelemetry-sdk/src/logs/batch_log_processor.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/opentelemetry-sdk/src/logs/batch_log_processor.rs b/opentelemetry-sdk/src/logs/batch_log_processor.rs index 0fd87595da..9aae314f29 100644 --- a/opentelemetry-sdk/src/logs/batch_log_processor.rs +++ b/opentelemetry-sdk/src/logs/batch_log_processor.rs @@ -151,8 +151,6 @@ impl Debug for BatchLogProcessor { impl LogProcessor for BatchLogProcessor { fn emit(&self, record: &mut SdkLogRecord, instrumentation: &InstrumentationScope) { - let _guard = Context::enter_telemetry_suppressed_scope(); - let result = self .logs_sender .try_send(Box::new((record.clone(), instrumentation.clone()))); @@ -209,6 +207,10 @@ impl LogProcessor for BatchLogProcessor { } } Err(mpsc::TrySendError::Disconnected(_)) => { + // The following `otel_warn!` may cause an infinite feedback loop of + // 'telemetry-induced-telemetry', potentially causing a stack overflow + let _guard = Context::enter_telemetry_suppressed_scope(); + // Given background thread is the only receiver, and it's // disconnected, it indicates the thread is shutdown otel_warn!(