Skip to content

Commit aef6512

Browse files
committed
more ignore spans
1 parent 192c75a commit aef6512

5 files changed

Lines changed: 96 additions & 11 deletions

File tree

sentry_sdk/_types.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,7 @@ class TextPart(TypedDict):
364364
type: Literal["text"]
365365
content: str
366366

367-
IgnoreSpansName = Union[str, Pattern]
367+
IgnoreSpansName = Union[str, Pattern[str]]
368368
IgnoreSpansContext = TypedDict(
369369
"IgnoreSpansContext",
370370
{"name": IgnoreSpansName, "attributes": Attributes},

sentry_sdk/scope.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1235,13 +1235,19 @@ def start_streamed_span(
12351235
# Get currently active span
12361236
parent_span = self.span or self.get_current_scope().span # type: ignore
12371237

1238+
if isinstance(parent_span, NoOpStreamedSpan):
1239+
# If the parent is an ignored span, attempt to reparent to the
1240+
# first non-ignored ancestor
1241+
parent_span = parent_span.last_valid_parent
1242+
12381243
# If no specific parent_span provided and there is no currently
12391244
# active span, this is a segment
12401245
if parent_span is None:
12411246
propagation_context = self.get_active_propagation_context()
12421247

1248+
span: "Union[StreamedSpan, NoOpStreamedSpan]"
12431249
if is_ignored_span(name, attributes):
1244-
span = NoOpStreamedSpan(name=name, scope=self)
1250+
span = NoOpStreamedSpan(name=name, scope=self, last_valid_parent=None)
12451251
else:
12461252
span = StreamedSpan(
12471253
name=name,
@@ -1259,7 +1265,9 @@ def start_streamed_span(
12591265
# This is a child span; take propagation context from the parent span
12601266
with new_scope():
12611267
if is_ignored_span(name, attributes):
1262-
span = NoOpStreamedSpan(name=name, scope=self)
1268+
span = NoOpStreamedSpan(
1269+
name=name, scope=self, last_valid_parent=parent_span
1270+
)
12631271
else:
12641272
span = StreamedSpan(
12651273
name=name,

sentry_sdk/traces.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -632,16 +632,23 @@ def _set_segment_attributes(self) -> None:
632632

633633

634634
class NoOpStreamedSpan(StreamedSpan):
635-
def __init__(self, *args, **kwargs):
635+
# XXX[span-first]: make this actually no-op
636+
def __init__(
637+
self,
638+
*args: "Any",
639+
last_valid_parent: "Optional[StreamedSpan]" = None,
640+
**kwargs: "Any",
641+
):
636642
self._sampled = False
643+
self.last_valid_parent = last_valid_parent
637644

638645
def __enter__(self) -> "NoOpStreamedSpan":
639646
return self
640647

641648
def __exit__(
642649
self, ty: "Optional[Any]", value: "Optional[Any]", tb: "Optional[Any]"
643650
) -> None:
644-
return self
651+
return
645652

646653

647654
def trace(

sentry_sdk/tracing_utils.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1474,14 +1474,14 @@ def add_sentry_baggage_to_headers(
14741474
)
14751475

14761476

1477-
def is_ignored_span(name: str, attributes: "Attributes") -> bool:
1477+
def is_ignored_span(name: str, attributes: "Optional[Attributes]") -> bool:
14781478
client = sentry_sdk.get_client()
14791479
ignore_spans = (client.options.get("_experiments") or {}).get("ignore_spans")
14801480

14811481
if not ignore_spans:
14821482
return False
14831483

1484-
def _match_name(rule: "Union[str, Pattern]") -> bool:
1484+
def _match_name(rule: "Union[str, Pattern[str]]") -> bool:
14851485
if isinstance(rule, Pattern):
14861486
return bool(rule.match(name))
14871487
return rule == name
@@ -1499,14 +1499,19 @@ def _match_name(rule: "Union[str, Pattern]") -> bool:
14991499
name_matches = _match_name(rule["name"])
15001500

15011501
if "attributes" in rule:
1502-
for attribute, value in rule["attributes"].items():
1503-
if attribute not in attributes:
1504-
attributes_match = False
1505-
break
1502+
if not attributes:
1503+
attributes_match = False
1504+
else:
1505+
for attribute, value in rule["attributes"].items():
1506+
if attribute not in attributes:
1507+
attributes_match = False
1508+
break
15061509

15071510
if name_matches and attributes_match:
15081511
return True
15091512

1513+
return False
1514+
15101515

15111516
# Circular imports
15121517
from sentry_sdk.tracing import (

tests/tracing/test_span_streaming.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -954,7 +954,9 @@ def test_ignore_spans_promoting(sentry_init, capture_envelopes):
954954
assert len(spans) == 2
955955
(span1, span2) = spans
956956
assert span1["name"] == "not ignored 1"
957+
assert span1["parent_span_id"] is None
957958
assert span2["name"] == "not ignored 2"
959+
assert span2["parent_span_id"] is None
958960

959961

960962
def test_ignore_spans_reparenting(sentry_init, capture_envelopes):
@@ -985,6 +987,69 @@ def test_ignore_spans_reparenting(sentry_init, capture_envelopes):
985987
(span3, span1) = spans
986988
assert span1["name"] == "not ignored segment"
987989
assert span3["name"] == "not ignored child"
990+
assert span3["parent_span_id"] == span1["span_id"]
991+
992+
993+
def test_ignore_spans_set_ignored_span_as_parent(sentry_init, capture_envelopes):
994+
sentry_init(
995+
traces_sample_rate=1.0,
996+
_experiments={
997+
"trace_lifecycle": "stream",
998+
"ignore_spans": ["ignored"],
999+
},
1000+
)
1001+
1002+
events = capture_envelopes()
1003+
1004+
with sentry_sdk.traces.start_span(name="ignored") as ignored_span:
1005+
assert ignored_span.sampled is False
1006+
1007+
with sentry_sdk.traces.start_span(
1008+
name="not ignored", parent_span=ignored_span
1009+
) as span:
1010+
assert span.sampled is True
1011+
assert span.parent_span_id is None
1012+
1013+
sentry_sdk.get_client().flush()
1014+
spans = envelopes_to_spans(events)
1015+
1016+
assert len(spans) == 1
1017+
(span,) = spans
1018+
assert span["name"] == "not ignored"
1019+
assert span["parent_span_id"] is None
1020+
1021+
1022+
def test_ignore_spans_set_ignored_child_span_as_parent(sentry_init, capture_envelopes):
1023+
sentry_init(
1024+
traces_sample_rate=1.0,
1025+
_experiments={
1026+
"trace_lifecycle": "stream",
1027+
"ignore_spans": ["ignored"],
1028+
},
1029+
)
1030+
1031+
events = capture_envelopes()
1032+
1033+
with sentry_sdk.traces.start_span(name="not ignored segment") as segment:
1034+
assert segment.sampled is True
1035+
1036+
with sentry_sdk.traces.start_span(name="ignored") as ignored_span:
1037+
assert ignored_span.sampled is False
1038+
1039+
with sentry_sdk.traces.start_span(
1040+
name="not ignored child", parent_span=ignored_span
1041+
) as span:
1042+
assert span.sampled is True
1043+
assert span.parent_span_id == segment.span_id
1044+
1045+
sentry_sdk.get_client().flush()
1046+
spans = envelopes_to_spans(events)
1047+
1048+
assert len(spans) == 2
1049+
(child, segment) = spans
1050+
assert segment["name"] == "not ignored segment"
1051+
assert child["name"] == "not ignored child"
1052+
assert child["parent_span_id"] == segment["span_id"]
9881053

9891054

9901055
def test_transport_format(sentry_init, capture_envelopes):

0 commit comments

Comments
 (0)