Skip to content

Commit 1b839c5

Browse files
committed
Update trace decorator to not use start_child
1 parent bc9af26 commit 1b839c5

File tree

4 files changed

+86
-94
lines changed

4 files changed

+86
-94
lines changed

sentry_sdk/tracing_utils.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -729,9 +729,10 @@ async def func_with_tracing(*args, **kwargs):
729729
)
730730
return await func(*args, **kwargs)
731731

732-
with span.start_child(
732+
with sentry_sdk.start_span(
733733
op=OP.FUNCTION,
734734
name=qualname_from_function(func),
735+
only_if_parent=True,
735736
):
736737
return await func(*args, **kwargs)
737738

@@ -757,9 +758,10 @@ def func_with_tracing(*args, **kwargs):
757758
)
758759
return func(*args, **kwargs)
759760

760-
with span.start_child(
761+
with sentry_sdk.start_span(
761762
op=OP.FUNCTION,
762763
name=qualname_from_function(func),
764+
only_if_parent=True,
763765
):
764766
return func(*args, **kwargs)
765767

tests/conftest.py

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@
33
import socket
44
import warnings
55
from threading import Thread
6-
from contextlib import contextmanager
76
from http.server import BaseHTTPRequestHandler, HTTPServer
8-
from unittest import mock
97

108
import pytest
119
import jsonschema
@@ -35,12 +33,6 @@
3533

3634
from tests import _warning_recorder, _warning_recorder_mgr
3735

38-
from typing import TYPE_CHECKING
39-
40-
if TYPE_CHECKING:
41-
from typing import Optional
42-
from collections.abc import Iterator
43-
4436

4537
SENTRY_EVENT_SCHEMA = "./checkouts/data-schemas/relay/event.schema.json"
4638

@@ -637,23 +629,6 @@ def werkzeug_set_cookie(client, servername, key, value):
637629
client.set_cookie(key, value)
638630

639631

640-
@contextmanager
641-
def patch_start_tracing_child(fake_transaction_is_none=False):
642-
# type: (bool) -> Iterator[Optional[mock.MagicMock]]
643-
if not fake_transaction_is_none:
644-
fake_transaction = mock.MagicMock()
645-
fake_start_child = mock.MagicMock()
646-
fake_transaction.start_child = fake_start_child
647-
else:
648-
fake_transaction = None
649-
fake_start_child = None
650-
651-
with mock.patch(
652-
"sentry_sdk.tracing_utils.get_current_span", return_value=fake_transaction
653-
):
654-
yield fake_start_child
655-
656-
657632
class ApproxDict(dict):
658633
def __eq__(self, other):
659634
# For an ApproxDict to equal another dict, the other dict just needs to contain

tests/test_basics.py

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -748,32 +748,36 @@ def _hello_world(word):
748748

749749

750750
def test_functions_to_trace(sentry_init, capture_events):
751-
functions_to_trace = [
752-
{"qualified_name": "tests.test_basics._hello_world"},
753-
{"qualified_name": "time.sleep"},
754-
]
755-
756-
sentry_init(
757-
traces_sample_rate=1.0,
758-
functions_to_trace=functions_to_trace,
759-
)
751+
original_sleep = time.sleep
752+
try:
753+
functions_to_trace = [
754+
{"qualified_name": "tests.test_basics._hello_world"},
755+
{"qualified_name": "time.sleep"},
756+
]
757+
758+
sentry_init(
759+
traces_sample_rate=1.0,
760+
functions_to_trace=functions_to_trace,
761+
)
760762

761-
events = capture_events()
763+
events = capture_events()
762764

763-
with start_span(name="something"):
764-
time.sleep(0)
765+
with start_span(name="something"):
766+
time.sleep(0)
765767

766-
for word in ["World", "You"]:
767-
_hello_world(word)
768+
for word in ["World", "You"]:
769+
_hello_world(word)
768770

769-
assert len(events) == 1
771+
assert len(events) == 1
770772

771-
(event,) = events
773+
(event,) = events
772774

773-
assert len(event["spans"]) == 3
774-
assert event["spans"][0]["description"] == "time.sleep"
775-
assert event["spans"][1]["description"] == "tests.test_basics._hello_world"
776-
assert event["spans"][2]["description"] == "tests.test_basics._hello_world"
775+
assert len(event["spans"]) == 3
776+
assert event["spans"][0]["description"] == "time.sleep"
777+
assert event["spans"][1]["description"] == "tests.test_basics._hello_world"
778+
assert event["spans"][2]["description"] == "tests.test_basics._hello_world"
779+
finally:
780+
time.sleep = original_sleep
777781

778782

779783
class WorldGreeter:

tests/tracing/test_decorator.py

Lines changed: 58 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@
33

44
import pytest
55

6+
import sentry_sdk
67
from sentry_sdk.tracing import trace
7-
from sentry_sdk.tracing_utils import start_child_span_decorator
88
from sentry_sdk.utils import logger
9-
from tests.conftest import patch_start_tracing_child
109

1110

1211
def my_example_function():
@@ -17,68 +16,80 @@ async def my_async_example_function():
1716
return "return_of_async_function"
1817

1918

20-
@pytest.mark.forked
21-
def test_trace_decorator():
22-
with patch_start_tracing_child() as fake_start_child:
19+
def test_trace_decorator(sentry_init, capture_events):
20+
sentry_init(traces_sample_rate=1.0)
21+
events = capture_events()
22+
23+
with sentry_sdk.start_span(name="test"):
2324
result = my_example_function()
24-
fake_start_child.assert_not_called()
2525
assert result == "return_of_sync_function"
2626

27-
result2 = start_child_span_decorator(my_example_function)()
28-
fake_start_child.assert_called_once_with(
29-
op="function", name="test_decorator.my_example_function"
30-
)
27+
result2 = trace(my_example_function)()
3128
assert result2 == "return_of_sync_function"
3229

30+
(event,) = events
31+
(span,) = event["spans"]
32+
assert span["op"] == "function"
33+
assert span["description"] == "test_decorator.my_example_function"
34+
35+
36+
def test_trace_decorator_no_trx(sentry_init, capture_events):
37+
sentry_init(traces_sample_rate=1.0)
38+
events = capture_events()
39+
40+
with mock.patch.object(logger, "debug", mock.Mock()) as fake_debug:
41+
result = my_example_function()
42+
assert result == "return_of_sync_function"
43+
fake_debug.assert_not_called()
3344

34-
@pytest.mark.forked
35-
def test_trace_decorator_no_trx():
36-
with patch_start_tracing_child(fake_transaction_is_none=True):
37-
with mock.patch.object(logger, "debug", mock.Mock()) as fake_debug:
38-
result = my_example_function()
39-
fake_debug.assert_not_called()
40-
assert result == "return_of_sync_function"
45+
result2 = trace(my_example_function)()
46+
assert result2 == "return_of_sync_function"
47+
fake_debug.assert_called_once_with(
48+
"Cannot create a child span for %s. "
49+
"Please start a Sentry transaction before calling this function.",
50+
"test_decorator.my_example_function",
51+
)
4152

42-
result2 = start_child_span_decorator(my_example_function)()
43-
fake_debug.assert_called_once_with(
44-
"Cannot create a child span for %s. "
45-
"Please start a Sentry transaction before calling this function.",
46-
"test_decorator.my_example_function",
47-
)
48-
assert result2 == "return_of_sync_function"
53+
assert len(events) == 0
4954

5055

51-
@pytest.mark.forked
5256
@pytest.mark.asyncio
53-
async def test_trace_decorator_async():
54-
with patch_start_tracing_child() as fake_start_child:
57+
async def test_trace_decorator_async(sentry_init, capture_events):
58+
sentry_init(traces_sample_rate=1.0)
59+
events = capture_events()
60+
61+
with sentry_sdk.start_span(name="test"):
5562
result = await my_async_example_function()
56-
fake_start_child.assert_not_called()
5763
assert result == "return_of_async_function"
5864

59-
result2 = await start_child_span_decorator(my_async_example_function)()
60-
fake_start_child.assert_called_once_with(
61-
op="function",
62-
name="test_decorator.my_async_example_function",
63-
)
65+
result2 = await trace(my_async_example_function)()
6466
assert result2 == "return_of_async_function"
6567

68+
(event,) = events
69+
(span,) = event["spans"]
70+
assert span["op"] == "function"
71+
assert span["description"] == "test_decorator.my_async_example_function"
72+
6673

6774
@pytest.mark.asyncio
68-
async def test_trace_decorator_async_no_trx():
69-
with patch_start_tracing_child(fake_transaction_is_none=True):
70-
with mock.patch.object(logger, "debug", mock.Mock()) as fake_debug:
71-
result = await my_async_example_function()
72-
fake_debug.assert_not_called()
73-
assert result == "return_of_async_function"
74-
75-
result2 = await start_child_span_decorator(my_async_example_function)()
76-
fake_debug.assert_called_once_with(
77-
"Cannot create a child span for %s. "
78-
"Please start a Sentry transaction before calling this function.",
79-
"test_decorator.my_async_example_function",
80-
)
81-
assert result2 == "return_of_async_function"
75+
async def test_trace_decorator_async_no_trx(sentry_init, capture_events):
76+
sentry_init(traces_sample_rate=1.0)
77+
events = capture_events()
78+
79+
with mock.patch.object(logger, "debug", mock.Mock()) as fake_debug:
80+
result = await my_async_example_function()
81+
fake_debug.assert_not_called()
82+
assert result == "return_of_async_function"
83+
84+
result2 = await trace(my_async_example_function)()
85+
fake_debug.assert_called_once_with(
86+
"Cannot create a child span for %s. "
87+
"Please start a Sentry transaction before calling this function.",
88+
"test_decorator.my_async_example_function",
89+
)
90+
assert result2 == "return_of_async_function"
91+
92+
assert len(events) == 0
8293

8394

8495
def test_functions_to_trace_signature_unchanged_sync(sentry_init):

0 commit comments

Comments
 (0)