Skip to content

Commit a59a35f

Browse files
elirangoshenclaude
andcommitted
Track JS bundle parse time as a Sentry span on Android HybridApp
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 477b221 commit a59a35f

1 file changed

Lines changed: 25 additions & 30 deletions

File tree

src/setup/telemetry/index.ts

Lines changed: 25 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import * as Sentry from '@sentry/react-native';
22
import {Platform} from 'react-native';
3-
import performance, {PerformanceObserver} from 'react-native-performance';
3+
import {PerformanceObserver} from 'react-native-performance';
44
import {isDevelopment} from '@libs/Environment/Environment';
5-
import {endSpan, getSpan, startSpan} from '@libs/telemetry/activeSpans';
5+
import {endSpan, startSpan} from '@libs/telemetry/activeSpans';
66
import {breadcrumbsIntegration, browserProfilingIntegration, consoleIntegration, navigationIntegration, tracingIntegration} from '@libs/telemetry/integrations';
77
import processBeforeSendTransactions from '@libs/telemetry/middlewares';
88
import CONFIG from '@src/CONFIG';
@@ -41,33 +41,28 @@ export default function (): void {
4141
op: CONST.TELEMETRY.SPAN_APP_STARTUP,
4242
});
4343

44-
const runJsBundleStartEntries = performance.getEntriesByName('runJsBundleStart');
45-
if (runJsBundleStartEntries.length > 0) {
46-
const jsParseStartSecs = (runJsBundleStartEntries.at(0)?.startTime ?? 0) / 1000;
47-
48-
startSpan(CONST.TELEMETRY.SPAN_JS_PARSE_TIME, {
49-
name: CONST.TELEMETRY.SPAN_JS_PARSE_TIME,
50-
op: CONST.TELEMETRY.SPAN_JS_PARSE_TIME,
51-
startTime: jsParseStartSecs,
52-
parentSpan: getSpan(CONST.TELEMETRY.SPAN_APP_STARTUP),
53-
});
54-
55-
const finishJsParseSpan = (endTimeSecs: number) => {
56-
endSpan(CONST.TELEMETRY.SPAN_JS_PARSE_TIME, endTimeSecs);
57-
};
58-
59-
const runJsBundleEndEntries = performance.getEntriesByName('runJsBundleEnd');
60-
if (runJsBundleEndEntries.length > 0) {
61-
finishJsParseSpan((runJsBundleEndEntries.at(0)?.startTime ?? 0) / 1000);
62-
} else {
63-
const observer = new PerformanceObserver((list) => {
64-
const entries = list.getEntriesByName('runJsBundleEnd');
65-
if (entries.length > 0) {
66-
finishJsParseSpan((entries.at(0)?.startTime ?? 0) / 1000);
67-
observer.disconnect();
68-
}
69-
});
70-
observer.observe({type: 'mark', buffered: true});
44+
// getEntriesByName() queries the JS-side entry store, which is only populated after
45+
// CONTENT_APPEARED fires (emitBufferedMarks). Since this code runs during JS bundle
46+
// execution — before content appears — the sync check always returns [].
47+
// Use a PerformanceObserver with type 'react-native-mark' (native marks arrive as
48+
// PerformanceReactNativeMark, not PerformanceMark) and buffered: true so it fires
49+
// when CONTENT_APPEARED flushes the native mark buffer to JS.
50+
let jsParseStartMs: number | undefined;
51+
const observer = new PerformanceObserver((list) => {
52+
for (const entry of list.getEntries()) {
53+
if (entry.name === 'runJsBundleStart' && jsParseStartMs === undefined) {
54+
jsParseStartMs = entry.startTime;
55+
startSpan(CONST.TELEMETRY.SPAN_JS_PARSE_TIME, {
56+
name: CONST.TELEMETRY.SPAN_JS_PARSE_TIME,
57+
op: CONST.TELEMETRY.SPAN_JS_PARSE_TIME,
58+
startTime: jsParseStartMs / 1000,
59+
});
60+
}
61+
if (entry.name === 'runJsBundleEnd' && jsParseStartMs !== undefined) {
62+
endSpan(CONST.TELEMETRY.SPAN_JS_PARSE_TIME, entry.startTime / 1000);
63+
observer.disconnect();
64+
}
7165
}
72-
}
66+
});
67+
observer.observe({type: 'react-native-mark', buffered: true});
7368
}

0 commit comments

Comments
 (0)