Skip to content

Commit 03a3269

Browse files
committed
Merge branch 'master' into py-2305-add-query-source-to-methods-that-were-missing-it
2 parents 310a2e3 + b3c6226 commit 03a3269

6 files changed

Lines changed: 252 additions & 171 deletions

File tree

scripts/populate_tox/package_dependencies.jsonl

Lines changed: 17 additions & 15 deletions
Large diffs are not rendered by default.

scripts/populate_tox/releases.jsonl

Lines changed: 31 additions & 29 deletions
Large diffs are not rendered by default.

tests/integrations/asyncpg/test_asyncpg.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,81 @@ async def test_query_source_enabled(
655655
assert SPANDATA.CODE_FUNCTION in data
656656

657657

658+
@pytest.mark.asyncio
659+
@pytest.mark.parametrize("span_streaming", [True, False])
660+
async def test_query_source(sentry_init, capture_events, capture_items, span_streaming):
661+
sentry_init(
662+
integrations=[AsyncPGIntegration()],
663+
traces_sample_rate=1.0,
664+
enable_db_query_source=True,
665+
db_query_source_threshold_ms=0,
666+
_experiments={
667+
"trace_lifecycle": "stream" if span_streaming else "static",
668+
},
669+
)
670+
671+
if span_streaming:
672+
items = capture_items("span")
673+
with sentry_sdk.traces.start_span(name="test_transaction"):
674+
conn: Connection = await connect(PG_CONNECTION_URI)
675+
676+
await conn.execute(
677+
"INSERT INTO users(name, password, dob) VALUES ('Alice', 'secret', '1990-12-25')",
678+
)
679+
680+
await conn.close()
681+
sentry_sdk.flush()
682+
683+
spans = [item.payload for item in items]
684+
685+
assert len(spans) == 3
686+
687+
connect_span = spans[0]
688+
insert_span = spans[1]
689+
segment = spans[2]
690+
691+
assert segment["name"] == "test_transaction"
692+
assert insert_span["name"].startswith("INSERT INTO")
693+
assert connect_span["name"] == "connect"
694+
data = insert_span.get("attributes", {})
695+
else:
696+
events = capture_events()
697+
698+
with start_transaction(name="test_transaction", sampled=True):
699+
conn: Connection = await connect(PG_CONNECTION_URI)
700+
701+
await conn.execute(
702+
"INSERT INTO users(name, password, dob) VALUES ('Alice', 'secret', '1990-12-25')",
703+
)
704+
705+
await conn.close()
706+
707+
(event,) = events
708+
span = event["spans"][-1]
709+
assert span["description"].startswith("INSERT INTO")
710+
data = span.get("data", {})
711+
712+
lineno_key = "code.line.number" if span_streaming else SPANDATA.CODE_LINENO
713+
filepath_key = "code.file.path" if span_streaming else SPANDATA.CODE_FILEPATH
714+
715+
assert lineno_key in data
716+
assert filepath_key in data
717+
assert SPANDATA.CODE_NAMESPACE in data
718+
assert SPANDATA.CODE_FUNCTION in data
719+
720+
assert type(data.get(lineno_key)) == int
721+
assert data.get(lineno_key) > 0
722+
assert (
723+
data.get(SPANDATA.CODE_NAMESPACE) == "tests.integrations.asyncpg.test_asyncpg"
724+
)
725+
assert data.get(filepath_key).endswith("tests/integrations/asyncpg/test_asyncpg.py")
726+
727+
is_relative_path = data.get(filepath_key)[0] != os.sep
728+
assert is_relative_path
729+
730+
assert data.get(SPANDATA.CODE_FUNCTION) == "test_query_source"
731+
732+
658733
@pytest.mark.asyncio
659734
@pytest.mark.parametrize("span_streaming", [True, False])
660735
async def test_query_source_with_module_in_search_path(

tests/integrations/django/test_basic.py

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -723,15 +723,17 @@ def test_transaction_style(
723723
):
724724
sentry_init(
725725
integrations=[DjangoIntegration(transaction_style=transaction_style)],
726+
traces_sample_rate=1.0,
726727
send_default_pii=True,
727728
)
728729
events = capture_events()
729730
content, status, headers = unpack_werkzeug_response(client.get(client_url))
730731
assert content == expected_response
731732

732-
(event,) = events
733-
assert event["transaction"] == expected_transaction
734-
assert event["transaction_info"] == {"source": expected_source}
733+
(error, transaction) = events
734+
assert error["transaction"] == expected_transaction
735+
assert transaction["transaction"] == expected_transaction
736+
assert transaction["transaction_info"] == {"source": expected_source}
735737

736738

737739
def test_request_body(sentry_init, client, capture_events):
@@ -1212,30 +1214,33 @@ def test_custom_urlconf_middleware(
12121214
)
12131215
events = capture_events()
12141216

1215-
content, status, _headers = unpack_werkzeug_response(client.get("/custom/ok"))
1216-
assert status.lower() == "200 ok"
1217-
assert content == b"custom ok"
1218-
1219-
event = events.pop(0)
1220-
assert event["transaction"] == "/custom/ok"
1221-
if middleware_spans:
1222-
assert "custom_urlconf_middleware" in render_span_tree(
1223-
event["spans"], event["contexts"]["trace"]
1224-
)
1217+
try:
1218+
content, status, _headers = unpack_werkzeug_response(client.get("/custom/ok"))
1219+
assert status.lower() == "200 ok"
1220+
assert content == b"custom ok"
1221+
1222+
event = events.pop(0)
1223+
assert event["transaction"] == "/custom/ok"
1224+
if middleware_spans:
1225+
assert "custom_urlconf_middleware" in render_span_tree(
1226+
event["spans"], event["contexts"]["trace"]
1227+
)
12251228

1226-
_content, status, _headers = unpack_werkzeug_response(client.get("/custom/exc"))
1227-
assert status.lower() == "500 internal server error"
1229+
_content, status, _headers = unpack_werkzeug_response(client.get("/custom/exc"))
1230+
assert status.lower() == "500 internal server error"
12281231

1229-
error_event, transaction_event = events
1230-
assert error_event["transaction"] == "/custom/exc"
1231-
assert error_event["exception"]["values"][-1]["mechanism"]["type"] == "django"
1232-
assert transaction_event["transaction"] == "/custom/exc"
1233-
if middleware_spans:
1234-
assert "custom_urlconf_middleware" in render_span_tree(
1235-
transaction_event["spans"], transaction_event["contexts"]["trace"]
1236-
)
1232+
error_event, transaction_event = events
1233+
assert error_event["transaction"] == "/custom/exc"
1234+
assert error_event["exception"]["values"][-1]["mechanism"]["type"] == "django"
1235+
assert transaction_event["transaction"] == "/custom/exc"
1236+
if middleware_spans:
1237+
assert "custom_urlconf_middleware" in render_span_tree(
1238+
transaction_event["spans"], transaction_event["contexts"]["trace"]
1239+
)
12371240

1238-
settings.MIDDLEWARE.pop(0)
1241+
finally:
1242+
settings.MIDDLEWARE.pop(0)
1243+
client.application.load_middleware()
12391244

12401245

12411246
def test_get_receiver_name():

tests/profiler/test_continuous_profiler.py

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -243,10 +243,6 @@ def assert_single_transaction_without_profile_chunks(envelopes):
243243
pytest.param(get_client_options(False), id="experiment"),
244244
],
245245
)
246-
@mock.patch(
247-
"sentry_sdk.profiler.continuous_profiler.ProfileBuffer.should_flush",
248-
lambda a, b: True,
249-
) # Force flushing profile of first transaction.
250246
def test_continuous_profiler_auto_start_and_manual_stop(
251247
sentry_init,
252248
capture_envelopes,
@@ -270,14 +266,11 @@ def test_continuous_profiler_auto_start_and_manual_stop(
270266
with sentry_sdk.start_span(op="op"):
271267
pass
272268

273-
# Wait so profiles are captured before assertions.
274-
sentry_sdk.profiler.continuous_profiler._scheduler.teardown()
275-
276-
assert_single_transaction_with_profile_chunks(envelopes, thread)
277-
278269
for _ in range(3):
279270
stop_profiler_func()
280271

272+
assert_single_transaction_with_profile_chunks(envelopes, thread)
273+
281274
envelopes.clear()
282275

283276
with sentry_sdk.start_transaction(name="profiling"):
@@ -292,9 +285,11 @@ def test_continuous_profiler_auto_start_and_manual_stop(
292285

293286
with sentry_sdk.start_transaction(name="profiling"):
294287
with sentry_sdk.start_span(op="op"):
295-
time.sleep(0.05)
288+
pass
296289

297-
assert_single_transaction_with_profile_chunks(envelopes, thread)
290+
stop_profiler_func()
291+
292+
assert_single_transaction_with_profile_chunks(envelopes, thread)
298293

299294

300295
@pytest.mark.parametrize(
@@ -431,12 +426,12 @@ def test_continuous_profiler_manual_start_and_stop_unsampled(
431426

432427
with sentry_sdk.start_transaction(name="profiling"):
433428
with sentry_sdk.start_span(op="op"):
434-
time.sleep(0.05)
435-
436-
assert_single_transaction_without_profile_chunks(envelopes)
429+
pass
437430

438431
stop_profiler_func()
439432

433+
assert_single_transaction_without_profile_chunks(envelopes)
434+
440435

441436
@pytest.mark.parametrize(
442437
"mode",
@@ -629,7 +624,6 @@ def test_continuous_profiler_manual_start_and_stop_noop_when_using_trace_lifecyl
629624
mock_teardown.assert_not_called()
630625

631626

632-
@mock.patch("sentry_sdk.profiler.continuous_profiler.PROFILE_BUFFER_SECONDS", 0.01)
633627
def test_continuous_profiler_run_does_not_null_buffer(
634628
sentry_init,
635629
capture_envelopes,
@@ -662,8 +656,7 @@ def test_continuous_profiler_run_does_not_null_buffer(
662656
envelopes.clear()
663657
with sentry_sdk.start_transaction(name="profiling"):
664658
with sentry_sdk.start_span(op="op"):
665-
time.sleep(0.1)
666-
assert_single_transaction_with_profile_chunks(envelopes, thread)
659+
pass
667660

668661
# Get the scheduler and create a sentinel buffer.
669662
# We'll call run() directly to verify it doesn't null out self.buffer.
@@ -673,6 +666,8 @@ def test_continuous_profiler_run_does_not_null_buffer(
673666
# Stop the profiler so the thread exits cleanly
674667
stop_profiler()
675668

669+
assert_single_transaction_with_profile_chunks(envelopes, thread)
670+
676671
# Now set up a fresh buffer and mark the scheduler as not running
677672
# (simulating the state right after ensure_running() created a new buffer
678673
# but the old thread hasn't done cleanup yet).

0 commit comments

Comments
 (0)