@@ -289,11 +289,13 @@ mod tests {
289289 use opentelemetry:: { logs:: AnyValue , Key } ;
290290 use opentelemetry_sdk:: error:: { OTelSdkError , OTelSdkResult } ;
291291 use opentelemetry_sdk:: logs:: { InMemoryLogExporter , LogProcessor } ;
292+ use opentelemetry_sdk:: logs:: { LogBatch , LogExporter } ;
292293 use opentelemetry_sdk:: logs:: { SdkLogRecord , SdkLoggerProvider } ;
293294 use opentelemetry_sdk:: trace:: { Sampler , SdkTracerProvider } ;
294- use tracing:: error;
295+ use tracing:: { error, warn } ;
295296 use tracing_subscriber:: prelude:: __tracing_subscriber_SubscriberExt;
296- use tracing_subscriber:: Layer ;
297+ use tracing_subscriber:: util:: SubscriberInitExt ;
298+ use tracing_subscriber:: { EnvFilter , Layer } ;
297299
298300 pub fn attributes_contains ( log_record : & SdkLogRecord , key : & Key , value : & AnyValue ) -> bool {
299301 log_record
@@ -311,6 +313,69 @@ mod tests {
311313 }
312314
313315 // cargo test --features=testing
316+
317+ #[ derive( Clone , Debug , Default ) ]
318+ struct ReentrantLogExporter ;
319+
320+ impl LogExporter for ReentrantLogExporter {
321+ async fn export ( & self , _batch : LogBatch < ' _ > ) -> OTelSdkResult {
322+ // This will cause a deadlock as the export itself creates a log
323+ // while still within the lock of the SimpleLogProcessor.
324+ warn ! ( name
: "my-event-name" , target
: "reentrant" , event_id =
20 , user_name =
"otel" , user_email =
"[email protected] " ) ; 325+ Ok ( ( ) )
326+ }
327+ }
328+
329+ #[ test]
330+ #[ ignore = "See issue: https://github.com/open-telemetry/opentelemetry-rust/issues/1745" ]
331+ fn simple_processor_deadlock ( ) {
332+ let exporter: ReentrantLogExporter = ReentrantLogExporter ;
333+ let logger_provider = SdkLoggerProvider :: builder ( )
334+ . with_simple_exporter ( exporter. clone ( ) )
335+ . build ( ) ;
336+
337+ let layer = layer:: OpenTelemetryTracingBridge :: new ( & logger_provider) ;
338+
339+ // Setting subscriber as global as that is the only way to test this scenario.
340+ tracing_subscriber:: registry ( ) . with ( layer) . init ( ) ;
341+ warn ! ( name
: "my-event-name" , target
: "my-system" , event_id =
20 , user_name =
"otel" , user_email =
"[email protected] " ) ; 342+ }
343+
344+ #[ test]
345+ #[ ignore = "While this test runs fine, this uses global subscriber and does not play well with other tests." ]
346+ fn simple_processor_no_deadlock ( ) {
347+ let exporter: ReentrantLogExporter = ReentrantLogExporter ;
348+ let logger_provider = SdkLoggerProvider :: builder ( )
349+ . with_simple_exporter ( exporter. clone ( ) )
350+ . build ( ) ;
351+
352+ let layer = layer:: OpenTelemetryTracingBridge :: new ( & logger_provider) ;
353+
354+ // This filter will prevent the deadlock as the reentrant log will be
355+ // ignored.
356+ let filter = EnvFilter :: new ( "debug" ) . add_directive ( "reentrant=error" . parse ( ) . unwrap ( ) ) ;
357+ // Setting subscriber as global as that is the only way to test this scenario.
358+ tracing_subscriber:: registry ( )
359+ . with ( filter)
360+ . with ( layer)
361+ . init ( ) ;
362+ warn ! ( name
: "my-event-name" , target
: "my-system" , event_id =
20 , user_name =
"otel" , user_email =
"[email protected] " ) ; 363+ }
364+
365+ #[ tokio:: test( flavor = "multi_thread" , worker_threads = 1 ) ]
366+ #[ ignore = "While this test runs fine, this uses global subscriber and does not play well with other tests." ]
367+ async fn batch_processor_no_deadlock ( ) {
368+ let exporter: ReentrantLogExporter = ReentrantLogExporter ;
369+ let logger_provider = SdkLoggerProvider :: builder ( )
370+ . with_batch_exporter ( exporter. clone ( ) )
371+ . build ( ) ;
372+
373+ let layer = layer:: OpenTelemetryTracingBridge :: new ( & logger_provider) ;
374+
375+ tracing_subscriber:: registry ( ) . with ( layer) . init ( ) ;
376+ warn ! ( name
: "my-event-name" , target
: "my-system" , event_id =
20 , user_name =
"otel" , user_email =
"[email protected] " ) ; 377+ }
378+
314379 #[ test]
315380 fn tracing_appender_standalone ( ) {
316381 // Arrange
0 commit comments