11"""This package"""
22from threading import Lock
3+ from collections import namedtuple
34
5+ from sentry_sdk ._compat import iteritems
46from sentry_sdk .utils import logger
5- from sentry_sdk .consts import INTEGRATIONS as _installed_integrations
67
78
89_installer_lock = Lock ()
10+ _installed_integrations = set ()
911
1012
11- def get_default_integrations ():
12- """Returns an iterator of default integration instances .
13+ def iter_default_integrations ():
14+ """Returns an iterator of default integration classes .
1315
1416 This returns the following default integration:
1517
@@ -25,54 +27,74 @@ def get_default_integrations():
2527 from sentry_sdk .integrations .atexit import AtexitIntegration
2628 from sentry_sdk .integrations .modules import ModulesIntegration
2729
28- yield LoggingIntegration ()
29- yield StdlibIntegration ()
30- yield ExcepthookIntegration ()
31- yield DedupeIntegration ()
32- yield AtexitIntegration ()
33- yield ModulesIntegration ()
30+ yield LoggingIntegration
31+ yield StdlibIntegration
32+ yield ExcepthookIntegration
33+ yield DedupeIntegration
34+ yield AtexitIntegration
35+ yield ModulesIntegration
3436
3537
3638def setup_integrations (integrations , with_defaults = True ):
3739 """Given a list of integration instances this installs them all. When
3840 `with_defaults` is set to `True` then all default integrations are added
3941 unless they were already provided before.
4042 """
41- integrations = list (integrations )
43+ integrations = dict (
44+ (integration .identifier , integration ) for integration in integrations or ()
45+ )
46+
4247 if with_defaults :
43- for instance in get_default_integrations ():
44- if not any (isinstance (x , type (instance )) for x in integrations ):
45- integrations .append (instance )
48+ for integration_cls in iter_default_integrations ():
49+ if integration_cls .identifier not in integrations :
50+ instance = integration_cls ()
51+ integrations [instance .identifier ] = instance
52+
53+ for identifier , integration in iteritems (integrations ):
54+ with _installer_lock :
55+ if identifier not in _installed_integrations :
56+ try :
57+ type (integration ).setup_once ()
58+ except NotImplementedError :
59+ if getattr (integration , "install" , None ) is not None :
60+ logger .warn (
61+ "Integration %s: The install method is "
62+ "deprecated. Use `setup_once`." ,
63+ identifier ,
64+ )
65+ integration .install ()
66+ else :
67+ raise
68+ _installed_integrations .add (identifier )
4669
47- for integration in integrations :
48- integration ()
70+ return integrations
71+
72+
73+ IntegrationAttachment = namedtuple (
74+ "IntegrationAttachment" , ["integration" , "client" , "hub" ]
75+ )
4976
5077
5178class Integration (object ):
52- """Baseclass for all integrations."""
79+ """Baseclass for all integrations.
5380
54- identifier = None
55- """A unique identifying string for the integration. Integrations must
56- set this as a class attribute.
81+ To accept options for an integration, implement your own constructor that
82+ saves those options on `self`.
5783 """
5884
59- def install (self ):
60- """An integration must implement all its code here. When the
61- `setup_integrations` function runs it will invoke this unless the
62- integration was already activated elsewhere.
85+ install = None
86+ """Legacy method, do not implement."""
87+
88+ @staticmethod
89+ def setup_once ():
6390 """
64- raise NotImplementedError ()
91+ Initialize the integration.
6592
66- def __call__ (self ):
67- assert self .identifier
68- with _installer_lock :
69- if self .identifier in _installed_integrations :
70- logger .warning (
71- "%s integration for Sentry is already "
72- "configured. Will ignore second configuration." ,
73- self .identifier ,
74- )
75- return
76-
77- self .install ()
78- _installed_integrations .append (self .identifier )
93+ This function is only called once, ever. Configuration is not available
94+ at this point, so the only thing to do here is to hook into exception
95+ handlers, and perhaps do monkeypatches.
96+
97+ Inside those hooks `Integration.current` can be used to access the
98+ instance again.
99+ """
100+ raise NotImplementedError ()
0 commit comments