@sentry/react-native 5.23.0-alpha.1 → 5.23.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. package/CHANGELOG.md +60 -48
  2. package/RNSentry.podspec +1 -1
  3. package/android/build.gradle +1 -1
  4. package/android/src/main/java/io/sentry/react/RNSentryModuleImpl.java +1 -54
  5. package/android/src/newarch/java/io/sentry/react/RNSentryModule.java +0 -10
  6. package/android/src/oldarch/java/io/sentry/react/RNSentryModule.java +0 -10
  7. package/dist/js/NativeRNSentry.d.ts +0 -2
  8. package/dist/js/NativeRNSentry.d.ts.map +1 -1
  9. package/dist/js/NativeRNSentry.js.map +1 -1
  10. package/dist/js/client.d.ts +0 -8
  11. package/dist/js/client.d.ts.map +1 -1
  12. package/dist/js/client.js +3 -19
  13. package/dist/js/client.js.map +1 -1
  14. package/dist/js/index.d.ts +5 -3
  15. package/dist/js/index.d.ts.map +1 -1
  16. package/dist/js/index.js +5 -3
  17. package/dist/js/index.js.map +1 -1
  18. package/dist/js/integrations/debugsymbolicator.d.ts +8 -60
  19. package/dist/js/integrations/debugsymbolicator.d.ts.map +1 -1
  20. package/dist/js/integrations/debugsymbolicator.js +137 -209
  21. package/dist/js/integrations/debugsymbolicator.js.map +1 -1
  22. package/dist/js/integrations/debugsymbolicatorutils.d.ts +18 -0
  23. package/dist/js/integrations/debugsymbolicatorutils.d.ts.map +1 -0
  24. package/dist/js/integrations/debugsymbolicatorutils.js +70 -0
  25. package/dist/js/integrations/debugsymbolicatorutils.js.map +1 -0
  26. package/dist/js/integrations/default.d.ts.map +1 -1
  27. package/dist/js/integrations/default.js +24 -49
  28. package/dist/js/integrations/default.js.map +1 -1
  29. package/dist/js/integrations/devicecontext.d.ts +8 -15
  30. package/dist/js/integrations/devicecontext.d.ts.map +1 -1
  31. package/dist/js/integrations/devicecontext.js +74 -74
  32. package/dist/js/integrations/devicecontext.js.map +1 -1
  33. package/dist/js/integrations/eventorigin.d.ts +8 -15
  34. package/dist/js/integrations/eventorigin.d.ts.map +1 -1
  35. package/dist/js/integrations/eventorigin.js +17 -17
  36. package/dist/js/integrations/eventorigin.js.map +1 -1
  37. package/dist/js/integrations/expocontext.d.ts +8 -15
  38. package/dist/js/integrations/expocontext.d.ts.map +1 -1
  39. package/dist/js/integrations/expocontext.js +28 -32
  40. package/dist/js/integrations/expocontext.js.map +1 -1
  41. package/dist/js/integrations/exports.d.ts +16 -0
  42. package/dist/js/integrations/exports.d.ts.map +1 -0
  43. package/dist/js/integrations/exports.js +16 -0
  44. package/dist/js/integrations/exports.js.map +1 -0
  45. package/dist/js/integrations/index.d.ts +4 -1
  46. package/dist/js/integrations/index.d.ts.map +1 -1
  47. package/dist/js/integrations/index.js +5 -1
  48. package/dist/js/integrations/index.js.map +1 -1
  49. package/dist/js/integrations/modulesloader.d.ts +8 -15
  50. package/dist/js/integrations/modulesloader.d.ts.map +1 -1
  51. package/dist/js/integrations/modulesloader.js +34 -31
  52. package/dist/js/integrations/modulesloader.js.map +1 -1
  53. package/dist/js/integrations/nativelinkederrors.d.ts +8 -51
  54. package/dist/js/integrations/nativelinkederrors.d.ts.map +1 -1
  55. package/dist/js/integrations/nativelinkederrors.js +112 -124
  56. package/dist/js/integrations/nativelinkederrors.js.map +1 -1
  57. package/dist/js/integrations/reactnativeerrorhandlers.d.ts +8 -54
  58. package/dist/js/integrations/reactnativeerrorhandlers.d.ts.map +1 -1
  59. package/dist/js/integrations/reactnativeerrorhandlers.js +109 -199
  60. package/dist/js/integrations/reactnativeerrorhandlers.js.map +1 -1
  61. package/dist/js/integrations/reactnativeerrorhandlersutils.d.ts +27 -0
  62. package/dist/js/integrations/reactnativeerrorhandlersutils.d.ts.map +1 -0
  63. package/dist/js/integrations/reactnativeerrorhandlersutils.js +77 -0
  64. package/dist/js/integrations/reactnativeerrorhandlersutils.js.map +1 -0
  65. package/dist/js/integrations/reactnativeinfo.d.ts +8 -15
  66. package/dist/js/integrations/reactnativeinfo.d.ts.map +1 -1
  67. package/dist/js/integrations/reactnativeinfo.js +51 -51
  68. package/dist/js/integrations/reactnativeinfo.js.map +1 -1
  69. package/dist/js/integrations/release.d.ts +8 -15
  70. package/dist/js/integrations/release.d.ts.map +1 -1
  71. package/dist/js/integrations/release.js +55 -57
  72. package/dist/js/integrations/release.js.map +1 -1
  73. package/dist/js/integrations/rewriteframes.js +2 -2
  74. package/dist/js/integrations/rewriteframes.js.map +1 -1
  75. package/dist/js/integrations/screenshot.d.ts +8 -23
  76. package/dist/js/integrations/screenshot.d.ts.map +1 -1
  77. package/dist/js/integrations/screenshot.js +31 -47
  78. package/dist/js/integrations/screenshot.js.map +1 -1
  79. package/dist/js/integrations/sdkinfo.d.ts +8 -16
  80. package/dist/js/integrations/sdkinfo.d.ts.map +1 -1
  81. package/dist/js/integrations/sdkinfo.js +54 -41
  82. package/dist/js/integrations/sdkinfo.js.map +1 -1
  83. package/dist/js/integrations/spotlight.d.ts +10 -2
  84. package/dist/js/integrations/spotlight.d.ts.map +1 -1
  85. package/dist/js/integrations/spotlight.js +14 -9
  86. package/dist/js/integrations/spotlight.js.map +1 -1
  87. package/dist/js/integrations/viewhierarchy.d.ts +8 -18
  88. package/dist/js/integrations/viewhierarchy.d.ts.map +1 -1
  89. package/dist/js/integrations/viewhierarchy.js +46 -43
  90. package/dist/js/integrations/viewhierarchy.js.map +1 -1
  91. package/dist/js/options.d.ts +2 -24
  92. package/dist/js/options.d.ts.map +1 -1
  93. package/dist/js/options.js.map +1 -1
  94. package/dist/js/profiling/integration.d.ts +8 -32
  95. package/dist/js/profiling/integration.d.ts.map +1 -1
  96. package/dist/js/profiling/integration.js +120 -119
  97. package/dist/js/profiling/integration.js.map +1 -1
  98. package/dist/js/tracing/nativeframes.d.ts +0 -4
  99. package/dist/js/tracing/nativeframes.d.ts.map +1 -1
  100. package/dist/js/tracing/nativeframes.js +14 -14
  101. package/dist/js/tracing/nativeframes.js.map +1 -1
  102. package/dist/js/tracing/reactnativetracing.d.ts.map +1 -1
  103. package/dist/js/tracing/reactnativetracing.js +9 -2
  104. package/dist/js/tracing/reactnativetracing.js.map +1 -1
  105. package/dist/js/tracing/timetodisplay.d.ts +1 -1
  106. package/dist/js/tracing/timetodisplay.d.ts.map +1 -1
  107. package/dist/js/tracing/timetodisplay.js +15 -7
  108. package/dist/js/tracing/timetodisplay.js.map +1 -1
  109. package/dist/js/utils/environment.d.ts +0 -4
  110. package/dist/js/utils/environment.d.ts.map +1 -1
  111. package/dist/js/utils/environment.js +0 -8
  112. package/dist/js/utils/environment.js.map +1 -1
  113. package/dist/js/version.d.ts +1 -1
  114. package/dist/js/version.d.ts.map +1 -1
  115. package/dist/js/version.js +1 -1
  116. package/dist/js/version.js.map +1 -1
  117. package/dist/js/wrapper.d.ts +1 -7
  118. package/dist/js/wrapper.d.ts.map +1 -1
  119. package/dist/js/wrapper.js +0 -24
  120. package/dist/js/wrapper.js.map +1 -1
  121. package/ios/RNSentry.mm +3 -73
  122. package/ios/RNSentryBreadcrumb.h +9 -0
  123. package/ios/RNSentryBreadcrumb.m +33 -0
  124. package/ios/RNSentryOnDrawReporter.h +23 -0
  125. package/ios/RNSentryOnDrawReporter.m +2 -17
  126. package/package.json +1 -9
  127. package/src/js/NativeRNSentry.ts +0 -2
  128. package/ts3.8/dist/js/NativeRNSentry.d.ts +0 -2
  129. package/ts3.8/dist/js/client.d.ts +0 -8
  130. package/ts3.8/dist/js/index.d.ts +5 -3
  131. package/ts3.8/dist/js/integrations/debugsymbolicator.d.ts +8 -60
  132. package/ts3.8/dist/js/integrations/debugsymbolicatorutils.d.ts +18 -0
  133. package/ts3.8/dist/js/integrations/devicecontext.d.ts +8 -15
  134. package/ts3.8/dist/js/integrations/eventorigin.d.ts +8 -15
  135. package/ts3.8/dist/js/integrations/expocontext.d.ts +8 -15
  136. package/ts3.8/dist/js/integrations/exports.d.ts +16 -0
  137. package/ts3.8/dist/js/integrations/index.d.ts +4 -1
  138. package/ts3.8/dist/js/integrations/modulesloader.d.ts +8 -15
  139. package/ts3.8/dist/js/integrations/nativelinkederrors.d.ts +8 -51
  140. package/ts3.8/dist/js/integrations/reactnativeerrorhandlers.d.ts +8 -54
  141. package/ts3.8/dist/js/integrations/reactnativeerrorhandlersutils.d.ts +27 -0
  142. package/ts3.8/dist/js/integrations/reactnativeinfo.d.ts +8 -15
  143. package/ts3.8/dist/js/integrations/release.d.ts +8 -15
  144. package/ts3.8/dist/js/integrations/screenshot.d.ts +8 -23
  145. package/ts3.8/dist/js/integrations/sdkinfo.d.ts +8 -16
  146. package/ts3.8/dist/js/integrations/spotlight.d.ts +10 -2
  147. package/ts3.8/dist/js/integrations/viewhierarchy.d.ts +8 -18
  148. package/ts3.8/dist/js/options.d.ts +2 -24
  149. package/ts3.8/dist/js/profiling/integration.d.ts +8 -32
  150. package/ts3.8/dist/js/tracing/nativeframes.d.ts +0 -4
  151. package/ts3.8/dist/js/tracing/timetodisplay.d.ts +1 -1
  152. package/ts3.8/dist/js/utils/environment.d.ts +0 -4
  153. package/ts3.8/dist/js/version.d.ts +1 -1
  154. package/ts3.8/dist/js/wrapper.d.ts +1 -7
  155. package/dist/js/integrations/mobilereplay.d.ts +0 -36
  156. package/dist/js/integrations/mobilereplay.d.ts.map +0 -1
  157. package/dist/js/integrations/mobilereplay.js +0 -97
  158. package/dist/js/integrations/mobilereplay.js.map +0 -1
  159. package/dist/js/utils/clientutils.d.ts +0 -8
  160. package/dist/js/utils/clientutils.d.ts.map +0 -1
  161. package/dist/js/utils/clientutils.js +0 -7
  162. package/dist/js/utils/clientutils.js.map +0 -1
  163. package/ts3.8/dist/js/integrations/mobilereplay.d.ts +0 -36
  164. package/ts3.8/dist/js/utils/clientutils.d.ts +0 -8
