Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions sentry_sdk/integrations/django/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -652,8 +652,8 @@ def execute(self, sql, params=None):
_set_db_data(span, self)
result = real_execute(self, sql, params)

with capture_internal_exceptions():
add_query_source(span)
with capture_internal_exceptions():
add_query_source(span)

return result

Expand All @@ -672,8 +672,8 @@ def executemany(self, sql, param_list):

result = real_executemany(self, sql, param_list)

with capture_internal_exceptions():
add_query_source(span)
with capture_internal_exceptions():
add_query_source(span)

return result

Expand Down
7 changes: 5 additions & 2 deletions sentry_sdk/integrations/django/templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,9 @@ def rendered_content(self):
name=_get_template_name_description(self.template_name),
origin=DjangoIntegration.origin,
) as span:
span.set_data("context", self.context_data)
if isinstance(self.context_data, dict):
for k, v in self.context_data.items():
span.set_data(f"context.{k}", v)
return real_rendered_content.fget(self)

SimpleTemplateResponse.rendered_content = rendered_content
Expand Down Expand Up @@ -101,7 +103,8 @@ def render(request, template_name, context=None, *args, **kwargs):
name=_get_template_name_description(template_name),
origin=DjangoIntegration.origin,
) as span:
span.set_data("context", context)
for k, v in context.items():
span.set_data(f"context.{k}", v)
return real_render(request, template_name, context, *args, **kwargs)

django.shortcuts.render = render
Expand Down
17 changes: 12 additions & 5 deletions tests/integrations/django/test_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
from werkzeug.test import Client

from django import VERSION as DJANGO_VERSION
from django.contrib.auth.models import User
from django.core.management import execute_from_command_line
from django.db.utils import OperationalError, ProgrammingError, DataError
from django.http.request import RawPostDataException
Expand Down Expand Up @@ -288,6 +287,9 @@ def test_user_captured(sentry_init, client, capture_events):
def test_queryset_repr(sentry_init, capture_events):
sentry_init(integrations=[DjangoIntegration()])
events = capture_events()

from django.contrib.auth.models import User

User.objects.create_user("john", "[email protected]", "johnpassword")

try:
Expand Down Expand Up @@ -374,7 +376,7 @@ def test_sql_queries(sentry_init, capture_events, with_integration):
crumb = event["breadcrumbs"]["values"][-1]

assert crumb["message"] == "SELECT count(*) FROM people_person WHERE foo = %s"
assert crumb["data"]["db.params"] == [123]
assert crumb["data"]["db.params"] == "[123]"


@pytest.mark.forked
Expand Down Expand Up @@ -409,7 +411,7 @@ def test_sql_dict_query_params(sentry_init, capture_events):
assert crumb["message"] == (
"SELECT count(*) FROM people_person WHERE foo = %(my_foo)s"
)
assert crumb["data"]["db.params"] == {"my_foo": 10}
assert crumb["data"]["db.params"] == str({"my_foo": 10})


@pytest.mark.forked
Expand Down Expand Up @@ -471,7 +473,7 @@ def test_sql_psycopg2_string_composition(sentry_init, capture_events, query):
(event,) = events
crumb = event["breadcrumbs"]["values"][-1]
assert crumb["message"] == ('SELECT %(my_param)s FROM "foobar"')
assert crumb["data"]["db.params"] == {"my_param": 10}
assert crumb["data"]["db.params"] == str({"my_param": 10})


