8000 ref: Instrument SQL, and change schema as discussed · getsentry/sentry-python@9cde1cd · GitHub
[go: up one dir, main page]

Skip to content

Commit 9cde1cd

Browse files
committed
ref: Instrument SQL, and change schema as discussed
1 parent cf9eda2 commit 9cde1cd

File tree

6 files changed

+104
-58
lines changed

6 files changed

+104
-58
lines changed

sentry_sdk/hub.py

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -366,8 +366,8 @@ def span(self, span=None, **kwargs):
366366
span.finish()
367367
self.capture_trace(span)
368368

369-
def trace(self, *args, **kwargs):
370-
return self.span(self.start_trace(*args, **kwargs))
369+
def trace(self, **kwargs):
370+
return self.span(self 8000 .start_trace(**kwargs))
371371

372372
def start_span(self, **kwargs):
373373
_, scope = self._stack[-1]
@@ -376,26 +376,36 @@ def start_span(self, **kwargs):
376376
return span.new_span(**kwargs)
377377
return None
378378

379-
def start_trace(self, transaction, **kwargs):
380-
_, scope = self._stack[-1]
381-
scope.span = span = Span.start_trace(transaction, **kwargs)
382-
return span
379+
def start_trace(self, **kwargs):
380+
span = Span.start_trace(**kwargs)
383381

384-
def capture_trace(self, span):
385-
if span.transaction is None:
382+
if self.client is None or span.sampled is False:
386383
return None
387384

388-
client = self.client
389-
390-
if client is None:
385+
sample_rate = self.client.options["traces_sample_rate"]
386+
if (
387+
sample_rate < 1.0
388+
and random.random() >= sample_rate
389+
and span.sampled is None
390+
):
391391
return None
392392

393-
sample_rate = client.options["traces_sample_rate"]
394-
if sample_rate < 1.0 and random.random() >= sample_rate:
393+
_, scope = self._stack[-1]
394+
scope.span = span
395+
return span
396+
397+
def capture_trace(self, span):
398+
if span.transaction is None or span.timestamp is None:
395399
return None
396400

397401
return self.capture_event(
398-
{"type": "none", "spans": [s.to_json() for s in span._finished_spans]}
402+
{
403+
"type": "transaction",
404+
"contexts": {"trace": span.get_trace_context()},
405+
"timestamp": span.timestamp,
406+
"start_timestamp": span.start_timestamp,
407+
"spans": [s.to_json() for s in span._finished_spans if s is not span],
408+
}
399409
)
400410

401411
@overload # noqa

sentry_sdk/integrations/django/__init__.py

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# -*- coding: utf-8 -*-
22
from __future__ import absolute_import
33

4+
import contextlib
45
import sys
56
import weakref
67

@@ -318,10 +319,12 @@ def format_sql(sql, params):
318319
return sql, rv
319320

320321

322+
@contextlib.contextmanager
321323
def record_sql(sql, params, cursor=None):
322324
# type: (Any, Any, Any) -> None
323325
hub = Hub.current
324326
if hub.get_integration(DjangoIntegration) is None:
327+
yield
325328
return
326329

327330
real_sql = None
@@ -353,9 +356,33 @@ def record_sql(sql, params, cursor=None):
353356
except Exception:
354357
pass
355358

359+
span = None
360+
356361
if real_sql:
357362
with capture_internal_exceptions():
358363
hub.add_breadcrumb(message=real_sql, category="query")
364+
span = hub.start_span(op="sql.query", description=real_sql)
365+
366+
if span is None:
367+
yield
368+
else:
369+
try:
370+
yield
371+
finally:
372+
span.set_tag("status", sys.exc_info()[1] is None)
373+
span.finish()
374+
375+
376+
@contextlib.contextmanager
377+
def record_many_sql(sql, param_list, cursor):
378+
ctxs = [record_sql(sql, params, cursor).__enter__() for params in param_list]
379+
380+
try:
381+
yield
382+
finally:
383+
einfo = sys.exc_info()
384+
for ctx in ctxs:
385+
ctx.__exit__(*einfo)
359386

360387

361388
def install_sql_hook():
@@ -373,21 +400,13 @@ def install_sql_hook():
373400
# This won't work on Django versions < 1.6
374401
return
375402

376-
def record_many_sql(sql, param_list, cursor):
377-
for params in param_list:
378-
record_sql(sql, params, cursor)
379-
380403
def execute(self, sql, params=None):
381-
try:
404+
with record_sql(sql, params, self.cursor):
382405
return real_execute(self, sql, params)
383-
finally:
384-
record_sql(sql, params, self.cursor)
385406

386407
def executemany(self, sql, param_list):
387-
try:
408+
with record_many_sql(sql, param_list, self.cursor):
388409
return real_executemany(self, sql, param_list)
389-
finally:
390-
record_many_sql(sql, param_list, self.cursor)
391410

392411
CursorWrapper.execute = execute
393412
CursorWrapper.executemany = executemany

sentry_sdk/integrations/stdlib.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,6 @@ def putrequest(self, method, url, *args, **kwargs):
2828
if hub.get_integration(StdlibIntegration) is None:
2929
return rv
3030

31-
self._sentrysdk_data_dict = data = {}
32-
self._sentrysdk_span = hub.start_span()
33-
3431
host = self.host
3532
port = self.port
3633
default_port = self.default_port
@@ -44,6 +41,11 @@ def putrequest(self, method, url, *args, **kwargs):
4441
url,
4542
)
4643

