diff --git a/sentry_chalice/sentry_chalice.py b/sentry_chalice/sentry_chalice.py index 9c5343c..847e5d5 100644 --- a/sentry_chalice/sentry_chalice.py +++ b/sentry_chalice/sentry_chalice.py @@ -1,26 +1,14 @@ import sys import traceback -from datetime import datetime import chalice from chalice import Chalice, ChaliceViewError, Response from chalice.app import EventSourceHandler as ChaliceEventSourceHandler from sentry_sdk._compat import reraise -from sentry_sdk._types import MYPY -from sentry_sdk.hub import Hub, _should_send_default_pii +from sentry_sdk.hub import Hub from sentry_sdk.integrations import Integration -from sentry_sdk.integrations._wsgi_common import _filter_headers -from sentry_sdk.integrations.aws_lambda import _get_cloudwatch_logs_url -from sentry_sdk.utils import ( - AnnotatedValue, - capture_internal_exceptions, - event_from_exception, -) - -if MYPY: - from typing import Any, Optional - - from sentry_sdk._types import Event, EventProcessor, Hint +from sentry_sdk.integrations.aws_lambda import _make_request_event_processor +from sentry_sdk.utils import capture_internal_exceptions, event_from_exception class EventSourceHandler(ChaliceEventSourceHandler): @@ -33,8 +21,11 @@ def __call__(self, event, context): event_obj = self.event_class(event, context) return self.func(event_obj) except Exception: + configured_time = context.get_remaining_time_in_millis() scope.add_event_processor( - _make_request_event_processor(event, context) + _make_request_event_processor( + event, context, configured_time + ) ) exc_info = sys.exc_info() event, hint = event_from_exception( @@ -67,10 +58,15 @@ def _get_view_function_response(app, view_function, function_args): hub.flush() except Exception: with capture_internal_exceptions(): + configured_time = ( + app.lambda_context.get_remaining_time_in_millis() + ) scope.transaction = app.lambda_context.function_name scope.add_event_processor( _make_request_event_processor( - app.current_request, app.lambda_context + app.current_request, + app.lambda_context, + configured_time, ) ) exc_info = sys.exc_info() @@ -110,56 +106,3 @@ def setup_once(): Chalice._get_view_function_response = _get_view_function_response # for everything else (like events) chalice.app.EventSourceHandler = EventSourceHandler - - -def _make_request_event_processor(current_request, lambda_context): - # type: (Any, Any) -> EventProcessor - start_time = datetime.now() - - def event_processor(event, hint, start_time=start_time): - # type: (Event, Hint, datetime) -> Optional[Event] - - extra = event.setdefault("extra", {}) - - extra["Chalice-lambda"] = { - "function_name": lambda_context.function_name, - "function_version": lambda_context.function_version, - "Lambda ARN": lambda_context.invoked_function_arn, - "aws_request_id": lambda_context.aws_request_id, - } - - extra["cloudwatch info"] = { - "url": _get_cloudwatch_logs_url(lambda_context, start_time), - "log_group": lambda_context.log_group_name, - "log_stream": lambda_context.log_stream_name, - } - - request_info = event.get("request", {}) - - request_info["method"] = current_request.context["httpMethod"] - - request_info["query_string"] = current_request.query_params - - request_info["headers"] = _filter_headers(current_request.headers) - - if current_request._body is None: - request_info["data"] = AnnotatedValue( - "", {"rem": [["!raw", "x", 0, 0]]} - ) - - if _should_send_default_pii(): - user_info = event.setdefault("user", {}) - - id = current_request.context["identity"]["userArn"] - if id is not None: - user_info.setdefault("id", id) - - ip = current_request.context["identity"]["sourceIp"] - if ip is not None: - user_info.setdefault("ip_address", ip) - - event["request"] = request_info - - return event - - return event_processor diff --git a/sentry_chalice/version.py b/sentry_chalice/version.py index e1424ed..73e3bb4 100644 --- a/sentry_chalice/version.py +++ b/sentry_chalice/version.py @@ -1 +1 @@ -__version__ = '0.3.1' +__version__ = '0.3.2' diff --git a/setup.cfg b/setup.cfg index 7c2f984..6b59258 100644 --- a/setup.cfg +++ b/setup.cfg @@ -20,5 +20,4 @@ ignore_missing_imports = true [coverage:report] precision = 2 exclude_lines = - if MYPY: __version__ = diff --git a/tests/conftest.py b/tests/conftest.py index 24ca574..aae150e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -54,3 +54,11 @@ def append_envelope(envelope): return events return inner + + +@pytest.fixture +def lambda_context_args(): + # LambdaContext has several positional args before the ones that we + # care about for the timing tests, this gives reasonable defaults for + # those arguments. Taken from chalice tests + return ['lambda_name', 256] diff --git a/tests/test_sentry_chalice.py b/tests/test_sentry_chalice.py index a7ccabc..528cf47 100644 --- a/tests/test_sentry_chalice.py +++ b/tests/test_sentry_chalice.py @@ -1,7 +1,26 @@ import pytest +from chalice.local import LambdaContext from chalice.test import Client +class FakeTimeSource(object): + # taken from chalice tests + def __init__(self, times): + """Create a fake source of second-precision time. + :type time: List + :param time: List of times that the time source should return in the + order it should return them. These should be in seconds. + """ + self._times = times + + def time(self): + """Get the next time. + This is for mimicing the Clock interface used in local. + """ + time = self._times.pop(0) + return time + + def test_exception_boom(app) -> None: with Client(app) as client: response = client.http.get('/boom') @@ -22,16 +41,23 @@ def test_has_request(app, capture_events): assert response.status_code == 500 (event,) = events - assert event["transaction"] == "api_handler" - assert "data" not in event["request"] - assert event["request"]["headers"] == {} + assert event["level"] == "error" + (exception,) = event["exception"]["values"] + assert exception["type"] == "Exception" -def test_scheduled_event(app): + +def test_scheduled_event(app, lambda_context_args): @app.schedule('rate(1 minutes)') def every_hour(event): raise Exception('only chalice event!') + time_source = FakeTimeSource([0, 5]) + context = LambdaContext( + *lambda_context_args, max_runtime_ms=10000, time_source=time_source + ) + # time_remaining = context.get_remaining_time_in_millis() + lambda_event = { "version": "0", "account": "123456789012", @@ -46,7 +72,7 @@ def every_hour(event): ], } with pytest.raises(Exception) as exc_info: - every_hour(lambda_event, context=None) + every_hour(lambda_event, context=context) assert str(exc_info.value) == 'only chalice event!'