@pytest.mark.forked
Expand Down Expand Up @@ -524,7 +526,7 @@ def test_sql_psycopg2_placeholders(sentry_init, capture_events):
{
"category": "query",
"data": {
"db.params": {"first_var": "fizz", "second_var": "not a date"},
"db.params": str({"first_var": "fizz", "second_var": "not a date"}),
"db.paramstyle": "format",
},
"message": 'insert into my_test_table ("foo", "bar") values (%(first_var)s, '
Expand Down Expand Up @@ -928,6 +930,11 @@ def test_render_spans(sentry_init, client, capture_events, render_span_tree):
transaction = events[0]
assert expected_line in render_span_tree(transaction)

render_span = next(
span for span in transaction["spans"] if span["op"] == "template.render"
)
assert "context.user_age" in render_span["data"]


if DJANGO_VERSION >= (1, 10):
EXPECTED_MIDDLEWARE_SPANS = """\
Expand Down
66 changes: 31 additions & 35 deletions tests/integrations/django/test_cache_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,9 @@ def test_cache_spans_item_size(sentry_init, client, capture_events, use_django_c

@pytest.mark.forked
@pytest_mark_django_db_decorator()
def test_cache_spans_get_many(sentry_init, capture_events, use_django_caching):
def test_cache_spans_get_many(
sentry_init, capture_events, use_django_caching, render_span_tree
):
sentry_init(
integrations=[
DjangoIntegration(
Expand All @@ -528,39 +530,34 @@ def test_cache_spans_get_many(sentry_init, capture_events, use_django_caching):

from django.core.cache import cache

with sentry_sdk.start_transaction():
with sentry_sdk.start_transaction(name="caches"):
cache.get_many([f"S{id}", f"S{id+1}"])
cache.set(f"S{id}", "Sensitive1")
cache.get_many([f"S{id}", f"S{id+1}"])

(transaction,) = events
assert len(transaction["spans"]) == 7

assert transaction["spans"][0]["op"] == "cache.get"
assert transaction["spans"][0]["description"] == f"S{id}, S{id+1}"

assert transaction["spans"][1]["op"] == "cache.get"
assert transaction["spans"][1]["description"] == f"S{id}"

assert transaction["spans"][2]["op"] == "cache.get"
assert transaction["spans"][2]["description"] == f"S{id+1}"

assert transaction["spans"][3]["op"] == "cache.put"
assert transaction["spans"][3]["description"] == f"S{id}"

assert transaction["spans"][4]["op"] == "cache.get"
assert transaction["spans"][4]["description"] == f"S{id}, S{id+1}"

assert transaction["spans"][5]["op"] == "cache.get"
assert transaction["spans"][5]["description"] == f"S{id}"

assert transaction["spans"][6]["op"] == "cache.get"
assert transaction["spans"][6]["description"] == f"S{id+1}"
assert (
render_span_tree(transaction)
== f"""\
- op="caches": description=null
- op="cache.get": description="S{id}, S{id+1}"
- op="cache.get": description="S{id}"
- op="cache.get": description="S{id+1}"
- op="cache.put": description="S{id}"
- op="cache.get": description="S{id}, S{id+1}"
- op="cache.get": description="S{id}"
- op="cache.get": description="S{id+1}"\
""" # noqa: E221
)


@pytest.mark.forked
@pytest_mark_django_db_decorator()
def test_cache_spans_set_many(sentry_init, capture_events, use_django_caching):
def test_cache_spans_set_many(
sentry_init, capture_events, use_django_caching, render_span_tree
):
sentry_init(
integrations=[
DjangoIntegration(
Expand All @@ -577,24 +574,23 @@ def test_cache_spans_set_many(sentry_init, capture_events, use_django_caching):

from django.core.cache import cache

with sentry_sdk.start_transaction():
with sentry_sdk.start_transaction(name="caches"):
cache.set_many({f"S{id}": "Sensitive1", f"S{id+1}": "Sensitive2"})
cache.get(f"S{id}")

(transaction,) = events
assert len(transaction["spans"]) == 4

assert transaction["spans"][0]["op"] == "cache.put"
assert transaction["spans"][0]["description"] == f"S{id}, S{id+1}"

assert transaction["spans"][1]["op"] == "cache.put"
assert transaction["spans"][1]["description"] == f"S{id}"

assert transaction["spans"][2]["op"] == "cache.put"
assert transaction["spans"][2]["description"] == f"S{id+1}"

assert transaction["spans"][3]["op"] == "cache.get"
assert transaction["spans"][3]["description"] == f"S{id}"
assert (
render_span_tree(transaction)
== f"""\
- op="caches": description=null
- op="cache.put": description="S{id}, S{id+1}"
- op="cache.put": description="S{id}"
- op="cache.put": description="S{id+1}"
- op="cache.get": description="S{id}"\
""" # noqa: E221
)


@pytest.mark.forked
Expand Down
85 changes: 38 additions & 47 deletions tests/integrations/django/test_db_query_data.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import os

import pytest
from contextlib import contextmanager
from datetime import datetime
from unittest import mock

Expand All @@ -15,7 +16,7 @@
from freezegun import freeze_time
from werkzeug.test import Client

from sentry_sdk import start_transaction
from sentry_sdk import start_transaction, start_span
from sentry_sdk.consts import SPANDATA
from sentry_sdk.integrations.django import DjangoIntegration
from sentry_sdk.tracing_utils import record_sql_queries
Expand Down Expand Up @@ -347,29 +348,24 @@ def test_no_query_source_if_duration_too_short(sentry_init, client, capture_even

events = capture_events()

class fake_record_sql_queries: # noqa: N801
def __init__(self, *args, **kwargs):
with freeze_time(datetime(2024, 1, 1, microsecond=0)):
with record_sql_queries(*args, **kwargs) as span:
self.span = span
freezer = freeze_time(datetime(2024, 1, 1, microsecond=99999))
freezer.start()

freezer.stop()

def __enter__(self):
return self.span

def __exit__(self, type, value, traceback):
pass

with mock.patch(
"sentry_sdk.integrations.django.record_sql_queries",
fake_record_sql_queries,
):
_, status, _ = unpack_werkzeug_response(
client.get(reverse("postgres_select_orm"))
)
def fake_start_span(*args, **kwargs): # noqa: N801
with freeze_time(datetime(2024, 1, 1, microsecond=0)):
return start_span(*args, **kwargs)

@contextmanager
def fake_record_sql_queries(*args, **kwargs): # noqa: N801
with freeze_time(datetime(2024, 1, 1, microsecond=99999)):
with record_sql_queries(*args, **kwargs) as span:
yield span

with mock.patch("sentry_sdk.start_span", fake_start_span):
with mock.patch(
"sentry_sdk.integrations.django.record_sql_queries",
fake_record_sql_queries,
):
_, status, _ = unpack_werkzeug_response(
client.get(reverse("postgres_select_orm"))
)

assert status == "200 OK"

Expand Down Expand Up @@ -407,29 +403,24 @@ def test_query_source_if_duration_over_threshold(sentry_init, client, capture_ev

events = capture_events()

class fake_record_sql_queries: # noqa: N801
def __init__(self, *args, **kwargs):
with freeze_time(datetime(2024, 1, 1, microsecond=0)):
with record_sql_queries(*args, **kwargs) as span:
self.span = span
freezer = freeze_time(datetime(2024, 1, 1, microsecond=99999))
freezer.start()

freezer.stop()

def __enter__(self):
return self.span

def __exit__(self, type, value, traceback):
pass

with mock.patch(
"sentry_sdk.integrations.django.record_sql_queries",
fake_record_sql_queries,
):
_, status, _ = unpack_werkzeug_response(
client.get(reverse("postgres_select_orm"))
)
def fake_start_span(*args, **kwargs): # noqa: N801
with freeze_time(datetime(2024, 1, 1, microsecond=0)):
return start_span(*args, **kwargs)

@contextmanager
def fake_record_sql_queries(*args, **kwargs): # noqa: N801
with freeze_time(datetime(2024, 1, 1, microsecond=100001)):
with record_sql_queries(*args, **kwargs) as span:
yield span

with mock.patch("sentry_sdk.start_span", fake_start_span):
with mock.patch(
"sentry_sdk.integrations.django.record_sql_queries",
fake_record_sql_queries,
):
_, status, _ = unpack_werkzeug_response(
client.get(reverse("postgres_select_orm"))
)

assert status == "200 OK"

Expand Down
1 change: 1 addition & 0 deletions tests/integrations/django/test_transactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
included_url_conf = ((re_path(r"^foo/bar/(?P<param>[\w]+)", lambda x: ""),), "")

from sentry_sdk.integrations.django.transactions import RavenResolver
from tests.integrations.django.myapp.wsgi import application # noqa: F401


example_url_conf = (
Expand Down
Loading