diff --git a/CHANGELOG.md b/CHANGELOG.md index fb280255f3..c97d7876c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## Unreleased + +- Filter out app start with more than 60s ([#2303](https://github.com/getsentry/sentry-react-native/pull/2303)) + ## 4.0.0 - Bump Sentry Cocoa 7.18.0 ([#2303](https://github.com/getsentry/sentry-react-native/pull/2303)) diff --git a/src/js/tracing/reactnativetracing.ts b/src/js/tracing/reactnativetracing.ts index ed235603bb..824d38653c 100644 --- a/src/js/tracing/reactnativetracing.ts +++ b/src/js/tracing/reactnativetracing.ts @@ -110,6 +110,8 @@ export class ReactNativeTracing implements Integration { * @inheritDoc */ public static id: string = 'ReactNativeTracing'; + /** We filter out App starts more than 60s */ + private static _maxAppStart: number = 60000; /** * @inheritDoc */ @@ -294,6 +296,13 @@ export class ReactNativeTracing implements Integration { const appStartDurationMilliseconds = this._appStartFinishTimestamp * 1000 - appStart.appStartTime; + // we filter out app start more than 60s. + // this could be due to many different reasons. + // we've seen app starts with hours, days and even months. + if (appStartDurationMilliseconds >= ReactNativeTracing._maxAppStart) { + return; + } + transaction.setMeasurement(appStartMode, appStartDurationMilliseconds); } diff --git a/test/tracing/reactnativetracing.test.ts b/test/tracing/reactnativetracing.test.ts index b7430f80ba..f6ddc5069d 100644 --- a/test/tracing/reactnativetracing.test.ts +++ b/test/tracing/reactnativetracing.test.ts @@ -165,6 +165,52 @@ describe('ReactNativeTracing', () => { }); }); + it('Does not add app start measurement if more than 60s', (done) => { + const integration = new ReactNativeTracing(); + + const timeOriginMilliseconds = Date.now(); + const appStartTimeMilliseconds = timeOriginMilliseconds - 65000; + const mockAppStartResponse: NativeAppStartResponse = { + isColdStart: false, + appStartTime: appStartTimeMilliseconds, + didFetchAppStart: false, + }; + + mockFunction(getTimeOriginMilliseconds).mockReturnValue( + timeOriginMilliseconds + ); + // eslint-disable-next-line @typescript-eslint/unbound-method + mockFunction(NATIVE.fetchNativeAppStart).mockResolvedValue( + mockAppStartResponse + ); + + const mockHub = getMockHub(); + integration.setupOnce(addGlobalEventProcessor, () => mockHub); + + // use setImmediate as app start is handled inside a promise. + setImmediate(() => { + const transaction = mockHub.getScope()?.getTransaction(); + + expect(transaction).toBeDefined(); + + jest.runOnlyPendingTimers(); + + if (transaction) { + expect( + // @ts-ignore access private for test + transaction._measurements?.app_start_warm + ).toBeUndefined(); + + expect( + // @ts-ignore access private for test + transaction._measurements?.app_start_cold + ).toBeUndefined(); + + done(); + } + }); + }); + it('Does not create app start transaction if didFetchAppStart == true', (done) => { const integration = new ReactNativeTracing();