@@ -76,6 +76,53 @@ mod tests {
7676 Context , KeyValue ,
7777 } ;
7878
79+ #[ test]
80+ fn span_modification_via_context ( ) {
81+ let exporter = InMemorySpanExporterBuilder :: new ( ) . build ( ) ;
82+ let provider = SdkTracerProvider :: builder ( )
83+ . with_span_processor ( SimpleSpanProcessor :: new ( exporter. clone ( ) ) )
84+ . build ( ) ;
85+ let tracer = provider. tracer ( "test_tracer" ) ;
86+
87+ #[ derive( Debug , PartialEq ) ]
88+ struct ValueA ( u64 ) ;
89+
90+ let span = tracer. start ( "span-name" ) ;
91+
92+ // start with Current, which should have no span
93+ let cx = Context :: current ( ) ;
94+ assert ! ( !cx. has_active_span( ) ) ;
95+
96+ // add span to context
97+ let cx_with_span = cx. with_span ( span) ;
98+ assert ! ( cx_with_span. has_active_span( ) ) ;
99+ assert ! ( !cx. has_active_span( ) ) ;
100+
101+ // modify the span by using span_ref from the context
102+ // this is the only way to modify the span as span
103+ // is moved to context.
104+ let span_ref = cx_with_span. span ( ) ;
105+ span_ref. set_attribute ( KeyValue :: new ( "attribute1" , "value1" ) ) ;
106+
107+ // create a new context, which should not affect the original
108+ let cx_with_span_and_more = cx_with_span. with_value ( ValueA ( 1 ) ) ;
109+
110+ // modify the span again using the new context.
111+ // this should still be using the original span itself.
112+ let span_ref_new = cx_with_span_and_more. span ( ) ;
113+ span_ref_new. set_attribute ( KeyValue :: new ( "attribute2" , "value2" ) ) ;
114+
115+ span_ref_new. end ( ) ;
116+
117+ let exported_spans = exporter
118+ . get_finished_spans ( )
119+ . expect ( "Spans are expected to be exported." ) ;
120+ // There should be a single span, with attributes from both modifications.
121+ assert_eq ! ( exported_spans. len( ) , 1 ) ;
122+ let span = & exported_spans[ 0 ] ;
123+ assert_eq ! ( span. attributes. len( ) , 2 ) ;
124+ }
125+
79126 #[ test]
80127 fn tracer_in_span ( ) {
81128 // Arrange
0 commit comments