Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(integrations): Add disabled_integrations #3328

Merged
merged 5 commits into from
Jul 23, 2024
Merged
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
2 changes: 1 addition & 1 deletion sentry_sdk/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,6 @@ def _setup_instrumentation(self, functions_to_trace):
function_obj = getattr(module_obj, function_name)
setattr(module_obj, function_name, trace(function_obj))
logger.debug("Enabled tracing for %s", function_qualname)

except module_not_found_error:
try:
# Try to import a class
Expand Down Expand Up @@ -372,6 +371,7 @@ def _capture_envelope(envelope):
with_auto_enabling_integrations=self.options[
"auto_enabling_integrations"
],
disabled_integrations=self.options["disabled_integrations"],
)

self.spotlight = None
Expand Down
1 change: 1 addition & 0 deletions sentry_sdk/consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,7 @@ def __init__(
profiles_sampler=None, # type: Optional[TracesSampler]
profiler_mode=None, # type: Optional[ProfilerMode]
auto_enabling_integrations=True, # type: bool
disabled_integrations=None, # type: Optional[Sequence[Integration]]
auto_session_tracking=True, # type: bool
send_client_reports=True, # type: bool
_experiments={}, # type: Experiments # noqa: B006
Expand Down
45 changes: 31 additions & 14 deletions sentry_sdk/integrations/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@


if TYPE_CHECKING:
from collections.abc import Sequence
from typing import Callable
from typing import Dict
from typing import Iterator
from typing import List
from typing import Optional
from typing import Set
from typing import Type

Expand Down Expand Up @@ -114,21 +116,33 @@ def iter_default_integrations(with_auto_enabling_integrations):


def setup_integrations(
integrations, with_defaults=True, with_auto_enabling_integrations=False
integrations,
with_defaults=True,
with_auto_enabling_integrations=False,
disabled_integrations=None,
):
# type: (List[Integration], bool, bool) -> Dict[str, Integration]
# type: (Sequence[Integration], bool, bool, Optional[Sequence[Integration]]) -> Dict[str, Integration]
"""
Given a list of integration instances, this installs them all.

When `with_defaults` is set to `True` all default integrations are added
unless they were already provided before.

`disabled_integrations` takes precedence over `with_defaults` and
`with_auto_enabling_integrations`.
"""
integrations = dict(
(integration.identifier, integration) for integration in integrations or ()
)

logger.debug("Setting up integrations (with default = %s)", with_defaults)

# Integrations that will not be enabled
disabled_integrations = [
integration if isinstance(integration, type) else type(integration)
for integration in disabled_integrations or []
]

# Integrations that are not explicitly set up by the user.
used_as_default_integration = set()

Expand All @@ -144,20 +158,23 @@ def setup_integrations(
for identifier, integration in integrations.items():
with _installer_lock:
if identifier not in _processed_integrations:
logger.debug(
"Setting up previously not enabled integration %s", identifier
)
try:
type(integration).setup_once()
except DidNotEnable as e:
if identifier not in used_as_default_integration:
raise

if type(integration) in disabled_integrations:
logger.debug("Ignoring integration %s", identifier)
else:
logger.debug(
"Did not enable default integration %s: %s", identifier, e
"Setting up previously not enabled integration %s", identifier
)
else:
_installed_integrations.add(identifier)
try:
type(integration).setup_once()
except DidNotEnable as e:
if identifier not in used_as_default_integration:
raise

logger.debug(
"Did not enable default integration %s: %s", identifier, e
)
else:
_installed_integrations.add(identifier)

_processed_integrations.add(identifier)

Expand Down
2 changes: 2 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from sentry_sdk.envelope import Envelope
from sentry_sdk.integrations import ( # noqa: F401
_DEFAULT_INTEGRATIONS,
_installed_integrations,
_processed_integrations,
)
from sentry_sdk.profiler import teardown_profiler
Expand Down Expand Up @@ -182,6 +183,7 @@ def reset_integrations():
except ValueError:
pass
_processed_integrations.clear()
_installed_integrations.clear()


@pytest.fixture
Expand Down
50 changes: 49 additions & 1 deletion tests/test_basics.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import datetime
import importlib
import logging
import os
import sys
Expand All @@ -7,12 +8,12 @@

import pytest
from sentry_sdk.client import Client

from tests.conftest import patch_start_tracing_child

import sentry_sdk
import sentry_sdk.scope
from sentry_sdk import (
get_client,
push_scope,
configure_scope,
capture_event,
Expand All @@ -27,11 +28,13 @@
)
from sentry_sdk.integrations import (
_AUTO_ENABLING_INTEGRATIONS,
_DEFAULT_INTEGRATIONS,
Integration,
setup_integrations,
)
from sentry_sdk.integrations.logging import LoggingIntegration
from sentry_sdk.integrations.redis import RedisIntegration
from sentry_sdk.integrations.stdlib import StdlibIntegration
from sentry_sdk.scope import add_global_event_processor
from sentry_sdk.utils import get_sdk_name, reraise
from sentry_sdk.tracing_utils import has_tracing_enabled
Expand Down Expand Up @@ -473,6 +476,51 @@ def test_integration_scoping(sentry_init, capture_events):
assert not events


default_integrations = [
getattr(
importlib.import_module(integration.rsplit(".", 1)[0]),
integration.rsplit(".", 1)[1],
)
for integration in _DEFAULT_INTEGRATIONS
]


@pytest.mark.forked
@pytest.mark.parametrize(
"provided_integrations,default_integrations,disabled_integrations,expected_integrations",
[
([], False, None, set()),
([], False, [], set()),
([LoggingIntegration()], False, None, {LoggingIntegration}),
([], True, None, set(default_integrations)),
(
[],
True,
[LoggingIntegration(), StdlibIntegration],
set(default_integrations) - {LoggingIntegration, StdlibIntegration},
),
],
)
def test_integrations(
sentry_init,
provided_integrations,
default_integrations,
disabled_integrations,
expected_integrations,
reset_integrations,
):
sentry_init(
integrations=provided_integrations,
default_integrations=default_integrations,
disabled_integrations=disabled_integrations,
auto_enabling_integrations=False,
debug=True,
)
assert {
type(integration) for integration in get_client().integrations.values()
} == expected_integrations


@pytest.mark.skip(
reason="This test is not valid anymore, because with the new Scopes calling bind_client on the Hub sets the client on the global scope. This test should be removed once the Hub is removed"
)
Expand Down
Loading