Skip to content

Commit 66ffc91

Browse files
authored
test: AWS Lambda on Python 3.7 (#174)
* test: AWS Lambda on Python 3.7 * fix(aws_lambda): Refactor to support Python 3.7
1 parent cc81d01 commit 66ffc91

File tree

3 files changed

+89
-46
lines changed

3 files changed

+89
-46
lines changed

scripts/aws-cleanup.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/bin/sh
2+
# Delete all AWS Lambda functions
3+
for func in $(aws lambda list-functions | jq .Functions[].FunctionName); do
4+
echo "Deleting $func"
5+
aws lambda delete-function --function-name $func
6+
done

sentry_sdk/integrations/aws_lambda.py

Lines changed: 81 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -12,73 +12,109 @@
1212
from sentry_sdk.integrations._wsgi_common import _filter_headers
1313

1414

15+
def _wrap_handler(handler):
16+
def sentry_handler(event, context, *args, **kwargs):
17+
hub = Hub.current
18+
integration = hub.get_integration(AwsLambdaIntegration)
19+
if integration is None:
20+
return handler(event, context, *args, **kwargs)
21+
22+
with hub.push_scope() as scope:
23+
with capture_internal_exceptions():
24+
scope.transaction = context.function_name
25+
scope.add_event_processor(_make_request_event_processor(event, context))
26+
27+
try:
28+
return handler(event, context, *args, **kwargs)
29+
except Exception:
30+
exc_info = sys.exc_info()
31+
event, hint = event_from_exception(
32+
exc_info,
33+
client_options=hub.client.options,
34+
mechanism={"type": "aws_lambda", "handled": False},
35+
)
36+
hub.capture_event(event, hint=hint)
37+
reraise(*exc_info)
38+
39+
return sentry_handler
40+
41+
42+
def _drain_queue():
43+
with capture_internal_exceptions():
44+
hub = Hub.current
45+
integration = hub.get_integration(AwsLambdaIntegration)
46+
if integration is not None:
47+
# Flush out the event queue before AWS kills the
48+
# process. This is not threadsafe.
49+
# make new transport with empty queue
50+
new_transport = hub.client.transport.copy()
51+
hub.client.close()
52+
hub.client.transport = new_transport
53+
54+
1555
class AwsLambdaIntegration(Integration):
1656
identifier = "aws_lambda"
1757

1858
@staticmethod
1959
def setup_once():
2060
import __main__ as lambda_bootstrap
2161

22-
if not hasattr(lambda_bootstrap, "make_final_handler"):
62+
pre_37 = True # Python 3.6 or 2.7
63+
64+
if not hasattr(lambda_bootstrap, "handle_http_request"):
65+
try:
66+
import bootstrap as lambda_bootstrap
67+
68+
pre_37 = False # Python 3.7
69+
except ImportError:
70+
pass
71+
72+
if not hasattr(lambda_bootstrap, "handle_event_request"):
2373
logger.warning(
2474
"Not running in AWS Lambda environment, "
2575
"AwsLambdaIntegration disabled"
2676
)
2777
return
2878

29-
import runtime as lambda_runtime
79+
if pre_37:
80+
old_handle_event_request = lambda_bootstrap.handle_event_request
3081

31-
old_make_final_handler = lambda_bootstrap.make_final_handler
82+
def sentry_handle_event_request(request_handler, *args, **kwargs):
83+
request_handler = _wrap_handler(request_handler)
84+
return old_handle_event_request(request_handler, *args, **kwargs)
3285

33-
def sentry_make_final_handler(*args, **kwargs):
34-
handler = old_make_final_handler(*args, **kwargs)
86+
lambda_bootstrap.handle_event_request = sentry_handle_event_request
3587

36-
def sentry_handler(event, context, *args, **kwargs):
37-
hub = Hub.current
38-
integration = hub.get_integration(AwsLambdaIntegration)
39-
if integration is None:
40-
return handler(event, context, *args, **kwargs)
88+
old_handle_http_request = lambda_bootstrap.handle_http_request
4189

42-
with hub.push_scope() as scope:
43-
with capture_internal_exceptions():
44-
scope.transaction = context.function_name
45-
scope.add_event_processor(
46-
_make_request_event_processor(event, context)
47-
)
90+
def sentry_handle_http_request(request_handler, *args, **kwargs):
91+
request_handler = _wrap_handler(request_handler)
92+
return old_handle_http_request(request_handler, *args, **kwargs)
4893

49-
try:
50-
return handler(event, context, *args, **kwargs)
51-
except Exception:
52-
exc_info = sys.exc_info()
53-
event, hint = event_from_exception(
54-
exc_info,
55-
client_options=hub.client.options,
56-
mechanism={"type": "aws_lambda", "handled": False},
57-
)
58-
hub.capture_event(event, hint=hint)
59-
reraise(*exc_info)
94+
lambda_bootstrap.handle_http_request = sentry_handle_http_request
95+
else:
96+
old_handle_event_request = lambda_bootstrap.handle_event_request
6097

61-
return sentry_handler
98+
def sentry_handle_event_request(
99+
lambda_runtime_client, request_handler, *args, **kwargs
100+
):
101+
request_handler = _wrap_handler(request_handler)
102+
return old_handle_event_request(
103+
lambda_runtime_client, request_handler, *args, **kwargs
104+
)
62105

63-
lambda_bootstrap.make_final_handler = sentry_make_final_handler
106+
lambda_bootstrap.handle_event_request = sentry_handle_event_request
64107

65-
old_report_done = lambda_runtime.report_done
108+
# This is the only function that is called in all Python environments
109+
# at the end of the request/response lifecycle. It is the only way to
110+
# do it in the Python 3.7 env.
111+
old_to_json = lambda_bootstrap.to_json
66112

67-
def sentry_report_done(*args, **kwargs):
68-
with capture_internal_exceptions():
69-
hub = Hub.current
70-
integration = hub.get_integration(AwsLambdaIntegration)
71-
if integration is not None:
72-
# Flush out the event queue before AWS kills the
73-
# process. This is not threadsafe.
74-
# make new transport with empty queue
75-
new_transport = hub.client.transport.copy()
76-
hub.client.close()
77-
hub.client.transport = new_transport
78-
79-
return old_report_done(*args, **kwargs)
80-
81-
lambda_runtime.report_done = sentry_report_done
113+
def sentry_to_json(*args, **kwargs):
114+
_drain_queue()
115+
return old_to_json(*args, **kwargs)
116+
117+
lambda_bootstrap.to_json = sentry_to_json
82118

83119

84120
def _make_request_event_processor(aws_event, aws_context):

tests/integrations/aws_lambda/test_aws.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ def shutdown(self, timeout, callback=None):
3434
# failing.
3535
for event in self._queue:
3636
print("EVENT:", json.dumps(event))
37+
del self._queue[:]
3738
3839
def init_sdk(**extra_init_args):
3940
sentry_sdk.init(
@@ -57,7 +58,7 @@ def lambda_client():
5758
)
5859

5960

60-
@pytest.fixture(params=["python3.6", "python2.7"])
61+
@pytest.fixture(params=["python3.6", "python3.7", "python2.7"])
6162
def run_lambda_function(tmpdir, lambda_client, request, assert_semaphore_acceptance):
6263
def inner(code, payload):
6364
runtime = request.param

0 commit comments

Comments
 (0)