import { FetchInstrumentation } from '@opentelemetry/instrumentation-fetch' import { XMLHttpRequestInstrumentation } from '@opentelemetry/instrumentation-xml-http-request' import { logger } from '../../utils' import { OTEL_IGNORE_URLS } from '../../config' import { type TracerReactNativeConfig } from '../../types' import { extractResponseBody, headersToObject, processHttpPayload, } from '../helpers' export function getInstrumentations(config: TracerReactNativeConfig) { const instrumentations = [] // Fetch instrumentation try { instrumentations.push( new FetchInstrumentation({ clearTimingResources: false, ignoreUrls: [...OTEL_IGNORE_URLS, ...(config.ignoreUrls || [])], propagateTraceHeaderCorsUrls: config.propagateTraceHeaderCorsUrls, applyCustomAttributesOnSpan: async (span, request, response) => { if (!config) return const { captureBody, captureHeaders } = config try { if (!captureBody && !captureHeaders) { return } // Try to get data from our fetch wrapper first // @ts-ignore const networkRequest = response?.networkRequest let requestBody: any = null let responseBody: string | null = null let requestHeaders: Record = {} let responseHeaders: Record = {} if (networkRequest) { // Use data captured by our fetch wrapper requestBody = networkRequest.requestBody responseBody = networkRequest.responseBody requestHeaders = networkRequest.requestHeaders || {} responseHeaders = networkRequest.responseHeaders || {} } else { // Fallback to original OpenTelemetry approach requestBody = request.body requestHeaders = headersToObject(request.headers) responseHeaders = headersToObject( response instanceof Response ? response.headers : undefined, ) if (response instanceof Response && response.body) { responseBody = await extractResponseBody(response) } } const payload = { requestBody, responseBody, requestHeaders, responseHeaders, } processHttpPayload(payload, config, span) } catch (error) { // eslint-disable-next-line logger.error('DEBUGGER_LIB', 'Failed to capture fetch payload', error) } }, }), ) } catch (error) { logger.warn('DEBUGGER_LIB', 'Fetch instrumentation not available', error) } // XMLHttpRequest instrumentation try { instrumentations.push( new XMLHttpRequestInstrumentation({ clearTimingResources: false, ignoreUrls: [...OTEL_IGNORE_URLS, ...(config.ignoreUrls || [])], propagateTraceHeaderCorsUrls: config.propagateTraceHeaderCorsUrls, applyCustomAttributesOnSpan: (span, xhr) => { if (!config) return const { captureBody, captureHeaders } = config try { if (!captureBody && !captureHeaders) { return } // @ts-ignore const networkRequest = xhr.networkRequest let requestBody: any = null let responseBody: string | null = null let requestHeaders: Record = {} let responseHeaders: Record = {} if (networkRequest) { requestBody = networkRequest.requestBody responseBody = networkRequest.responseBody requestHeaders = networkRequest.requestHeaders || {} responseHeaders = networkRequest.responseHeaders || {} } const payload = { requestBody, responseBody, requestHeaders, responseHeaders, } processHttpPayload(payload, config, span) } catch (error) { // eslint-disable-next-line logger.error('DEBUGGER_LIB', 'Failed to capture xml-http payload', error) } }, }), ) } catch (error) { logger.warn( 'DEBUGGER_LIB', 'XMLHttpRequest instrumentation not available', error, ) } // Custom React Native instrumentations // try { // instrumentations.push(new ReactNativeInstrumentation()) // } catch (error) { // console.warn('React Native instrumentation not available:', error) // } return instrumentations }