Skip to content

Commit 0e6aa6d

Browse files
authored
feat(profiling): Support for multithreaded profiles (getsentry#1570)
A signal handler can only be installed on the main thread, this was the reason why we could not use signals to profile multithreaded programs. This change installs the signal handler during sdk initialization which should happen on the main thread. The timers are still started on the individual threads to allow for profiles being recorded from different threads.
1 parent 033b236 commit 0e6aa6d

File tree

8 files changed

+302
-162
lines changed

8 files changed

+302
-162
lines changed

sentry_sdk/_types.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
"attachment",
4646
"session",
4747
"internal",
48+
"profile",
4849
]
4950
SessionStatus = Literal["ok", "exited", "crashed", "abnormal"]
5051
EndpointType = Literal["store", "envelope"]

sentry_sdk/client.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,7 @@ def capture_event(
403403
if is_transaction:
404404
if "profile" in event_opt:
405405
event_opt["profile"]["transaction_id"] = event_opt["event_id"]
406+
event_opt["profile"]["environment"] = event_opt.get("environment")
406407
event_opt["profile"]["version_name"] = event_opt.get("release", "")
407408
envelope.add_profile(event_opt.pop("profile"))
408409
envelope.add_transaction(event_opt)

sentry_sdk/envelope.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,8 @@ def data_category(self):
252252
return "error"
253253
elif ty == "client_report":
254254
return "internal"
255+
elif ty == "profile":
256+
return "profile"
255257
else:
256258
return "default"
257259

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
from sentry_sdk.integrations import DidNotEnable, Integration
2+
from sentry_sdk.profiler import _setup_profiler
3+
4+
5+
class ProfilingIntegration(Integration):
6+
identifier = "profiling"
7+
8+
@staticmethod
9+
def setup_once():
10+
# type: () -> None
11+
try:
12+
_setup_profiler()
13+
except ValueError:
14+
raise DidNotEnable("Profiling can only be enabled from the main thread.")

sentry_sdk/integrations/wsgi.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from sentry_sdk.tracing import Transaction, TRANSACTION_SOURCE_ROUTE
1212
from sentry_sdk.sessions import auto_session_tracking
1313
from sentry_sdk.integrations._wsgi_common import _filter_headers
14-
from sentry_sdk.profiler import profiling
14+
from sentry_sdk.profiler import start_profiling
1515

1616
from sentry_sdk._types import MYPY
1717

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

132132
with hub.start_transaction(
133133
transaction, custom_sampling_context={"wsgi_environ": environ}
134-
), profiling(transaction, hub):
134+
), start_profiling(transaction, hub):
135135
try:
136136
rv = self.app(
137137
environ,

0 commit comments

Comments
 (0)