44+
self._sentrysdk_data_dict = data = {}
45+
self._sentrysdk_span = hub.start_span(
46+
op="http", description="%s %s" % (real_url, method)
47+
)
48+
4749
for key, value in hub.iter_trace_propagation_headers():
4850
self.putheader(key, value)
4951

@@ -66,6 +68,8 @@ def getresponse(self, *args, **kwargs):
6668
span = self._sentrysdk_span
6769
if span is not None:
6870
span.set_tag("status_code", rv.status)
71+
for k, v in data.items():
72+
span.set_data(k, v)
6973
span.finish()
7074

7175
hub.add_breadcrumb(

sentry_sdk/scope.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -212,10 +212,9 @@ def _drop(event, cause, ty):
212212
event.setdefault("contexts", {}).update(self._contexts)
213213

214214
if self._span is not None:
215 F42D -
event.setdefault("contexts", {})["trace"] = {
216-
"trace_id": self._span.trace_id,
217-
"span_id": self._span.span_id,
218-
}
215+
contexts = event.setdefault("contexts", {})
216+
if not contexts.get("trace"):
217+
contexts["trace"] = self._span.get_trace_context()
219218

220219
exc_info = hint.get("exc_info") if hint is not None else None
221220
if exc_info is not None:

sentry_sdk/tracing.py

Lines changed: 37 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -24,29 +24,41 @@ class Span(object):
2424
__slots__ = (
2525
"trace_id",
2626
"span_id",
27-
"ref",
28-
"ref_type",
27+
"parent_span_id",
28+
"same_process_as_parent",
2929
"sampled",
3030
"transaction",
31+
"op",
32+
"description",
33+
"start_timestamp",
34+
"timestamp",
3135
"_tags",
36+
"_data",
3237
"_finished_spans",
33-
"start",
34-
"end",
3538
)
3639

3740
def __init__(
38-
self, trace_id, span_id, transaction=None, ref=None, ref_type=None, sampled=None
41+
self,
42+
trace_id,
43+
span_id,
44+
parent_span_id=None,
45+
same_process_as_parent=True,
46+
sampled=None,
47+
transaction=None,
48+
op=None,
49+
description=None,
3950
):
4051
self.trace_id = trace_id
4152
self.span_id = span_id
42-
self.ref = ref
43-
self.ref_type = ref_type
53+
self.parent_span_id = parent_span_id
54+
self.same_process_as_parent = same_process_as_parent
4455
self.sampled = sampled
4556
self.transaction = transaction
4657
self._tags = {}
58+
self._data = {}
4759
self._finished_spans = []
48-
self.start = datetime.now()
49-
self.end = None
60+
self.start_timestamp = datetime.now()
61+
self.timestamp = None
5062

5163
def __repr__(self):
5264
return "<%s(transaction=%r, trace_id=%r, span_id=%r, ref=%r)>" % (
@@ -58,24 +70,18 @@ def __repr__(self):
5870
)
5971

6072
@classmethod
61-
def start_trace(cls, transaction=None, sampled=None):
62-
return cls(
63-
transaction=transaction,
64-
trace_id=uuid.uuid4().hex,
65-
span_id=uuid.uuid4().hex[16:],
66-
sampled=sampled,
67-
)
73+
def start_trace(cls, **kwargs):
74+
return cls(trace_id=uuid.uuid4().hex, span_id=uuid.uuid4().hex[16:], **kwargs)
6875

69-
def new_span(self, ref_type="child"):
76+
def new_span(self, **kwargs):
7077
if self.trace_id is None:
7178
return Span.start_trace()
7279

7380
rv = Span(
7481
trace_id=self.trace_id,
7582
span_id=uuid.uuid4().hex[16:],
76-
ref=self,
77-
ref_type=ref_type,
78-
sampled=self.sampled,
83+
parent_span_id=self.span_id,
84+
**kwargs
7985
)
8086
rv._finished_spans = self._finished_spans
8187
return rv
@@ -124,17 +130,24 @@ def to_traceparent(self):
124130
def set_tag(self, key, value):
125131
self._tags[key] = value
126132

133+
def set_data(self, key, value):
134+
self._data[key] = value
135+
127136
def finish(self):
128-
self.end = datetime.now()
137+
self.timestamp = datetime.now()
129138
self._finished_spans.append(self)
130139

131140
def to_json(self):
132141
return {
133142
"trace_id": self.trace_id,
134143
"span_id": self.span_id,
135-
"ref_span_id": self.ref and self.ref.span_id or None,
144+
"parent_span_id": self.parent_span_id,
136145
"transaction": self.transaction,
137146
"tags": self._tags,
138-
"start": self.start,
139-
"end": self.end,
147+
"data": self._data,
148+
"start_timestamp": self.start_timestamp,
149+
"timestamp": self.timestamp,
140150
}
151+
152+
def get_trace_context(self):
153+
return {"trace_id": self.trace_id, "span_id": self.span_id}

tests/test_tracing.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ def test_basic(sentry_init, capture_events, sample_rate):
88
sentry_init(traces_sample_rate=sample_rate)
99
events = capture_events()
1010

11-
with Hub.current.trace("hi"):
12-
with Hub.current.span():
13-
1 / 0
11+
with Hub.current.trace(transaction="hi"):
12+
with pytest.raises(ZeroDivisionError):
13+
with Hub.current.span():
14+
1 / 0
1415

1516
with Hub.current.span():
1617
pass

0 commit comments

Comments
 (0)
0