wrapGenerationFunctionWithSentry.js 4.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. import { _nullishCoalesce, _optionalChain } from '@sentry/utils';
  2. import { addTracingExtensions, withIsolationScope, getCurrentScope, startSpanManual, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, handleCallbackErrors, captureException, getClient } from '@sentry/core';
  3. import { winterCGHeadersToDict, propagationContextFromHeaders } from '@sentry/utils';
  4. import { isNotFoundNavigationError, isRedirectNavigationError } from './nextNavigationErrorUtils.js';
  5. import { commonObjectToPropagationContext } from './utils/commonObjectTracing.js';
  6. /**
  7. * Wraps a generation function (e.g. generateMetadata) with Sentry error and performance instrumentation.
  8. */
  9. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  10. function wrapGenerationFunctionWithSentry(
  11. generationFunction,
  12. context,
  13. ) {
  14. addTracingExtensions();
  15. const { requestAsyncStorage, componentRoute, componentType, generationFunctionIdentifier } = context;
  16. return new Proxy(generationFunction, {
  17. apply: (originalFunction, thisArg, args) => {
  18. let headers = undefined;
  19. // We try-catch here just in case anything goes wrong with the async storage here goes wrong since it is Next.js internal API
  20. try {
  21. headers = _optionalChain([requestAsyncStorage, 'optionalAccess', _ => _.getStore, 'call', _2 => _2(), 'optionalAccess', _3 => _3.headers]);
  22. } catch (e) {
  23. /** empty */
  24. }
  25. let data = undefined;
  26. if (_optionalChain([getClient, 'call', _4 => _4(), 'optionalAccess', _5 => _5.getOptions, 'call', _6 => _6(), 'access', _7 => _7.sendDefaultPii])) {
  27. const props = args[0];
  28. const params = props && typeof props === 'object' && 'params' in props ? props.params : undefined;
  29. const searchParams =
  30. props && typeof props === 'object' && 'searchParams' in props ? props.searchParams : undefined;
  31. data = { params, searchParams };
  32. }
  33. return withIsolationScope(isolationScope => {
  34. isolationScope.setSDKProcessingMetadata({
  35. request: {
  36. headers: headers ? winterCGHeadersToDict(headers) : undefined,
  37. },
  38. });
  39. isolationScope.setExtra('route_data', data);
  40. const incomingPropagationContext = propagationContextFromHeaders(
  41. _nullishCoalesce(_optionalChain([headers, 'optionalAccess', _8 => _8.get, 'call', _9 => _9('sentry-trace')]), () => ( undefined)),
  42. _optionalChain([headers, 'optionalAccess', _10 => _10.get, 'call', _11 => _11('baggage')]),
  43. );
  44. const propagationContext = commonObjectToPropagationContext(headers, incomingPropagationContext);
  45. isolationScope.setPropagationContext(propagationContext);
  46. getCurrentScope().setPropagationContext(propagationContext);
  47. return startSpanManual(
  48. {
  49. op: 'function.nextjs',
  50. name: `${componentType}.${generationFunctionIdentifier} (${componentRoute})`,
  51. data,
  52. attributes: {
  53. [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route',
  54. [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.nextjs',
  55. },
  56. },
  57. span => {
  58. return handleCallbackErrors(
  59. () => originalFunction.apply(thisArg, args),
  60. err => {
  61. if (isNotFoundNavigationError(err)) {
  62. // We don't want to report "not-found"s
  63. _optionalChain([span, 'optionalAccess', _12 => _12.setStatus, 'call', _13 => _13('not_found')]);
  64. } else if (isRedirectNavigationError(err)) {
  65. // We don't want to report redirects
  66. _optionalChain([span, 'optionalAccess', _14 => _14.setStatus, 'call', _15 => _15('ok')]);
  67. } else {
  68. _optionalChain([span, 'optionalAccess', _16 => _16.setStatus, 'call', _17 => _17('internal_error')]);
  69. captureException(err, {
  70. mechanism: {
  71. handled: false,
  72. },
  73. });
  74. }
  75. },
  76. () => {
  77. _optionalChain([span, 'optionalAccess', _18 => _18.end, 'call', _19 => _19()]);
  78. },
  79. );
  80. },
  81. );
  82. });
  83. },
  84. });
  85. }
  86. export { wrapGenerationFunctionWithSentry };
  87. //# sourceMappingURL=wrapGenerationFunctionWithSentry.js.map