Skip to content

Commit 8830013

Browse files
committed
feat(profiling): Enable profiling on all transactions
Up to now, we've only been profiling WSGI transactions. This change will enable profiling for all transactions.
1 parent 43ca991 commit 8830013

File tree

5 files changed

+34
-24
lines changed

5 files changed

+34
-24
lines changed

sentry_sdk/hub.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,7 @@ def start_transaction(
547547
}
548548
sampling_context.update(custom_sampling_context)
549549
transaction._set_initial_sampling_decision(sampling_context=sampling_context)
550+
transaction._set_profiling_decision()
550551

551552
# we don't bother to keep spans if we already know we're not going to
552553
# send the transaction

sentry_sdk/integrations/asgi.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
from sentry_sdk.hub import Hub, _should_send_default_pii
1515
from sentry_sdk.integrations._wsgi_common import _filter_headers
1616
from sentry_sdk.integrations.modules import _get_installed_modules
17-
from sentry_sdk.profiler import start_profiling
1817
from sentry_sdk.sessions import auto_session_tracking
1918
from sentry_sdk.tracing import (
2019
SOURCE_FOR_STYLE,
@@ -176,7 +175,7 @@ async def _run_app(self, scope, callback):
176175

177176
with hub.start_transaction(
178177
transaction, custom_sampling_context={"asgi_scope": scope}
179-
), start_profiling(transaction, hub):
178+
):
180179
# XXX: Would be cool to have correct span status, but we
181180
# would have to wrap send(). That is a bit hard to do with
182181
# the current abstraction over ASGI 2/3.

sentry_sdk/integrations/wsgi.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
from sentry_sdk.tracing import Transaction, TRANSACTION_SOURCE_ROUTE
1313
from sentry_sdk.sessions import auto_session_tracking
1414
from sentry_sdk.integrations._wsgi_common import _filter_headers
15-
from sentry_sdk.profiler import start_profiling
1615

1716
from sentry_sdk._types import MYPY
1817

@@ -132,7 +131,7 @@ def __call__(self, environ, start_response):
132131

133132
with hub.start_transaction(
134133
transaction, custom_sampling_context={"wsgi_environ": environ}
135-
), start_profiling(transaction, hub):
134+
):
136135
try:
137136
rv = self.app(
138137
environ,

sentry_sdk/profiler.py

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ def __init__(
347347

348348
transaction._profile = self
349349

350-
def __enter__(self):
350+
def start(self):
351351
# type: () -> None
352352
hub = self.hub or sentry_sdk.Hub.current
353353

@@ -360,8 +360,8 @@ def __enter__(self):
360360
self.start_ns = nanosecond_time()
361361
self.scheduler.start_profiling(self)
362362

363-
def __exit__(self, ty, value, tb):
364-
# type: (Optional[Any], Optional[Any], Optional[Any]) -> None
363+
def stop(self):
364+
# type: () -> None
365365
self.scheduler.stop_profiling(self)
366366
self.stop_ns = nanosecond_time()
367367

@@ -370,6 +370,14 @@ def __exit__(self, ty, value, tb):
370370

371371
scope.profile = old_profile
372372

373+
def __enter__(self):
374+
# type: () -> None
375+
self.start()
376+
377+
def __exit__(self, ty, value, tb):
378+
# type: (Optional[Any], Optional[Any], Optional[Any]) -> None
379+
self.stop()
380+
373381
def write(self, ts, sample):
374382
# type: (int, RawSample) -> None
375383
if ts < self.start_ns:
@@ -477,6 +485,15 @@ def to_json(self, event_opt, options):
477485
],
478486
}
479487

488+
@staticmethod
489+
def from_transaction(transaction, hub):
490+
# type: (sentry_sdk.tracing.Transaction, Optional[sentry_sdk.Hub]) -> Optional[Profile]
491+
if not _should_profile(transaction, hub):
492+
return None
493+
494+
assert _scheduler is not None
495+
return Profile(_scheduler, transaction, hub)
496+
480497

481498
class Scheduler(object):
482499
mode = "unknown"
@@ -714,7 +731,7 @@ def run(self):
714731

715732

716733
def _should_profile(transaction, hub):
717-
# type: (sentry_sdk.tracing.Transaction, sentry_sdk.Hub) -> bool
734+
# type: (sentry_sdk.tracing.Transaction, Optional[sentry_sdk.Hub]) -> bool
718735

719736
# The corresponding transaction was not sampled,
720737
# so don't generate a profile for it.
@@ -725,6 +742,7 @@ def _should_profile(transaction, hub):
725742
if _scheduler is None:
726743
return False
727744

745+
hub = hub or sentry_sdk.Hub.current
728746
client = hub.client
729747

730748
# The client is None, so we can't get the sample rate.
@@ -740,17 +758,3 @@ def _should_profile(transaction, hub):
740758
return False
741759

742760
return random.random() < float(profiles_sample_rate)
743-
744-
745-
@contextmanager
746-
def start_profiling(transaction, hub=None):
747-
# type: (sentry_sdk.tracing.Transaction, Optional[sentry_sdk.Hub]) -> Generator[None, None, None]
748-
hub = hub or sentry_sdk.Hub.current
749-
750-
# if profiling was not enabled, this should be a noop
751-
if _should_profile(transaction, hub):
752-
assert _scheduler is not None
753-
with Profile(_scheduler, transaction, hub):
754-
yield
755-
else:
756-
yield

sentry_sdk/tracing.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import sentry_sdk
99
from sentry_sdk.consts import INSTRUMENTER
10+
from sentry_sdk.profiler import Profile
1011
from sentry_sdk.utils import logger
1112
from sentry_sdk._types import MYPY
1213

@@ -21,7 +22,6 @@
2122
from typing import Tuple
2223
from typing import Iterator
2324

24-
import sentry_sdk.profiler
2525
from sentry_sdk._types import Event, SamplingContext, MeasurementUnit
2626

2727
BAGGAGE_HEADER_NAME = "baggage"
@@ -604,7 +604,7 @@ def __init__(
604604
self._third_party_tracestate = third_party_tracestate
605605
self._measurements = {} # type: Dict[str, Any]
606606
self._contexts = {} # type: Dict[str, Any]
607-
self._profile = None # type: Optional[sentry_sdk.profiler.Profile]
607+
self._profile = None # type: Optional[Profile]
608608
self._baggage = baggage
609609
# for profiling, we want to know on which thread a transaction is started
610610
# to accurately show the active thread in the UI
@@ -708,6 +708,7 @@ def finish(self, hub=None, end_timestamp=None):
708708
} # type: Event
709709

710710
if hub.client is not None and self._profile is not None:
711+
self._profile.stop()
711712
event["profile"] = self._profile
712713

713714
if has_custom_measurements_enabled():
@@ -853,6 +854,12 @@ def _set_initial_sampling_decision(self, sampling_context):
853854
)
854855
)
855856

857+
def _set_profiling_decision(self):
858+
# type: () -> None
859+
self._profile = Profile.from_transaction(self, self.hub)
860+
if self._profile is not None:
861+
self._profile.start()
862+
856863

857864
class NoOpSpan(Span):
858865
def __repr__(self):

0 commit comments

Comments
 (0)