Skip to content

Commit a53a1c2

Browse files
committed
more tests
1 parent 2383afa commit a53a1c2

2 files changed

Lines changed: 160 additions & 10 deletions

File tree

sentry_sdk/traces.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,6 @@ class StreamedSpan:
230230
"_scope",
231231
"_flags",
232232
"_context_manager_state",
233-
"_profile",
234233
"_continuous_profile",
235234
"_baggage",
236235
"sample_rate",
@@ -296,7 +295,6 @@ def __init__(
296295
self._sample_rand = _generate_sample_rand(self.trace_id)
297296

298297
self._flags: dict[str, bool] = {}
299-
self._profile = None
300298
self._continuous_profile: "Optional[ContinuousProfile]" = None
301299

302300
self._update_active_thread()
@@ -320,7 +318,7 @@ def __enter__(self) -> "StreamedSpan":
320318

321319
if self.is_segment():
322320
sampling_context = {
323-
"transaction_context": {
321+
"transaction_context": { # XXX[span-first]: rename?
324322
"trace_id": self.trace_id,
325323
"span_id": self.span_id,
326324
"parent_span_id": self.parent_span_id,
@@ -341,9 +339,6 @@ def __exit__(
341339
self, ty: "Optional[Any]", value: "Optional[Any]", tb: "Optional[Any]"
342340
) -> None:
343341
if self.is_segment():
344-
if self._profile is not None:
345-
self._profile.__exit__(ty, value, tb)
346-
347342
if self._continuous_profile is not None:
348343
self._continuous_profile.stop()
349344

@@ -440,6 +435,12 @@ def get_attributes(self) -> "Attributes":
440435
def set_attribute(self, key: str, value: "AttributeValue") -> None:
441436
self.attributes[key] = format_attribute(value)
442437

438+
def remove_attribute(self, key: str) -> None:
439+
try:
440+
del self.attributes[key]
441+
except KeyError:
442+
pass
443+
443444
def set_attributes(self, attributes: "Attributes") -> None:
444445
for key, value in attributes.items():
445446
self.set_attribute(key, value)

tests/tracing/test_span_streaming.py

Lines changed: 153 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import pytest
77

88
import sentry_sdk
9+
from sentry_sdk.traces import SegmentSource
910

1011
minimum_python_38 = pytest.mark.skipif(
1112
sys.version_info < (3, 8), reason="Asyncio tests need Python >= 3.8"
@@ -43,9 +44,9 @@ def test_start_span(sentry_init, capture_envelopes):
4344

4445
events = capture_envelopes()
4546

46-
with sentry_sdk.traces.start_span(name="segment"):
47-
with sentry_sdk.traces.start_span(name="child"):
48-
...
47+
with sentry_sdk.traces.start_span(name="segment") as segment:
48+
with sentry_sdk.traces.start_span(name="child") as child:
49+
assert child.segment == segment
4950

5051
sentry_sdk.get_client().flush()
5152
spans = envelopes_to_spans(events)
@@ -85,6 +86,7 @@ def test_start_span_no_context_manager(sentry_init, capture_envelopes):
8586
segment.start()
8687
child = sentry_sdk.traces.start_span(name="child")
8788
child.start()
89+
assert child.segment == segment
8890
child.finish()
8991
segment.finish()
9092

@@ -113,6 +115,37 @@ def test_start_span_no_context_manager(sentry_init, capture_envelopes):
113115
assert segment["status"] == "ok"
114116

115117

118+
def test_span_sampled_at_start(sentry_init, capture_envelopes):
119+
# Test that if a span is created without the context manager, it is sampled
120+
# at .start() time rather then creation time
121+
122+
def traces_sampler(sampling_context):
123+
assert "delayed_attribute" in sampling_context["attributes"]
124+
assert sampling_context["attributes"]["delayed_attribute"] == 12
125+
return 1.0
126+
127+
sentry_init(
128+
traces_sampler=traces_sampler,
129+
_experiments={"trace_lifecycle": "stream"},
130+
)
131+
132+
events = capture_envelopes()
133+
134+
segment = sentry_sdk.traces.start_span(name="segment")
135+
segment.set_attribute("delayed_attribute", 12)
136+
segment.start()
137+
segment.finish()
138+
139+
sentry_sdk.get_client().flush()
140+
spans = envelopes_to_spans(events)
141+
142+
assert len(spans) == 1
143+
(segment,) = spans
144+
145+
assert segment["name"] == "segment"
146+
assert segment["attributes"]["delayed_attribute"] == 12
147+
148+
116149
def test_start_span_attributes(sentry_init, capture_envelopes):
117150
sentry_init(
118151
traces_sample_rate=1.0,
@@ -165,6 +198,79 @@ def traces_sampler(sampling_context):
165198
assert span["attributes"]["my_attribute"] == "my_value"
166199

167200

201+
def test_span_attributes(sentry_init, capture_envelopes):
202+
sentry_init(
203+
traces_sample_rate=1.0,
204+
_experiments={"trace_lifecycle": "stream"},
205+
)
206+
207+
events = capture_envelopes()
208+
209+
class Class:
210+
pass
211+
212+
with sentry_sdk.traces.start_span(
213+
name="segment", attributes={"attribute1": "value"}
214+
) as span:
215+
assert span.get_attributes()["attribute1"] == "value"
216+
span.set_attribute("attribute2", 47)
217+
span.remove_attribute("attribute1")
218+
span.set_attributes({"attribute3": 4.5, "attribute4": False})
219+
assert "attribute1" not in span.get_attributes()
220+
attributes = span.get_attributes()
221+
assert attributes["attribute2"] == 47
222+
assert attributes["attribute3"] == 4.5
223+
assert attributes["attribute4"] is False
224+
225+
sentry_sdk.get_client().flush()
226+
spans = envelopes_to_spans(events)
227+
228+
assert len(spans) == 1
229+
(span,) = spans
230+
231+
assert span["name"] == "segment"
232+
assert "attribute1" not in span["attributes"]
233+
assert span["attributes"]["attribute2"] == 47
234+
assert span["attributes"]["attribute3"] == 4.5
235+
assert span["attributes"]["attribute4"] is False
236+
237+
238+
def test_span_attributes_serialize_early(sentry_init, capture_envelopes):
239+
sentry_init(
240+
traces_sample_rate=1.0,
241+
_experiments={"trace_lifecycle": "stream"},
242+
)
243+
244+
events = capture_envelopes()
245+
246+
class Class:
247+
pass
248+
249+
with sentry_sdk.traces.start_span(name="span") as span:
250+
span.set_attributes(
251+
{
252+
# arrays of different types will be serialized
253+
"attribute1": [123, "text"],
254+
# so will custom class instances
255+
"attribute2": Class(),
256+
}
257+
)
258+
attributes = span.get_attributes()
259+
assert isinstance(attributes["attribute1"], str)
260+
assert attributes["attribute1"] == "[123, 'text']"
261+
assert isinstance(attributes["attribute2"], str)
262+
assert "Class" in attributes["attribute2"]
263+
264+
sentry_sdk.get_client().flush()
265+
spans = envelopes_to_spans(events)
266+
267+
assert len(spans) == 1
268+
(span,) = spans
269+
270+
assert span["attributes"]["attribute1"] == "[123, 'text']"
271+
assert "Class" in span["attributes"]["attribute2"]
272+
273+
168274
def test_traces_sampler_drops_span(sentry_init, capture_envelopes):
169275
def traces_sampler(sampling_context):
170276
assert "attributes" in sampling_context
@@ -432,7 +538,6 @@ def traced_function(): ...
432538

433539

434540
@minimum_python_38
435-
@pytest.mark.asyncio
436541
def test_trace_decorator_async(sentry_init, capture_envelopes):
437542
sentry_init(
438543
traces_sample_rate=1.0,
@@ -459,6 +564,50 @@ async def traced_function(): ...
459564
assert span["status"] == "ok"
460565

461566

567+
def test_set_span_op(sentry_init, capture_envelopes):
568+
sentry_init(
569+
traces_sample_rate=1.0,
570+
_experiments={"trace_lifecycle": "stream"},
571+
)
572+
573+
events = capture_envelopes()
574+
575+
with sentry_sdk.traces.start_span(name="span") as span:
576+
span.set_op("function")
577+
assert span.get_attributes()["sentry.op"] == "function"
578+
579+
sentry_sdk.get_client().flush()
580+
spans = envelopes_to_spans(events)
581+
582+
assert len(spans) == 1
583+
(span,) = spans
584+
585+
assert span["name"] == "span"
586+
assert span["attributes"]["sentry.op"] == "function"
587+
588+
589+
def test_set_span_source(sentry_init, capture_envelopes):
590+
sentry_init(
591+
traces_sample_rate=1.0,
592+
_experiments={"trace_lifecycle": "stream"},
593+
)
594+
595+
events = capture_envelopes()
596+
597+
with sentry_sdk.traces.start_span(name="span") as span:
598+
span.set_source(SegmentSource.TASK)
599+
assert span.get_attributes()["sentry.span.source"] == SegmentSource.TASK.value
600+
601+
sentry_sdk.get_client().flush()
602+
spans = envelopes_to_spans(events)
603+
604+
assert len(spans) == 1
605+
(span,) = spans
606+
607+
assert span["name"] == "span"
608+
assert span["attributes"]["sentry.span.source"] == SegmentSource.TASK.value
609+
610+
462611
def test_transport_format(sentry_init, capture_envelopes):
463612
sentry_init(
464613
server_name="test-server",

0 commit comments

Comments
 (0)