@@ -32,6 +32,10 @@ def span_event_start_fmt(span_processor_name, span_name):
3232 return span_processor_name + ":" + span_name + ":start"
3333
3434
35+ def span_event_ending_fmt (span_processor_name , span_name ):
36+ return span_processor_name + ":" + span_name + ":ending"
37+
38+
3539def span_event_end_fmt (span_processor_name , span_name ):
3640 return span_processor_name + ":" + span_name + ":end"
3741
@@ -50,6 +54,11 @@ def on_end(self, span: "trace.Span") -> None:
5054 self .span_list .append (span_event_end_fmt (self .name , span .name ))
5155
5256
57+ class MyExtendedSpanProcessor (MySpanProcessor ):
58+ def _on_ending (self , span : "trace.Span" ) -> None :
59+ self .span_list .append (span_event_ending_fmt (self .name , span .name ))
60+
61+
5362class TestSpanProcessor (unittest .TestCase ):
5463 def test_span_processor (self ):
5564 tracer_provider = trace .TracerProvider ()
@@ -120,6 +129,84 @@ def test_span_processor(self):
120129 # compare if two lists are the same
121130 self .assertListEqual (spans_calls_list , expected_list )
122131
132+ def test_span_processor_with_on_ending (self ):
133+ tracer_provider = trace .TracerProvider ()
134+ tracer = tracer_provider .get_tracer (__name__ )
135+
136+ spans_calls_list = [] # filled by MySpanProcessor
137+ expected_list = [] # filled by hand
138+
139+ # Span processors are created but not added to the tracer yet
140+ sp1 = MyExtendedSpanProcessor ("SP1" , spans_calls_list )
141+ sp2 = MyExtendedSpanProcessor ("SP2" , spans_calls_list )
142+
143+ with tracer .start_as_current_span ("foo" ):
144+ with tracer .start_as_current_span ("bar" ):
145+ with tracer .start_as_current_span ("baz" ):
146+ pass
147+
148+ # at this point lists must be empty
149+ self .assertEqual (len (spans_calls_list ), 0 )
150+
151+ # add single span processor
152+ tracer_provider .add_span_processor (sp1 )
153+
154+ with tracer .start_as_current_span ("foo" ):
155+ expected_list .append (span_event_start_fmt ("SP1" , "foo" ))
156+
157+ with tracer .start_as_current_span ("bar" ):
158+ expected_list .append (span_event_start_fmt ("SP1" , "bar" ))
159+
160+ with tracer .start_as_current_span ("baz" ):
161+ expected_list .append (span_event_start_fmt ("SP1" , "baz" ))
162+
163+ expected_list .append (span_event_ending_fmt ("SP1" , "baz" ))
164+ expected_list .append (span_event_end_fmt ("SP1" , "baz" ))
165+
166+ expected_list .append (span_event_ending_fmt ("SP1" , "bar" ))
167+ expected_list .append (span_event_end_fmt ("SP1" , "bar" ))
168+
169+ expected_list .append (span_event_ending_fmt ("SP1" , "foo" ))
170+ expected_list .append (span_event_end_fmt ("SP1" , "foo" ))
171+
172+ self .assertListEqual (spans_calls_list , expected_list )
173+
174+ spans_calls_list .clear ()
175+ expected_list .clear ()
176+
177+ # go for multiple span processors
178+ tracer_provider .add_span_processor (sp2 )
179+
180+ with tracer .start_as_current_span ("foo" ):
181+ expected_list .append (span_event_start_fmt ("SP1" , "foo" ))
182+ expected_list .append (span_event_start_fmt ("SP2" , "foo" ))
183+
184+ with tracer .start_as_current_span ("bar" ):
185+ expected_list .append (span_event_start_fmt ("SP1" , "bar" ))
186+ expected_list .append (span_event_start_fmt ("SP2" , "bar" ))
187+
188+ with tracer .start_as_current_span ("baz" ):
189+ expected_list .append (span_event_start_fmt ("SP1" , "baz" ))
190+ expected_list .append (span_event_start_fmt ("SP2" , "baz" ))
191+
192+ expected_list .append (span_event_ending_fmt ("SP1" , "baz" ))
193+ expected_list .append (span_event_ending_fmt ("SP2" , "baz" ))
194+ expected_list .append (span_event_end_fmt ("SP1" , "baz" ))
195+ expected_list .append (span_event_end_fmt ("SP2" , "baz" ))
196+
197+ expected_list .append (span_event_ending_fmt ("SP1" , "bar" ))
198+ expected_list .append (span_event_ending_fmt ("SP2" , "bar" ))
199+ expected_list .append (span_event_end_fmt ("SP1" , "bar" ))
200+ expected_list .append (span_event_end_fmt ("SP2" , "bar" ))
201+
202+ expected_list .append (span_event_ending_fmt ("SP1" , "foo" ))
203+ expected_list .append (span_event_ending_fmt ("SP2" , "foo" ))
204+ expected_list .append (span_event_end_fmt ("SP1" , "foo" ))
205+ expected_list .append (span_event_end_fmt ("SP2" , "foo" ))
206+
207+ # compare if two lists are the same
208+ self .assertListEqual (spans_calls_list , expected_list )
209+
123210 def test_add_span_processor_after_span_creation (self ):
124211 tracer_provider = trace .TracerProvider ()
125212 tracer = tracer_provider .get_tracer (__name__ )
@@ -176,6 +263,20 @@ def test_on_start(self):
176263 )
177264 multi_processor .shutdown ()
178265
266+ def test_on_ending (self ):
267+ multi_processor = self .create_multi_span_processor ()
268+
269+ mocks = [mock .Mock (spec = trace .SpanProcessor ) for _ in range (0 , 5 )]
270+ for mock_processor in mocks :
271+ multi_processor .add_span_processor (mock_processor )
272+
273+ span = self .create_default_span ()
274+ multi_processor ._on_ending (span )
275+
276+ for mock_processor in mocks :
277+ mock_processor ._on_ending .assert_called_once_with (span )
278+ multi_processor .shutdown ()
279+
179280 def test_on_end (self ):
180281 multi_processor = self .create_multi_span_processor ()
181282
0 commit comments