chalice.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. import sys
  2. from functools import wraps
  3. import sentry_sdk
  4. from sentry_sdk.integrations import Integration, DidNotEnable
  5. from sentry_sdk.integrations.aws_lambda import _make_request_event_processor
  6. from sentry_sdk.tracing import TransactionSource
  7. from sentry_sdk.utils import (
  8. capture_internal_exceptions,
  9. event_from_exception,
  10. parse_version,
  11. reraise,
  12. )
  13. try:
  14. import chalice # type: ignore
  15. from chalice import __version__ as CHALICE_VERSION
  16. from chalice import Chalice, ChaliceViewError
  17. from chalice.app import EventSourceHandler as ChaliceEventSourceHandler # type: ignore
  18. except ImportError:
  19. raise DidNotEnable("Chalice is not installed")
  20. from typing import TYPE_CHECKING
  21. if TYPE_CHECKING:
  22. from typing import Any
  23. from typing import Dict
  24. from typing import TypeVar
  25. from typing import Callable
  26. F = TypeVar("F", bound=Callable[..., Any])
  27. class EventSourceHandler(ChaliceEventSourceHandler): # type: ignore
  28. def __call__(self, event: "Any", context: "Any") -> "Any":
  29. client = sentry_sdk.get_client()
  30. with sentry_sdk.isolation_scope() as scope:
  31. with capture_internal_exceptions():
  32. configured_time = context.get_remaining_time_in_millis()
  33. scope.add_event_processor(
  34. _make_request_event_processor(event, context, configured_time)
  35. )
  36. try:
  37. return ChaliceEventSourceHandler.__call__(self, event, context)
  38. except Exception:
  39. exc_info = sys.exc_info()
  40. event, hint = event_from_exception(
  41. exc_info,
  42. client_options=client.options,
  43. mechanism={"type": "chalice", "handled": False},
  44. )
  45. sentry_sdk.capture_event(event, hint=hint)
  46. client.flush()
  47. reraise(*exc_info)
  48. def _get_view_function_response(
  49. app: "Any", view_function: "F", function_args: "Any"
  50. ) -> "F":
  51. @wraps(view_function)
  52. def wrapped_view_function(**function_args: "Any") -> "Any":
  53. client = sentry_sdk.get_client()
  54. with sentry_sdk.isolation_scope() as scope:
  55. with capture_internal_exceptions():
  56. configured_time = app.lambda_context.get_remaining_time_in_millis()
  57. scope.set_transaction_name(
  58. app.lambda_context.function_name,
  59. source=TransactionSource.COMPONENT,
  60. )
  61. scope.add_event_processor(
  62. _make_request_event_processor(
  63. app.current_request.to_dict(),
  64. app.lambda_context,
  65. configured_time,
  66. )
  67. )
  68. try:
  69. return view_function(**function_args)
  70. except Exception as exc:
  71. if isinstance(exc, ChaliceViewError):
  72. raise
  73. exc_info = sys.exc_info()
  74. event, hint = event_from_exception(
  75. exc_info,
  76. client_options=client.options,
  77. mechanism={"type": "chalice", "handled": False},
  78. )
  79. sentry_sdk.capture_event(event, hint=hint)
  80. client.flush()
  81. raise
  82. return wrapped_view_function # type: ignore
  83. class ChaliceIntegration(Integration):
  84. identifier = "chalice"
  85. @staticmethod
  86. def setup_once() -> None:
  87. version = parse_version(CHALICE_VERSION)
  88. if version is None:
  89. raise DidNotEnable("Unparsable Chalice version: {}".format(CHALICE_VERSION))
  90. if version < (1, 20):
  91. old_get_view_function_response = Chalice._get_view_function_response
  92. else:
  93. from chalice.app import RestAPIEventHandler
  94. old_get_view_function_response = (
  95. RestAPIEventHandler._get_view_function_response
  96. )
  97. def sentry_event_response(
  98. app: "Any", view_function: "F", function_args: "Dict[str, Any]"
  99. ) -> "Any":
  100. wrapped_view_function = _get_view_function_response(
  101. app, view_function, function_args
  102. )
  103. return old_get_view_function_response(
  104. app, wrapped_view_function, function_args
  105. )
  106. if version < (1, 20):
  107. Chalice._get_view_function_response = sentry_event_response
  108. else:
  109. RestAPIEventHandler._get_view_function_response = sentry_event_response
  110. # for everything else (like events)
  111. chalice.app.EventSourceHandler = EventSourceHandler