99from sentry_sdk ._types import MYPY
1010
1111if MYPY :
12- from typing import Iterator
12+ from typing import Callable
1313 from typing import Dict
14+ from typing import Iterator
1415 from typing import List
1516 from typing import Set
17+ from typing import Tuple
1618 from typing import Type
17- from typing import Callable
1819
1920
2021_installer_lock = Lock ()
2122_installed_integrations = set () # type: Set[str]
2223
2324
24- def _generate_default_integrations_iterator (* import_strings ):
25- # type: (*str) -> Callable[[], Iterator[Type[Integration]]]
26- def iter_default_integrations ():
27- # type: () -> Iterator[Type[Integration]]
25+ def _generate_default_integrations_iterator (integrations , auto_enabling_integrations ):
26+ # type: (Tuple[str, ...], Tuple[str, ...]) -> Callable[[bool], Iterator[Type[Integration]]]
27+
28+ def iter_default_integrations (with_auto_enabling_integrations ):
29+ # type: (bool) -> Iterator[Type[Integration]]
2830 """Returns an iterator of the default integration classes:
2931 """
3032 from importlib import import_module
3133
32- for import_string in import_strings :
33- module , cls = import_string .rsplit ("." , 1 )
34- yield getattr (import_module (module ), cls )
34+ if with_auto_enabling_integrations :
35+ all_import_strings = integrations + auto_enabling_integrations
36+ else :
37+ all_import_strings = integrations
38+
39+ for import_string in all_import_strings :
40+ try :
41+ module , cls = import_string .rsplit ("." , 1 )
42+ yield getattr (import_module (module ), cls )
43+ except (DidNotEnable , SyntaxError ) as e :
44+ logger .debug (
45+ "Did not import default integration %s: %s" , import_string , e
46+ )
3547
3648 if isinstance (iter_default_integrations .__doc__ , str ):
37- for import_string in import_strings :
49+ for import_string in integrations :
3850 iter_default_integrations .__doc__ += "\n - `{}`" .format (import_string )
3951
4052 return iter_default_integrations
4153
4254
55+ _AUTO_ENABLING_INTEGRATIONS = (
56+ "sentry_sdk.integrations.django.DjangoIntegration" ,
57+ "sentry_sdk.integrations.flask.FlaskIntegration" ,
58+ "sentry_sdk.integrations.bottle.BottleIntegration" ,
59+ "sentry_sdk.integrations.falcon.FalconIntegration" ,
60+ "sentry_sdk.integrations.sanic.SanicIntegration" ,
61+ "sentry_sdk.integrations.celery.CeleryIntegration" ,
62+ "sentry_sdk.integrations.rq.RqIntegration" ,
63+ "sentry_sdk.integrations.aiohttp.AioHttpIntegration" ,
64+ "sentry_sdk.integrations.tornado.TornadoIntegration" ,
65+ "sentry_sdk.integrations.sqlalchemy.SqlalchemyIntegration" ,
66+ )
67+
68+
4369iter_default_integrations = _generate_default_integrations_iterator (
44- "sentry_sdk.integrations.logging.LoggingIntegration" ,
45- "sentry_sdk.integrations.stdlib.StdlibIntegration" ,
46- "sentry_sdk.integrations.excepthook.ExcepthookIntegration" ,
47- "sentry_sdk.integrations.dedupe.DedupeIntegration" ,
48- "sentry_sdk.integrations.atexit.AtexitIntegration" ,
49- "sentry_sdk.integrations.modules.ModulesIntegration" ,
50- "sentry_sdk.integrations.argv.ArgvIntegration" ,
51- "sentry_sdk.integrations.threading.ThreadingIntegration" ,
70+ integrations = (
71+ # stdlib/base runtime integrations
72+ "sentry_sdk.integrations.logging.LoggingIntegration" ,
73+ "sentry_sdk.integrations.stdlib.StdlibIntegration" ,
74+ "sentry_sdk.integrations.excepthook.ExcepthookIntegration" ,
75+ "sentry_sdk.integrations.dedupe.DedupeIntegration" ,
76+ "sentry_sdk.integrations.atexit.AtexitIntegration" ,
77+ "sentry_sdk.integrations.modules.ModulesIntegration" ,
78+ "sentry_sdk.integrations.argv.ArgvIntegration" ,
79+ "sentry_sdk.integrations.threading.ThreadingIntegration" ,
80+ ),
81+ auto_enabling_integrations = _AUTO_ENABLING_INTEGRATIONS ,
5282)
5383
5484del _generate_default_integrations_iterator
5585
5686
57- def setup_integrations (integrations , with_defaults = True ):
58- # type: (List[Integration], bool) -> Dict[str, Integration]
87+ def setup_integrations (
88+ integrations , with_defaults = True , with_auto_enabling_integrations = False
89+ ):
90+ # type: (List[Integration], bool, bool) -> Dict[str, Integration]
5991 """Given a list of integration instances this installs them all. When
6092 `with_defaults` is set to `True` then all default integrations are added
6193 unless they were already provided before.
@@ -66,11 +98,17 @@ def setup_integrations(integrations, with_defaults=True):
6698
6799 logger .debug ("Setting up integrations (with default = %s)" , with_defaults )
68100
101+ # Integrations that are not explicitly set up by the user.
102+ used_as_default_integration = set ()
103+
69104 if with_defaults :
70- for integration_cls in iter_default_integrations ():
105+ for integration_cls in iter_default_integrations (
106+ with_auto_enabling_integrations
107+ ):
71108 if integration_cls .identifier not in integrations :
72109 instance = integration_cls ()
73110 integrations [instance .identifier ] = instance
111+ used_as_default_integration .add (instance .identifier )
74112
75113 for identifier , integration in iteritems (integrations ):
76114 with _installer_lock :
@@ -90,6 +128,14 @@ def setup_integrations(integrations, with_defaults=True):
90128 integration .install ()
91129 else :
92130 raise
131+ except DidNotEnable as e :
132+ if identifier not in used_as_default_integration :
133+ raise
134+
135+ logger .debug (
136+ "Did not enable default integration %s: %s" , identifier , e
137+ )
138+
93139 _installed_integrations .add (identifier )
94140
95141 for identifier in integrations :
@@ -98,6 +144,16 @@ def setup_integrations(integrations, with_defaults=True):
98144 return integrations
99145
100146
147+ class DidNotEnable (Exception ):
148+ """
149+ The integration could not be enabled due to a trivial user error like
150+ `flask` not being installed for the `FlaskIntegration`.
151+
152+ This exception is silently swallowed for default integrations, but reraised
153+ for explicitly enabled integrations.
154+ """
155+
156+
101157class Integration (object ):
102158 """Baseclass for all integrations.
103159
0 commit comments