Skip to content

Commit

Permalink
Merge pull request #94 from SEKOIA-IO/feat/send_exception_to_api
Browse files Browse the repository at this point in the history
feat: Forward exceptions to the API
  • Loading branch information
Darkheir authored Nov 8, 2023
2 parents bfcae8a + be73266 commit cf2f531
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 14 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added

- Add property to connector with `User-Agent` header to third party services
- Forward exceptions to the API

## [1.6.2] - 2023-11-06

Expand Down
15 changes: 8 additions & 7 deletions sekoia_automation/trigger.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ def _execute_once(self) -> None:
# Configuration errors are considered to be critical
except (TriggerConfigurationError, ModuleConfigurationError) as e:
self.log_exception(e)
self.log(str(e), "critical")
self.log("Configuration error", "critical")
except (ConnectionError, HTTPClientError) as ex:
# Error while communicating with the S3 storage
# Don't increment the error count because this is an internal issue
Expand Down Expand Up @@ -286,15 +286,19 @@ def send_event(
remove_directory,
)

# Try to send the log record to the API
# If it can't be done, give up after 10 attempts and capture the logging error
def log_exception(self, exception: Exception, **kwargs):
super().log_exception(exception, **kwargs)
# Send error to the API
message = kwargs.get("message", "An exception occurred")
self.log(f"{message}\n{exception}", level="error", propagate=False)

def log(self, message: str, level: str = "info", *args, **kwargs) -> None:
if level == "critical" and self._critical_log_sent:
# Prevent sending multiple critical errors
level = "error"

super().log(message, level, *args, **kwargs)
if kwargs.pop("propagate", True):
super().log(message, level, *args, **kwargs)

self._logs.append(
{
Expand Down Expand Up @@ -403,9 +407,6 @@ def _handle_trigger_exception(self, e: Exception):
# Increase the consecutive error count
self._error_count += 1

# Make sure the error is recorded and available to the user
self.log(str(e), level="error")

# If there was more than 5 errors without any event being sent,
# log a critical error.
if self._is_error_critical():
Expand Down
20 changes: 13 additions & 7 deletions tests/test_trigger.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ def run(self):

trigger = TestTrigger()

with patch("sentry_sdk.capture_message") as sentry_patch:
with patch("sentry_sdk.capture_exception") as sentry_patch:
trigger._execute_once()
sentry_patch.assert_called()

Expand Down Expand Up @@ -365,9 +365,10 @@ def run(self):
trigger.execute()

# configuration errors are directly considered to be critical
assert mocked_trigger_logs.call_count == 1
assert mocked_trigger_logs.call_count == 2
assert mocked_trigger_logs.request_history[0].json()["logs"][0]["level"] == "error"
assert (
mocked_trigger_logs.request_history[0].json()["logs"][0]["level"] == "critical"
mocked_trigger_logs.request_history[1].json()["logs"][0]["level"] == "critical"
)


Expand Down Expand Up @@ -478,31 +479,34 @@ def test_trigger_liveness_not_found(monitored_trigger):
assert res.status_code == 404


def test_trigger_s3_connection_error():
def test_trigger_s3_connection_error(mocked_trigger_logs):
trigger = ErrorTrigger()
trigger.ex = ConnectionError(error="Err")

with patch("sentry_sdk.capture_exception") as sentry_patch:
trigger._execute_once()
sentry_patch.assert_called()
assert mocked_trigger_logs.called is True
assert trigger._error_count == 0


def test_trigger_s3_server_error_int():
def test_trigger_s3_server_error_int(mocked_trigger_logs):
trigger = ErrorTrigger()
trigger.ex = ClientError({"Error": {"Code": 500}}, "foo")
with patch("sentry_sdk.capture_exception") as sentry_patch:
trigger._execute_once()
sentry_patch.assert_called()
assert mocked_trigger_logs.called is True
assert trigger._error_count == 0


def test_trigger_s3_server_error_str():
def test_trigger_s3_server_error_str(mocked_trigger_logs):
trigger = ErrorTrigger()
trigger.ex = ClientError({"Error": {"Code": "ServiceUnavailable"}}, "foo")
with patch("sentry_sdk.capture_exception") as sentry_patch:
trigger._execute_once()
sentry_patch.assert_called()
assert mocked_trigger_logs.called is True
assert trigger._error_count == 0


Expand All @@ -513,6 +517,7 @@ def test_trigger_s3_client_error_int(mocked_trigger_logs):
trigger._execute_once()
sentry_patch.assert_called()
assert mocked_trigger_logs.called is True
assert mocked_trigger_logs.call_count == 1
assert trigger._error_count == 1


Expand All @@ -526,12 +531,13 @@ def test_trigger_s3_client_error_str(mocked_trigger_logs):
assert trigger._error_count == 1


def test_trigger_send_server_error():
def test_trigger_send_server_error(mocked_trigger_logs):
trigger = ErrorTrigger()
trigger.ex = SendEventError("Server error", 500)
with patch("sentry_sdk.capture_exception") as sentry_patch:
trigger._execute_once()
sentry_patch.assert_called()
assert mocked_trigger_logs.called is True
assert trigger._error_count == 0


Expand Down

0 comments on commit cf2f531

Please sign in to comment.