Skip to content

Commit 46eb82c

Browse files
Remove performance papercuts (#4675)
Removing some papercuts: * don't guess ASGI version everytime the middleware is initialized if we already know * remove debug logs (they're bad in async code) * use `.copy()` instead of copying stuff via constructor (e.g. `dict(old_old)`) * make UUID generation lazier Ref #4660 Closes #3908 --------- Co-authored-by: Neel Shah <[email protected]>
1 parent 775dae8 commit 46eb82c

File tree

9 files changed

+58
-57
lines changed

9 files changed

+58
-57
lines changed

sentry_sdk/integrations/asgi.py

Lines changed: 11 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
import sentry_sdk
1313
from sentry_sdk.api import continue_trace
1414
from sentry_sdk.consts import OP
15-
1615
from sentry_sdk.integrations._asgi_common import (
1716
_get_headers,
1817
_get_request_data,
@@ -42,7 +41,6 @@
4241

4342
if TYPE_CHECKING:
4443
from typing import Any
45-
from typing import Callable
4644
from typing import Dict
4745
from typing import Optional
4846
from typing import Tuple
@@ -102,6 +100,7 @@ def __init__(
102100
mechanism_type="asgi", # type: str
103101
span_origin="manual", # type: str
104102
http_methods_to_capture=DEFAULT_HTTP_METHODS_TO_CAPTURE, # type: Tuple[str, ...]
103+
asgi_version=None, # type: Optional[int]
105104
):
106105
# type: (...) -> None
107106
"""
@@ -140,10 +139,16 @@ def __init__(
140139
self.app = app
141140
self.http_methods_to_capture = http_methods_to_capture
142141

143-
if _looks_like_asgi3(app):
144-
self.__call__ = self._run_asgi3 # type: Callable[..., Any]
145-
else:
146-
self.__call__ = self._run_asgi2
142+
if asgi_version is None:
143+
if _looks_like_asgi3(app):
144+
asgi_version = 3
145+
else:
146+
asgi_version = 2
147+
148+
if asgi_version == 3:
149+
self.__call__ = self._run_asgi3
150+
elif asgi_version == 2:
151+
self.__call__ = self._run_asgi2 # type: ignore
147152

148153
def _capture_lifespan_exception(self, exc):
149154
# type: (Exception) -> None
@@ -217,28 +222,16 @@ async def _run_app(self, scope, receive, send, asgi_version):
217222
source=transaction_source,
218223
origin=self.span_origin,
219224
)
220-
logger.debug(
221-
"[ASGI] Created transaction (continuing trace): %s",
222-
transaction,
223-
)
224225
else:
225226
transaction = Transaction(
226227
op=OP.HTTP_SERVER,
227228
name=transaction_name,
228229
source=transaction_source,
229230
origin=self.span_origin,
230231
)
231-
logger.debug(
232-
"[ASGI] Created transaction (new): %s", transaction
233-
)
234232

235233
if transaction:
236234
transaction.set_tag("asgi.type", ty)
237-
logger.debug(
238-
"[ASGI] Set transaction name and source on transaction: '%s' / '%s'",
239-
transaction.name,
240-
transaction.source,
241-
)
242235

243236
with (
244237
sentry_sdk.start_transaction(
@@ -248,7 +241,6 @@ async def _run_app(self, scope, receive, send, asgi_version):
248241
if transaction is not None
249242
else nullcontext()
250243
):
251-
logger.debug("[ASGI] Started transaction: %s", transaction)
252244
try:
253245

254246
async def _sentry_wrapped_send(event):
@@ -303,12 +295,6 @@ def event_processor(self, event, hint, asgi_scope):
303295
event["transaction"] = name
304296
event["transaction_info"] = {"source": source}
305297

306-
logger.debug(
307-
"[ASGI] Set transaction name and source in event_processor: '%s' / '%s'",
308-
event["transaction"],
309-
event["transaction_info"]["source"],
310-
)
311-
312298
return event
313299

314300
# Helper functions.

sentry_sdk/integrations/django/asgi.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ async def sentry_patched_asgi_handler(self, receive, send):
155155
http_methods_to_capture=integration.http_methods_to_capture,
156156
)
157157

158-
return await middleware(self.scope)(receive, send)
158+
return await middleware(self.scope)(receive, send) # type: ignore
159159

160160
cls.__call__ = sentry_patched_asgi_handler
161161

sentry_sdk/integrations/fastapi.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,7 @@
66
from sentry_sdk.integrations import DidNotEnable
77
from sentry_sdk.scope import should_send_default_pii
88
from sentry_sdk.tracing import SOURCE_FOR_STYLE, TransactionSource
9-
from sentry_sdk.utils import (
10-
transaction_from_function,
11-
logger,
12-
)
9+
from sentry_sdk.utils import transaction_from_function
1310

1411
from typing import TYPE_CHECKING
1512

@@ -66,9 +63,6 @@ def _set_transaction_name_and_source(scope, transaction_style, request):
6663
source = SOURCE_FOR_STYLE[transaction_style]
6764

6865
scope.set_transaction_name(name, source=source)
69-
logger.debug(
70-
"[FastAPI] Set transaction name and source on scope: %s / %s", name, source
71-
)
7266

7367

7468
def patch_get_request_handler():

sentry_sdk/integrations/litestar.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ def __init__(self, app, span_origin=LitestarIntegration.origin):
8585
transaction_style="endpoint",
8686
mechanism_type="asgi",
8787
span_origin=span_origin,
88+
asgi_version=3,
8889
)
8990

9091
def _capture_request_exception(self, exc):
@@ -116,7 +117,6 @@ def injection_wrapper(self, *args, **kwargs):
116117
*(kwargs.get("after_exception") or []),
117118
]
118119

119-
SentryLitestarASGIMiddleware.__call__ = SentryLitestarASGIMiddleware._run_asgi3 # type: ignore
120120
middleware = kwargs.get("middleware") or []
121121
kwargs["middleware"] = [SentryLitestarASGIMiddleware, *middleware]
122122
old__init__(self, *args, **kwargs)

sentry_sdk/integrations/quart.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,8 @@ async def sentry_patched_asgi_app(self, scope, receive, send):
9595
middleware = SentryAsgiMiddleware(
9696
lambda *a, **kw: old_app(self, *a, **kw),
9797
span_origin=QuartIntegration.origin,
98+
asgi_version=3,
9899
)
99-
middleware.__call__ = middleware._run_asgi3
100100
return await middleware(scope, receive, send)
101101

102102
Quart.__call__ = sentry_patched_asgi_app

sentry_sdk/integrations/starlette.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
capture_internal_exceptions,
3030
ensure_integration_enabled,
3131
event_from_exception,
32-
logger,
3332
parse_version,
3433
transaction_from_function,
3534
)
@@ -403,9 +402,9 @@ async def _sentry_patched_asgi_app(self, scope, receive, send):
403402
if integration
404403
else DEFAULT_HTTP_METHODS_TO_CAPTURE
405404
),
405+
asgi_version=3,
406406
)
407407

408-
middleware.__call__ = middleware._run_asgi3
409408
return await middleware(scope, receive, send)
410409

411410
Starlette.__call__ = _sentry_patched_asgi_app
@@ -723,9 +722,6 @@ def _set_transaction_name_and_source(scope, transaction_style, request):
723722
source = TransactionSource.ROUTE
724723

725724
scope.set_transaction_name(name, source=source)
726-
logger.debug(
727-
"[Starlette] Set transaction name and source on scope: %s / %s", name, source
728-
)
729725

730726

731727
def _get_transaction_from_middleware(app, asgi_scope, integration):

sentry_sdk/integrations/starlite.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ def __init__(self, app, span_origin=StarliteIntegration.origin):
6565
transaction_style="endpoint",
6666
mechanism_type="asgi",
6767
span_origin=span_origin,
68+
asgi_version=3,
6869
)
6970

7071

@@ -94,7 +95,6 @@ def injection_wrapper(self, *args, **kwargs):
9495
]
9596
)
9697

97-
SentryStarliteASGIMiddleware.__call__ = SentryStarliteASGIMiddleware._run_asgi3 # type: ignore
9898
middleware = kwargs.get("middleware") or []
9999
kwargs["middleware"] = [SentryStarliteASGIMiddleware, *middleware]
100100
old__init__(self, *args, **kwargs)

sentry_sdk/scope.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
from typing import TYPE_CHECKING
4949

5050
if TYPE_CHECKING:
51-
from collections.abc import Mapping, MutableMapping
51+
from collections.abc import Mapping
5252

5353
from typing import Any
5454
from typing import Callable
@@ -238,24 +238,24 @@ def __copy__(self):
238238
rv._name = self._name
239239
rv._fingerprint = self._fingerprint
240240
rv._transaction = self._transaction
241-
rv._transaction_info = dict(self._transaction_info)
241+
rv._transaction_info = self._transaction_info.copy()
242242
rv._user = self._user
243243

244-
rv._tags = dict(self._tags)
245-
rv._contexts = dict(self._contexts)
246-
rv._extras = dict(self._extras)
244+
rv._tags = self._tags.copy()
245+
rv._contexts = self._contexts.copy()
246+
rv._extras = self._extras.copy()
247247

248248
rv._breadcrumbs = copy(self._breadcrumbs)
249-
rv._n_breadcrumbs_truncated = copy(self._n_breadcrumbs_truncated)
250-
rv._event_processors = list(self._event_processors)
251-
rv._error_processors = list(self._error_processors)
249+
rv._n_breadcrumbs_truncated = self._n_breadcrumbs_truncated
250+
rv._event_processors = self._event_processors.copy()
251+
rv._error_processors = self._error_processors.copy()
252252
rv._propagation_context = self._propagation_context
253253

254254
rv._should_capture = self._should_capture
255255
rv._span = self._span
256256
rv._session = self._session
257257
rv._force_auto_session_tracking = self._force_auto_session_tracking
258-
rv._attachments = list(self._attachments)
258+
rv._attachments = self._attachments.copy()
259259

260260
rv._profile = self._profile
261261

@@ -683,12 +683,12 @@ def clear(self):
683683
self._level = None # type: Optional[LogLevelStr]
684684
self._fingerprint = None # type: Optional[List[str]]
685685
self._transaction = None # type: Optional[str]
686-
self._transaction_info = {} # type: MutableMapping[str, str]
686+
self._transaction_info = {} # type: dict[str, str]
687687
self._user = None # type: Optional[Dict[str, Any]]
688688

689689
self._tags = {} # type: Dict[str, Any]
690690
self._contexts = {} # type: Dict[str, Dict[str, Any]]
691-
self._extras = {} # type: MutableMapping[str, Any]
691+
self._extras = {} # type: dict[str, Any]
692692
self._attachments = [] # type: List[Attachment]
693693

694694
self.clear_breadcrumbs()

sentry_sdk/tracing.py

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -257,8 +257,8 @@ class Span:
257257
"""
258258

259259
__slots__ = (
260-
"trace_id",
261-
"span_id",
260+
"_trace_id",
261+
"_span_id",
262262
"parent_span_id",
263263
"same_process_as_parent",
264264
"sampled",
@@ -301,8 +301,8 @@ def __init__(
301301
name=None, # type: Optional[str]
302302
):
303303
# type: (...) -> None
304-
self.trace_id = trace_id or uuid.uuid4().hex
305-
self.span_id = span_id or uuid.uuid4().hex[16:]
304+
self._trace_id = trace_id
305+
self._span_id = span_id
306306
self.parent_span_id = parent_span_id
307307
self.same_process_as_parent = same_process_as_parent
308308
self.sampled = sampled
@@ -356,6 +356,32 @@ def init_span_recorder(self, maxlen):
356356
if self._span_recorder is None:
357357
self._span_recorder = _SpanRecorder(maxlen)
358358

359+
@property
360+
def trace_id(self):
361+
# type: () -> str
362+
if not self._trace_id:
363+
self._trace_id = uuid.uuid4().hex
364+
365+
return self._trace_id
366+
367+
@trace_id.setter
368+
def trace_id(self, value):
369+
# type: (str) -> None
370+
self._trace_id = value
371+
372+
@property
373+
def span_id(self):
374+
# type: () -> str
375+
if not self._span_id:
376+
self._span_id = uuid.uuid4().hex[16:]
377+
378+
return self._span_id
379+
380+
@span_id.setter
381+
def span_id(self, value):
382+
# type: (str) -> None
383+
self._span_id = value
384+
359385
def _get_local_aggregator(self):
360386
# type: (...) -> LocalAggregator
361387
rv = self._local_aggregator
@@ -822,7 +848,6 @@ def __init__( # type: ignore[misc]
822848
**kwargs, # type: Unpack[SpanKwargs]
823849
):
824850
# type: (...) -> None
825-
826851
super().__init__(**kwargs)
827852

828853
self.name = name

0 commit comments

Comments
 (0)