integration.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. import { defineIntegration, convertIntegrationFnToClass, getCurrentScope } from '@sentry/core';
  2. import { logger } from '@sentry/utils';
  3. import { DEBUG_BUILD } from '../debug-build.js';
  4. import { startProfileForTransaction } from './hubextensions.js';
  5. import { isAutomatedPageLoadTransaction, shouldProfileTransaction, getActiveProfilesCount, findProfiledTransactionsFromEnvelope, takeProfileFromGlobalCache, createProfilingEvent, addProfilesToEnvelope } from './utils.js';
  6. const INTEGRATION_NAME = 'BrowserProfiling';
  7. const _browserProfilingIntegration = (() => {
  8. return {
  9. name: INTEGRATION_NAME,
  10. // TODO v8: Remove this
  11. setupOnce() {}, // eslint-disable-line @typescript-eslint/no-empty-function
  12. setup(client) {
  13. const scope = getCurrentScope();
  14. // eslint-disable-next-line deprecation/deprecation
  15. const transaction = scope.getTransaction();
  16. if (transaction && isAutomatedPageLoadTransaction(transaction)) {
  17. if (shouldProfileTransaction(transaction)) {
  18. startProfileForTransaction(transaction);
  19. }
  20. }
  21. if (typeof client.on !== 'function') {
  22. logger.warn('[Profiling] Client does not support hooks, profiling will be disabled');
  23. return;
  24. }
  25. client.on('startTransaction', (transaction) => {
  26. if (shouldProfileTransaction(transaction)) {
  27. startProfileForTransaction(transaction);
  28. }
  29. });
  30. client.on('beforeEnvelope', (envelope) => {
  31. // if not profiles are in queue, there is nothing to add to the envelope.
  32. if (!getActiveProfilesCount()) {
  33. return;
  34. }
  35. const profiledTransactionEvents = findProfiledTransactionsFromEnvelope(envelope);
  36. if (!profiledTransactionEvents.length) {
  37. return;
  38. }
  39. const profilesToAddToEnvelope = [];
  40. for (const profiledTransaction of profiledTransactionEvents) {
  41. const context = profiledTransaction && profiledTransaction.contexts;
  42. const profile_id = context && context['profile'] && context['profile']['profile_id'];
  43. const start_timestamp = context && context['profile'] && context['profile']['start_timestamp'];
  44. if (typeof profile_id !== 'string') {
  45. DEBUG_BUILD && logger.log('[Profiling] cannot find profile for a transaction without a profile context');
  46. continue;
  47. }
  48. if (!profile_id) {
  49. DEBUG_BUILD && logger.log('[Profiling] cannot find profile for a transaction without a profile context');
  50. continue;
  51. }
  52. // Remove the profile from the transaction context before sending, relay will take care of the rest.
  53. if (context && context['profile']) {
  54. delete context.profile;
  55. }
  56. const profile = takeProfileFromGlobalCache(profile_id);
  57. if (!profile) {
  58. DEBUG_BUILD && logger.log(`[Profiling] Could not retrieve profile for transaction: ${profile_id}`);
  59. continue;
  60. }
  61. const profileEvent = createProfilingEvent(
  62. profile_id,
  63. start_timestamp ,
  64. profile,
  65. profiledTransaction ,
  66. );
  67. if (profileEvent) {
  68. profilesToAddToEnvelope.push(profileEvent);
  69. }
  70. }
  71. addProfilesToEnvelope(envelope , profilesToAddToEnvelope);
  72. });
  73. },
  74. };
  75. }) ;
  76. const browserProfilingIntegration = defineIntegration(_browserProfilingIntegration);
  77. /**
  78. * Browser profiling integration. Stores any event that has contexts["profile"]["profile_id"]
  79. * This exists because we do not want to await async profiler.stop calls as transaction.finish is called
  80. * in a synchronous context. Instead, we handle sending the profile async from the promise callback and
  81. * rely on being able to pull the event from the cache when we need to construct the envelope. This makes the
  82. * integration less reliable as we might be dropping profiles when the cache is full.
  83. *
  84. * @experimental
  85. * @deprecated Use `browserProfilingIntegration()` instead.
  86. */
  87. // eslint-disable-next-line deprecation/deprecation
  88. const BrowserProfilingIntegration = convertIntegrationFnToClass(
  89. INTEGRATION_NAME,
  90. browserProfilingIntegration,
  91. ) ;
  92. // eslint-disable-next-line deprecation/deprecation
  93. export { BrowserProfilingIntegration, browserProfilingIntegration };
  94. //# sourceMappingURL=integration.js.map