Skip to content

Commit

Permalink
Merge pull request #552 from bugsnag/PLAT-12942/fix-platform-extensions
Browse files Browse the repository at this point in the history
React Native platform extensions improvements
  • Loading branch information
yousif-bugsnag authored Dec 19, 2024
2 parents 2bdf2b7 + 1dccffb commit 4947aea
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 34 deletions.
28 changes: 2 additions & 26 deletions packages/platforms/react-native/lib/client.ts
Original file line number Diff line number Diff line change
@@ -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'
Expand All @@ -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)
Expand Down Expand Up @@ -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
35 changes: 28 additions & 7 deletions packages/platforms/react-native/lib/platform-extensions.tsx
Original file line number Diff line number Diff line change
@@ -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<SpanOptions, 'isFirstClass'>

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 () => {
Expand All @@ -27,8 +29,27 @@ export const platformExtensions = (appStartTime: number, clock: Clock, spanFacto
return <App />
}
},
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<ReactNativeConfiguration>
client.start(finalConfig)
}
})

Expand Down
Original file line number Diff line number Diff line change
@@ -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'

Expand All @@ -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()

Expand Down

0 comments on commit 4947aea

Please sign in to comment.