@@ -61,6 +61,43 @@ def get_parent_context() -> context.Context:
6161 )
6262 return set_span_in_context (bottom_span )
6363
64+ @staticmethod
65+ def _build_ancestor_chain (span : ReadableSpan , spans_by_id : dict ) -> List [ReadableSpan ]:
66+ """Build a complete ancestor chain by traversing parents.
67+
68+ Args:
69+ span: The starting span
70+ spans_by_id: Dictionary to populate with discovered spans
71+
72+ Returns:
73+ List of ancestors from bottom (the span) to top (root)
74+ """
75+ chain = []
76+ current = span
77+ visited = set ()
78+
79+ while current :
80+ span_id = current .get_span_context ().span_id
81+
82+ # Avoid infinite loops
83+ if span_id in visited :
84+ break
85+ visited .add (span_id )
86+
87+ chain .append (current )
88+ spans_by_id [span_id ] = current
89+
90+ # Move to parent if it exists
91+ if current .parent :
92+ parent_id = current .parent .span_id
93+ # Try to get parent from already known spans
94+ current = spans_by_id .get (parent_id )
95+ # If not found, we can't traverse further
96+ else :
97+ break
98+
99+ return chain
100+
64101 @staticmethod
65102 def _get_bottom_most_span (
66103 current_span : ReadableSpan , external_span : ReadableSpan
@@ -80,102 +117,63 @@ def _get_bottom_most_span(
80117 current_span_id = current_span .get_span_context ().span_id
81118 external_span_id = external_span .get_span_context ().span_id
82119
83- current_parent_id = (
84- f"{ current_span .parent .span_id :016x} " if current_span .parent else "None"
85- )
86- external_parent_id = (
87- f"{ external_span .parent .span_id :016x} " if external_span .parent else "None"
88- )
89-
90- logger .info (
91- f"current_span: '{ current_span .name } ' (id: { current_span_id :016x} , parent: { current_parent_id } )"
92- )
93- logger .info (
94- f"external_span: '{ external_span .name } ' (id: { external_span_id :016x} , parent: { external_parent_id } )"
95- )
96-
97- # Build complete ancestor chain by combining external ancestors with both spans
120+ # Start by adding external ancestors to our known spans
98121 external_ancestors = UiPathTracingManager .get_ancestor_spans () or []
99-
100- # Create a map of all known spans by ID
101122 spans_by_id = {}
102123 for ancestor in external_ancestors :
103124 spans_by_id [ancestor .get_span_context ().span_id ] = ancestor
104125
105- # Add both current spans to the map
106- spans_by_id [ current_span_id ] = current_span
107- spans_by_id [ external_span_id ] = external_span
126+ # Build complete ancestor chains for both spans
127+ logger . info ( "Building ancestor chain for current_span..." )
128+ current_chain = UiPathTracingManager . _build_ancestor_chain ( current_span , spans_by_id )
108129
109- logger .info (f"Total known spans: { len (spans_by_id )} " )
110- logger .info ("All known spans:" )
111- for span in spans_by_id .values ():
112- span_id = span .get_span_context ().span_id
113- parent_id = f"{ span .parent .span_id :016x} " if span .parent else "None"
114- logger .info (f" { span .name } (id: { span_id :016x} , parent: { parent_id } )" )
130+ logger .info ("Building ancestor chain for external_span..." )
131+ external_chain = UiPathTracingManager ._build_ancestor_chain (external_span , spans_by_id )
115132
116- # Check direct parent-child relationships
117- current_parent = current_span .parent
118- external_parent = external_span .parent
133+ logger .info (f"current_span chain length (depth): { len (current_chain )} " )
134+ logger .info (f"external_span chain length (depth): { len (external_chain )} " )
119135
120- # Check if current_span is a child of external_span
121- if current_parent and current_parent .span_id == external_span_id :
122- logger .info (f"RESULT: current_span '{ current_span .name } ' is a direct child of external_span -> returning current_span" )
123- logger .info ("=" * 80 )
124- return current_span
125-
126- # Check if external_span is a child of current_span
127- if external_parent and external_parent .span_id == current_span_id :
128- logger .info (f"RESULT: external_span '{ external_span .name } ' is a direct child of current_span -> returning external_span" )
129- logger .info ("=" * 80 )
130- return external_span
136+ # Log the chains
137+ logger .info ("current_span chain (bottom to top):" )
138+ for i , span in enumerate (current_chain ):
139+ span_id = span .get_span_context ().span_id
140+ parent_id = f"{ span .parent .span_id :016x} " if span .parent else "None"
141+ logger .info (f" [{ i } ] { span .name } (id: { span_id :016x} , parent: { parent_id } )" )
131142
132- # Check if parents are in the known spans - find which one is deeper
133- current_parent_span = spans_by_id .get (current_parent .span_id ) if current_parent else None
134- external_parent_span = spans_by_id .get (external_parent .span_id ) if external_parent else None
143+ logger .info ("external_span chain (bottom to top):" )
144+ for i , span in enumerate (external_chain ):
145+ span_id = span .get_span_context ().span_id
146+ parent_id = f"{ span .parent .span_id :016x} " if span .parent else "None"
147+ logger .info (f" [{ i } ] { span .name } (id: { span_id :016x} , parent: { parent_id } )" )
135148
136- if current_parent_span and not external_parent_span :
137- logger .info ("RESULT: current_span has a parent in the tree, external_span doesn't -> returning current_span" )
149+ # The span with the longer chain is deeper
150+ if len (current_chain ) > len (external_chain ):
151+ logger .info (f"RESULT: current_span is deeper (chain length { len (current_chain )} > { len (external_chain )} ) -> returning current_span" )
138152 logger .info ("=" * 80 )
139153 return current_span
140-
141- if external_parent_span and not current_parent_span :
142- logger .info ("RESULT: external_span has a parent in the tree, current_span doesn't -> returning external_span" )
154+ elif len (external_chain ) > len (current_chain ):
155+ logger .info (f"RESULT: external_span is deeper (chain length { len (external_chain )} > { len (current_chain )} ) -> returning external_span" )
143156 logger .info ("=" * 80 )
144157 return external_span
158+ else :
159+ # Same depth - check if one is an ancestor of the other
160+ current_span_ids = {s .get_span_context ().span_id for s in current_chain }
161+ external_span_ids = {s .get_span_context ().span_id for s in external_chain }
145162
146- # Both have parents in the tree - need to determine which is deeper
147- # Calculate depth by traversing parent chains
148- if current_parent_span and external_parent_span :
149- current_depth = 0
150- external_depth = 0
151-
152- # Count current_span ancestors
153- temp_span = current_span
154- while temp_span and temp_span .parent :
155- current_depth += 1
156- temp_span = spans_by_id .get (temp_span .parent .span_id )
157-
158- # Count external_span ancestors
159- temp_span = external_span
160- while temp_span and temp_span .parent :
161- external_depth += 1
162- temp_span = spans_by_id .get (temp_span .parent .span_id )
163-
164- logger .info (f"current_span depth: { current_depth } , external_span depth: { external_depth } " )
165-
166- if current_depth > external_depth :
167- logger .info (f"RESULT: current_span is deeper (depth { current_depth } > { external_depth } ) -> returning current_span" )
163+ if external_span_id in current_span_ids :
164+ logger .info ("RESULT: external_span is in current_span's chain -> returning current_span (deeper)" )
168165 logger .info ("=" * 80 )
169166 return current_span
170- else :
171- logger .info (f"RESULT: external_span is deeper (depth { external_depth } >= { current_depth } ) -> returning external_span" )
167+
168+ if current_span_id in external_span_ids :
169+ logger .info ("RESULT: current_span is in external_span's chain -> returning external_span (deeper)" )
172170 logger .info ("=" * 80 )
173171 return external_span
174172
175- # Default: return external_span
176- logger .info (f"RESULT: Cannot determine hierarchy -> defaulting to external_span ' { external_span . name } ' " )
177- logger .info ("=" * 80 )
178- return external_span
173+ # Same depth, different branches - default to external
174+ logger .info (f"RESULT: Same depth ( { len ( current_chain ) } ), different branches -> defaulting to external_span" )
175+ logger .info ("=" * 80 )
176+ return external_span
179177
180178 @staticmethod
181179 def get_external_current_span ():
0 commit comments