From bffdb6658b7239d483c627209c301ed95cfa126f Mon Sep 17 00:00:00 2001 From: Steve Kirkland Date: Thu, 19 Jun 2025 15:48:03 +0100 Subject: [PATCH 1/8] WIP --- CHANGELOG.md | 4 +++- bugsnag/configuration.py | 40 +++++++++++++++++++++++++++---------- bugsnag/delivery.py | 6 ++++-- tests/test_configuration.py | 2 +- 4 files changed, 38 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index de416556..3495a5ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,8 +5,10 @@ Changelog ### Enhancements -* Remove depricated `datetime.utcnow()` method call from utils class +* Remove deprecated `datetime.utcnow()` method call from utils class [#394](https://github.com/bugsnag/bugsnag-python/pull/394). +* Set default endpoints based on API key + [#399](https://github.com/bugsnag/bugsnag-php/pull/399) ## v4.7.1 (2024-05-22) diff --git a/bugsnag/configuration.py b/bugsnag/configuration.py index 114de35b..15bf9cc6 100644 --- a/bugsnag/configuration.py +++ b/bugsnag/configuration.py @@ -30,8 +30,11 @@ validate_int_setter, validate_path_setter ) -from bugsnag.delivery import (create_default_delivery, DEFAULT_ENDPOINT, - DEFAULT_SESSIONS_ENDPOINT) +from bugsnag.delivery import (create_default_delivery, + DEFAULT_ENDPOINT, + DEFAULT_SESSIONS_ENDPOINT, + HUB_ENDPOINT, + HUB_SESSIONS_ENDPOINT) from bugsnag.uwsgi import warn_if_running_uwsgi_without_threads from bugsnag.error import Error @@ -55,6 +58,11 @@ _sentinel = object() +def _is_hub_api_key(api_key: str) -> bool: + hub_prefix = "00000" + return api_key is not None and api_key.startswith(hub_prefix) + + class Configuration: """ Global app-level Bugsnag configuration settings. @@ -83,8 +91,8 @@ def __init__(self, logger=_sentinel): "django.http.Http404", "django.http.response.Http404", ] - self.endpoint = DEFAULT_ENDPOINT - self.session_endpoint = DEFAULT_SESSIONS_ENDPOINT + self.endpoint = None + self.session_endpoint = None self.auto_capture_sessions = True self.traceback_exclude_modules = [] @@ -126,8 +134,6 @@ def configure(self, api_key=None, app_type=None, app_version=None, Validate and set configuration options. Will warn if an option is of an incorrect type. """ - if api_key is not None: - self.api_key = api_key if app_type is not None: self.app_type = app_type if app_version is not None: @@ -140,8 +146,6 @@ def configure(self, api_key=None, app_type=None, app_version=None, self.auto_capture_sessions = auto_capture_sessions if delivery is not None: self.delivery = delivery - if endpoint is not None: - self.endpoint = endpoint if hostname is not None: self.hostname = hostname if ignore_classes is not None: @@ -162,8 +166,6 @@ def configure(self, api_key=None, app_type=None, app_version=None, self.send_code = send_code if send_environment is not None: self.send_environment = send_environment - if session_endpoint is not None: - self.session_endpoint = session_endpoint if traceback_exclude_modules is not None: self.traceback_exclude_modules = traceback_exclude_modules if logger is not _sentinel: @@ -175,6 +177,11 @@ def configure(self, api_key=None, app_type=None, app_version=None, if max_breadcrumbs is not None: self.max_breadcrumbs = max_breadcrumbs + # Default endpoints depend on the API key + if api_key is not None: + self.api_key = api_key + self._initialize_endpoints(endpoint, session_endpoint, self.api_key) + return self def get(self, name): @@ -584,6 +591,19 @@ def _create_null_logger(self) -> logging.Logger: return logger + def _initialize_endpoints(self, endpoint, session_endpoint, api_key): + if endpoint is None and session_endpoint is None: + if _is_hub_api_key(api_key): + self.endpoint = HUB_ENDPOINT + self.session_endpoint = HUB_SESSIONS_ENDPOINT + else: + self.endpoint = DEFAULT_ENDPOINT + self.session_endpoint = DEFAULT_SESSIONS_ENDPOINT + if endpoint is not None: + self.endpoint = endpoint + if session_endpoint is not None: + self.session_endpoint = session_endpoint + class RequestConfiguration: """ diff --git a/bugsnag/delivery.py b/bugsnag/delivery.py index 6dc8cd05..f36d121a 100644 --- a/bugsnag/delivery.py +++ b/bugsnag/delivery.py @@ -28,6 +28,8 @@ DEFAULT_ENDPOINT = 'https://notify.bugsnag.com' DEFAULT_SESSIONS_ENDPOINT = 'https://sessions.bugsnag.com' +HUB_ENDPOINT = 'https://notify.insighthub.smartbear.com' +HUB_SESSIONS_ENDPOINT = 'https://sessions.insighthub.smartbear.com' __all__ = ('default_headers', 'Delivery') @@ -82,8 +84,8 @@ def deliver_sessions(self, config, payload: Any, options=None): """ Sends sessions to Bugsnag """ - if (config.endpoint != DEFAULT_ENDPOINT and config.session_endpoint == - DEFAULT_SESSIONS_ENDPOINT): + if ((config.endpoint != DEFAULT_ENDPOINT and config.session_endpoint == DEFAULT_SESSIONS_ENDPOINT) or + (config.endpoint != HUB_ENDPOINT and config.session_endpoint == HUB_SESSIONS_ENDPOINT)): if not self.sent_session_warning: warnings.warn('The session endpoint has not been configured. ' 'No sessions will be sent to Bugsnag.') diff --git a/tests/test_configuration.py b/tests/test_configuration.py index 03266940..439da5c9 100644 --- a/tests/test_configuration.py +++ b/tests/test_configuration.py @@ -83,7 +83,7 @@ def test_hostname(self): def test_session_tracking_defaults(self): c = Configuration() self.assertTrue(c.auto_capture_sessions) - self.assertEqual(c.session_endpoint, "https://sessions.bugsnag.com") + self.assertEqual(c.session_endpoint, None) def test_default_middleware_location(self): c = Configuration() From 8e7508c53a743a7753a4646648af42641ba823e3 Mon Sep 17 00:00:00 2001 From: Steve Kirkland Date: Thu, 19 Jun 2025 17:17:39 +0100 Subject: [PATCH 2/8] Only default endpoints if not already set --- bugsnag/configuration.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bugsnag/configuration.py b/bugsnag/configuration.py index 15bf9cc6..f6bb9a11 100644 --- a/bugsnag/configuration.py +++ b/bugsnag/configuration.py @@ -592,13 +592,16 @@ def _create_null_logger(self) -> logging.Logger: return logger def _initialize_endpoints(self, endpoint, session_endpoint, api_key): - if endpoint is None and session_endpoint is None: + # Default endpoints depending on the API key, if not already set + if (endpoint is None and session_endpoint is None and + self.endpoint is None and self.session_endpoint is None): if _is_hub_api_key(api_key): self.endpoint = HUB_ENDPOINT self.session_endpoint = HUB_SESSIONS_ENDPOINT else: self.endpoint = DEFAULT_ENDPOINT self.session_endpoint = DEFAULT_SESSIONS_ENDPOINT + # Do set endpoints if explicitly provided if endpoint is not None: self.endpoint = endpoint if session_endpoint is not None: From e5b0227c83c176a0fa3deaad25923d176287bd82 Mon Sep 17 00:00:00 2001 From: Steve Kirkland Date: Thu, 19 Jun 2025 18:46:59 +0100 Subject: [PATCH 3/8] Fix linter errors --- bugsnag/configuration.py | 2 +- bugsnag/delivery.py | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/bugsnag/configuration.py b/bugsnag/configuration.py index f6bb9a11..be5df9e4 100644 --- a/bugsnag/configuration.py +++ b/bugsnag/configuration.py @@ -594,7 +594,7 @@ def _create_null_logger(self) -> logging.Logger: def _initialize_endpoints(self, endpoint, session_endpoint, api_key): # Default endpoints depending on the API key, if not already set if (endpoint is None and session_endpoint is None and - self.endpoint is None and self.session_endpoint is None): + self.endpoint is None and self.session_endpoint is None): if _is_hub_api_key(api_key): self.endpoint = HUB_ENDPOINT self.session_endpoint = HUB_SESSIONS_ENDPOINT diff --git a/bugsnag/delivery.py b/bugsnag/delivery.py index f36d121a..1a8f03cb 100644 --- a/bugsnag/delivery.py +++ b/bugsnag/delivery.py @@ -84,8 +84,10 @@ def deliver_sessions(self, config, payload: Any, options=None): """ Sends sessions to Bugsnag """ - if ((config.endpoint != DEFAULT_ENDPOINT and config.session_endpoint == DEFAULT_SESSIONS_ENDPOINT) or - (config.endpoint != HUB_ENDPOINT and config.session_endpoint == HUB_SESSIONS_ENDPOINT)): + if ((config.endpoint != DEFAULT_ENDPOINT and + config.session_endpoint == DEFAULT_SESSIONS_ENDPOINT) or + (config.endpoint != HUB_ENDPOINT and + config.session_endpoint == HUB_SESSIONS_ENDPOINT)): if not self.sent_session_warning: warnings.warn('The session endpoint has not been configured. ' 'No sessions will be sent to Bugsnag.') From 2fae759d62f07f133d06608cf8762fce7fc4e046 Mon Sep 17 00:00:00 2001 From: Steve Kirkland Date: Thu, 19 Jun 2025 18:57:26 +0100 Subject: [PATCH 4/8] 5 space indent --- bugsnag/configuration.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bugsnag/configuration.py b/bugsnag/configuration.py index be5df9e4..239786da 100644 --- a/bugsnag/configuration.py +++ b/bugsnag/configuration.py @@ -594,7 +594,7 @@ def _create_null_logger(self) -> logging.Logger: def _initialize_endpoints(self, endpoint, session_endpoint, api_key): # Default endpoints depending on the API key, if not already set if (endpoint is None and session_endpoint is None and - self.endpoint is None and self.session_endpoint is None): + self.endpoint is None and self.session_endpoint is None): if _is_hub_api_key(api_key): self.endpoint = HUB_ENDPOINT self.session_endpoint = HUB_SESSIONS_ENDPOINT From 654734fbce0b7ab38426bd1675c20c4d525c39e7 Mon Sep 17 00:00:00 2001 From: Steve Kirkland Date: Thu, 19 Jun 2025 19:02:38 +0100 Subject: [PATCH 5/8] 4 space indent --- bugsnag/configuration.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bugsnag/configuration.py b/bugsnag/configuration.py index 239786da..8e94fb1d 100644 --- a/bugsnag/configuration.py +++ b/bugsnag/configuration.py @@ -594,7 +594,8 @@ def _create_null_logger(self) -> logging.Logger: def _initialize_endpoints(self, endpoint, session_endpoint, api_key): # Default endpoints depending on the API key, if not already set if (endpoint is None and session_endpoint is None and - self.endpoint is None and self.session_endpoint is None): + self.endpoint is None and self.session_endpoint is None): + if _is_hub_api_key(api_key): self.endpoint = HUB_ENDPOINT self.session_endpoint = HUB_SESSIONS_ENDPOINT From 794a08909b8c03f1c1ec74c054b902c31c80f5f5 Mon Sep 17 00:00:00 2001 From: Steve Kirkland Date: Thu, 19 Jun 2025 19:09:58 +0100 Subject: [PATCH 6/8] bracket on new line --- bugsnag/configuration.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/bugsnag/configuration.py b/bugsnag/configuration.py index 8e94fb1d..20125937 100644 --- a/bugsnag/configuration.py +++ b/bugsnag/configuration.py @@ -593,9 +593,12 @@ def _create_null_logger(self) -> logging.Logger: def _initialize_endpoints(self, endpoint, session_endpoint, api_key): # Default endpoints depending on the API key, if not already set - if (endpoint is None and session_endpoint is None and - self.endpoint is None and self.session_endpoint is None): - + if ( + endpoint is None and + session_endpoint is None and + self.endpoint is None and + self.session_endpoint is None + ): if _is_hub_api_key(api_key): self.endpoint = HUB_ENDPOINT self.session_endpoint = HUB_SESSIONS_ENDPOINT From 0b44ee06878c6056efe5d788bd8f3553a25679e9 Mon Sep 17 00:00:00 2001 From: Steve Kirkland Date: Fri, 20 Jun 2025 13:55:11 +0100 Subject: [PATCH 7/8] Unit tests added --- tests/test_configuration.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/test_configuration.py b/tests/test_configuration.py index 439da5c9..57dfe03e 100644 --- a/tests/test_configuration.py +++ b/tests/test_configuration.py @@ -114,6 +114,16 @@ def test_validate_endpoint(self): c.configure(endpoint='https://notify.example.com') assert c.endpoint == 'https://notify.example.com' + def test_validate_endpoint_bugsnag_api_key(self): + c = Configuration() + c.configure(api_key='12312312312312312312312312321312') + assert c.endpoint == 'https://notify.bugsnag.com' + + def test_validate_endpoint_hub_api_key(self): + c = Configuration() + c.configure(api_key='00000312312312312312312312321312') + assert c.endpoint == 'https://notify.insighthub.smartbear.com' + def test_validate_app_type(self): c = Configuration() assert c.app_type is None @@ -410,6 +420,17 @@ def test_validate_session_endpoint(self): c.configure(session_endpoint='https://sessions.example.com') assert c.session_endpoint == 'https://sessions.example.com' + def test_validate_session_endpoint_bugsnag_api_key(self): + c = Configuration() + c.configure(api_key='12312312312312312312312312321312') + assert c.session_endpoint == 'https://sessions.bugsnag.com' + + def test_validate_session_endpoint_hub_api_key(self): + c = Configuration() + c.configure(api_key='00000312312312312312312312321312') + assert (c.session_endpoint == + 'https://sessions.insighthub.smartbear.com') + def test_validate_traceback_exclude_modules(self): c = Configuration() with pytest.warns(RuntimeWarning) as record: From 46a749c5b12210ba71a95b5b736d6b0b62b7f387 Mon Sep 17 00:00:00 2001 From: Steve Kirkland Date: Fri, 20 Jun 2025 18:15:44 +0100 Subject: [PATCH 8/8] Do not configure Client when initialised for singleton clients --- bugsnag/client.py | 5 +++-- bugsnag/legacy.py | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/bugsnag/client.py b/bugsnag/client.py index 558b074a..9717ce9a 100644 --- a/bugsnag/client.py +++ b/bugsnag/client.py @@ -32,10 +32,11 @@ class Client: """ def __init__(self, configuration: Optional[Configuration] = None, - install_sys_hook=True, **kwargs): + install_sys_hook=True, configure=True, **kwargs): self.configuration = configuration or Configuration() # type: Configuration # noqa: E501 self.session_tracker = SessionTracker(self.configuration) - self.configuration.configure(**kwargs) + if configure: + self.configuration.configure(**kwargs) self._context = ContextLocalState(self) self._request_tracker = RequestTracker() diff --git a/bugsnag/legacy.py b/bugsnag/legacy.py index 018e6735..32848b52 100644 --- a/bugsnag/legacy.py +++ b/bugsnag/legacy.py @@ -7,7 +7,7 @@ from bugsnag.configuration import RequestConfiguration from bugsnag.client import Client -default_client = Client() +default_client = Client(configure=False) configuration = default_client.configuration logger = configuration.logger ExcInfoType = Tuple[Type, Exception, types.TracebackType]