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

Skip to content

Commit 270ff43

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

File tree

6 files changed

+103
-63
lines changed

6 files changed

+103
-63
lines changed

sentry_sdk/hub.py

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -366,8 +366,8 @@ def span(self, span=None, **kwargs):
< 8000 /td>
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.start_trace(**kwargs))
371371

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

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

384386
def capture_trace(self, span):
385-
if span.transaction is None:
386-
return None
387-
388-
client = self.client
389-
390-
if client is None:
387+
if (
388+
span.transaction is None
389+
or span.timestamp is None
390+
or self.client is None
391+
or span.sampled is False
392+
):
391393
return None
392394

393-
sample_rate = client.options["traces_sample_rate"]
395+
sample_rate = self.client.options["traces_sample_rate"]
394396
if sample_rate < 1.0 and random.random() >= sample_rate:
395397
return None
396398

397399
return self.capture_event(
398-
{"type": "none", "spans": [s.to_json() for s in span._finished_spans]}
400+
{
401+
"type": "transaction",
402+
"contexts": {"trace": span.get_trace_context()},
403+
"timestamp": span.timestamp,
404+
"start_timestamp": span.start_timestamp,
405+
"spans": [s.to_json() for s in span._finished_spans if s is not span],
406+
}
399407
)
400408

401409
@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-
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: 40 additions & 31 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
@@ -89,7 +95,7 @@ def continue_from_headers(cls, headers):
8995
parent = cls.from_traceparent(headers.get("sentry-trace"))
9096
if parent is None:
9197
return cls.start_trace()
92-
return parent.new_span("follows_from")
98+
return parent.new_span(same_process_as_parent=False)
9399

94100
def iter_headers(self):
95101
yield "sentry-trace", self.to_traceparent()
@@ -110,31 +116,34 @@ def from_traceparent(cls, traceparent):
110116
if span_id is not None:
111117
span_id = int(span_id, 16)
112118
if sampled is not None:
113-
sampled = sampled == "1"
119+
sampled = sampled != "0"
114120

115121
return cls(trace_id=trace_id, span_id=span_id, sampled=sampled)
116122

117123
def to_traceparent(self):
118-
return "%s-%s-%s" % (
119-
self.trace_id,
120-
self.span_id,
121-
"1" if not self.sampled else "0",
122-
)
124+
return "%s-%s-%s" % (self.trace_id, self.span_id, "1" if self.sampled else "0")
123125

124126
def set_tag(self, key, value):
125127
self._tags[key] = value
126128

129+
def set_data(self, key, value):
130+
self._data[key] = value
131+
127132
def finish(self):
128-
self.end = datetime.now()
133+
self.timestamp = datetime.now()
129134
self._finished_spans.append(self)
130135

131136
def to_json(self):
132137
return {
133138
"trace_id": self.trace_id,
134139
"span_id": self.span_id,
135-
"ref_span_id": self.ref and self.ref.span_id or None,
140+
"parent_span_id": self.parent_span_id,
136141
"transaction": self.transaction,
137142
"tags": self._tags,
138-
"start": self.start,
139-
"end": self.end,
143+
"data": self._data,
144+
"start_timestamp": self.start_timestamp,
145+
"timestamp": self.timestamp,
140146
}
147+
148+
def get_trace_context(self):
149+
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