diff --git a/sentry_sdk/integrations/opentelemetry/span_processor.py b/sentry_sdk/integrations/opentelemetry/span_processor.py index bf3ff62d1b..c7b3fa30ab 100644 --- a/sentry_sdk/integrations/opentelemetry/span_processor.py +++ b/sentry_sdk/integrations/opentelemetry/span_processor.py @@ -63,6 +63,7 @@ def __init__(self): self._children_spans = defaultdict( list ) # type: DefaultDict[int, List[ReadableSpan]] + self._dropped_spans = defaultdict(lambda: 0) # type: DefaultDict[int, int] def on_start(self, span, parent_context=None): # type: (Span, Optional[Context]) -> None @@ -143,12 +144,17 @@ def _flush_root_span(self, span): if not transaction_event: return + collected_spans, dropped_spans = self._collect_children(span) spans = [] - for child in self._collect_children(span): + for child in collected_spans: span_json = self._span_to_json(child) if span_json: spans.append(span_json) + transaction_event["spans"] = spans + if dropped_spans > 0: + transaction_event["_dropped_spans"] = dropped_spans + # TODO-neel-potel sort and cutoff max spans sentry_sdk.capture_event(transaction_event) @@ -166,25 +172,29 @@ def _append_child_span(self, span): children_spans = self._children_spans[span.parent.span_id] if len(children_spans) < max_spans: children_spans.append(span) + else: + self._dropped_spans[span.parent.span_id] += 1 def _collect_children(self, span): - # type: (ReadableSpan) -> List[ReadableSpan] + # type: (ReadableSpan) -> tuple[List[ReadableSpan], int] if not span.context: - return [] + return [], 0 children = [] + dropped_spans = 0 bfs_queue = deque() # type: Deque[int] bfs_queue.append(span.context.span_id) while bfs_queue: parent_span_id = bfs_queue.popleft() node_children = self._children_spans.pop(parent_span_id, []) + dropped_spans += self._dropped_spans.pop(parent_span_id, 0) children.extend(node_children) bfs_queue.extend( [child.context.span_id for child in node_children if child.context] ) - return children + return children, dropped_spans # we construct the event from scratch here # and not use the current Transaction class for easier refactoring diff --git a/tests/tracing/test_misc.py b/tests/tracing/test_misc.py index 0ff5fa6e7d..a807c6eb74 100644 --- a/tests/tracing/test_misc.py +++ b/tests/tracing/test_misc.py @@ -15,7 +15,7 @@ def test_span_trimming(sentry_init, capture_events): with start_span(name="hi"): for i in range(10): - with start_span(op="foo{}".format(i)): + with start_span(op=f"foo{i}"): pass (event,) = events @@ -29,7 +29,6 @@ def test_span_trimming(sentry_init, capture_events): assert event["_meta"]["spans"][""]["len"] == 10 assert "_dropped_spans" not in event - assert "dropped_spans" not in event def test_span_data_scrubbing_and_trimming(sentry_init, capture_events): @@ -42,7 +41,7 @@ def test_span_data_scrubbing_and_trimming(sentry_init, capture_events): span.set_data("datafoo", "databar") for i in range(10): - with start_span(op="foo{}".format(i)): + with start_span(op=f"foo{i}"): pass (event,) = events