Skip to content

Commit f144312

Browse files
committed
add-events-chalice
1 parent aafc23b commit f144312

1 file changed

Lines changed: 42 additions & 58 deletions

File tree

sentry_sdk/integrations/chalice.py

Lines changed: 42 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
import sys
22
import traceback
3-
from datetime import datetime, timedelta
4-
from os import environ
3+
from datetime import datetime
54

5+
import chalice
66
from chalice import Chalice, ChaliceViewError, Response
7+
from chalice.app import EventSourceHandler as ChaliceEventSourceHandler
78
from sentry_sdk._types import MYPY
89
from sentry_sdk.hub import Hub, _should_send_default_pii
910
from sentry_sdk.integrations import Integration
1011
from sentry_sdk.integrations._wsgi_common import _filter_headers
11-
from sentry_sdk.integrations.aws_lambda import AwsLambdaIntegration
12+
from sentry_sdk.integrations.aws_lambda import _get_cloudwatch_logs_url
1213
from sentry_sdk.utils import (
1314
AnnotatedValue,
1415
capture_internal_exceptions,
@@ -21,6 +22,32 @@
2122
from sentry_sdk._types import Event, EventProcessor, Hint
2223

2324

25+
class EventSourceHandler(ChaliceEventSourceHandler):
26+
27+
def __call__(self, event, context):
28+
hub = Hub.current
29+
client = hub.client
30+
31+
with hub.push_scope() as scope:
32+
try:
33+
event_obj = self.event_class(event, context)
34+
return self.func(event_obj)
35+
except Exception:
36+
scope.add_event_processor(
37+
_make_request_event_processor(
38+
event, context
39+
)
40+
)
41+
exc_info = sys.exc_info()
42+
event, hint = event_from_exception(
43+
exc_info,
44+
client_options=client.options,
45+
mechanism={"type": "chalice", "handled": False},
46+
)
47+
hub.capture_event(event, hint=hint)
48+
hub.flush()
49+
50+
2451
def _get_view_function_response(app, view_function, function_args):
2552
hub = Hub.current
2653
client = hub.client
@@ -83,7 +110,7 @@ def setup_once():
83110
# for @app.route()
84111
Chalice._get_view_function_response = _get_view_function_response
85112
# for everything else (like events)
86-
AwsLambdaIntegration.setup_once()
113+
chalice.app.EventSourceHandler = EventSourceHandler
87114

88115

89116
def _make_request_event_processor(current_request, lambda_context):
@@ -92,36 +119,32 @@ def _make_request_event_processor(current_request, lambda_context):
92119

93120
def event_processor(event, hint, start_time=start_time):
94121
# type: (Event, Hint, datetime) -> Optional[Event]
122+
95123
extra = event.setdefault("extra", {})
96-
extra["lambda"] = {
124+
125+
extra["Chalice-lambda"] = {
97126
"function_name": lambda_context.function_name,
98127
"function_version": lambda_context.function_version,
99-
"invoked_function_arn": lambda_context.invoked_function_arn,
128+
"Lambda ARN": lambda_context.invoked_function_arn,
100129
"aws_request_id": lambda_context.aws_request_id,
101130
}
102131

103-
extra["cloudwatch logs"] = {
132+
extra["cloudwatch-info"] = {
104133
"url": _get_cloudwatch_logs_url(lambda_context, start_time),
105134
"log_group": lambda_context.log_group_name,
106135
"log_stream": lambda_context.log_stream_name,
107136
}
108137

109-
request = event.get("request", {})
110-
if "httpMethod" in current_request.context:
111-
request["method"] = current_request.context["httpMethod"]
138+
request_info = event.get("request", {})
112139

113-
request["url"] = _get_url(current_request, lambda_context)
140+
request_info["method"] = current_request.context["httpMethod"]
114141

115-
if "query_params" in current_request.to_dict():
116-
request["query_string"] = current_request.query_params
142+
request_info["query_string"] = current_request.query_params
117143

118-
if "headers" in current_request.to_dict():
119-
request["headers"] = _filter_headers(current_request.headers)
144+
request_info["headers"] = _filter_headers(current_request.headers)
120145

121146
if current_request._body is None:
122-
# Unfortunately couldn't find a way to get structured body from AWS
123-
# event. Meaning every body is unstructured to us.
124-
request["data"] = AnnotatedValue(
147+
request_info["data"] = AnnotatedValue(
125148
"", {"rem": [["!raw", "x", 0, 0]]}
126149
)
127150

@@ -136,47 +159,8 @@ def event_processor(event, hint, start_time=start_time):
136159
if ip is not None:
137160
user_info.setdefault("ip_address", ip)
138161

139-
event["request"] = request
162+
event["request"] = request_info
140163

141164
return event
142165

143166
return event_processor
144-
145-
146-
def _get_url(event, context):
147-
# type: (Any, Any) -> str
148-
path = event.context["path"]
149-
headers = event.headers
150-
host = headers.get("Host", None)
151-
proto = headers.get("X-Forwarded-Proto", None)
152-
if proto and host and path:
153-
return "{}://{}{}".format(proto, host, path)
154-
return "awslambda:///{}".format(context.function_name)
155-
156-
157-
def _get_cloudwatch_logs_url(context, start_time):
158-
# type: (Any, datetime) -> str
159-
"""
160-
Generates a CloudWatchLogs console URL based on the context object
161-
Arguments:
162-
context {Any} -- context from lambda handler
163-
Returns:
164-
str -- AWS Console URL to logs.
165-
"""
166-
formatstring = "%Y-%m-%dT%H:%M:%S"
167-
168-
url = (
169-
"https://console.aws.amazon.com/cloudwatch/home?region={region}"
170-
"#logEventViewer:group={log_group};stream={log_stream}"
171-
";start={start_time};end={end_time}"
172-
).format(
173-
region=environ.get("AWS_REGION"),
174-
log_group=context.log_group_name,
175-
log_stream=context.log_stream_name,
176-
start_time=(start_time - timedelta(seconds=1)).strftime(formatstring),
177-
end_time=(datetime.now() + timedelta(seconds=2)).strftime(
178-
formatstring
179-
),
180-
)
181-
182-
return url

0 commit comments

Comments
 (0)