Skip to content

Commit 54a6cfd

Browse files
authored
Merge pull request #525 from UiPath/fix/terminal_display_trace_spans
fix: display trace spans in terminal realtime
2 parents 81a2db6 + 63e7f49 commit 54a6cfd

2 files changed

Lines changed: 31 additions & 33 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "uipath"
3-
version = "2.1.30"
3+
version = "2.1.31"
44
description = "Python SDK and CLI for UiPath Platform, enabling programmatic interaction with automation services, process management, and deployment tools."
55
readme = { file = "README.md", content-type = "text/markdown" }
66
requires-python = ">=3.10"

src/uipath/_cli/_dev/_terminal/_components/_details.py

Lines changed: 30 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -275,34 +275,38 @@ def _build_spans_tree(self, trace_messages: list[TraceMessage]):
275275
spans_tree = self.query_one("#spans-tree", Tree)
276276
root = spans_tree.root
277277

278-
# Group spans by parent relationship
279-
root_spans = []
280-
child_spans: Dict[str, List[TraceMessage]] = {}
281-
282-
for trace_msg in trace_messages:
283-
if not trace_msg.parent_span_id:
284-
root_spans.append(trace_msg)
285-
else:
286-
if trace_msg.parent_span_id not in child_spans:
287-
child_spans[trace_msg.parent_span_id] = []
288-
child_spans[trace_msg.parent_span_id].append(trace_msg)
278+
# Filter out spans without parents (artificial root spans)
279+
spans_by_id = {
280+
msg.span_id: msg for msg in trace_messages if msg.parent_span_id is not None
281+
}
289282

290-
# Build tree recursively
283+
# Build parent-to-children mapping once upfront
284+
children_by_parent: Dict[str, List[TraceMessage]] = {}
285+
for msg in spans_by_id.values():
286+
if msg.parent_span_id:
287+
if msg.parent_span_id not in children_by_parent:
288+
children_by_parent[msg.parent_span_id] = []
289+
children_by_parent[msg.parent_span_id].append(msg)
290+
291+
# Find root spans (parent doesn't exist in our filtered data)
292+
root_spans = [
293+
msg
294+
for msg in trace_messages
295+
if msg.parent_span_id and msg.parent_span_id not in spans_by_id
296+
]
297+
298+
# Build tree recursively for each root span
291299
for root_span in sorted(root_spans, key=lambda x: x.timestamp):
292-
if root_span.span_id in child_spans:
293-
for child in sorted(
294-
child_spans[root_span.span_id], key=lambda x: x.timestamp
295-
):
296-
self._add_span_node(root, child, child_spans)
300+
self._add_span_with_children(root, root_span, children_by_parent)
297301

298-
def _add_span_node(
302+
def _add_span_with_children(
299303
self,
300304
parent_node: TreeNode[str],
301305
trace_msg: TraceMessage,
302-
child_spans: Dict[str, List[TraceMessage]],
306+
children_by_parent: Dict[str, List[TraceMessage]],
303307
):
304-
"""Recursively add span nodes to the tree."""
305-
# Create display label for the span
308+
"""Recursively add a span and all its children."""
309+
# Create the node for this span
306310
color_map = {
307311
"started": "🔵",
308312
"running": "🟡",
@@ -311,26 +315,20 @@ def _add_span_node(
311315
"error": "🔴",
312316
}
313317
status_icon = color_map.get(trace_msg.status.lower(), "⚪")
314-
315318
duration_str = (
316319
f" ({trace_msg.duration_ms:.1f}ms)" if trace_msg.duration_ms else ""
317320
)
318321
label = f"{status_icon} {trace_msg.span_name}{duration_str}"
319322

320-
# Add node to tree
321323
node = parent_node.add(label)
322-
node.data = trace_msg.span_id # Store span_id for reference
324+
node.data = trace_msg.span_id
323325
self.span_tree_nodes[trace_msg.span_id] = node
324-
325326
node.expand()
326327

327-
# Add child spans (sorted by timestamp)
328-
if trace_msg.span_id in child_spans:
329-
sorted_children = sorted(
330-
child_spans[trace_msg.span_id], key=lambda x: x.timestamp
331-
)
332-
for child_span in sorted_children:
333-
self._add_span_node(node, child_span, child_spans)
328+
# Get children from prebuilt mapping - O(1) lookup
329+
children = children_by_parent.get(trace_msg.span_id, [])
330+
for child in sorted(children, key=lambda x: x.timestamp):
331+
self._add_span_with_children(node, child, children_by_parent)
334332

335333
def on_tree_node_selected(self, event: Tree.NodeSelected[str]) -> None:
336334
"""Handle span selection in the tree."""

0 commit comments

Comments
 (0)