sentry-sdk 2.27.0__py2.py3-none-any.whl → 3.0.0a1__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of sentry-sdk might be problematic. Click here for more details.

Files changed (110) hide show
  1. sentry_sdk/__init__.py +4 -8
  2. sentry_sdk/_compat.py +0 -1
  3. sentry_sdk/_init_implementation.py +6 -44
  4. sentry_sdk/_log_batcher.py +47 -28
  5. sentry_sdk/_types.py +2 -64
  6. sentry_sdk/ai/monitoring.py +14 -10
  7. sentry_sdk/ai/utils.py +1 -1
  8. sentry_sdk/api.py +69 -163
  9. sentry_sdk/client.py +25 -72
  10. sentry_sdk/consts.py +42 -23
  11. sentry_sdk/debug.py +0 -10
  12. sentry_sdk/envelope.py +2 -10
  13. sentry_sdk/feature_flags.py +2 -2
  14. sentry_sdk/integrations/__init__.py +4 -2
  15. sentry_sdk/integrations/_asgi_common.py +3 -3
  16. sentry_sdk/integrations/_wsgi_common.py +11 -40
  17. sentry_sdk/integrations/aiohttp.py +104 -57
  18. sentry_sdk/integrations/anthropic.py +10 -7
  19. sentry_sdk/integrations/arq.py +24 -13
  20. sentry_sdk/integrations/asgi.py +102 -83
  21. sentry_sdk/integrations/asyncio.py +1 -0
  22. sentry_sdk/integrations/asyncpg.py +45 -30
  23. sentry_sdk/integrations/aws_lambda.py +109 -92
  24. sentry_sdk/integrations/boto3.py +38 -9
  25. sentry_sdk/integrations/bottle.py +1 -1
  26. sentry_sdk/integrations/celery/__init__.py +48 -38
  27. sentry_sdk/integrations/clickhouse_driver.py +59 -28
  28. sentry_sdk/integrations/cohere.py +2 -0
  29. sentry_sdk/integrations/django/__init__.py +25 -46
  30. sentry_sdk/integrations/django/asgi.py +6 -2
  31. sentry_sdk/integrations/django/caching.py +13 -22
  32. sentry_sdk/integrations/django/middleware.py +1 -0
  33. sentry_sdk/integrations/django/signals_handlers.py +3 -1
  34. sentry_sdk/integrations/django/templates.py +8 -12
  35. sentry_sdk/integrations/django/transactions.py +1 -6
  36. sentry_sdk/integrations/django/views.py +5 -2
  37. sentry_sdk/integrations/falcon.py +7 -25
  38. sentry_sdk/integrations/fastapi.py +3 -3
  39. sentry_sdk/integrations/flask.py +1 -1
  40. sentry_sdk/integrations/gcp.py +63 -38
  41. sentry_sdk/integrations/graphene.py +6 -13
  42. sentry_sdk/integrations/grpc/aio/client.py +14 -8
  43. sentry_sdk/integrations/grpc/aio/server.py +19 -21
  44. sentry_sdk/integrations/grpc/client.py +8 -6
  45. sentry_sdk/integrations/grpc/server.py +12 -14
  46. sentry_sdk/integrations/httpx.py +47 -12
  47. sentry_sdk/integrations/huey.py +26 -22
  48. sentry_sdk/integrations/huggingface_hub.py +1 -0
  49. sentry_sdk/integrations/langchain.py +22 -15
  50. sentry_sdk/integrations/litestar.py +4 -2
  51. sentry_sdk/integrations/logging.py +12 -3
  52. sentry_sdk/integrations/openai.py +2 -0
  53. sentry_sdk/integrations/pymongo.py +18 -25
  54. sentry_sdk/integrations/pyramid.py +1 -1
  55. sentry_sdk/integrations/quart.py +3 -3
  56. sentry_sdk/integrations/ray.py +23 -17
  57. sentry_sdk/integrations/redis/_async_common.py +30 -18
  58. sentry_sdk/integrations/redis/_sync_common.py +28 -18
  59. sentry_sdk/integrations/redis/modules/caches.py +13 -10
  60. sentry_sdk/integrations/redis/modules/queries.py +14 -11
  61. sentry_sdk/integrations/redis/rb.py +4 -4
  62. sentry_sdk/integrations/redis/redis.py +6 -6
  63. sentry_sdk/integrations/redis/redis_cluster.py +18 -16
  64. sentry_sdk/integrations/redis/redis_py_cluster_legacy.py +4 -4
  65. sentry_sdk/integrations/redis/utils.py +63 -19
  66. sentry_sdk/integrations/rq.py +68 -23
  67. sentry_sdk/integrations/rust_tracing.py +28 -43
  68. sentry_sdk/integrations/sanic.py +23 -13
  69. sentry_sdk/integrations/socket.py +9 -5
  70. sentry_sdk/integrations/sqlalchemy.py +8 -8
  71. sentry_sdk/integrations/starlette.py +11 -31
  72. sentry_sdk/integrations/starlite.py +4 -2
  73. sentry_sdk/integrations/stdlib.py +56 -9
  74. sentry_sdk/integrations/strawberry.py +40 -59
  75. sentry_sdk/integrations/threading.py +10 -26
  76. sentry_sdk/integrations/tornado.py +57 -18
  77. sentry_sdk/integrations/trytond.py +4 -1
  78. sentry_sdk/integrations/wsgi.py +84 -38
  79. sentry_sdk/opentelemetry/__init__.py +9 -0
  80. sentry_sdk/opentelemetry/consts.py +33 -0
  81. sentry_sdk/opentelemetry/contextvars_context.py +73 -0
  82. sentry_sdk/{integrations/opentelemetry → opentelemetry}/propagator.py +19 -28
  83. sentry_sdk/opentelemetry/sampler.py +326 -0
  84. sentry_sdk/opentelemetry/scope.py +218 -0
  85. sentry_sdk/opentelemetry/span_processor.py +329 -0
  86. sentry_sdk/opentelemetry/tracing.py +35 -0
  87. sentry_sdk/opentelemetry/utils.py +476 -0
  88. sentry_sdk/profiler/__init__.py +0 -40
  89. sentry_sdk/profiler/continuous_profiler.py +1 -30
  90. sentry_sdk/profiler/transaction_profiler.py +5 -56
  91. sentry_sdk/scope.py +107 -351
  92. sentry_sdk/sessions.py +0 -87
  93. sentry_sdk/tracing.py +418 -1144
  94. sentry_sdk/tracing_utils.py +126 -164
  95. sentry_sdk/transport.py +4 -104
  96. sentry_sdk/utils.py +169 -152
  97. {sentry_sdk-2.27.0.dist-info → sentry_sdk-3.0.0a1.dist-info}/METADATA +3 -5
  98. sentry_sdk-3.0.0a1.dist-info/RECORD +154 -0
  99. {sentry_sdk-2.27.0.dist-info → sentry_sdk-3.0.0a1.dist-info}/WHEEL +1 -1
  100. sentry_sdk-3.0.0a1.dist-info/entry_points.txt +2 -0
  101. sentry_sdk/hub.py +0 -739
  102. sentry_sdk/integrations/opentelemetry/__init__.py +0 -7
  103. sentry_sdk/integrations/opentelemetry/consts.py +0 -5
  104. sentry_sdk/integrations/opentelemetry/integration.py +0 -58
  105. sentry_sdk/integrations/opentelemetry/span_processor.py +0 -391
  106. sentry_sdk/metrics.py +0 -965
  107. sentry_sdk-2.27.0.dist-info/RECORD +0 -152
  108. sentry_sdk-2.27.0.dist-info/entry_points.txt +0 -2
  109. {sentry_sdk-2.27.0.dist-info → sentry_sdk-3.0.0a1.dist-info}/licenses/LICENSE +0 -0
  110. {sentry_sdk-2.27.0.dist-info → sentry_sdk-3.0.0a1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,476 @@
1
+ import re
2
+ from typing import cast
3
+ from datetime import datetime, timezone
4
+
5
+ from urllib3.util import parse_url as urlparse
6
+ from urllib.parse import quote, unquote
7
+ from opentelemetry.trace import (
8
+ Span as AbstractSpan,
9
+ SpanKind,
10
+ StatusCode,
11
+ format_trace_id,
12
+ format_span_id,
13
+ TraceState,
14
+ )
15
+ from opentelemetry.semconv.trace import SpanAttributes
16
+ from opentelemetry.sdk.trace import ReadableSpan
17
+
18
+ import sentry_sdk
19
+ from sentry_sdk.utils import Dsn
20
+ from sentry_sdk.consts import (
21
+ SPANSTATUS,
22
+ OP,
23
+ SPANDATA,
24
+ DEFAULT_SPAN_ORIGIN,
25
+ LOW_QUALITY_TRANSACTION_SOURCES,
26
+ )
27
+ from sentry_sdk.opentelemetry.consts import SentrySpanAttribute
28
+ from sentry_sdk.tracing_utils import Baggage, get_span_status_from_http_code
29
+
30
+ from sentry_sdk._types import TYPE_CHECKING
31
+
32
+ if TYPE_CHECKING:
33
+ from typing import Any, Optional, Mapping, Sequence, Union
34
+ from sentry_sdk._types import OtelExtractedSpanData
35
+
36
+
37
+ GRPC_ERROR_MAP = {
38
+ "1": SPANSTATUS.CANCELLED,
39
+ "2": SPANSTATUS.UNKNOWN_ERROR,
40
+ "3": SPANSTATUS.INVALID_ARGUMENT,
41
+ "4": SPANSTATUS.DEADLINE_EXCEEDED,
42
+ "5": SPANSTATUS.NOT_FOUND,
43
+ "6": SPANSTATUS.ALREADY_EXISTS,
44
+ "7": SPANSTATUS.PERMISSION_DENIED,
45
+ "8": SPANSTATUS.RESOURCE_EXHAUSTED,
46
+ "9": SPANSTATUS.FAILED_PRECONDITION,
47
+ "10": SPANSTATUS.ABORTED,
48
+ "11": SPANSTATUS.OUT_OF_RANGE,
49
+ "12": SPANSTATUS.UNIMPLEMENTED,
50
+ "13": SPANSTATUS.INTERNAL_ERROR,
51
+ "14": SPANSTATUS.UNAVAILABLE,
52
+ "15": SPANSTATUS.DATA_LOSS,
53
+ "16": SPANSTATUS.UNAUTHENTICATED,
54
+ }
55
+
56
+
57
+ def is_sentry_span(span):
58
+ # type: (ReadableSpan) -> bool
59
+ """
60
+ Break infinite loop:
61
+ HTTP requests to Sentry are caught by OTel and send again to Sentry.
62
+ """
63
+ from sentry_sdk import get_client
64
+
65
+ if not span.attributes:
66
+ return False
67
+
68
+ span_url = span.attributes.get(SpanAttributes.HTTP_URL, None)
69
+ span_url = cast("Optional[str]", span_url)
70
+
71
+ if not span_url:
72
+ return False
73
+
74
+ dsn_url = None
75
+ client = get_client()
76
+
77
+ if client.dsn:
78
+ try:
79
+ dsn_url = Dsn(client.dsn).netloc
80
+ except Exception:
81
+ pass
82
+
83
+ if not dsn_url:
84
+ return False
85
+
86
+ if dsn_url in span_url:
87
+ return True
88
+
89
+ return False
90
+
91
+
92
+ def convert_from_otel_timestamp(time):
93
+ # type: (int) -> datetime
94
+ """Convert an OTel nanosecond-level timestamp to a datetime."""
95
+ return datetime.fromtimestamp(time / 1e9, timezone.utc)
96
+
97
+
98
+ def convert_to_otel_timestamp(time):
99
+ # type: (Union[datetime, float]) -> int
100
+ """Convert a datetime to an OTel timestamp (with nanosecond precision)."""
101
+ if isinstance(time, datetime):
102
+ return int(time.timestamp() * 1e9)
103
+ return int(time * 1e9)
104
+
105
+
106
+ def extract_transaction_name_source(span):
107
+ # type: (ReadableSpan) -> tuple[Optional[str], Optional[str]]
108
+ if not span.attributes:
109
+ return (None, None)
110
+ return (
111
+ cast("Optional[str]", span.attributes.get(SentrySpanAttribute.NAME)),
112
+ cast("Optional[str]", span.attributes.get(SentrySpanAttribute.SOURCE)),
113
+ )
114
+
115
+
116
+ def extract_span_data(span):
117
+ # type: (ReadableSpan) -> OtelExtractedSpanData
118
+ op = span.name
119
+ description = span.name
120
+ status, http_status = extract_span_status(span)
121
+ origin = None
122
+ if span.attributes is None:
123
+ return (op, description, status, http_status, origin)
124
+
125
+ attribute_op = cast("Optional[str]", span.attributes.get(SentrySpanAttribute.OP))
126
+ op = attribute_op or op
127
+ description = cast(
128
+ "str", span.attributes.get(SentrySpanAttribute.DESCRIPTION) or description
129
+ )
130
+ origin = cast("Optional[str]", span.attributes.get(SentrySpanAttribute.ORIGIN))
131
+
132
+ http_method = span.attributes.get(SpanAttributes.HTTP_METHOD)
133
+ http_method = cast("Optional[str]", http_method)
134
+ if http_method:
135
+ return span_data_for_http_method(span)
136
+
137
+ db_query = span.attributes.get(SpanAttributes.DB_SYSTEM)
138
+ if db_query:
139
+ return span_data_for_db_query(span)
140
+
141
+ rpc_service = span.attributes.get(SpanAttributes.RPC_SERVICE)
142
+ if rpc_service:
143
+ return (
144
+ attribute_op or "rpc",
145
+ description,
146
+ status,
147
+ http_status,
148
+ origin,
149
+ )
150
+
151
+ messaging_system = span.attributes.get(SpanAttributes.MESSAGING_SYSTEM)
152
+ if messaging_system:
153
+ return (
154
+ attribute_op or "message",
155
+ description,
156
+ status,
157
+ http_status,
158
+ origin,
159
+ )
160
+
161
+ faas_trigger = span.attributes.get(SpanAttributes.FAAS_TRIGGER)
162
+ if faas_trigger:
163
+ return (str(faas_trigger), description, status, http_status, origin)
164
+
165
+ return (op, description, status, http_status, origin)
166
+
167
+
168
+ def span_data_for_http_method(span):
169
+ # type: (ReadableSpan) -> OtelExtractedSpanData
170
+ span_attributes = span.attributes or {}
171
+
172
+ op = cast("Optional[str]", span_attributes.get(SentrySpanAttribute.OP))
173
+ if op is None:
174
+ op = "http"
175
+
176
+ if span.kind == SpanKind.SERVER:
177
+ op += ".server"
178
+ elif span.kind == SpanKind.CLIENT:
179
+ op += ".client"
180
+
181
+ http_method = span_attributes.get(SpanAttributes.HTTP_METHOD)
182
+ route = span_attributes.get(SpanAttributes.HTTP_ROUTE)
183
+ target = span_attributes.get(SpanAttributes.HTTP_TARGET)
184
+ peer_name = span_attributes.get(SpanAttributes.NET_PEER_NAME)
185
+
186
+ # TODO-neel-potel remove description completely
187
+ description = span_attributes.get(
188
+ SentrySpanAttribute.DESCRIPTION
189
+ ) or span_attributes.get(SentrySpanAttribute.NAME)
190
+ description = cast("Optional[str]", description)
191
+ if description is None:
192
+ description = f"{http_method}"
193
+
194
+ if route:
195
+ description = f"{http_method} {route}"
196
+ elif target:
197
+ description = f"{http_method} {target}"
198
+ elif peer_name:
199
+ description = f"{http_method} {peer_name}"
200
+ else:
201
+ url = span_attributes.get(SpanAttributes.HTTP_URL)
202
+ url = cast("Optional[str]", url)
203
+
204
+ if url:
205
+ parsed_url = urlparse(url)
206
+ url = "{}://{}{}".format(
207
+ parsed_url.scheme, parsed_url.netloc, parsed_url.path
208
+ )
209
+ description = f"{http_method} {url}"
210
+
211
+ status, http_status = extract_span_status(span)
212
+
213
+ origin = cast("Optional[str]", span_attributes.get(SentrySpanAttribute.ORIGIN))
214
+
215
+ return (op, description, status, http_status, origin)
216
+
217
+
218
+ def span_data_for_db_query(span):
219
+ # type: (ReadableSpan) -> OtelExtractedSpanData
220
+ span_attributes = span.attributes or {}
221
+
222
+ op = cast("str", span_attributes.get(SentrySpanAttribute.OP, OP.DB))
223
+
224
+ statement = span_attributes.get(SpanAttributes.DB_STATEMENT, None)
225
+ statement = cast("Optional[str]", statement)
226
+
227
+ description = statement or span.name
228
+ origin = cast("Optional[str]", span_attributes.get(SentrySpanAttribute.ORIGIN))
229
+
230
+ return (op, description, None, None, origin)
231
+
232
+
233
+ def extract_span_status(span):
234
+ # type: (ReadableSpan) -> tuple[Optional[str], Optional[int]]
235
+ span_attributes = span.attributes or {}
236
+ status = span.status or None
237
+
238
+ if status:
239
+ inferred_status, http_status = infer_status_from_attributes(span_attributes)
240
+
241
+ if status.status_code == StatusCode.OK:
242
+ return (SPANSTATUS.OK, http_status)
243
+ elif status.status_code == StatusCode.ERROR:
244
+ if status.description is None:
245
+ if inferred_status:
246
+ return (inferred_status, http_status)
247
+
248
+ if http_status is not None:
249
+ return (inferred_status, http_status)
250
+
251
+ if (
252
+ status.description is not None
253
+ and status.description in GRPC_ERROR_MAP.values()
254
+ ):
255
+ return (status.description, None)
256
+ else:
257
+ return (SPANSTATUS.UNKNOWN_ERROR, None)
258
+
259
+ inferred_status, http_status = infer_status_from_attributes(span_attributes)
260
+ if inferred_status:
261
+ return (inferred_status, http_status)
262
+
263
+ if status and status.status_code == StatusCode.UNSET:
264
+ return (None, None)
265
+ else:
266
+ return (SPANSTATUS.UNKNOWN_ERROR, None)
267
+
268
+
269
+ def infer_status_from_attributes(span_attributes):
270
+ # type: (Mapping[str, str | bool | int | float | Sequence[str] | Sequence[bool] | Sequence[int] | Sequence[float]]) -> tuple[Optional[str], Optional[int]]
271
+ http_status = get_http_status_code(span_attributes)
272
+
273
+ if http_status:
274
+ return (get_span_status_from_http_code(http_status), http_status)
275
+
276
+ grpc_status = span_attributes.get(SpanAttributes.RPC_GRPC_STATUS_CODE)
277
+ if grpc_status:
278
+ return (GRPC_ERROR_MAP.get(str(grpc_status), SPANSTATUS.UNKNOWN_ERROR), None)
279
+
280
+ return (None, None)
281
+
282
+
283
+ def get_http_status_code(span_attributes):
284
+ # type: (Mapping[str, str | bool | int | float | Sequence[str] | Sequence[bool] | Sequence[int] | Sequence[float]]) -> Optional[int]
285
+ try:
286
+ http_status = span_attributes.get(SpanAttributes.HTTP_RESPONSE_STATUS_CODE)
287
+ except AttributeError:
288
+ # HTTP_RESPONSE_STATUS_CODE was added in 1.21, so if we're on an older
289
+ # OTel version SpanAttributes.HTTP_RESPONSE_STATUS_CODE will throw an
290
+ # AttributeError
291
+ http_status = None
292
+
293
+ if http_status is None:
294
+ # Fall back to the deprecated attribute
295
+ http_status = span_attributes.get(SpanAttributes.HTTP_STATUS_CODE)
296
+
297
+ http_status = cast("Optional[int]", http_status)
298
+
299
+ return http_status
300
+
301
+
302
+ def extract_span_attributes(span, namespace):
303
+ # type: (ReadableSpan, str) -> dict[str, Any]
304
+ """
305
+ Extract Sentry-specific span attributes and make them look the way Sentry expects.
306
+ """
307
+ extracted_attrs = {} # type: dict[str, Any]
308
+
309
+ for attr, value in (span.attributes or {}).items():
310
+ if attr.startswith(namespace):
311
+ key = attr[len(namespace) + 1 :]
312
+ extracted_attrs[key] = value
313
+
314
+ return extracted_attrs
315
+
316
+
317
+ def get_trace_context(span, span_data=None):
318
+ # type: (ReadableSpan, Optional[OtelExtractedSpanData]) -> dict[str, Any]
319
+ if not span.context:
320
+ return {}
321
+
322
+ trace_id = format_trace_id(span.context.trace_id)
323
+ span_id = format_span_id(span.context.span_id)
324
+ parent_span_id = format_span_id(span.parent.span_id) if span.parent else None
325
+
326
+ if span_data is None:
327
+ span_data = extract_span_data(span)
328
+
329
+ (op, _, status, _, origin) = span_data
330
+
331
+ trace_context = {
332
+ "trace_id": trace_id,
333
+ "span_id": span_id,
334
+ "parent_span_id": parent_span_id,
335
+ "op": op,
336
+ "origin": origin or DEFAULT_SPAN_ORIGIN,
337
+ } # type: dict[str, Any]
338
+
339
+ if status:
340
+ trace_context["status"] = status
341
+
342
+ if span.attributes:
343
+ trace_context["data"] = dict(span.attributes)
344
+
345
+ trace_state = get_trace_state(span)
346
+ trace_context["dynamic_sampling_context"] = dsc_from_trace_state(trace_state)
347
+
348
+ # TODO-neel-potel profiler thread_id, thread_name
349
+
350
+ return trace_context
351
+
352
+
353
+ def trace_state_from_baggage(baggage):
354
+ # type: (Baggage) -> TraceState
355
+ items = []
356
+ for k, v in baggage.sentry_items.items():
357
+ key = Baggage.SENTRY_PREFIX + quote(k)
358
+ val = quote(str(v))
359
+ items.append((key, val))
360
+ return TraceState(items)
361
+
362
+
363
+ def baggage_from_trace_state(trace_state):
364
+ # type: (TraceState) -> Baggage
365
+ return Baggage(dsc_from_trace_state(trace_state))
366
+
367
+
368
+ def serialize_trace_state(trace_state):
369
+ # type: (TraceState) -> str
370
+ sentry_items = []
371
+ for k, v in trace_state.items():
372
+ if Baggage.SENTRY_PREFIX_REGEX.match(k):
373
+ sentry_items.append((k, v))
374
+ return ",".join(key + "=" + value for key, value in sentry_items)
375
+
376
+
377
+ def dsc_from_trace_state(trace_state):
378
+ # type: (TraceState) -> dict[str, str]
379
+ dsc = {}
380
+ for k, v in trace_state.items():
381
+ if Baggage.SENTRY_PREFIX_REGEX.match(k):
382
+ key = re.sub(Baggage.SENTRY_PREFIX_REGEX, "", k)
383
+ dsc[unquote(key)] = unquote(v)
384
+ return dsc
385
+
386
+
387
+ def has_incoming_trace(trace_state):
388
+ # type: (TraceState) -> bool
389
+ """
390
+ The existence of a sentry-trace_id in the baggage implies we continued an upstream trace.
391
+ """
392
+ return (Baggage.SENTRY_PREFIX + "trace_id") in trace_state
393
+
394
+
395
+ def get_trace_state(span):
396
+ # type: (Union[AbstractSpan, ReadableSpan]) -> TraceState
397
+ """
398
+ Get the existing trace_state with sentry items
399
+ or populate it if we are the head SDK.
400
+ """
401
+ span_context = span.get_span_context()
402
+ if not span_context:
403
+ return TraceState()
404
+
405
+ trace_state = span_context.trace_state
406
+
407
+ if has_incoming_trace(trace_state):
408
+ return trace_state
409
+ else:
410
+ client = sentry_sdk.get_client()
411
+ if not client.is_active():
412
+ return trace_state
413
+
414
+ options = client.options or {}
415
+
416
+ trace_state = trace_state.update(
417
+ Baggage.SENTRY_PREFIX + "trace_id",
418
+ quote(format_trace_id(span_context.trace_id)),
419
+ )
420
+
421
+ if options.get("environment"):
422
+ trace_state = trace_state.update(
423
+ Baggage.SENTRY_PREFIX + "environment", quote(options["environment"])
424
+ )
425
+
426
+ if options.get("release"):
427
+ trace_state = trace_state.update(
428
+ Baggage.SENTRY_PREFIX + "release", quote(options["release"])
429
+ )
430
+
431
+ if options.get("dsn"):
432
+ trace_state = trace_state.update(
433
+ Baggage.SENTRY_PREFIX + "public_key",
434
+ quote(Dsn(options["dsn"]).public_key),
435
+ )
436
+
437
+ root_span = get_sentry_meta(span, "root_span")
438
+ if root_span and isinstance(root_span, ReadableSpan):
439
+ transaction_name, transaction_source = extract_transaction_name_source(
440
+ root_span
441
+ )
442
+
443
+ if (
444
+ transaction_name
445
+ and transaction_source not in LOW_QUALITY_TRANSACTION_SOURCES
446
+ ):
447
+ trace_state = trace_state.update(
448
+ Baggage.SENTRY_PREFIX + "transaction", quote(transaction_name)
449
+ )
450
+
451
+ return trace_state
452
+
453
+
454
+ def get_sentry_meta(span, key):
455
+ # type: (Union[AbstractSpan, ReadableSpan], str) -> Any
456
+ sentry_meta = getattr(span, "_sentry_meta", None)
457
+ return sentry_meta.get(key) if sentry_meta else None
458
+
459
+
460
+ def set_sentry_meta(span, key, value):
461
+ # type: (Union[AbstractSpan, ReadableSpan], str, Any) -> None
462
+ sentry_meta = getattr(span, "_sentry_meta", {})
463
+ sentry_meta[key] = value
464
+ span._sentry_meta = sentry_meta # type: ignore[union-attr]
465
+
466
+
467
+ def get_profile_context(span):
468
+ # type: (ReadableSpan) -> Optional[dict[str, str]]
469
+ if not span.attributes:
470
+ return None
471
+
472
+ profiler_id = cast("Optional[str]", span.attributes.get(SPANDATA.PROFILER_ID))
473
+ if profiler_id is None:
474
+ return None
475
+
476
+ return {"profiler_id": profiler_id}
@@ -1,49 +1,9 @@
1
1
  from sentry_sdk.profiler.continuous_profiler import (
2
- start_profile_session,
3
2
  start_profiler,
4
- stop_profile_session,
5
3
  stop_profiler,
6
4
  )
7
- from sentry_sdk.profiler.transaction_profiler import (
8
- MAX_PROFILE_DURATION_NS,
9
- PROFILE_MINIMUM_SAMPLES,
10
- Profile,
11
- Scheduler,
12
- ThreadScheduler,
13
- GeventScheduler,
14
- has_profiling_enabled,
15
- setup_profiler,
16
- teardown_profiler,
17
- )
18
- from sentry_sdk.profiler.utils import (
19
- DEFAULT_SAMPLING_FREQUENCY,
20
- MAX_STACK_DEPTH,
21
- get_frame_name,
22
- extract_frame,
23
- extract_stack,
24
- frame_id,
25
- )
26
5
 
27
6
  __all__ = [
28
- "start_profile_session", # TODO: Deprecate this in favor of `start_profiler`
29
7
  "start_profiler",
30
- "stop_profile_session", # TODO: Deprecate this in favor of `stop_profiler`
31
8
  "stop_profiler",
32
- # DEPRECATED: The following was re-exported for backwards compatibility. It
33
- # will be removed from sentry_sdk.profiler in a future release.
34
- "MAX_PROFILE_DURATION_NS",
35
- "PROFILE_MINIMUM_SAMPLES",
36
- "Profile",
37
- "Scheduler",
38
- "ThreadScheduler",
39
- "GeventScheduler",
40
- "has_profiling_enabled",
41
- "setup_profiler",
42
- "teardown_profiler",
43
- "DEFAULT_SAMPLING_FREQUENCY",
44
- "MAX_STACK_DEPTH",
45
- "get_frame_name",
46
- "extract_frame",
47
- "extract_stack",
48
- "frame_id",
49
9
  ]
@@ -5,7 +5,6 @@ import sys
5
5
  import threading
6
6
  import time
7
7
  import uuid
8
- import warnings
9
8
  from collections import deque
10
9
  from datetime import datetime, timezone
11
10
 
@@ -88,15 +87,9 @@ def setup_continuous_profiler(options, sdk_info, capture_func):
88
87
  else:
89
88
  default_profiler_mode = ThreadContinuousScheduler.mode
90
89
 
90
+ profiler_mode = default_profiler_mode
91
91
  if options.get("profiler_mode") is not None:
92
92
  profiler_mode = options["profiler_mode"]
93
- else:
94
- # TODO: deprecate this and just use the existing `profiler_mode`
95
- experiments = options.get("_experiments", {})
96
-
97
- profiler_mode = (
98
- experiments.get("continuous_profiling_mode") or default_profiler_mode
99
- )
100
93
 
101
94
  frequency = DEFAULT_SAMPLING_FREQUENCY
102
95
 
@@ -152,17 +145,6 @@ def start_profiler():
152
145
  _scheduler.manual_start()
153
146
 
154
147
 
155
- def start_profile_session():
156
- # type: () -> None
157
-
158
- warnings.warn(
159
- "The `start_profile_session` function is deprecated. Please use `start_profile` instead.",
160
- DeprecationWarning,
161
- stacklevel=2,
162
- )
163
- start_profiler()
164
-
165
-
166
148
  def stop_profiler():
167
149
  # type: () -> None
168
150
  if _scheduler is None:
@@ -171,17 +153,6 @@ def stop_profiler():
171
153
  _scheduler.manual_stop()
172
154
 
173
155
 
174
- def stop_profile_session():
175
- # type: () -> None
176
-
177
- warnings.warn(
178
- "The `stop_profile_session` function is deprecated. Please use `stop_profile` instead.",
179
- DeprecationWarning,
180
- stacklevel=2,
181
- )
182
- stop_profiler()
183
-
184
-
185
156
  def teardown_continuous_profiler():
186
157
  # type: () -> None
187
158
  stop_profiler()