@@ -79,3 +79,107 @@ def fake_func(self):
7979 self .global_context = span_context
8080 self .global_trace_id = span_context .trace_id
8181 self .global_span_id = span_context .span_id
82+
83+ def print_square (self , num ):
84+ with self ._tracer .start_as_current_span ("square" ):
85+ return num * num
86+
87+ def print_cube (self , num ):
88+ with self ._tracer .start_as_current_span ("cube" ):
89+ return num * num * num
90+
91+ def print_square_with_thread (self , num ):
92+ with self ._tracer .start_as_current_span ("square" ):
93+ cube_thread = threading .Thread (target = self .print_cube , args = (10 ,))
94+
95+ cube_thread .start ()
96+ cube_thread .join ()
97+ return num * num
98+
99+ def calculate (self , num ):
100+ with self ._tracer .start_as_current_span ("calculate" ):
101+ square_thread = threading .Thread (
102+ target = self .print_square , args = (num ,)
103+ )
104+ cube_thread = threading .Thread (target = self .print_cube , args = (num ,))
105+ square_thread .start ()
106+ square_thread .join ()
107+
108+ cube_thread .start ()
109+ cube_thread .join ()
110+
111+ def test_without_thread_nesting (self ):
112+ square_thread = threading .Thread (target = self .print_square , args = (10 ,))
113+
114+ with self ._tracer .start_as_current_span ("root" ):
115+ square_thread .start ()
116+ square_thread .join ()
117+
118+ spans = self .memory_exporter .get_finished_spans ()
119+ self .assertEqual (len (spans ), 2 )
120+
121+ # pylint: disable=unbalanced-tuple-unpacking
122+ target , root = spans [:2 ]
123+
124+ self .assertIs (target .parent , root .get_span_context ())
125+ self .assertIsNone (root .parent )
126+
127+ def test_with_thread_nesting (self ):
128+ #
129+ # Following scenario is tested.
130+ # threadA -> methodA -> threadB -> methodB
131+ #
132+
133+ square_thread = threading .Thread (
134+ target = self .print_square_with_thread , args = (10 ,)
135+ )
136+
137+ with self ._tracer .start_as_current_span ("root" ):
138+ square_thread .start ()
139+ square_thread .join ()
140+
141+ spans = self .memory_exporter .get_finished_spans ()
142+
143+ self .assertEqual (len (spans ), 3 )
144+ # pylint: disable=unbalanced-tuple-unpacking
145+ cube , square , root = spans [:3 ]
146+
147+ self .assertIs (cube .parent , square .get_span_context ())
148+ self .assertIs (square .parent , root .get_span_context ())
149+ self .assertIsNone (root .parent )
150+
151+ def test_with_thread_multi_nesting (self ):
152+ #
153+ # Following scenario is tested.
154+ # / threadB -> methodB
155+ # threadA -> methodA ->
156+ # \ threadC -> methodC
157+ #
158+ calculate_thread = threading .Thread (target = self .calculate , args = (10 ,))
159+
160+ with self ._tracer .start_as_current_span ("root" ):
161+ calculate_thread .start ()
162+ calculate_thread .join ()
163+
164+ spans = self .memory_exporter .get_finished_spans ()
165+
166+ self .assertEqual (len (spans ), 4 )
167+
168+ # pylint: disable=unbalanced-tuple-unpacking
169+ cube , square , calculate , root = spans [:4 ]
170+
171+ self .assertIs (cube .parent , calculate .get_span_context ())
172+ self .assertIs (square .parent , calculate .get_span_context ())
173+ self .assertIs (calculate .parent , root .get_span_context ())
174+ self .assertIsNone (root .parent )
175+
176+ def test_uninstrumented (self ):
177+ ThreadingInstrumentor ().uninstrument ()
178+
179+ square_thread = threading .Thread (target = self .print_square , args = (10 ,))
180+ square_thread .start ()
181+ square_thread .join ()
182+ spans = self .memory_exporter .get_finished_spans ()
183+ self .assertEqual (len (spans ), 1 )
184+
185+ ThreadingInstrumentor ().instrument ()
0 commit comments