@@ -1,4 +1,5 @@
1
- import { getActiveTransaction } from '@sentry/core';
1
+ /* eslint-disable complexity */
2
+ import { convertIntegrationFnToClass, getActiveTransaction, getClient, getCurrentHub } from '@sentry/core';
2
3
  import { logger, uuid4 } from '@sentry/utils';
3
4
  import { Platform } from 'react-native';
4
5
  import { isHermesEnabled } from '../utils/environment';
@@ -7,132 +8,28 @@ import { PROFILE_QUEUE } from './cache';
7
8
  import { MAX_PROFILE_DURATION_MS } from './constants';
8
9
  import { convertToSentryProfile } from './convertHermesProfile';
9
10
  import { addProfilesToEnvelope, createHermesProfilingEvent, enrichCombinedProfileWithEventContext, findProfiledTransactionsFromEnvelope, } from './utils';
11
+ const INTEGRATION_NAME = 'HermesProfiling';
10
12
  const MS_TO_NS = 1e6;
11
13
  /**
12
14
  * Profiling integration creates a profile for each transaction and adds it to the event envelope.
13
15
  *
14
16
  * @experimental
15
17
  */
16
- export class HermesProfiling {
17
- constructor() {
18
- /**
19
- * @inheritDoc
20
- */
21
- this.name = HermesProfiling.id;
22
- this._startCurrentProfileForActiveTransaction = () => {
23
- if (this._currentProfile) {
24
- return;
25
- }
26
- const transaction = this._getCurrentHub && getActiveTransaction(this._getCurrentHub());
27
- transaction && this._startCurrentProfile(transaction);
28
- };
29
- this._startCurrentProfile = (transaction) => {
30
- this._finishCurrentProfile();
31
- const shouldStartProfiling = this._shouldStartProfiling(transaction);
32
- if (!shouldStartProfiling) {
33
- return;
34
- }
35
- this._currentProfileTimeout = setTimeout(this._finishCurrentProfile, MAX_PROFILE_DURATION_MS);
36
- this._startNewProfile(transaction);
37
- };
38
- this._shouldStartProfiling = (transaction) => {
39
- if (!transaction.sampled) {
40
- logger.log('[Profiling] Transaction is not sampled, skipping profiling');
41
- return false;
42
- }
43
- const client = this._getCurrentHub && this._getCurrentHub().getClient();
44
- const options = client && client.getOptions();
45
- const profilesSampleRate = options && options._experiments && typeof options._experiments.profilesSampleRate === 'number'
46
- ? options._experiments.profilesSampleRate
47
- : undefined;
48
- if (profilesSampleRate === undefined) {
49
- logger.log('[Profiling] Profiling disabled, enable it by setting `profilesSampleRate` option to SDK init call.');
50
- return false;
51
- }
52
- // Check if we should sample this profile
53
- if (Math.random() > profilesSampleRate) {
54
- logger.log('[Profiling] Skip profiling transaction due to sampling.');
55
- return false;
56
- }
57
- return true;
58
- };
59
- /**
60
- * Starts a new profile and links it to the transaction.
61
- */
62
- this._startNewProfile = (transaction) => {
63
- const profileStartTimestampNs = startProfiling();
64
- if (!profileStartTimestampNs) {
65
- return;
66
- }
67
- this._currentProfile = {
68
- profile_id: uuid4(),
69
- startTimestampNs: profileStartTimestampNs,
70
- };
71
- transaction.setContext('profile', { profile_id: this._currentProfile.profile_id });
72
- // @ts-expect-error profile_id is not part of the metadata type
73
- transaction.setMetadata({ profile_id: this._currentProfile.profile_id });
74
- logger.log('[Profiling] started profiling: ', this._currentProfile.profile_id);
75
- };
76
- /**
77
- * Stops profiling and adds the profile to the queue to be processed on beforeEnvelope.
78
- */
79
- this._finishCurrentProfile = () => {
80
- this._clearCurrentProfileTimeout();
81
- if (this._currentProfile === undefined) {
82
- return;
83
- }
84
- const profile = stopProfiling(this._currentProfile.startTimestampNs);
85
- if (!profile) {
86
- logger.warn('[Profiling] Stop failed. Cleaning up...');
87
- this._currentProfile = undefined;
88
- return;
89
- }
90
- PROFILE_QUEUE.add(this._currentProfile.profile_id, profile);
91
- logger.log('[Profiling] finished profiling: ', this._currentProfile.profile_id);
92
- this._currentProfile = undefined;
93
- };
94
- this._createProfileEventFor = (profiledTransaction) => {
95
- var _a, _b, _c;
96
- const profile_id = (_b = (_a = profiledTransaction === null || profiledTransaction === void 0 ? void 0 : profiledTransaction.contexts) === null || _a === void 0 ? void 0 : _a['profile']) === null || _b === void 0 ? void 0 : _b['profile_id'];
97
- if (typeof profile_id !== 'string') {
98
- logger.log('[Profiling] cannot find profile for a transaction without a profile context');
99
- return null;
100
- }
101
- // Remove the profile from the transaction context before sending, relay will take care of the rest.
102
- if ((_c = profiledTransaction === null || profiledTransaction === void 0 ? void 0 : profiledTransaction.contexts) === null || _c === void 0 ? void 0 : _c['.profile']) {
103
- delete profiledTransaction.contexts.profile;
104
- }
105
- const profile = PROFILE_QUEUE.get(profile_id);
106
- PROFILE_QUEUE.delete(profile_id);
107
- if (!profile) {
108
- logger.log(`[Profiling] cannot find profile ${profile_id} for transaction ${profiledTransaction.event_id}`);
109
- return null;
110
- }
111
- const profileWithEvent = enrichCombinedProfileWithEventContext(profile_id, profile, profiledTransaction);
112
- logger.log(`[Profiling] Created profile ${profile_id} for transaction ${profiledTransaction.event_id}`);
113
- return profileWithEvent;
114
- };
115
- this._clearCurrentProfileTimeout = () => {
116
- this._currentProfileTimeout !== undefined && clearTimeout(this._currentProfileTimeout);
117
- this._currentProfileTimeout = undefined;
118
- };
119
- }
120
- /**
121
- * @inheritDoc
122
- */
123
- setupOnce(_, getCurrentHub) {
18
+ export const hermesProfilingIntegration = () => {
19
+ let _currentProfile;
20
+ let _currentProfileTimeout;
21
+ const setupOnce = () => {
124
22
  if (!isHermesEnabled()) {
125
23
  logger.log('[Profiling] Hermes is not enabled, not adding profiling integration.');
126
24
  return;
127
25
  }
128
- this._getCurrentHub = getCurrentHub;
129
- const client = getCurrentHub().getClient();
26
+ const client = getClient();
130
27
  if (!client || typeof client.on !== 'function') {
131
28
  return;
132
29
  }
133
- this._startCurrentProfileForActiveTransaction();
134
- client.on('startTransaction', this._startCurrentProfile);
135
- client.on('finishTransaction', this._finishCurrentProfile);
30
+ _startCurrentProfileForActiveTransaction();
31
+ client.on('startTransaction', _startCurrentProfile);
32
+ client.on('finishTransaction', _finishCurrentProfile);
136
33
  client.on('beforeEnvelope', (envelope) => {
137
34
  if (!PROFILE_QUEUE.size()) {
138
35
  return;
@@ -144,19 +41,123 @@ export class HermesProfiling {
144
41
  }
145
42
  const profilesToAddToEnvelope = [];
146
43
  for (const profiledTransaction of profiledTransactions) {
147
- const profile = this._createProfileEventFor(profiledTransaction);
44
+ const profile = _createProfileEventFor(profiledTransaction);
148
45
  if (profile) {
149
46
  profilesToAddToEnvelope.push(profile);
150
47
  }
151
48
  }
152
49
  addProfilesToEnvelope(envelope, profilesToAddToEnvelope);
153
50
  });
154
- }
155
- }
51
+ };
52
+ const _startCurrentProfileForActiveTransaction = () => {
53
+ if (_currentProfile) {
54
+ return;
55
+ }
56
+ const transaction = getActiveTransaction(getCurrentHub());
57
+ transaction && _startCurrentProfile(transaction);
58
+ };
59
+ const _startCurrentProfile = (transaction) => {
60
+ _finishCurrentProfile();
61
+ const shouldStartProfiling = _shouldStartProfiling(transaction);
62
+ if (!shouldStartProfiling) {
63
+ return;
64
+ }
65
+ _currentProfileTimeout = setTimeout(_finishCurrentProfile, MAX_PROFILE_DURATION_MS);
66
+ _startNewProfile(transaction);
67
+ };
68
+ const _shouldStartProfiling = (transaction) => {
69
+ if (!transaction.sampled) {
70
+ logger.log('[Profiling] Transaction is not sampled, skipping profiling');
71
+ return false;
72
+ }
73
+ const client = getClient();
74
+ const options = client && client.getOptions();
75
+ const profilesSampleRate = options && options._experiments && typeof options._experiments.profilesSampleRate === 'number'
76
+ ? options._experiments.profilesSampleRate
77
+ : undefined;
78
+ if (profilesSampleRate === undefined) {
79
+ logger.log('[Profiling] Profiling disabled, enable it by setting `profilesSampleRate` option to SDK init call.');
80
+ return false;
81
+ }
82
+ // Check if we should sample this profile
83
+ if (Math.random() > profilesSampleRate) {
84
+ logger.log('[Profiling] Skip profiling transaction due to sampling.');
85
+ return false;
86
+ }
87
+ return true;
88
+ };
89
+ /**
90
+ * Starts a new profile and links it to the transaction.
91
+ */
92
+ const _startNewProfile = (transaction) => {
93
+ const profileStartTimestampNs = startProfiling();
94
+ if (!profileStartTimestampNs) {
95
+ return;
96
+ }
97
+ _currentProfile = {
98
+ profile_id: uuid4(),
99
+ startTimestampNs: profileStartTimestampNs,
100
+ };
101
+ transaction.setContext('profile', { profile_id: _currentProfile.profile_id });
102
+ // @ts-expect-error profile_id is not part of the metadata type
103
+ transaction.setMetadata({ profile_id: _currentProfile.profile_id });
104
+ logger.log('[Profiling] started profiling: ', _currentProfile.profile_id);
105
+ };
106
+ /**
107
+ * Stops profiling and adds the profile to the queue to be processed on beforeEnvelope.
108
+ */
109
+ const _finishCurrentProfile = () => {
110
+ _clearCurrentProfileTimeout();
111
+ if (_currentProfile === undefined) {
112
+ return;
113
+ }
114
+ const profile = stopProfiling(_currentProfile.startTimestampNs);
115
+ if (!profile) {
116
+ logger.warn('[Profiling] Stop failed. Cleaning up...');
117
+ _currentProfile = undefined;
118
+ return;
119
+ }
120
+ PROFILE_QUEUE.add(_currentProfile.profile_id, profile);
121
+ logger.log('[Profiling] finished profiling: ', _currentProfile.profile_id);
122
+ _currentProfile = undefined;
123
+ };
124
+ const _createProfileEventFor = (profiledTransaction) => {
125
+ var _a, _b, _c;
126
+ const profile_id = (_b = (_a = profiledTransaction === null || profiledTransaction === void 0 ? void 0 : profiledTransaction.contexts) === null || _a === void 0 ? void 0 : _a['profile']) === null || _b === void 0 ? void 0 : _b['profile_id'];
127
+ if (typeof profile_id !== 'string') {
128
+ logger.log('[Profiling] cannot find profile for a transaction without a profile context');
129
+ return null;
130
+ }
131
+ // Remove the profile from the transaction context before sending, relay will take care of the rest.
132
+ if ((_c = profiledTransaction === null || profiledTransaction === void 0 ? void 0 : profiledTransaction.contexts) === null || _c === void 0 ? void 0 : _c['.profile']) {
133
+ delete profiledTransaction.contexts.profile;
134
+ }
135
+ const profile = PROFILE_QUEUE.get(profile_id);
136
+ PROFILE_QUEUE.delete(profile_id);
137
+ if (!profile) {
138
+ logger.log(`[Profiling] cannot find profile ${profile_id} for transaction ${profiledTransaction.event_id}`);
139
+ return null;
140
+ }
141
+ const profileWithEvent = enrichCombinedProfileWithEventContext(profile_id, profile, profiledTransaction);
142
+ logger.log(`[Profiling] Created profile ${profile_id} for transaction ${profiledTransaction.event_id}`);
143
+ return profileWithEvent;
144
+ };
145
+ const _clearCurrentProfileTimeout = () => {
146
+ _currentProfileTimeout !== undefined && clearTimeout(_currentProfileTimeout);
147
+ _currentProfileTimeout = undefined;
148
+ };
149
+ return {
150
+ name: INTEGRATION_NAME,
151
+ setupOnce,
152
+ };
153
+ };
156
154
  /**
157
- * @inheritDoc
155
+ * Profiling integration creates a profile for each transaction and adds it to the event envelope.
156
+ *
157
+ * @deprecated Use `hermesProfilingIntegration()` instead.
158
158
  */
159
- HermesProfiling.id = 'HermesProfiling';
159
+ // eslint-disable-next-line deprecation/deprecation
160
+ export const HermesProfiling = convertIntegrationFnToClass(INTEGRATION_NAME, hermesProfilingIntegration);
160
161
  /**
161
162
  * Starts Profilers and returns the timestamp when profiling started in nanoseconds.
162
163
  */
@@ -1 +1 @@
1
- {"version":3,"file":"integration.js","sourceRoot":"","sources":["../../../src/js/profiling/integration.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable complexity */\nimport type { Hub } from '@sentry/core';\nimport { getActiveTransaction } from '@sentry/core';\nimport type { Envelope, Event, EventProcessor, Integration, ThreadCpuProfile, Transaction } from '@sentry/types';\nimport { logger, uuid4 } from '@sentry/utils';\nimport { Platform } from 'react-native';\n\nimport { isHermesEnabled } from '../utils/environment';\nimport { NATIVE } from '../wrapper';\nimport { PROFILE_QUEUE } from './cache';\nimport { MAX_PROFILE_DURATION_MS } from './constants';\nimport { convertToSentryProfile } from './convertHermesProfile';\nimport type { NativeAndroidProfileEvent, NativeProfileEvent } from './nativeTypes';\nimport type { AndroidCombinedProfileEvent, CombinedProfileEvent, HermesProfileEvent, ProfileEvent } from './types';\nimport {\n addProfilesToEnvelope,\n createHermesProfilingEvent,\n enrichCombinedProfileWithEventContext,\n findProfiledTransactionsFromEnvelope,\n} from './utils';\n\nconst MS_TO_NS: number = 1e6;\n\n/**\n * Profiling integration creates a profile for each transaction and adds it to the event envelope.\n *\n * @experimental\n */\nexport class HermesProfiling implements Integration {\n /**\n * @inheritDoc\n */\n public static id: string = 'HermesProfiling';\n\n /**\n * @inheritDoc\n */\n public name: string = HermesProfiling.id;\n\n private _getCurrentHub?: () => Hub;\n\n private _currentProfile:\n | {\n profile_id: string;\n startTimestampNs: number;\n }\n | undefined;\n\n private _currentProfileTimeout: number | undefined;\n\n /**\n * @inheritDoc\n */\n public setupOnce(_: (e: EventProcessor) => void, getCurrentHub: () => Hub): void {\n if (!isHermesEnabled()) {\n logger.log('[Profiling] Hermes is not enabled, not adding profiling integration.');\n return;\n }\n\n this._getCurrentHub = getCurrentHub;\n const client = getCurrentHub().getClient();\n\n if (!client || typeof client.on !== 'function') {\n return;\n }\n\n this._startCurrentProfileForActiveTransaction();\n client.on('startTransaction', this._startCurrentProfile);\n\n client.on('finishTransaction', this._finishCurrentProfile);\n\n client.on('beforeEnvelope', (envelope: Envelope) => {\n if (!PROFILE_QUEUE.size()) {\n return;\n }\n\n const profiledTransactions = findProfiledTransactionsFromEnvelope(envelope);\n if (!profiledTransactions.length) {\n logger.log('[Profiling] no profiled transactions found in envelope');\n return;\n }\n\n const profilesToAddToEnvelope: ProfileEvent[] = [];\n for (const profiledTransaction of profiledTransactions) {\n const profile = this._createProfileEventFor(profiledTransaction);\n if (profile) {\n profilesToAddToEnvelope.push(profile);\n }\n }\n addProfilesToEnvelope(envelope, profilesToAddToEnvelope);\n });\n }\n\n private _startCurrentProfileForActiveTransaction = (): void => {\n if (this._currentProfile) {\n return;\n }\n const transaction = this._getCurrentHub && getActiveTransaction(this._getCurrentHub());\n transaction && this._startCurrentProfile(transaction);\n };\n\n private _startCurrentProfile = (transaction: Transaction): void => {\n this._finishCurrentProfile();\n\n const shouldStartProfiling = this._shouldStartProfiling(transaction);\n if (!shouldStartProfiling) {\n return;\n }\n\n this._currentProfileTimeout = setTimeout(this._finishCurrentProfile, MAX_PROFILE_DURATION_MS);\n this._startNewProfile(transaction);\n };\n\n private _shouldStartProfiling = (transaction: Transaction): boolean => {\n if (!transaction.sampled) {\n logger.log('[Profiling] Transaction is not sampled, skipping profiling');\n return false;\n }\n\n const client = this._getCurrentHub && this._getCurrentHub().getClient();\n const options = client && client.getOptions();\n\n const profilesSampleRate =\n options && options._experiments && typeof options._experiments.profilesSampleRate === 'number'\n ? options._experiments.profilesSampleRate\n : undefined;\n if (profilesSampleRate === undefined) {\n logger.log('[Profiling] Profiling disabled, enable it by setting `profilesSampleRate` option to SDK init call.');\n return false;\n }\n\n // Check if we should sample this profile\n if (Math.random() > profilesSampleRate) {\n logger.log('[Profiling] Skip profiling transaction due to sampling.');\n return false;\n }\n\n return true;\n };\n\n /**\n * Starts a new profile and links it to the transaction.\n */\n private _startNewProfile = (transaction: Transaction): void => {\n const profileStartTimestampNs = startProfiling();\n if (!profileStartTimestampNs) {\n return;\n }\n\n this._currentProfile = {\n profile_id: uuid4(),\n startTimestampNs: profileStartTimestampNs,\n };\n transaction.setContext('profile', { profile_id: this._currentProfile.profile_id });\n // @ts-expect-error profile_id is not part of the metadata type\n transaction.setMetadata({ profile_id: this._currentProfile.profile_id });\n logger.log('[Profiling] started profiling: ', this._currentProfile.profile_id);\n };\n\n /**\n * Stops profiling and adds the profile to the queue to be processed on beforeEnvelope.\n */\n private _finishCurrentProfile = (): void => {\n this._clearCurrentProfileTimeout();\n if (this._currentProfile === undefined) {\n return;\n }\n\n const profile = stopProfiling(this._currentProfile.startTimestampNs);\n if (!profile) {\n logger.warn('[Profiling] Stop failed. Cleaning up...');\n this._currentProfile = undefined;\n return;\n }\n\n PROFILE_QUEUE.add(this._currentProfile.profile_id, profile);\n\n logger.log('[Profiling] finished profiling: ', this._currentProfile.profile_id);\n this._currentProfile = undefined;\n };\n\n private _createProfileEventFor = (profiledTransaction: Event): ProfileEvent | null => {\n const profile_id = profiledTransaction?.contexts?.['profile']?.['profile_id'];\n\n if (typeof profile_id !== 'string') {\n logger.log('[Profiling] cannot find profile for a transaction without a profile context');\n return null;\n }\n\n // Remove the profile from the transaction context before sending, relay will take care of the rest.\n if (profiledTransaction?.contexts?.['.profile']) {\n delete profiledTransaction.contexts.profile;\n }\n\n const profile = PROFILE_QUEUE.get(profile_id);\n PROFILE_QUEUE.delete(profile_id);\n\n if (!profile) {\n logger.log(`[Profiling] cannot find profile ${profile_id} for transaction ${profiledTransaction.event_id}`);\n return null;\n }\n\n const profileWithEvent = enrichCombinedProfileWithEventContext(profile_id, profile, profiledTransaction);\n logger.log(`[Profiling] Created profile ${profile_id} for transaction ${profiledTransaction.event_id}`);\n\n return profileWithEvent;\n };\n\n private _clearCurrentProfileTimeout = (): void => {\n this._currentProfileTimeout !== undefined && clearTimeout(this._currentProfileTimeout);\n this._currentProfileTimeout = undefined;\n };\n}\n\n/**\n * Starts Profilers and returns the timestamp when profiling started in nanoseconds.\n */\nexport function startProfiling(): number | null {\n const started = NATIVE.startProfiling();\n if (!started) {\n return null;\n }\n\n return Date.now() * MS_TO_NS;\n}\n\n/**\n * Stops Profilers and returns collected combined profile.\n */\nexport function stopProfiling(\n profileStartTimestampNs: number,\n): CombinedProfileEvent | AndroidCombinedProfileEvent | null {\n const collectedProfiles = NATIVE.stopProfiling();\n if (!collectedProfiles) {\n return null;\n }\n const profileEndTimestampNs = Date.now() * MS_TO_NS;\n\n const hermesProfile = convertToSentryProfile(collectedProfiles.hermesProfile);\n if (!hermesProfile) {\n return null;\n }\n\n const hermesProfileEvent = createHermesProfilingEvent(hermesProfile);\n if (!hermesProfileEvent) {\n return null;\n }\n\n if (collectedProfiles.androidProfile) {\n const durationNs = profileEndTimestampNs - profileStartTimestampNs;\n return createAndroidWithHermesProfile(hermesProfileEvent, collectedProfiles.androidProfile, durationNs);\n } else if (collectedProfiles.nativeProfile) {\n return addNativeProfileToHermesProfile(hermesProfileEvent, collectedProfiles.nativeProfile);\n }\n\n return hermesProfileEvent;\n}\n\n/**\n * Creates Android profile event with attached javascript profile.\n */\nexport function createAndroidWithHermesProfile(\n hermes: HermesProfileEvent,\n nativeAndroid: NativeAndroidProfileEvent,\n durationNs: number,\n): AndroidCombinedProfileEvent {\n return {\n ...nativeAndroid,\n platform: 'android',\n js_profile: hermes.profile,\n duration_ns: durationNs.toString(10),\n active_thread_id: hermes.transaction.active_thread_id,\n };\n}\n\n/**\n * Merges Hermes and Native profile events into one.\n */\nexport function addNativeProfileToHermesProfile(\n hermes: HermesProfileEvent,\n native: NativeProfileEvent,\n): CombinedProfileEvent {\n return {\n ...hermes,\n profile: addNativeThreadCpuProfileToHermes(hermes.profile, native.profile, hermes.transaction.active_thread_id),\n debug_meta: {\n images: native.debug_meta.images,\n },\n measurements: native.measurements,\n };\n}\n\n/**\n * Merges Hermes And Native profiles into one.\n */\nexport function addNativeThreadCpuProfileToHermes(\n hermes: ThreadCpuProfile,\n native: ThreadCpuProfile,\n hermes_active_thread_id: string | undefined,\n): CombinedProfileEvent['profile'] {\n // assumes thread ids are unique\n hermes.thread_metadata = { ...native.thread_metadata, ...hermes.thread_metadata };\n // assumes queue ids are unique\n hermes.queue_metadata = { ...native.queue_metadata, ...hermes.queue_metadata };\n\n // recalculate frames and stacks using offset\n const framesOffset = hermes.frames.length;\n const stacksOffset = hermes.stacks.length;\n\n if (native.frames) {\n for (const frame of native.frames) {\n hermes.frames.push({\n function: frame.function,\n instruction_addr: frame.instruction_addr,\n platform: Platform.OS === 'ios' ? 'cocoa' : undefined,\n });\n }\n }\n hermes.stacks = [\n ...(hermes.stacks || []),\n ...(native.stacks || []).map(stack => stack.map(frameId => frameId + framesOffset)),\n ];\n hermes.samples = [\n ...(hermes.samples || []),\n ...(native.samples || [])\n .filter(sample => sample.thread_id !== hermes_active_thread_id)\n .map(sample => ({\n ...sample,\n stack_id: stacksOffset + sample.stack_id,\n })),\n ];\n\n return hermes;\n}\n"]}
1
+ {"version":3,"file":"integration.js","sourceRoot":"","sources":["../../../src/js/profiling/integration.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable complexity */\nimport { convertIntegrationFnToClass, getActiveTransaction, getClient, getCurrentHub } from '@sentry/core';\nimport type {\n Envelope,\n Event,\n Integration,\n IntegrationClass,\n IntegrationFn,\n ThreadCpuProfile,\n Transaction,\n} from '@sentry/types';\nimport { logger, uuid4 } from '@sentry/utils';\nimport { Platform } from 'react-native';\n\nimport { isHermesEnabled } from '../utils/environment';\nimport { NATIVE } from '../wrapper';\nimport { PROFILE_QUEUE } from './cache';\nimport { MAX_PROFILE_DURATION_MS } from './constants';\nimport { convertToSentryProfile } from './convertHermesProfile';\nimport type { NativeAndroidProfileEvent, NativeProfileEvent } from './nativeTypes';\nimport type { AndroidCombinedProfileEvent, CombinedProfileEvent, HermesProfileEvent, ProfileEvent } from './types';\nimport {\n addProfilesToEnvelope,\n createHermesProfilingEvent,\n enrichCombinedProfileWithEventContext,\n findProfiledTransactionsFromEnvelope,\n} from './utils';\n\nconst INTEGRATION_NAME = 'HermesProfiling';\n\nconst MS_TO_NS: number = 1e6;\n\n/**\n * Profiling integration creates a profile for each transaction and adds it to the event envelope.\n *\n * @experimental\n */\nexport const hermesProfilingIntegration: IntegrationFn = () => {\n let _currentProfile:\n | {\n profile_id: string;\n startTimestampNs: number;\n }\n | undefined;\n let _currentProfileTimeout: number | undefined;\n\n const setupOnce = (): void => {\n if (!isHermesEnabled()) {\n logger.log('[Profiling] Hermes is not enabled, not adding profiling integration.');\n return;\n }\n\n const client = getClient();\n\n if (!client || typeof client.on !== 'function') {\n return;\n }\n\n _startCurrentProfileForActiveTransaction();\n client.on('startTransaction', _startCurrentProfile);\n\n client.on('finishTransaction', _finishCurrentProfile);\n\n client.on('beforeEnvelope', (envelope: Envelope) => {\n if (!PROFILE_QUEUE.size()) {\n return;\n }\n\n const profiledTransactions = findProfiledTransactionsFromEnvelope(envelope);\n if (!profiledTransactions.length) {\n logger.log('[Profiling] no profiled transactions found in envelope');\n return;\n }\n\n const profilesToAddToEnvelope: ProfileEvent[] = [];\n for (const profiledTransaction of profiledTransactions) {\n const profile = _createProfileEventFor(profiledTransaction);\n if (profile) {\n profilesToAddToEnvelope.push(profile);\n }\n }\n addProfilesToEnvelope(envelope, profilesToAddToEnvelope);\n });\n };\n\n const _startCurrentProfileForActiveTransaction = (): void => {\n if (_currentProfile) {\n return;\n }\n const transaction = getActiveTransaction(getCurrentHub());\n transaction && _startCurrentProfile(transaction);\n };\n\n const _startCurrentProfile = (transaction: Transaction): void => {\n _finishCurrentProfile();\n\n const shouldStartProfiling = _shouldStartProfiling(transaction);\n if (!shouldStartProfiling) {\n return;\n }\n\n _currentProfileTimeout = setTimeout(_finishCurrentProfile, MAX_PROFILE_DURATION_MS);\n _startNewProfile(transaction);\n };\n\n const _shouldStartProfiling = (transaction: Transaction): boolean => {\n if (!transaction.sampled) {\n logger.log('[Profiling] Transaction is not sampled, skipping profiling');\n return false;\n }\n\n const client = getClient();\n const options = client && client.getOptions();\n\n const profilesSampleRate =\n options && options._experiments && typeof options._experiments.profilesSampleRate === 'number'\n ? options._experiments.profilesSampleRate\n : undefined;\n if (profilesSampleRate === undefined) {\n logger.log('[Profiling] Profiling disabled, enable it by setting `profilesSampleRate` option to SDK init call.');\n return false;\n }\n\n // Check if we should sample this profile\n if (Math.random() > profilesSampleRate) {\n logger.log('[Profiling] Skip profiling transaction due to sampling.');\n return false;\n }\n\n return true;\n };\n\n /**\n * Starts a new profile and links it to the transaction.\n */\n const _startNewProfile = (transaction: Transaction): void => {\n const profileStartTimestampNs = startProfiling();\n if (!profileStartTimestampNs) {\n return;\n }\n\n _currentProfile = {\n profile_id: uuid4(),\n startTimestampNs: profileStartTimestampNs,\n };\n transaction.setContext('profile', { profile_id: _currentProfile.profile_id });\n // @ts-expect-error profile_id is not part of the metadata type\n transaction.setMetadata({ profile_id: _currentProfile.profile_id });\n logger.log('[Profiling] started profiling: ', _currentProfile.profile_id);\n };\n\n /**\n * Stops profiling and adds the profile to the queue to be processed on beforeEnvelope.\n */\n const _finishCurrentProfile = (): void => {\n _clearCurrentProfileTimeout();\n if (_currentProfile === undefined) {\n return;\n }\n\n const profile = stopProfiling(_currentProfile.startTimestampNs);\n if (!profile) {\n logger.warn('[Profiling] Stop failed. Cleaning up...');\n _currentProfile = undefined;\n return;\n }\n\n PROFILE_QUEUE.add(_currentProfile.profile_id, profile);\n\n logger.log('[Profiling] finished profiling: ', _currentProfile.profile_id);\n _currentProfile = undefined;\n };\n\n const _createProfileEventFor = (profiledTransaction: Event): ProfileEvent | null => {\n const profile_id = profiledTransaction?.contexts?.['profile']?.['profile_id'];\n\n if (typeof profile_id !== 'string') {\n logger.log('[Profiling] cannot find profile for a transaction without a profile context');\n return null;\n }\n\n // Remove the profile from the transaction context before sending, relay will take care of the rest.\n if (profiledTransaction?.contexts?.['.profile']) {\n delete profiledTransaction.contexts.profile;\n }\n\n const profile = PROFILE_QUEUE.get(profile_id);\n PROFILE_QUEUE.delete(profile_id);\n\n if (!profile) {\n logger.log(`[Profiling] cannot find profile ${profile_id} for transaction ${profiledTransaction.event_id}`);\n return null;\n }\n\n const profileWithEvent = enrichCombinedProfileWithEventContext(profile_id, profile, profiledTransaction);\n logger.log(`[Profiling] Created profile ${profile_id} for transaction ${profiledTransaction.event_id}`);\n\n return profileWithEvent;\n };\n\n const _clearCurrentProfileTimeout = (): void => {\n _currentProfileTimeout !== undefined && clearTimeout(_currentProfileTimeout);\n _currentProfileTimeout = undefined;\n };\n\n return {\n name: INTEGRATION_NAME,\n setupOnce,\n };\n};\n\n/**\n * Profiling integration creates a profile for each transaction and adds it to the event envelope.\n *\n * @deprecated Use `hermesProfilingIntegration()` instead.\n */\n// eslint-disable-next-line deprecation/deprecation\nexport const HermesProfiling = convertIntegrationFnToClass(\n INTEGRATION_NAME,\n hermesProfilingIntegration,\n) as IntegrationClass<Integration>;\n\n/**\n * Starts Profilers and returns the timestamp when profiling started in nanoseconds.\n */\nexport function startProfiling(): number | null {\n const started = NATIVE.startProfiling();\n if (!started) {\n return null;\n }\n\n return Date.now() * MS_TO_NS;\n}\n\n/**\n * Stops Profilers and returns collected combined profile.\n */\nexport function stopProfiling(\n profileStartTimestampNs: number,\n): CombinedProfileEvent | AndroidCombinedProfileEvent | null {\n const collectedProfiles = NATIVE.stopProfiling();\n if (!collectedProfiles) {\n return null;\n }\n const profileEndTimestampNs = Date.now() * MS_TO_NS;\n\n const hermesProfile = convertToSentryProfile(collectedProfiles.hermesProfile);\n if (!hermesProfile) {\n return null;\n }\n\n const hermesProfileEvent = createHermesProfilingEvent(hermesProfile);\n if (!hermesProfileEvent) {\n return null;\n }\n\n if (collectedProfiles.androidProfile) {\n const durationNs = profileEndTimestampNs - profileStartTimestampNs;\n return createAndroidWithHermesProfile(hermesProfileEvent, collectedProfiles.androidProfile, durationNs);\n } else if (collectedProfiles.nativeProfile) {\n return addNativeProfileToHermesProfile(hermesProfileEvent, collectedProfiles.nativeProfile);\n }\n\n return hermesProfileEvent;\n}\n\n/**\n * Creates Android profile event with attached javascript profile.\n */\nexport function createAndroidWithHermesProfile(\n hermes: HermesProfileEvent,\n nativeAndroid: NativeAndroidProfileEvent,\n durationNs: number,\n): AndroidCombinedProfileEvent {\n return {\n ...nativeAndroid,\n platform: 'android',\n js_profile: hermes.profile,\n duration_ns: durationNs.toString(10),\n active_thread_id: hermes.transaction.active_thread_id,\n };\n}\n\n/**\n * Merges Hermes and Native profile events into one.\n */\nexport function addNativeProfileToHermesProfile(\n hermes: HermesProfileEvent,\n native: NativeProfileEvent,\n): CombinedProfileEvent {\n return {\n ...hermes,\n profile: addNativeThreadCpuProfileToHermes(hermes.profile, native.profile, hermes.transaction.active_thread_id),\n debug_meta: {\n images: native.debug_meta.images,\n },\n measurements: native.measurements,\n };\n}\n\n/**\n * Merges Hermes And Native profiles into one.\n */\nexport function addNativeThreadCpuProfileToHermes(\n hermes: ThreadCpuProfile,\n native: ThreadCpuProfile,\n hermes_active_thread_id: string | undefined,\n): CombinedProfileEvent['profile'] {\n // assumes thread ids are unique\n hermes.thread_metadata = { ...native.thread_metadata, ...hermes.thread_metadata };\n // assumes queue ids are unique\n hermes.queue_metadata = { ...native.queue_metadata, ...hermes.queue_metadata };\n\n // recalculate frames and stacks using offset\n const framesOffset = hermes.frames.length;\n const stacksOffset = hermes.stacks.length;\n\n if (native.frames) {\n for (const frame of native.frames) {\n hermes.frames.push({\n function: frame.function,\n instruction_addr: frame.instruction_addr,\n platform: Platform.OS === 'ios' ? 'cocoa' : undefined,\n });\n }\n }\n hermes.stacks = [\n ...(hermes.stacks || []),\n ...(native.stacks || []).map(stack => stack.map(frameId => frameId + framesOffset)),\n ];\n hermes.samples = [\n ...(hermes.samples || []),\n ...(native.samples || [])\n .filter(sample => sample.thread_id !== hermes_active_thread_id)\n .map(sample => ({\n ...sample,\n stack_id: stacksOffset + sample.stack_id,\n })),\n ];\n\n return hermes;\n}\n"]}
@@ -18,10 +18,6 @@ export interface FramesMeasurements extends Measurements {
18
18
  * Instrumentation to add native slow/frozen frames measurements onto transactions.
19
19
  */
20
20
  export declare class NativeFramesInstrumentation {
21
- /** The native frames at the transaction finish time, keyed by traceId. */
22
- private _finishFrames;
23
- /** The listeners for each native frames response, keyed by traceId */
24
- private _framesListeners;
25
21
  /** The native frames at the finish time of the most recent span. */
26
22
  private _lastSpanFinishFrames?;
27
23
  constructor(addGlobalEventProcessor: (e: EventProcessor) => void, doesExist: () => boolean);
@@ -1 +1 @@
1
- {"version":3,"file":"nativeframes.d.ts","sourceRoot":"","sources":["../../../src/js/tracing/nativeframes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAQ,WAAW,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,KAAK,EAAS,cAAc,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAO1F,MAAM,WAAW,kBAAmB,SAAQ,YAAY;IACtD,YAAY,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,eAAe,CAAA;KAAE,CAAC;IACvD,WAAW,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,eAAe,CAAA;KAAE,CAAC;IACtD,aAAa,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,eAAe,CAAA;KAAE,CAAC;CACzD;AAQD;;GAEG;AACH,qBAAa,2BAA2B;IACtC,0EAA0E;IAC1E,OAAO,CAAC,aAAa,CAA4F;IACjH,sEAAsE;IACtE,OAAO,CAAC,gBAAgB,CAAsC;IAC9D,oEAAoE;IACpE,OAAO,CAAC,qBAAqB,CAAC,CAG5B;gBAEiB,uBAAuB,EAAE,CAAC,CAAC,EAAE,cAAc,KAAK,IAAI,EAAE,SAAS,EAAE,MAAM,OAAO;IAMjG;;;OAGG;IACI,kBAAkB,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI;IAkBzD;;OAEG;IACI,mBAAmB,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI;IAM1D;;;OAGG;IACH,OAAO,CAAC,aAAa;IAiBrB;;OAEG;YACW,sBAAsB;IAyBpC;;OAEG;IACH,OAAO,CAAC,oBAAoB;IA4C5B;;OAEG;YACW,0BAA0B;IAoBxC;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAU3B;;;OAGG;YACW,aAAa;CA+C5B"}
1
+ {"version":3,"file":"nativeframes.d.ts","sourceRoot":"","sources":["../../../src/js/tracing/nativeframes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAQ,WAAW,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,KAAK,EAAS,cAAc,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAO1F,MAAM,WAAW,kBAAmB,SAAQ,YAAY;IACtD,YAAY,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,eAAe,CAAA;KAAE,CAAC;IACvD,WAAW,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,eAAe,CAAA;KAAE,CAAC;IACtD,aAAa,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,eAAe,CAAA;KAAE,CAAC;CACzD;AAcD;;GAEG;AACH,qBAAa,2BAA2B;IACtC,oEAAoE;IACpE,OAAO,CAAC,qBAAqB,CAAC,CAG5B;gBAEiB,uBAAuB,EAAE,CAAC,CAAC,EAAE,cAAc,KAAK,IAAI,EAAE,SAAS,EAAE,MAAM,OAAO;IAMjG;;;OAGG;IACI,kBAAkB,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI;IAkBzD;;OAEG;IACI,mBAAmB,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI;IAM1D;;;OAGG;IACH,OAAO,CAAC,aAAa;IAiBrB;;OAEG;YACW,sBAAsB;IAyBpC;;OAEG;IACH,OAAO,CAAC,oBAAoB;IA4C5B;;OAEG;YACW,0BAA0B;IAoBxC;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAU3B;;;OAGG;YACW,aAAa;CA+C5B"}
@@ -2,6 +2,10 @@ import { __awaiter } from "tslib";
2
2
  import { logger, timestampInSeconds } from '@sentry/utils';
3
3
  import { NATIVE } from '../wrapper';
4
4
  import { instrumentChildSpanFinish } from './utils';
5
+ /** The listeners for each native frames response, keyed by traceId. This must be global to avoid closure issues and reading outdated values. */
6
+ const _framesListeners = new Map();
7
+ /** The native frames at the transaction finish time, keyed by traceId. This must be global to avoid closure issues and reading outdated values. */
8
+ const _finishFrames = new Map();
5
9
  /**
6
10
  * A margin of error of 50ms is allowed for the async native bridge call.
7
11
  * Anything larger would reduce the accuracy of our frames measurements.
@@ -12,10 +16,6 @@ const MARGIN_OF_ERROR_SECONDS = 0.05;
12
16
  */
13
17
  export class NativeFramesInstrumentation {
14
18
  constructor(addGlobalEventProcessor, doesExist) {
15
- /** The native frames at the transaction finish time, keyed by traceId. */
16
- this._finishFrames = new Map();
17
- /** The listeners for each native frames response, keyed by traceId */
18
- this._framesListeners = new Map();
19
19
  logger.log('[ReactNativeTracing] Native frames instrumentation initialized.');
20
20
  addGlobalEventProcessor(event => this._processEvent(event, doesExist));
21
21
  }
@@ -71,18 +71,18 @@ export class NativeFramesInstrumentation {
71
71
  */
72
72
  _getFramesMeasurements(traceId, finalEndTimestamp, startFrames) {
73
73
  return __awaiter(this, void 0, void 0, function* () {
74
- if (this._finishFrames.has(traceId)) {
74
+ if (_finishFrames.has(traceId)) {
75
75
  return this._prepareMeasurements(traceId, finalEndTimestamp, startFrames);
76
76
  }
77
77
  return new Promise(resolve => {
78
78
  const timeout = setTimeout(() => {
79
- this._framesListeners.delete(traceId);
79
+ _framesListeners.delete(traceId);
80
80
  resolve(null);
81
81
  }, 2000);
82
- this._framesListeners.set(traceId, () => {
82
+ _framesListeners.set(traceId, () => {
83
83
  resolve(this._prepareMeasurements(traceId, finalEndTimestamp, startFrames));
84
84
  clearTimeout(timeout);
85
- this._framesListeners.delete(traceId);
85
+ _framesListeners.delete(traceId);
86
86
  });
87
87
  });
88
88
  });
@@ -93,7 +93,7 @@ export class NativeFramesInstrumentation {
93
93
  _prepareMeasurements(traceId, finalEndTimestamp, // The actual transaction finish time.
94
94
  startFrames) {
95
95
  let finalFinishFrames;
96
- const finish = this._finishFrames.get(traceId);
96
+ const finish = _finishFrames.get(traceId);
97
97
  if (finish &&
98
98
  finish.nativeFrames &&
99
99
  // Must be in the margin of error of the actual transaction finish time (finalEndTimestamp)
@@ -138,11 +138,11 @@ export class NativeFramesInstrumentation {
138
138
  if (startFrames) {
139
139
  finishFrames = yield NATIVE.fetchNativeFrames();
140
140
  }
141
- this._finishFrames.set(transaction.traceId, {
141
+ _finishFrames.set(transaction.traceId, {
142
142
  nativeFrames: finishFrames,
143
143
  timestamp,
144
144
  });
145
- (_a = this._framesListeners.get(transaction.traceId)) === null || _a === void 0 ? void 0 : _a();
145
+ (_a = _framesListeners.get(transaction.traceId)) === null || _a === void 0 ? void 0 : _a();
146
146
  setTimeout(() => this._cancelFinishFrames(transaction), 2000);
147
147
  });
148
148
  }
@@ -150,8 +150,8 @@ export class NativeFramesInstrumentation {
150
150
  * On a finish frames failure, we cancel the await.
151
151
  */
152
152
  _cancelFinishFrames(transaction) {
153
- if (this._finishFrames.has(transaction.traceId)) {
154
- this._finishFrames.delete(transaction.traceId);
153
+ if (_finishFrames.has(transaction.traceId)) {
154
+ _finishFrames.delete(transaction.traceId);
155
155
  logger.log(`[NativeFrames] Native frames timed out for ${transaction.op} transaction ${transaction.name}. Not adding native frames measurements.`);
156
156
  }
157
157
  }
@@ -176,7 +176,7 @@ export class NativeFramesInstrumentation {
176
176
  else {
177
177
  logger.log(`[Measurements] Adding measurements to ${traceContext.op} transaction ${event.transaction}: ${JSON.stringify(measurements, undefined, 2)}`);
178
178
  event.measurements = Object.assign(Object.assign({}, ((_b = event.measurements) !== null && _b !== void 0 ? _b : {})), measurements);
179
- this._finishFrames.delete(traceId);
179
+ _finishFrames.delete(traceId);
180
180
  }
181
181
  delete traceContext.data.__startFrames;
182
182
  }
@@ -1 +1 @@
1
- {"version":3,"file":"nativeframes.js","sourceRoot":"","sources":["../../../src/js/tracing/nativeframes.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Span, Transaction } from '@sentry/core';\nimport type { Event, EventProcessor, Measurements, MeasurementUnit } from '@sentry/types';\nimport { logger, timestampInSeconds } from '@sentry/utils';\n\nimport type { NativeFramesResponse } from '../NativeRNSentry';\nimport { NATIVE } from '../wrapper';\nimport { instrumentChildSpanFinish } from './utils';\n\nexport interface FramesMeasurements extends Measurements {\n frames_total: { value: number; unit: MeasurementUnit };\n frames_slow: { value: number; unit: MeasurementUnit };\n frames_frozen: { value: number; unit: MeasurementUnit };\n}\n\n/**\n * A margin of error of 50ms is allowed for the async native bridge call.\n * Anything larger would reduce the accuracy of our frames measurements.\n */\nconst MARGIN_OF_ERROR_SECONDS = 0.05;\n\n/**\n * Instrumentation to add native slow/frozen frames measurements onto transactions.\n */\nexport class NativeFramesInstrumentation {\n /** The native frames at the transaction finish time, keyed by traceId. */\n private _finishFrames: Map<string, { timestamp: number; nativeFrames: NativeFramesResponse | null }> = new Map();\n /** The listeners for each native frames response, keyed by traceId */\n private _framesListeners: Map<string, () => void> = new Map();\n /** The native frames at the finish time of the most recent span. */\n private _lastSpanFinishFrames?: {\n timestamp: number;\n nativeFrames: NativeFramesResponse;\n };\n\n public constructor(addGlobalEventProcessor: (e: EventProcessor) => void, doesExist: () => boolean) {\n logger.log('[ReactNativeTracing] Native frames instrumentation initialized.');\n\n addGlobalEventProcessor(event => this._processEvent(event, doesExist));\n }\n\n /**\n * To be called when a transaction is started.\n * Logs the native frames at this start point and instruments child span finishes.\n */\n public onTransactionStart(transaction: Transaction): void {\n void NATIVE.fetchNativeFrames()\n .then(framesMetrics => {\n if (framesMetrics) {\n transaction.setData('__startFrames', framesMetrics);\n }\n })\n .then(undefined, error => {\n logger.error(`[ReactNativeTracing] Error while fetching native frames: ${error}`);\n });\n\n instrumentChildSpanFinish(transaction, (_: Span, endTimestamp?: number) => {\n if (!endTimestamp) {\n this._onSpanFinish();\n }\n });\n }\n\n /**\n * To be called when a transaction is finished\n */\n public onTransactionFinish(transaction: Transaction): void {\n this._fetchFramesForTransaction(transaction).then(undefined, (reason: unknown) => {\n logger.error(`[ReactNativeTracing] Error while fetching native frames:`, reason);\n });\n }\n\n /**\n * Called on a span finish to fetch native frames to support transactions with trimEnd.\n * Only to be called when a span does not have an end timestamp.\n */\n private _onSpanFinish(): void {\n const timestamp = timestampInSeconds();\n\n void NATIVE.fetchNativeFrames()\n .then(nativeFrames => {\n if (nativeFrames) {\n this._lastSpanFinishFrames = {\n timestamp,\n nativeFrames,\n };\n }\n })\n .then(undefined, error => {\n logger.error(`[ReactNativeTracing] Error while fetching native frames: ${error}`);\n });\n }\n\n /**\n * Returns the computed frames measurements and awaits for them if they are not ready yet.\n */\n private async _getFramesMeasurements(\n traceId: string,\n finalEndTimestamp: number,\n startFrames: NativeFramesResponse,\n ): Promise<FramesMeasurements | null> {\n if (this._finishFrames.has(traceId)) {\n return this._prepareMeasurements(traceId, finalEndTimestamp, startFrames);\n }\n\n return new Promise(resolve => {\n const timeout = setTimeout(() => {\n this._framesListeners.delete(traceId);\n\n resolve(null);\n }, 2000);\n\n this._framesListeners.set(traceId, () => {\n resolve(this._prepareMeasurements(traceId, finalEndTimestamp, startFrames));\n\n clearTimeout(timeout);\n this._framesListeners.delete(traceId);\n });\n });\n }\n\n /**\n * Returns the computed frames measurements given ready data\n */\n private _prepareMeasurements(\n traceId: string,\n finalEndTimestamp: number, // The actual transaction finish time.\n startFrames: NativeFramesResponse,\n ): FramesMeasurements | null {\n let finalFinishFrames: NativeFramesResponse | undefined;\n\n const finish = this._finishFrames.get(traceId);\n if (\n finish &&\n finish.nativeFrames &&\n // Must be in the margin of error of the actual transaction finish time (finalEndTimestamp)\n Math.abs(finish.timestamp - finalEndTimestamp) < MARGIN_OF_ERROR_SECONDS\n ) {\n finalFinishFrames = finish.nativeFrames;\n } else if (\n this._lastSpanFinishFrames &&\n Math.abs(this._lastSpanFinishFrames.timestamp - finalEndTimestamp) < MARGIN_OF_ERROR_SECONDS\n ) {\n // Fallback to the last span finish if it is within the margin of error of the actual finish timestamp.\n // This should be the case for trimEnd.\n finalFinishFrames = this._lastSpanFinishFrames.nativeFrames;\n } else {\n return null;\n }\n\n const measurements = {\n frames_total: {\n value: finalFinishFrames.totalFrames - startFrames.totalFrames,\n unit: 'none',\n },\n frames_frozen: {\n value: finalFinishFrames.frozenFrames - startFrames.frozenFrames,\n unit: 'none',\n },\n frames_slow: {\n value: finalFinishFrames.slowFrames - startFrames.slowFrames,\n unit: 'none',\n },\n };\n\n return measurements;\n }\n\n /**\n * Fetch finish frames for a transaction at the current time. Calls any awaiting listeners.\n */\n private async _fetchFramesForTransaction(transaction: Transaction): Promise<void> {\n const startFrames = transaction.data.__startFrames as NativeFramesResponse | undefined;\n\n // This timestamp marks when the finish frames were retrieved. It should be pretty close to the transaction finish.\n const timestamp = timestampInSeconds();\n let finishFrames: NativeFramesResponse | null = null;\n if (startFrames) {\n finishFrames = await NATIVE.fetchNativeFrames();\n }\n\n this._finishFrames.set(transaction.traceId, {\n nativeFrames: finishFrames,\n timestamp,\n });\n\n this._framesListeners.get(transaction.traceId)?.();\n\n setTimeout(() => this._cancelFinishFrames(transaction), 2000);\n }\n\n /**\n * On a finish frames failure, we cancel the await.\n */\n private _cancelFinishFrames(transaction: Transaction): void {\n if (this._finishFrames.has(transaction.traceId)) {\n this._finishFrames.delete(transaction.traceId);\n\n logger.log(\n `[NativeFrames] Native frames timed out for ${transaction.op} transaction ${transaction.name}. Not adding native frames measurements.`,\n );\n }\n }\n\n /**\n * Adds frames measurements to an event. Called from a valid event processor.\n * Awaits for finish frames if needed.\n */\n private async _processEvent(event: Event, doesExist: () => boolean): Promise<Event> {\n if (!doesExist()) {\n return event;\n }\n\n if (event.type === 'transaction' && event.transaction && event.contexts && event.contexts.trace) {\n const traceContext = event.contexts.trace as {\n data?: { [key: string]: unknown };\n trace_id: string;\n name?: string;\n op?: string;\n };\n\n const traceId = traceContext.trace_id;\n\n if (traceId && traceContext.data?.__startFrames && event.timestamp) {\n const measurements = await this._getFramesMeasurements(\n traceId,\n event.timestamp,\n traceContext.data.__startFrames as NativeFramesResponse,\n );\n\n if (!measurements) {\n logger.log(\n `[NativeFrames] Could not fetch native frames for ${traceContext.op} transaction ${event.transaction}. Not adding native frames measurements.`,\n );\n } else {\n logger.log(\n `[Measurements] Adding measurements to ${traceContext.op} transaction ${\n event.transaction\n }: ${JSON.stringify(measurements, undefined, 2)}`,\n );\n\n event.measurements = {\n ...(event.measurements ?? {}),\n ...measurements,\n };\n\n this._finishFrames.delete(traceId);\n }\n\n delete traceContext.data.__startFrames;\n }\n }\n\n return event;\n }\n}\n"]}
1
+ {"version":3,"file":"nativeframes.js","sourceRoot":"","sources":["../../../src/js/tracing/nativeframes.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Span, Transaction } from '@sentry/core';\nimport type { Event, EventProcessor, Measurements, MeasurementUnit } from '@sentry/types';\nimport { logger, timestampInSeconds } from '@sentry/utils';\n\nimport type { NativeFramesResponse } from '../NativeRNSentry';\nimport { NATIVE } from '../wrapper';\nimport { instrumentChildSpanFinish } from './utils';\n\nexport interface FramesMeasurements extends Measurements {\n frames_total: { value: number; unit: MeasurementUnit };\n frames_slow: { value: number; unit: MeasurementUnit };\n frames_frozen: { value: number; unit: MeasurementUnit };\n}\n\n/** The listeners for each native frames response, keyed by traceId. This must be global to avoid closure issues and reading outdated values. */\nconst _framesListeners: Map<string, () => void> = new Map();\n\n/** The native frames at the transaction finish time, keyed by traceId. This must be global to avoid closure issues and reading outdated values. */\nconst _finishFrames: Map<string, { timestamp: number; nativeFrames: NativeFramesResponse | null }> = new Map();\n\n/**\n * A margin of error of 50ms is allowed for the async native bridge call.\n * Anything larger would reduce the accuracy of our frames measurements.\n */\nconst MARGIN_OF_ERROR_SECONDS = 0.05;\n\n/**\n * Instrumentation to add native slow/frozen frames measurements onto transactions.\n */\nexport class NativeFramesInstrumentation {\n /** The native frames at the finish time of the most recent span. */\n private _lastSpanFinishFrames?: {\n timestamp: number;\n nativeFrames: NativeFramesResponse;\n };\n\n public constructor(addGlobalEventProcessor: (e: EventProcessor) => void, doesExist: () => boolean) {\n logger.log('[ReactNativeTracing] Native frames instrumentation initialized.');\n\n addGlobalEventProcessor(event => this._processEvent(event, doesExist));\n }\n\n /**\n * To be called when a transaction is started.\n * Logs the native frames at this start point and instruments child span finishes.\n */\n public onTransactionStart(transaction: Transaction): void {\n void NATIVE.fetchNativeFrames()\n .then(framesMetrics => {\n if (framesMetrics) {\n transaction.setData('__startFrames', framesMetrics);\n }\n })\n .then(undefined, error => {\n logger.error(`[ReactNativeTracing] Error while fetching native frames: ${error}`);\n });\n\n instrumentChildSpanFinish(transaction, (_: Span, endTimestamp?: number) => {\n if (!endTimestamp) {\n this._onSpanFinish();\n }\n });\n }\n\n /**\n * To be called when a transaction is finished\n */\n public onTransactionFinish(transaction: Transaction): void {\n this._fetchFramesForTransaction(transaction).then(undefined, (reason: unknown) => {\n logger.error(`[ReactNativeTracing] Error while fetching native frames:`, reason);\n });\n }\n\n /**\n * Called on a span finish to fetch native frames to support transactions with trimEnd.\n * Only to be called when a span does not have an end timestamp.\n */\n private _onSpanFinish(): void {\n const timestamp = timestampInSeconds();\n\n void NATIVE.fetchNativeFrames()\n .then(nativeFrames => {\n if (nativeFrames) {\n this._lastSpanFinishFrames = {\n timestamp,\n nativeFrames,\n };\n }\n })\n .then(undefined, error => {\n logger.error(`[ReactNativeTracing] Error while fetching native frames: ${error}`);\n });\n }\n\n /**\n * Returns the computed frames measurements and awaits for them if they are not ready yet.\n */\n private async _getFramesMeasurements(\n traceId: string,\n finalEndTimestamp: number,\n startFrames: NativeFramesResponse,\n ): Promise<FramesMeasurements | null> {\n if (_finishFrames.has(traceId)) {\n return this._prepareMeasurements(traceId, finalEndTimestamp, startFrames);\n }\n\n return new Promise(resolve => {\n const timeout = setTimeout(() => {\n _framesListeners.delete(traceId);\n\n resolve(null);\n }, 2000);\n\n _framesListeners.set(traceId, () => {\n resolve(this._prepareMeasurements(traceId, finalEndTimestamp, startFrames));\n\n clearTimeout(timeout);\n _framesListeners.delete(traceId);\n });\n });\n }\n\n /**\n * Returns the computed frames measurements given ready data\n */\n private _prepareMeasurements(\n traceId: string,\n finalEndTimestamp: number, // The actual transaction finish time.\n startFrames: NativeFramesResponse,\n ): FramesMeasurements | null {\n let finalFinishFrames: NativeFramesResponse | undefined;\n\n const finish = _finishFrames.get(traceId);\n if (\n finish &&\n finish.nativeFrames &&\n // Must be in the margin of error of the actual transaction finish time (finalEndTimestamp)\n Math.abs(finish.timestamp - finalEndTimestamp) < MARGIN_OF_ERROR_SECONDS\n ) {\n finalFinishFrames = finish.nativeFrames;\n } else if (\n this._lastSpanFinishFrames &&\n Math.abs(this._lastSpanFinishFrames.timestamp - finalEndTimestamp) < MARGIN_OF_ERROR_SECONDS\n ) {\n // Fallback to the last span finish if it is within the margin of error of the actual finish timestamp.\n // This should be the case for trimEnd.\n finalFinishFrames = this._lastSpanFinishFrames.nativeFrames;\n } else {\n return null;\n }\n\n const measurements = {\n frames_total: {\n value: finalFinishFrames.totalFrames - startFrames.totalFrames,\n unit: 'none',\n },\n frames_frozen: {\n value: finalFinishFrames.frozenFrames - startFrames.frozenFrames,\n unit: 'none',\n },\n frames_slow: {\n value: finalFinishFrames.slowFrames - startFrames.slowFrames,\n unit: 'none',\n },\n };\n\n return measurements;\n }\n\n /**\n * Fetch finish frames for a transaction at the current time. Calls any awaiting listeners.\n */\n private async _fetchFramesForTransaction(transaction: Transaction): Promise<void> {\n const startFrames = transaction.data.__startFrames as NativeFramesResponse | undefined;\n\n // This timestamp marks when the finish frames were retrieved. It should be pretty close to the transaction finish.\n const timestamp = timestampInSeconds();\n let finishFrames: NativeFramesResponse | null = null;\n if (startFrames) {\n finishFrames = await NATIVE.fetchNativeFrames();\n }\n\n _finishFrames.set(transaction.traceId, {\n nativeFrames: finishFrames,\n timestamp,\n });\n\n _framesListeners.get(transaction.traceId)?.();\n\n setTimeout(() => this._cancelFinishFrames(transaction), 2000);\n }\n\n /**\n * On a finish frames failure, we cancel the await.\n */\n private _cancelFinishFrames(transaction: Transaction): void {\n if (_finishFrames.has(transaction.traceId)) {\n _finishFrames.delete(transaction.traceId);\n\n logger.log(\n `[NativeFrames] Native frames timed out for ${transaction.op} transaction ${transaction.name}. Not adding native frames measurements.`,\n );\n }\n }\n\n /**\n * Adds frames measurements to an event. Called from a valid event processor.\n * Awaits for finish frames if needed.\n */\n private async _processEvent(event: Event, doesExist: () => boolean): Promise<Event> {\n if (!doesExist()) {\n return event;\n }\n\n if (event.type === 'transaction' && event.transaction && event.contexts && event.contexts.trace) {\n const traceContext = event.contexts.trace as {\n data?: { [key: string]: unknown };\n trace_id: string;\n name?: string;\n op?: string;\n };\n\n const traceId = traceContext.trace_id;\n\n if (traceId && traceContext.data?.__startFrames && event.timestamp) {\n const measurements = await this._getFramesMeasurements(\n traceId,\n event.timestamp,\n traceContext.data.__startFrames as NativeFramesResponse,\n );\n\n if (!measurements) {\n logger.log(\n `[NativeFrames] Could not fetch native frames for ${traceContext.op} transaction ${event.transaction}. Not adding native frames measurements.`,\n );\n } else {\n logger.log(\n `[Measurements] Adding measurements to ${traceContext.op} transaction ${\n event.transaction\n }: ${JSON.stringify(measurements, undefined, 2)}`,\n );\n\n event.measurements = {\n ...(event.measurements ?? {}),\n ...measurements,\n };\n\n _finishFrames.delete(traceId);\n }\n\n delete traceContext.data.__startFrames;\n }\n }\n\n return event;\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"reactnativetracing.d.ts","sourceRoot":"","sources":["../../../src/js/tracing/reactnativetracing.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"reactnativetracing.d.ts","sourceRoot":"","sources":["../../../src/js/tracing/reactnativetracing.ts"],"names":[],"mappings":"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"}
@@ -226,10 +226,16 @@ export class ReactNativeTracing {
226
226
  return;
227
227
  }
228
228
  const appStart = yield NATIVE.fetchNativeAppStart();
229
- if (!appStart || appStart.didFetchAppStart) {
229
+ if (!appStart) {
230
+ logger.warn('[ReactNativeTracing] Not instrumenting App Start because native returned null.');
231
+ return;
232
+ }
233
+ if (appStart.didFetchAppStart) {
234
+ logger.warn('[ReactNativeTracing] Not instrumenting App Start because this start was already reported.');
230
235
  return;
231
236
  }
232
237
  if (!this.useAppStartWithProfiler) {
238
+ logger.warn('[ReactNativeTracing] `Sentry.wrap` not detected, using JS context init as app start end.');
233
239
  this._appStartFinishTimestamp = getTimeOriginMilliseconds() / 1000;
234
240
  }
235
241
  if (this.options.routingInstrumentation) {
@@ -253,13 +259,14 @@ export class ReactNativeTracing {
253
259
  var _a, _b;
254
260
  const appStartDurationMilliseconds = this._getAppStartDurationMilliseconds(appStart);
255
261
  if (!appStartDurationMilliseconds) {
256
- logger.warn('App start was never finished.');
262
+ logger.warn('[ReactNativeTracing] App start end has not been recorded, not adding app start span.');
257
263
  return;
258
264
  }
259
265
  // we filter out app start more than 60s.
260
266
  // this could be due to many different reasons.
261
267
  // we've seen app starts with hours, days and even months.
262
268
  if (appStartDurationMilliseconds >= ReactNativeTracing._maxAppStart) {
269
+ logger.warn('[ReactNativeTracing] App start duration is over a minute long, not adding app start span.');
263
270
  return;
264
271
  }
265
272
  const appStartTimeSeconds = appStart.appStartTime / 1000;