chalice.py 4.6 KB

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