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

Fix AWS Lambda tests #3495

Merged
merged 5 commits into from
Sep 5, 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
62 changes: 62 additions & 0 deletions sentry_sdk/integrations/aws_lambda.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import json
import re
import sys
from copy import deepcopy
from datetime import datetime, timedelta, timezone
Expand Down Expand Up @@ -56,6 +58,11 @@ def sentry_init_error(*args, **kwargs):
)
sentry_sdk.capture_event(sentry_event, hint=hint)

else:
# Fall back to AWS lambdas JSON representation of the error
sentry_event = _event_from_error_json(json.loads(args[1]))
sentry_sdk.capture_event(sentry_event)

return init_error(*args, **kwargs)

return sentry_init_error # type: ignore
Expand Down Expand Up @@ -428,3 +435,58 @@ def _get_cloudwatch_logs_url(aws_context, start_time):
)

return url


def _parse_formatted_traceback(formatted_tb):
# type: (list[str]) -> list[dict[str, Any]]
frames = []
for frame in formatted_tb:
match = re.match(r'File "(.+)", line (\d+), in (.+)', frame.strip())
if match:
file_name, line_number, func_name = match.groups()
line_number = int(line_number)
frames.append(
{
"filename": file_name,
"function": func_name,
"lineno": line_number,
"vars": None,
"pre_context": None,
"context_line": None,
"post_context": None,
}
)
return frames


def _event_from_error_json(error_json):
# type: (dict[str, Any]) -> Event
"""
Converts the error JSON from AWS Lambda into a Sentry error event.
This is not a full fletched event, but better than nothing.

This is an example of where AWS creates the error JSON:
https://github.com/aws/aws-lambda-python-runtime-interface-client/blob/2.2.1/awslambdaric/bootstrap.py#L479
"""
event = {
"level": "error",
"exception": {
"values": [
{
"type": error_json.get("errorType"),
"value": error_json.get("errorMessage"),
"stacktrace": {
"frames": _parse_formatted_traceback(
error_json.get("stackTrace", [])
),
},
"mechanism": {
"type": "aws_lambda",
"handled": False,
},
}
],
},
} # type: Event

return event
21 changes: 11 additions & 10 deletions tests/integrations/aws_lambda/test_aws.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@

import pytest

RUNTIMES_TO_TEST = [
"python3.8",
"python3.9",
"python3.10",
"python3.11",
"python3.12",
]

LAMBDA_PRELUDE = """
from sentry_sdk.integrations.aws_lambda import AwsLambdaIntegration, get_lambda_bootstrap
Expand Down Expand Up @@ -137,15 +144,7 @@ def lambda_client():
return get_boto_client()


@pytest.fixture(
params=[
"python3.8",
"python3.9",
"python3.10",
"python3.11",
"python3.12",
]
)
@pytest.fixture(params=RUNTIMES_TO_TEST)
def lambda_runtime(request):
return request.param

Expand Down Expand Up @@ -331,7 +330,9 @@ def test_init_error(run_lambda_function, lambda_runtime):
syntax_check=False,
)

(event,) = envelope_items
# We just take the last one, because it could be that in the output of the Lambda
# invocation there is still the envelope of the previous invocation of the function.
event = envelope_items[-1]
assert event["exception"]["values"][0]["value"] == "name 'func' is not defined"


Expand Down
Loading