Skip to content

Commit cd2f51b

Browse files
authored
feat(profiling): Add profile context to transaction (#1860)
This adds the profile context to the transaction envelope. See https://github.com/getsentry/rfcs/blob/main/text/0047-introduce-profile-context.md
1 parent d515233 commit cd2f51b

File tree

3 files changed

+45
-1
lines changed

3 files changed

+45
-1
lines changed

sentry_sdk/profiler.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,11 @@
103103
},
104104
)
105105

106+
ProfileContext = TypedDict(
107+
"ProfileContext",
108+
{"profile_id": str},
109+
)
110+
106111
try:
107112
from gevent.monkey import is_module_patched # type: ignore
108113
except ImportError:
@@ -343,6 +348,7 @@ def __init__(
343348
self.start_ns = 0 # type: int
344349
self.stop_ns = 0 # type: int
345350
self.active = False # type: bool
351+
self.event_id = uuid.uuid4().hex # type: str
346352

347353
self.indexed_frames = {} # type: Dict[RawFrame, int]
348354
self.indexed_stacks = {} # type: Dict[RawStackId, int]
@@ -352,6 +358,10 @@ def __init__(
352358

353359
transaction._profile = self
354360

361+
def get_profile_context(self):
362+
# type: () -> ProfileContext
363+
return {"profile_id": self.event_id}
364+
355365
def __enter__(self):
356366
# type: () -> None
357367
hub = self.hub or sentry_sdk.Hub.current
@@ -444,7 +454,7 @@ def to_json(self, event_opt, options):
444454

445455
return {
446456
"environment": event_opt.get("environment"),
447-
"event_id": uuid.uuid4().hex,
457+
"event_id": self.event_id,
448458
"platform": "python",
449459
"profile": profile,
450460
"release": event_opt.get("release", ""),

sentry_sdk/tracing.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -709,6 +709,7 @@ def finish(self, hub=None, end_timestamp=None):
709709

710710
if hub.client is not None and self._profile is not None:
711711
event["profile"] = self._profile
712+
contexts.update({"profile": self._profile.get_profile_context()})
712713

713714
if has_custom_measurements_enabled():
714715
event["measurements"] = self._measurements

tests/integrations/wsgi/test_wsgi.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,3 +323,36 @@ def test_app(environ, start_response):
323323
for item in envelope.items:
324324
count_item_types[item.type] += 1
325325
assert count_item_types["profile"] == profile_count
326+
327+
328+
def test_profile_context_sent(sentry_init, capture_envelopes, teardown_profiling):
329+
def test_app(environ, start_response):
330+
start_response("200 OK", [])
331+
return ["Go get the ball! Good dog!"]
332+
333+
sentry_init(
334+
traces_sample_rate=1.0,
335+
_experiments={"profiles_sample_rate": 1.0},
336+
)
337+
app = SentryWsgiMiddleware(test_app)
338+
envelopes = capture_envelopes()
339+
340+
client = Client(app)
341+
client.get("/")
342+
343+
transaction = None
344+
profile = None
345+
for envelope in envelopes:
346+
for item in envelope.items:
347+
if item.type == "profile":
348+
assert profile is None # should only have 1 profile
349+
profile = item
350+
elif item.type == "transaction":
351+
assert transaction is None # should only have 1 transaction
352+
transaction = item
353+
354+
assert transaction is not None
355+
assert profile is not None
356+
assert transaction.payload.json["contexts"]["profile"] == {
357+
"profile_id": profile.payload.json["event_id"],
358+
}

0 commit comments

Comments
 (0)