Skip to content

Commit 9fc3bd2

Browse files
authored
Fix AWS Lambda tests (#3495)
AWS changed their Lambda run times, so we no longer have access to the current exception during the init phase of the Lambda function. I am trying to fix this upstream: aws/aws-lambda-python-runtime-interface-client#172 This PR adds a fall back to the errror json object provided by AWS. This has way less data than a real exception in it, but it is better than nothing. Fixes #3464
1 parent e99873d commit 9fc3bd2

File tree

2 files changed

+73
-10
lines changed

2 files changed

+73
-10
lines changed

Diff for: sentry_sdk/integrations/aws_lambda.py

+62
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import json
2+
import re
13
import sys
24
from copy import deepcopy
35
from datetime import datetime, timedelta, timezone
@@ -56,6 +58,11 @@ def sentry_init_error(*args, **kwargs):
5658
)
5759
sentry_sdk.capture_event(sentry_event, hint=hint)
5860

61+
else:
62+
# Fall back to AWS lambdas JSON representation of the error
63+
sentry_event = _event_from_error_json(json.loads(args[1]))
64+
sentry_sdk.capture_event(sentry_event)
65+
5966
return init_error(*args, **kwargs)
6067

6168
return sentry_init_error # type: ignore
@@ -428,3 +435,58 @@ def _get_cloudwatch_logs_url(aws_context, start_time):
428435
)
429436

430437
return url
438+
439+
440+
def _parse_formatted_traceback(formatted_tb):
441+
# type: (list[str]) -> list[dict[str, Any]]
442+
frames = []
443+
for frame in formatted_tb:
444+
match = re.match(r'File "(.+)", line (\d+), in (.+)', frame.strip())
445+
if match:
446+
file_name, line_number, func_name = match.groups()
447+
line_number = int(line_number)
448+
frames.append(
449+
{
450+
"filename": file_name,
451+
"function": func_name,
452+
"lineno": line_number,
453+
"vars": None,
454+
"pre_context": None,
455+
"context_line": None,
456+
"post_context": None,
457+
}
458+
)
459+
return frames
460+
461+
462+
def _event_from_error_json(error_json):
463+
# type: (dict[str, Any]) -> Event
464+
"""
465+
Converts the error JSON from AWS Lambda into a Sentry error event.
466+
This is not a full fletched event, but better than nothing.
467+
468+
This is an example of where AWS creates the error JSON:
469+
https://github.com/aws/aws-lambda-python-runtime-interface-client/blob/2.2.1/awslambdaric/bootstrap.py#L479
470+
"""
471+
event = {
472+
"level": "error",
473+
"exception": {
474+
"values": [
475+
{
476+
"type": error_json.get("errorType"),
477+
"value": error_json.get("errorMessage"),
478+
"stacktrace": {
479+
"frames": _parse_formatted_traceback(
480+
error_json.get("stackTrace", [])
481+
),
482+
},
483+
"mechanism": {
484+
"type": "aws_lambda",
485+
"handled": False,
486+
},
487+
}
488+
],
489+
},
490+
} # type: Event
491+
492+
return event

Diff for: tests/integrations/aws_lambda/test_aws.py

+11-10
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,13 @@
3636

3737
import pytest
3838

39+
RUNTIMES_TO_TEST = [
40+
"python3.8",
41+
"python3.9",
42+
"python3.10",
43+
"python3.11",
44+
"python3.12",
45+
]
3946

4047
LAMBDA_PRELUDE = """
4148
from sentry_sdk.integrations.aws_lambda import AwsLambdaIntegration, get_lambda_bootstrap
@@ -137,15 +144,7 @@ def lambda_client():
137144
return get_boto_client()
138145

139146

140-
@pytest.fixture(
141-
params=[
142-
"python3.8",
143-
"python3.9",
144-
"python3.10",
145-
"python3.11",
146-
"python3.12",
147-
]
148-
)
147+
@pytest.fixture(params=RUNTIMES_TO_TEST)
149148
def lambda_runtime(request):
150149
return request.param
151150

@@ -331,7 +330,9 @@ def test_init_error(run_lambda_function, lambda_runtime):
331330
syntax_check=False,
332331
)
333332

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

337338

0 commit comments

Comments
 (0)