wrapRouteHandlerWithSentry.js 3.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. import { _nullishCoalesce, _optionalChain } from '@sentry/utils';
  2. import { addTracingExtensions, withIsolationScope, continueTrace, startSpan, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, handleCallbackErrors, captureException, setHttpStatus } from '@sentry/core';
  3. import { winterCGHeadersToDict } from '@sentry/utils';
  4. import { isRedirectNavigationError } from './nextNavigationErrorUtils.js';
  5. import { platformSupportsStreaming } from './utils/platformSupportsStreaming.js';
  6. import { flushQueue } from './utils/responseEnd.js';
  7. /**
  8. * Wraps a Next.js route handler with performance and error instrumentation.
  9. */
  10. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  11. function wrapRouteHandlerWithSentry(
  12. routeHandler,
  13. context,
  14. ) {
  15. addTracingExtensions();
  16. // eslint-disable-next-line deprecation/deprecation
  17. const { method, parameterizedRoute, baggageHeader, sentryTraceHeader, headers } = context;
  18. return new Proxy(routeHandler, {
  19. apply: (originalFunction, thisArg, args) => {
  20. return withIsolationScope(async isolationScope => {
  21. isolationScope.setSDKProcessingMetadata({
  22. request: {
  23. headers: headers ? winterCGHeadersToDict(headers) : undefined,
  24. },
  25. });
  26. return continueTrace(
  27. {
  28. sentryTrace: _nullishCoalesce(_nullishCoalesce(sentryTraceHeader, () => ( _optionalChain([headers, 'optionalAccess', _ => _.get, 'call', _2 => _2('sentry-trace')]))), () => ( undefined)),
  29. baggage: _nullishCoalesce(baggageHeader, () => ( _optionalChain([headers, 'optionalAccess', _3 => _3.get, 'call', _4 => _4('baggage')]))),
  30. },
  31. async () => {
  32. try {
  33. return await startSpan(
  34. {
  35. op: 'http.server',
  36. name: `${method} ${parameterizedRoute}`,
  37. attributes: {
  38. [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route',
  39. [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.nextjs',
  40. },
  41. },
  42. async span => {
  43. const response = await handleCallbackErrors(
  44. () => originalFunction.apply(thisArg, args),
  45. error => {
  46. // Next.js throws errors when calling `redirect()`. We don't wanna report these.
  47. if (!isRedirectNavigationError(error)) {
  48. captureException(error, {
  49. mechanism: {
  50. handled: false,
  51. },
  52. });
  53. }
  54. },
  55. );
  56. try {
  57. span && setHttpStatus(span, response.status);
  58. } catch (e) {
  59. // best effort - response may be undefined?
  60. }
  61. return response;
  62. },
  63. );
  64. } finally {
  65. if (!platformSupportsStreaming() || process.env.NEXT_RUNTIME === 'edge') {
  66. // 1. Edge transport requires manual flushing
  67. // 2. Lambdas require manual flushing to prevent execution freeze before the event is sent
  68. await flushQueue();
  69. }
  70. }
  71. },
  72. );
  73. });
  74. },
  75. });
  76. }
  77. export { wrapRouteHandlerWithSentry };
  78. //# sourceMappingURL=wrapRouteHandlerWithSentry.js.map