@@ -97,7 +97,6 @@ pub struct Context {
9797 #[ cfg( feature = "trace" ) ]
9898 pub ( crate ) span : Option < Arc < SynchronizedSpan > > ,
9999 entries : Option < Arc < EntryMap > > ,
100- suppress_telemetry : bool ,
101100}
102101
103102type EntryMap = HashMap < TypeId , Arc < dyn Any + Sync + Send > , BuildHasherDefault < IdHasher > > ;
@@ -245,7 +244,6 @@ impl Context {
245244 entries,
246245 #[ cfg( feature = "trace" ) ]
247246 span : self . span . clone ( ) ,
248- suppress_telemetry : self . suppress_telemetry ,
249247 }
250248 }
251249
@@ -332,97 +330,19 @@ impl Context {
332330 }
333331 }
334332
335- /// Returns whether telemetry is suppressed in this context.
336- #[ inline]
337- pub fn is_telemetry_suppressed ( & self ) -> bool {
338- self . suppress_telemetry
339- }
340-
341- /// Returns a new context with telemetry suppression enabled.
342- pub fn with_telemetry_suppressed ( & self ) -> Self {
343- Context {
344- entries : self . entries . clone ( ) ,
345- #[ cfg( feature = "trace" ) ]
346- span : self . span . clone ( ) ,
347- suppress_telemetry : true ,
348- }
349- }
350-
351- /// Enters a scope where telemetry is suppressed.
352- ///
353- /// This method is specifically designed for OpenTelemetry components (like Exporters,
354- /// Processors etc.) to prevent generating recursive or self-referential
355- /// telemetry data when performing their own operations.
356- ///
357- /// Without suppression, we have a telemetry-induced-telemetry situation
358- /// where, operations like exporting telemetry could generate new telemetry
359- /// about the export process itself, potentially causing:
360- /// - Infinite telemetry feedback loops
361- /// - Excessive resource consumption
362- ///
363- /// This method:
364- /// 1. Takes the current context
365- /// 2. Creates a new context from current, with `suppress_telemetry` set to `true`
366- /// 3. Attaches it to the current thread
367- /// 4. Returns a guard that restores the previous context when dropped
368- ///
369- /// OTel SDK components would check `is_current_telemetry_suppressed()` before
370- /// generating new telemetry, but not end users.
371- ///
372- /// # Examples
373- ///
374- /// ```
375- /// use opentelemetry::Context;
376- ///
377- /// // Example: Inside an exporter's implementation
378- /// fn example_export_function() {
379- /// // Prevent telemetry-generating operations from creating more telemetry
380- /// let _guard = Context::enter_telemetry_suppressed_scope();
381- ///
382- /// // Verify suppression is active
383- /// assert_eq!(Context::is_current_telemetry_suppressed(), true);
384- ///
385- /// // Here you would normally perform operations that might generate telemetry
386- /// // but now they won't because the context has suppression enabled
387- /// }
388- ///
389- /// // Demonstrate the function
390- /// example_export_function();
391- /// ```
392- pub fn enter_telemetry_suppressed_scope ( ) -> ContextGuard {
393- Self :: map_current ( |cx| cx. with_telemetry_suppressed ( ) ) . attach ( )
394- }
395-
396- /// Returns whether telemetry is suppressed in the current context.
397- ///
398- /// This method is used by OpenTelemetry components to determine whether they should
399- /// generate new telemetry in the current execution context. It provides a performant
400- /// way to check the suppression state.
401- ///
402- /// End-users generally should not use this method directly, as it is primarily intended for
403- /// OpenTelemetry SDK components.
404- ///
405- ///
406- #[ inline]
407- pub fn is_current_telemetry_suppressed ( ) -> bool {
408- Self :: map_current ( |cx| cx. is_telemetry_suppressed ( ) )
409- }
410-
411333 #[ cfg( feature = "trace" ) ]
412334 pub ( crate ) fn current_with_synchronized_span ( value : SynchronizedSpan ) -> Self {
413- Self :: map_current ( |cx| Context {
335+ Context {
414336 span : Some ( Arc :: new ( value) ) ,
415- entries : cx. entries . clone ( ) ,
416- suppress_telemetry : cx. suppress_telemetry ,
417- } )
337+ entries : Context :: map_current ( |cx| cx. entries . clone ( ) ) ,
338+ }
418339 }
419340
420341 #[ cfg( feature = "trace" ) ]
421342 pub ( crate ) fn with_synchronized_span ( & self , value : SynchronizedSpan ) -> Self {
422343 Context {
423344 span : Some ( Arc :: new ( value) ) ,
424345 entries : self . entries . clone ( ) ,
425- suppress_telemetry : self . suppress_telemetry ,
426346 }
427347 }
428348}
@@ -445,9 +365,7 @@ impl fmt::Debug for Context {
445365 #[ cfg( not( feature = "trace" ) ) ]
446366 let entries = self . entries . as_ref ( ) . map_or ( 0 , |e| e. len ( ) ) ;
447367
448- dbg. field ( "entries count" , & entries)
449- . field ( "suppress_telemetry" , & self . suppress_telemetry )
450- . finish ( )
368+ dbg. field ( "entries count" , & entries) . finish ( )
451369 }
452370}
453371
@@ -985,158 +903,4 @@ mod tests {
985903 assert_eq ! ( Context :: current( ) . get:: <ValueA >( ) , None ) ;
986904 assert_eq ! ( Context :: current( ) . get:: <ValueB >( ) , None ) ;
987905 }
988-
989- #[ test]
990- fn test_is_telemetry_suppressed ( ) {
991- // Default context has suppression disabled
992- let cx = Context :: new ( ) ;
993- assert ! ( !cx. is_telemetry_suppressed( ) ) ;
994-
995- // With suppression enabled
996- let suppressed = cx. with_telemetry_suppressed ( ) ;
997- assert ! ( suppressed. is_telemetry_suppressed( ) ) ;
998- }
999-
1000- #[ test]
1001- fn test_with_telemetry_suppressed ( ) {
1002- // Start with a normal context
1003- let cx = Context :: new ( ) ;
1004- assert ! ( !cx. is_telemetry_suppressed( ) ) ;
1005-
1006- // Create a suppressed context
1007- let suppressed = cx. with_telemetry_suppressed ( ) ;
1008-
1009- // Original should remain unchanged
1010- assert ! ( !cx. is_telemetry_suppressed( ) ) ;
1011-
1012- // New context should be suppressed
1013- assert ! ( suppressed. is_telemetry_suppressed( ) ) ;
1014-
1015- // Test with values to ensure they're preserved
1016- let cx_with_value = cx. with_value ( ValueA ( 42 ) ) ;
1017- let suppressed_with_value = cx_with_value. with_telemetry_suppressed ( ) ;
1018-
1019- assert ! ( !cx_with_value. is_telemetry_suppressed( ) ) ;
1020- assert ! ( suppressed_with_value. is_telemetry_suppressed( ) ) ;
1021- assert_eq ! ( suppressed_with_value. get:: <ValueA >( ) , Some ( & ValueA ( 42 ) ) ) ;
1022- }
1023-
1024- #[ test]
1025- fn test_enter_telemetry_suppressed_scope ( ) {
1026- // Ensure we start with a clean context
1027- let _reset_guard = Context :: new ( ) . attach ( ) ;
1028-
1029- // Default context should not be suppressed
1030- assert ! ( !Context :: is_current_telemetry_suppressed( ) ) ;
1031-
1032- // Add an entry to the current context
1033- let cx_with_value = Context :: current ( ) . with_value ( ValueA ( 42 ) ) ;
1034- let _guard_with_value = cx_with_value. attach ( ) ;
1035-
1036- // Verify the entry is present and context is not suppressed
1037- assert_eq ! ( Context :: current( ) . get:: <ValueA >( ) , Some ( & ValueA ( 42 ) ) ) ;
1038- assert ! ( !Context :: is_current_telemetry_suppressed( ) ) ;
1039-
1040- // Enter a suppressed scope
1041- {
1042- let _guard = Context :: enter_telemetry_suppressed_scope ( ) ;
1043-
1044- // Verify suppression is active and the entry is still present
1045- assert ! ( Context :: is_current_telemetry_suppressed( ) ) ;
1046- assert ! ( Context :: current( ) . is_telemetry_suppressed( ) ) ;
1047- assert_eq ! ( Context :: current( ) . get:: <ValueA >( ) , Some ( & ValueA ( 42 ) ) ) ;
1048- }
1049-
1050- // After guard is dropped, should be back to unsuppressed and entry should still be present
1051- assert ! ( !Context :: is_current_telemetry_suppressed( ) ) ;
1052- assert ! ( !Context :: current( ) . is_telemetry_suppressed( ) ) ;
1053- assert_eq ! ( Context :: current( ) . get:: <ValueA >( ) , Some ( & ValueA ( 42 ) ) ) ;
1054- }
1055-
1056- #[ test]
1057- fn test_nested_suppression_scopes ( ) {
1058- // Ensure we start with a clean context
1059- let _reset_guard = Context :: new ( ) . attach ( ) ;
1060-
1061- // Default context should not be suppressed
1062- assert ! ( !Context :: is_current_telemetry_suppressed( ) ) ;
1063-
1064- // First level suppression
1065- {
1066- let _outer = Context :: enter_telemetry_suppressed_scope ( ) ;
1067- assert ! ( Context :: is_current_telemetry_suppressed( ) ) ;
1068-
1069- // Second level. This component is unaware of Suppression,
1070- // and just attaches a new context. Since it is from current,
1071- // it'll already have suppression enabled.
1072- {
1073- let _inner = Context :: current ( ) . with_value ( ValueA ( 1 ) ) . attach ( ) ;
1074- assert ! ( Context :: is_current_telemetry_suppressed( ) ) ;
1075- assert_eq ! ( Context :: current( ) . get:: <ValueA >( ) , Some ( & ValueA ( 1 ) ) ) ;
1076- }
1077-
1078- // Another scenario. This component is unaware of Suppression,
1079- // and just attaches a new context, not from Current. Since it is
1080- // not from current it will not have suppression enabled.
1081- {
1082- let _inner = Context :: new ( ) . with_value ( ValueA ( 1 ) ) . attach ( ) ;
1083- assert ! ( !Context :: is_current_telemetry_suppressed( ) ) ;
1084- assert_eq ! ( Context :: current( ) . get:: <ValueA >( ) , Some ( & ValueA ( 1 ) ) ) ;
1085- }
1086-
1087- // Still suppressed after inner scope
1088- assert ! ( Context :: is_current_telemetry_suppressed( ) ) ;
1089- }
1090-
1091- // Back to unsuppressed
1092- assert ! ( !Context :: is_current_telemetry_suppressed( ) ) ;
1093- }
1094-
1095- #[ tokio:: test( flavor = "multi_thread" , worker_threads = 4 ) ]
1096- async fn test_async_suppression ( ) {
1097- async fn nested_operation ( ) {
1098- assert ! ( Context :: is_current_telemetry_suppressed( ) ) ;
1099-
1100- let cx_with_additional_value = Context :: current ( ) . with_value ( ValueB ( 24 ) ) ;
1101-
1102- async {
1103- assert_eq ! (
1104- Context :: current( ) . get:: <ValueB >( ) ,
1105- Some ( & ValueB ( 24 ) ) ,
1106- "Parent value should still be available after adding new value"
1107- ) ;
1108- assert ! ( Context :: is_current_telemetry_suppressed( ) ) ;
1109-
1110- // Do some async work to simulate real-world scenario
1111- sleep ( Duration :: from_millis ( 10 ) ) . await ;
1112-
1113- // Values should still be available after async work
1114- assert_eq ! (
1115- Context :: current( ) . get:: <ValueB >( ) ,
1116- Some ( & ValueB ( 24 ) ) ,
1117- "Parent value should still be available after adding new value"
1118- ) ;
1119- assert ! ( Context :: is_current_telemetry_suppressed( ) ) ;
1120- }
1121- . with_context ( cx_with_additional_value)
1122- . await ;
1123- }
1124-
1125- // Set up suppressed context, but don't attach it to current
1126- let suppressed_parent = Context :: new ( ) . with_telemetry_suppressed ( ) ;
1127- // Current should not be suppressed as we haven't attached it
1128- assert ! ( !Context :: is_current_telemetry_suppressed( ) ) ;
1129-
1130- // Create and run async operation with the suppressed context explicitly propagated
1131- nested_operation ( )
1132- . with_context ( suppressed_parent. clone ( ) )
1133- . await ;
1134-
1135- // After async operation completes:
1136- // Suppression should be active
1137- assert ! ( suppressed_parent. is_telemetry_suppressed( ) ) ;
1138-
1139- // Current should still be not suppressed
1140- assert ! ( !Context :: is_current_telemetry_suppressed( ) ) ;
1141- }
1142906}
0 commit comments