diff --git a/packages/platforms/react-native/lib/client.ts b/packages/platforms/react-native/lib/client.ts index 70b18ef1c..f498a2e2f 100644 --- a/packages/platforms/react-native/lib/client.ts +++ b/packages/platforms/react-native/lib/client.ts @@ -1,12 +1,11 @@ import { createClient } from '@bugsnag/core-performance' import createFetchDeliveryFactory from '@bugsnag/delivery-fetch-performance' import { createXmlHttpRequestTracker } from '@bugsnag/request-tracker-performance' -import { AppRegistry, AppState, Platform } from 'react-native' +import { AppRegistry, AppState } from 'react-native' import { FileSystem } from 'react-native-file-access' import { AppStartPlugin, NetworkRequestPlugin } from './auto-instrumentation' import createClock from './clock' import createSchema from './config' -import type { ReactNativeConfiguration } from './config' import createIdGenerator from './id-generator' import NativeBugsnagPerformance from './native' import persistenceFactory from './persistence' @@ -25,8 +24,6 @@ import { ReactNativeSpanFactory } from './span-factory' // @ts-expect-error Element implicitly has an 'any' type because type 'typeof globalThis' has no index signature. const isDebuggingRemotely = !global.nativeCallSyncHook && !global.RN$Bridgeless -const isNativePerformanceAvailable = NativeBugsnagPerformance !== null && NativeBugsnagPerformance.isNativePerformanceAvailable() - const clock = createClock(performance) const appStartTime = clock.now() const deliveryFactory = createFetchDeliveryFactory(fetch, clock) @@ -56,28 +53,7 @@ const BugsnagPerformance = createClient({ spanAttributesSource, retryQueueFactory: createRetryQueueFactory(FileSystem), spanFactory: ReactNativeSpanFactory, - platformExtensions: (spanFactory, spanContextStorage) => platformExtensions(appStartTime, clock, spanFactory as ReactNativeSpanFactory, spanContextStorage) + platformExtensions: (spanFactory, spanContextStorage) => platformExtensions(appStartTime, clock, schema, spanFactory as ReactNativeSpanFactory, spanContextStorage) }) -BugsnagPerformance.attach = (config) => { - const logger = schema.logger.validate(config?.logger) ? config.logger : schema.logger.defaultValue - if (!isNativePerformanceAvailable) { - logger.warn(`Could not attach to native SDK. No compatible version of Bugsnag ${Platform.OS} performance was found`) - return - } - - const nativeConfig = NativeBugsnagPerformance?.getNativeConfiguration() - if (!nativeConfig) { - logger.warn(`Could not attach to native SDK. Bugsnag ${Platform.OS} performance has not been started`) - return - } - - const finalConfig: ReactNativeConfiguration = { - ...config, - ...nativeConfig - } - - BugsnagPerformance.start(finalConfig) -} - export default BugsnagPerformance diff --git a/packages/platforms/react-native/lib/platform-extensions.tsx b/packages/platforms/react-native/lib/platform-extensions.tsx index 17c5b3614..1f7b0c419 100644 --- a/packages/platforms/react-native/lib/platform-extensions.tsx +++ b/packages/platforms/react-native/lib/platform-extensions.tsx @@ -1,20 +1,22 @@ -import type { Clock, SpanContextStorage, SpanOptions } from '@bugsnag/core-performance' +import type { Client, Clock, SpanContextStorage, SpanOptions } from '@bugsnag/core-performance' import React from 'react' -import type { ReactNativeAttachConfiguration } from './config' +import { Platform } from 'react-native' +import NativeBugsnagPerformance from './native' +import type { ReactNativeAttachConfiguration, ReactNativeConfiguration, ReactNativeSchema } from './config' import { createAppStartSpan } from './create-app-start-span' import { createNavigationSpan } from './create-navigation-span' import type { ReactNativeSpanFactory } from './span-factory' type NavigationSpanOptions = Omit -export const platformExtensions = (appStartTime: number, clock: Clock, spanFactory: ReactNativeSpanFactory, spanContextStorage: SpanContextStorage) => ({ - startNavigationSpan: (routeName: string, spanOptions?: NavigationSpanOptions) => { +export const platformExtensions = (appStartTime: number, clock: Clock, schema: ReactNativeSchema, spanFactory: ReactNativeSpanFactory, spanContextStorage: SpanContextStorage) => ({ + startNavigationSpan: function (routeName: string, spanOptions?: NavigationSpanOptions) { const cleanOptions = spanFactory.validateSpanOptions(routeName, spanOptions) cleanOptions.options.isFirstClass = true const span = createNavigationSpan(spanFactory, cleanOptions.name, cleanOptions.options) return spanFactory.toPublicApi(span) }, - withInstrumentedAppStarts: (App: React.FC) => { + withInstrumentedAppStarts: function (App: React.FC) { const appStartSpan = createAppStartSpan(spanFactory, appStartTime) return () => { @@ -27,8 +29,27 @@ export const platformExtensions = (appStartTime: number, clock: Clock, spanFacto return } }, - attach: (config?: ReactNativeAttachConfiguration) => { - // this noop implementation is overridden by the client and is just defined here for correct typing + attach: function (config?: ReactNativeAttachConfiguration) { + const logger = schema.logger.validate(config?.logger) ? config.logger : schema.logger.defaultValue + const isNativePerformanceAvailable = NativeBugsnagPerformance !== null && NativeBugsnagPerformance.isNativePerformanceAvailable() + if (!isNativePerformanceAvailable) { + logger.warn(`Could not attach to native SDK. No compatible version of Bugsnag ${Platform.OS} performance was found`) + return + } + + const nativeConfig = NativeBugsnagPerformance?.getNativeConfiguration() + if (!nativeConfig) { + logger.warn(`Could not attach to native SDK. Bugsnag ${Platform.OS} performance has not been started`) + return + } + + const finalConfig: ReactNativeConfiguration = { + ...config, + ...nativeConfig + } + + const client = this as unknown as Client + client.start(finalConfig) } }) diff --git a/packages/platforms/react-native/tests/platform-extensions.test.ts b/packages/platforms/react-native/tests/platform-extensions.test.ts index 19597e7d7..393f854a8 100644 --- a/packages/platforms/react-native/tests/platform-extensions.test.ts +++ b/packages/platforms/react-native/tests/platform-extensions.test.ts @@ -1,4 +1,5 @@ import type { ReactNativeSpanFactory } from '../lib' +import createSchema from '../lib/config' import { platformExtensions } from '../lib/platform-extensions' import { createTestClient, IncrementingClock, InMemoryDelivery, VALID_API_KEY } from '@bugsnag/js-performance-test-utilities' @@ -8,7 +9,11 @@ describe('startNavigationSpan', () => { it('creates a navigation span', async () => { const delivery = new InMemoryDelivery() const clock = new IncrementingClock() - const testClient = createTestClient({ deliveryFactory: () => delivery, platformExtensions: (spanFactory, spanContextStorage) => platformExtensions(0, clock, spanFactory as unknown as ReactNativeSpanFactory, spanContextStorage) }) + const testClient = createTestClient({ + deliveryFactory: () => delivery, + platformExtensions: (spanFactory, spanContextStorage) => platformExtensions(0, clock, createSchema(), spanFactory as unknown as ReactNativeSpanFactory, spanContextStorage) + }) + testClient.start({ apiKey: VALID_API_KEY }) await jest.runOnlyPendingTimersAsync()