Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions .github/workflows/test-integrations-misc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,10 @@ jobs:
run: |
set -x # print commands that are executed
./scripts/runtox.sh "py${{ matrix.python-version }}-loguru"
- name: Test opentelemetry
run: |
set -x # print commands that are executed
./scripts/runtox.sh "py${{ matrix.python-version }}-opentelemetry"
- name: Test otlp
run: |
set -x # print commands that are executed
./scripts/runtox.sh "py${{ matrix.python-version }}-otlp"
- name: Test potel
run: |
set -x # print commands that are executed
./scripts/runtox.sh "py${{ matrix.python-version }}-potel"
- name: Test pure_eval
run: |
set -x # print commands that are executed
Expand Down
37 changes: 37 additions & 0 deletions MIGRATION_GUIDE.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,40 @@
# Sentry SDK 3.0 Migration Guide


Looking to upgrade from Sentry SDK 2.x to 3.x? Here's a comprehensive list of what's changed. Looking for a more digestable summary? See the [guide in the docs](https://docs.sentry.io/platforms/python/migration/2.x-to-3.x) with the most common migration patterns.

## New Features


## Changed

- The Strawberry integration won't auto-enable anymore if we detect `strawberry-graphql` is installed. Set it up manually, setting the `async_execution` integration option to either `True` or `False` depending on if your app is async or sync.

```python
from sentry_sdk.integrations.strawberry import StrawberryIntegration

sentry_sdk.init(
integrations=[
StrawberryIntegration(async_execution=True), # or False
],
...
)
```

- The UnraisableHookIntegration is now enabled by default.
- We now don't suppress chained exceptions in the ASGI and asyncio integrations by default. The related `suppress_asgi_chained_exceptions` experimental option was removed.

## Removed

- Transaction profiling and related code was removed.
- Removed the deprecated Hub class and all uses of hub throughout the SDK in arguments, options, etc. Use a scope instead.
- The `SentrySpanProcessor`, `SentryPropagator`, `instrumenter`, and associated OpenTelemetry compatibility code was removed along with the `opentelemetry` extra and the `SentryPropagator` entrypoint. Use the `OTLPIntegration` instead.
- Removed the `auto_session_tracing` decorator. Use `track_session` instead.
- The experimental option `otel_powered_performance` has been removed together with the associated `OpenTelemetryIntegration` and `opentelemetry-experimental` extra.

## Deprecated


# Sentry SDK 2.0 Migration Guide

Looking to upgrade from Sentry SDK 1.x to 2.x? Here's a comprehensive list of what's changed. Looking for a more digestable summary? See the [guide in the docs](https://docs.sentry.io/platforms/python/migration/1.x-to-2.x) with the most common migration patterns.
Expand Down
6 changes: 0 additions & 6 deletions docs/apidocs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@
API Docs
========

.. autoclass:: sentry_sdk.Hub
:members:

.. autoclass:: sentry_sdk.Scope
:members:

Expand Down Expand Up @@ -32,9 +29,6 @@ API Docs
.. autoclass:: sentry_sdk.tracing.Span
:members:

.. autoclass:: sentry_sdk.profiler.transaction_profiler.Profile
:members:

.. autoclass:: sentry_sdk.session.Session
:members:

Expand Down
8 changes: 1 addition & 7 deletions scripts/find_raise_from_none.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,11 @@ def main():
for module_path in walk_package_modules():
scan_file(module_path)

# TODO: Investigate why we suppress exception chains here.
ignored_raises = {
pathlib.Path("sentry_sdk/integrations/asgi.py"): 2,
pathlib.Path("sentry_sdk/integrations/asyncio.py"): 1,
}

raise_from_none_count = {
file: len(occurences)
for file, occurences in RaiseFromNoneVisitor.line_numbers.items()
}
if raise_from_none_count != ignored_raises:
if raise_from_none_count:
exc = Exception("Detected unexpected raise ... from None.")
exc.add_note(
"Raise ... from None suppresses chained exceptions, removing valuable context."
Expand Down
2 changes: 0 additions & 2 deletions scripts/populate_tox/populate_tox.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,7 @@
"shadowed_module",
"gcp",
"gevent",
"opentelemetry",
"otlp",
"potel",
}

# Free-threading is experimentally supported in 3.13, and officially supported in 3.14.
Expand Down
16 changes: 0 additions & 16 deletions scripts/populate_tox/tox.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,9 @@ envlist =
# GCP
{py3.7}-gcp

# OpenTelemetry (OTel)
{py3.7,py3.9,py3.12,py3.13,py3.14,py3.14t}-opentelemetry

# OpenTelemetry with OTLP
{py3.7,py3.9,py3.12,py3.13,py3.14}-otlp

# OpenTelemetry Experimental (POTel)
{py3.8,py3.9,py3.10,py3.11,py3.12,py3.13}-potel

# === Integrations - Auto-generated ===
# These come from the populate_tox.py script.

Expand Down Expand Up @@ -139,18 +133,10 @@ deps =
aws_lambda: uvicorn
aws_lambda: pyyaml

# OpenTelemetry (OTel)
opentelemetry: opentelemetry-distro
opentelemetry: pytest-forked

# OpenTelemetry with OTLP
otlp: opentelemetry-distro[otlp]
otlp: responses

# OpenTelemetry Experimental (POTel)
potel: opentelemetry-distro
potel: pytest-forked

# === Integrations - Auto-generated ===
# These come from the populate_tox.py script.

Expand Down Expand Up @@ -240,9 +226,7 @@ setenv =
aws_lambda: _TESTPATH=tests/integrations/aws_lambda
cloud_resource_context: _TESTPATH=tests/integrations/cloud_resource_context
gcp: _TESTPATH=tests/integrations/gcp
opentelemetry: _TESTPATH=tests/integrations/opentelemetry
otlp: _TESTPATH=tests/integrations/otlp
potel: _TESTPATH=tests/integrations/opentelemetry
socket: _TESTPATH=tests/integrations/socket

# These TESTPATH definitions are auto-generated by toxgen
Expand Down
2 changes: 0 additions & 2 deletions scripts/split_tox_gh_actions/split_tox_gh_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,9 +163,7 @@
],
"Misc": [
"loguru",
"opentelemetry",
"otlp",
"potel",
"pure_eval",
"trytond",
"typer",
Expand Down
4 changes: 0 additions & 4 deletions sentry_sdk/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
from sentry_sdk.api import * # noqa # isort: skip

__all__ = [ # noqa
"Hub",
"Scope",
"Client",
"Transport",
Expand Down Expand Up @@ -66,6 +65,3 @@

init_debug_support()
del init_debug_support

# circular imports
from sentry_sdk.hub import Hub
4 changes: 1 addition & 3 deletions sentry_sdk/_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,6 @@ class DataCollection(TypedDict):
"monitor_config": Mapping[str, object],
"monitor_slug": Optional[str],
"platform": Literal["python"],
"profile": object, # Should be sentry_sdk.profiler.Profile, but we can't import that here due to circular imports
"release": Optional[str],
"request": dict[str, object],
"sdk": Mapping[str, object],
Expand Down Expand Up @@ -418,7 +417,6 @@ class DataCollection(TypedDict):
"attachment",
"session",
"internal",
"profile",
"profile_chunk",
"monitor",
"span",
Expand All @@ -429,7 +427,7 @@ class DataCollection(TypedDict):
SessionStatus = Literal["ok", "exited", "crashed", "abnormal"]

ContinuousProfilerMode = Literal["thread", "gevent", "unknown"]
ProfilerMode = Union[ContinuousProfilerMode, Literal["sleep"]]
ProfilerMode = Union[ContinuousProfilerMode]

MonitorConfigScheduleType = Literal["crontab", "interval"]
MonitorConfigScheduleUnit = Literal[
Expand Down
6 changes: 1 addition & 5 deletions sentry_sdk/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

from sentry_sdk import Client, tracing_utils
from sentry_sdk._init_implementation import init
from sentry_sdk.consts import INSTRUMENTER
from sentry_sdk.crons import monitor
from sentry_sdk.scope import Scope, _ScopeManager, isolation_scope, new_scope
from sentry_sdk.traces import StreamedSpan
Expand Down Expand Up @@ -383,7 +382,6 @@ def start_span(
@scopemethod
def start_transaction(
transaction: "Optional[Transaction]" = None,
instrumenter: str = INSTRUMENTER.SENTRY,
custom_sampling_context: "Optional[SamplingContext]" = None,
**kwargs: "Unpack[TransactionKwargs]",
) -> "Union[Transaction, NoOpSpan]":
Expand Down Expand Up @@ -411,15 +409,13 @@ def start_transaction(

:param transaction: The transaction to start. If omitted, we create and
start a new transaction.
:param instrumenter: This parameter is meant for internal use only. It
will be removed in the next major version.
:param custom_sampling_context: The transaction's custom sampling context.
:param kwargs: Optional keyword arguments to be passed to the Transaction
constructor. See :py:class:`sentry_sdk.tracing.Transaction` for
available arguments.
"""
return get_current_scope().start_transaction(
transaction, instrumenter, custom_sampling_context, **kwargs
transaction, custom_sampling_context, **kwargs
)


Expand Down
53 changes: 9 additions & 44 deletions sentry_sdk/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
from sentry_sdk.consts import (
DEFAULT_MAX_VALUE_LENGTH,
DEFAULT_OPTIONS,
INSTRUMENTER,
SPANDATA,
SPANSTATUS,
VERSION,
Expand All @@ -28,15 +27,10 @@
_resolve_data_collection,
)
from sentry_sdk.envelope import Envelope, Item, PayloadRef
from sentry_sdk.integrations import _DEFAULT_INTEGRATIONS, setup_integrations
from sentry_sdk.integrations import setup_integrations
from sentry_sdk.integrations.dedupe import DedupeIntegration
from sentry_sdk.monitor import Monitor
from sentry_sdk.profiler.continuous_profiler import setup_continuous_profiler
from sentry_sdk.profiler.transaction_profiler import (
Profile,
has_profiling_enabled,
setup_profiler,
)
from sentry_sdk.scrubber import EventScrubber
from sentry_sdk.serializer import serialize
from sentry_sdk.sessions import SessionFlusher
Expand Down Expand Up @@ -336,9 +330,6 @@ def _get_options(*args: "Optional[str]", **kwargs: "Any") -> "Dict[str, Any]":
if rv["server_name"] is None and hasattr(socket, "gethostname"):
rv["server_name"] = socket.gethostname()

if rv["instrumenter"] is None:
rv["instrumenter"] = INSTRUMENTER.SENTRY

if rv["project_root"] is None:
try:
project_root = os.getcwd()
Expand Down Expand Up @@ -632,7 +623,6 @@ def _record_lost_event(
self.options["send_default_pii"] = True
self.options["error_sampler"] = sample_all
self.options["traces_sampler"] = sample_all
self.options["profiles_sampler"] = sample_all
# data_collection was resolved in _get_options() before this
# spotlight override flipped send_default_pii on. Re-derive it so
# data_collection agrees with should_send_default_pii() in
Expand Down Expand Up @@ -681,19 +671,6 @@ def _record_lost_event(
)
)

if self.options["_experiments"].get("otel_powered_performance", False):
logger.debug(
"[OTel] Enabling experimental OTel-powered performance monitoring."
)
self.options["instrumenter"] = INSTRUMENTER.OTEL
if (
"sentry_sdk.integrations.opentelemetry.integration.OpenTelemetryIntegration"
not in _DEFAULT_INTEGRATIONS
):
_DEFAULT_INTEGRATIONS.append(
"sentry_sdk.integrations.opentelemetry.integration.OpenTelemetryIntegration",
)

self.integrations = setup_integrations(
self.options["integrations"],
with_defaults=self.options["default_integrations"],
Expand All @@ -708,20 +685,14 @@ def _record_lost_event(
SDK_INFO["name"] = sdk_name
logger.debug("Setting SDK name to '%s'", sdk_name)

if has_profiling_enabled(self.options):
try:
setup_profiler(self.options)
except Exception as e:
logger.debug("Can not set up profiler. (%s)", e)
else:
try:
setup_continuous_profiler(
self.options,
sdk_info=SDK_INFO,
capture_func=_capture_envelope,
)
except Exception as e:
logger.debug("Can not set up continuous profiler. (%s)", e)
try:
setup_continuous_profiler(
self.options,
sdk_info=SDK_INFO,
capture_func=_capture_envelope,
)
except Exception as e:
logger.debug("Can not set up continuous profiler. (%s)", e)

finally:
_client_init_debug.set(old_debug)
Expand All @@ -733,7 +704,6 @@ def _record_lost_event(
or self.log_batcher
or self.metrics_batcher
or self.span_batcher
or has_profiling_enabled(self.options)
or isinstance(self.transport, HttpTransportCore)
):
# If we have anything on that could spawn a background thread, we
Expand Down Expand Up @@ -1121,8 +1091,6 @@ def capture_event(
if not self._should_capture(event, hint, scope):
return None

profile = event.pop("profile", None)

event_id = event.get("event_id")
if event_id is None:
event["event_id"] = event_id = uuid.uuid4().hex
Expand Down Expand Up @@ -1163,9 +1131,6 @@ def capture_event(

envelope = Envelope(headers=headers)

if is_transaction and isinstance(profile, Profile):
envelope.add_profile(profile.to_json(event_opt, self.options))

if is_transaction and not span_recorder_has_gen_ai_span:
envelope.add_transaction(event_opt)
elif is_transaction:
Expand Down
Loading
Loading