diff --git a/CHANGELOG.md b/CHANGELOG.md index 36e4256dc..21c34c634 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +### Fixes + +- App Start Native Frames can start with zeroed values ([#3881](https://github.com/getsentry/sentry-react-native/pull/3881)) + ## 5.24.0 ### Features diff --git a/android/src/main/java/io/sentry/react/RNSentryModuleImpl.java b/android/src/main/java/io/sentry/react/RNSentryModuleImpl.java index 9b9195d4d..b73bf6a75 100644 --- a/android/src/main/java/io/sentry/react/RNSentryModuleImpl.java +++ b/android/src/main/java/io/sentry/react/RNSentryModuleImpl.java @@ -381,11 +381,6 @@ public void fetchNativeFrames(Promise promise) { } } - if (totalFrames == 0 && slowFrames == 0 && frozenFrames == 0) { - promise.resolve(null); - return; - } - WritableMap map = Arguments.createMap(); map.putInt("totalFrames", totalFrames); map.putInt("slowFrames", slowFrames); diff --git a/ios/RNSentry.mm b/ios/RNSentry.mm index 1ae62f71e..8c774ddbb 100644 --- a/ios/RNSentry.mm +++ b/ios/RNSentry.mm @@ -415,12 +415,6 @@ - (NSDictionary*) fetchNativeStackFramesBy: (NSArray*)instructionsAdd NSNumber *total = [NSNumber numberWithLong:frames.total]; NSNumber *frozen = [NSNumber numberWithLong:frames.frozen]; NSNumber *slow = [NSNumber numberWithLong:frames.slow]; - NSNumber *zero = [NSNumber numberWithLong:0L]; - - if ([total isEqualToNumber:zero] && [frozen isEqualToNumber:zero] && [slow isEqualToNumber:zero]) { - resolve(nil); - return; - } resolve(@{ @"totalFrames": total, diff --git a/src/js/tracing/nativeframes.ts b/src/js/tracing/nativeframes.ts index 6174091f6..9f6e44156 100644 --- a/src/js/tracing/nativeframes.ts +++ b/src/js/tracing/nativeframes.ts @@ -192,6 +192,17 @@ export class NativeFramesInstrumentation { }, }; + if ( + measurements.frames_frozen.value <= 0 && + measurements.frames_slow.value <= 0 && + measurements.frames_total.value <= 0 + ) { + logger.warn( + `[NativeFrames] Detected zero slow or frozen frames. Not adding measurements to traceId (${traceId}).`, + ); + return null; + } + return measurements; } diff --git a/test/tracing/nativeframes.test.ts b/test/tracing/nativeframes.test.ts index 821e92d94..402fd8a33 100644 --- a/test/tracing/nativeframes.test.ts +++ b/test/tracing/nativeframes.test.ts @@ -98,6 +98,80 @@ describe('NativeFramesInstrumentation', () => { ); }); + it('sets native frames measurements on a transaction event (start frames zero)', async () => { + const startFrames = { + totalFrames: 0, + slowFrames: 0, + frozenFrames: 0, + }; + const finishFrames = { + totalFrames: 100, + slowFrames: 20, + frozenFrames: 5, + }; + mockFunction(NATIVE.fetchNativeFrames).mockResolvedValueOnce(startFrames).mockResolvedValueOnce(finishFrames); + + await startSpan({ name: 'test' }, async () => { + await Promise.resolve(); // native frames fetch is async call this will flush the start frames fetch promise + }); + + await jest.runOnlyPendingTimersAsync(); + await client.flush(); + + expect(client.event!).toEqual( + expect.objectContaining>({ + measurements: expect.objectContaining({ + frames_total: { + value: 100, + unit: 'none', + }, + frames_slow: { + value: 20, + unit: 'none', + }, + frames_frozen: { + value: 5, + unit: 'none', + }, + }), + }), + ); + }); + + it('does not sent zero value native frames measurements', async () => { + const startFrames = { + totalFrames: 100, + slowFrames: 20, + frozenFrames: 5, + }; + const finishFrames = { + totalFrames: 100, + slowFrames: 20, + frozenFrames: 5, + }; + mockFunction(NATIVE.fetchNativeFrames).mockResolvedValueOnce(startFrames).mockResolvedValueOnce(finishFrames); + + await startSpan({ name: 'test' }, async () => { + await Promise.resolve(); // native frames fetch is async call this will flush the start frames fetch promise + }); + + await jest.runOnlyPendingTimersAsync(); + await client.flush(); + + expect(client.event!).toEqual( + expect.objectContaining>({ + measurements: expect.toBeOneOf([ + expect.not.objectContaining({ + frames_total: expect.any(Object), + frames_slow: expect.any(Object), + frames_frozen: expect.any(Object), + }), + undefined, + ]), + }), + ); + }); + it('does not set measurements on transactions without startFrames', async () => { const startFrames = null; const finishFrames = {