Skip to content

Commit f2f3399

Browse files
fix(performance): add more debug logs to native frames integration (#3880)
1 parent 70e6261 commit f2f3399

File tree

3 files changed

+52
-12
lines changed

3 files changed

+52
-12
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
- This doesn't change the app start measurement length, but add child spans (more detail) into the existing app start span
99
- Added JS Bundle Execution start information to the application start measurements ([#3857](https://github.com/getsentry/sentry-react-native/pull/3857))
1010

11+
### Fixes
12+
13+
- Add more expressive debug logs to Native Frames Integration ([#3880](https://github.com/getsentry/sentry-react-native/pull/3880))
14+
1115
### Dependencies
1216

1317
- Bump Cocoa SDK from v8.27.0 to v8.28.0 ([#3866](https://github.com/getsentry/sentry-react-native/pull/3866))

src/js/tracing/nativeframes.ts

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@ import type { NativeFramesResponse } from '../NativeRNSentry';
66
import { NATIVE } from '../wrapper';
77
import { instrumentChildSpanFinish } from './utils';
88

9+
/**
10+
* Timeout from the final native frames fetch to processing the associated transaction.
11+
* If the transaction is not processed by this time, the native frames will be dropped
12+
* and not added to the event.
13+
*/
14+
const FINAL_FRAMES_TIMEOUT_MS = 2000;
15+
916
export interface FramesMeasurements extends Measurements {
1017
frames_total: { value: number; unit: MeasurementUnit };
1118
frames_slow: { value: number; unit: MeasurementUnit };
@@ -45,14 +52,24 @@ export class NativeFramesInstrumentation {
4552
* Logs the native frames at this start point and instruments child span finishes.
4653
*/
4754
public onTransactionStart(transaction: Transaction): void {
55+
logger.debug(`[NativeFrames] Fetching frames for root span start (${transaction.spanContext().spanId}).`);
4856
void NATIVE.fetchNativeFrames()
4957
.then(framesMetrics => {
5058
if (framesMetrics) {
5159
transaction.setData('__startFrames', framesMetrics);
60+
} else {
61+
logger.warn(
62+
`[NativeFrames] Fetched frames for root span start (${
63+
transaction.spanContext().spanId
64+
}), but no frames were returned.`,
65+
);
5266
}
5367
})
5468
.then(undefined, error => {
55-
logger.error(`[ReactNativeTracing] Error while fetching native frames: ${error}`);
69+
logger.error(
70+
`[NativeFrames] Error while fetching frames for root span start (${transaction.spanContext().spanId})`,
71+
error,
72+
);
5673
});
5774

5875
instrumentChildSpanFinish(transaction, (_: Span, endTimestamp?: number) => {
@@ -66,8 +83,11 @@ export class NativeFramesInstrumentation {
6683
* To be called when a transaction is finished
6784
*/
6885
public onTransactionFinish(transaction: Transaction): void {
69-
this._fetchFramesForTransaction(transaction).then(undefined, (reason: unknown) => {
70-
logger.error(`[ReactNativeTracing] Error while fetching native frames:`, reason);
86+
this._fetchEndFramesForTransaction(transaction).then(undefined, (reason: unknown) => {
87+
logger.error(
88+
`[NativeFrames] Error while fetching frames for root span start (${transaction.spanContext().spanId})`,
89+
reason,
90+
);
7191
});
7292
}
7393

@@ -88,7 +108,7 @@ export class NativeFramesInstrumentation {
88108
}
89109
})
90110
.then(undefined, error => {
91-
logger.error(`[ReactNativeTracing] Error while fetching native frames: ${error}`);
111+
logger.error(`[NativeFrames] Error while fetching frames for child span end.`, error);
92112
});
93113
}
94114

@@ -101,17 +121,20 @@ export class NativeFramesInstrumentation {
101121
startFrames: NativeFramesResponse,
102122
): Promise<FramesMeasurements | null> {
103123
if (_finishFrames.has(traceId)) {
124+
logger.debug(`[NativeFrames] Native end frames already fetched for trace id (${traceId}).`);
104125
return this._prepareMeasurements(traceId, finalEndTimestamp, startFrames);
105126
}
106127

107128
return new Promise(resolve => {
108129
const timeout = setTimeout(() => {
130+
logger.debug(`[NativeFrames] Native end frames listener removed by timeout for trace id (${traceId}).`);
109131
_framesListeners.delete(traceId);
110132

111133
resolve(null);
112134
}, 2000);
113135

114136
_framesListeners.set(traceId, () => {
137+
logger.debug(`[NativeFrames] Native end frames listener called for trace id (${traceId}).`);
115138
resolve(this._prepareMeasurements(traceId, finalEndTimestamp, startFrames));
116139

117140
clearTimeout(timeout);
@@ -137,15 +160,20 @@ export class NativeFramesInstrumentation {
137160
// Must be in the margin of error of the actual transaction finish time (finalEndTimestamp)
138161
Math.abs(finish.timestamp - finalEndTimestamp) < MARGIN_OF_ERROR_SECONDS
139162
) {
163+
logger.debug(`[NativeFrames] Using frames from root span end (traceId, ${traceId}).`);
140164
finalFinishFrames = finish.nativeFrames;
141165
} else if (
142166
this._lastSpanFinishFrames &&
143167
Math.abs(this._lastSpanFinishFrames.timestamp - finalEndTimestamp) < MARGIN_OF_ERROR_SECONDS
144168
) {
145169
// Fallback to the last span finish if it is within the margin of error of the actual finish timestamp.
146170
// This should be the case for trimEnd.
171+
logger.debug(`[NativeFrames] Using native frames from last span end (traceId, ${traceId}).`);
147172
finalFinishFrames = this._lastSpanFinishFrames.nativeFrames;
148173
} else {
174+
logger.warn(
175+
`[NativeFrames] Frames were collected within larger than margin of error delay for traceId (${traceId}). Dropping the inaccurate values.`,
176+
);
149177
return null;
150178
}
151179

@@ -170,7 +198,7 @@ export class NativeFramesInstrumentation {
170198
/**
171199
* Fetch finish frames for a transaction at the current time. Calls any awaiting listeners.
172200
*/
173-
private async _fetchFramesForTransaction(transaction: Transaction): Promise<void> {
201+
private async _fetchEndFramesForTransaction(transaction: Transaction): Promise<void> {
174202
const startFrames = transaction.data.__startFrames as NativeFramesResponse | undefined;
175203

176204
// This timestamp marks when the finish frames were retrieved. It should be pretty close to the transaction finish.
@@ -187,13 +215,13 @@ export class NativeFramesInstrumentation {
187215

188216
_framesListeners.get(transaction.traceId)?.();
189217

190-
setTimeout(() => this._cancelFinishFrames(transaction), 2000);
218+
setTimeout(() => this._cancelEndFrames(transaction), FINAL_FRAMES_TIMEOUT_MS);
191219
}
192220

193221
/**
194222
* On a finish frames failure, we cancel the await.
195223
*/
196-
private _cancelFinishFrames(transaction: Transaction): void {
224+
private _cancelEndFrames(transaction: Transaction): void {
197225
if (_finishFrames.has(transaction.traceId)) {
198226
_finishFrames.delete(transaction.traceId);
199227

@@ -222,18 +250,20 @@ export class NativeFramesInstrumentation {
222250

223251
const traceId = traceContext.trace_id;
224252

253+
if (!traceContext.data?.__startFrames) {
254+
logger.warn(
255+
`[NativeFrames] Start frames of transaction ${event.transaction} (eventId, ${event.event_id}) are missing, but it already ended.`,
256+
);
257+
}
258+
225259
if (traceId && traceContext.data?.__startFrames && event.timestamp) {
226260
const measurements = await this._getFramesMeasurements(
227261
traceId,
228262
event.timestamp,
229263
traceContext.data.__startFrames as NativeFramesResponse,
230264
);
231265

232-
if (!measurements) {
233-
logger.log(
234-
`[NativeFrames] Could not fetch native frames for ${traceContext.op} transaction ${event.transaction}. Not adding native frames measurements.`,
235-
);
236-
} else {
266+
if (measurements) {
237267
logger.log(
238268
`[Measurements] Adding measurements to ${traceContext.op} transaction ${
239269
event.transaction

src/js/tracing/reactnativetracing.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,12 @@ export class ReactNativeTracing implements Integration {
279279
// Only if this method is called at or within margin of error to the start timestamp.
280280
this.nativeFramesInstrumentation?.onTransactionStart(transaction);
281281
this.stallTrackingInstrumentation?.onTransactionStart(transaction);
282+
} else {
283+
logger.warn(
284+
`[ReactNativeTracing] onTransactionStart called with delay (larger than margin of error) for transaction ${
285+
transaction.description
286+
} (${transaction.spanContext().spanId}). Not fetching native frames or tracking stalls.`,
287+
);
282288
}
283289
}
284290

0 commit comments

Comments
 (0)