@grafana/faro-react-native-tracing 1.3.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.md +33 -0
  2. package/dist/cjs/exporters/faroTraceExporter.js +2 -1
  3. package/dist/cjs/exporters/faroTraceExporter.js.map +1 -1
  4. package/dist/cjs/exporters/faroTraceExporter.utils.js +33 -0
  5. package/dist/cjs/exporters/faroTraceExporter.utils.js.map +1 -1
  6. package/dist/cjs/instrumentation.js +259 -44
  7. package/dist/cjs/instrumentation.js.map +1 -1
  8. package/dist/cjs/instrumentations/getDefaultOTELInstrumentations.js +28 -20
  9. package/dist/cjs/instrumentations/getDefaultOTELInstrumentations.js.map +1 -1
  10. package/dist/cjs/instrumentations/instrumentationUtils.js +15 -0
  11. package/dist/cjs/instrumentations/instrumentationUtils.js.map +1 -1
  12. package/dist/cjs/processors/httpRequestMonitorSpanProcessor.js +27 -13
  13. package/dist/cjs/processors/httpRequestMonitorSpanProcessor.js.map +1 -1
  14. package/dist/cjs/types.js.map +1 -1
  15. package/dist/esm/exporters/faroTraceExporter.js +2 -1
  16. package/dist/esm/exporters/faroTraceExporter.js.map +1 -1
  17. package/dist/esm/exporters/faroTraceExporter.utils.js +32 -0
  18. package/dist/esm/exporters/faroTraceExporter.utils.js.map +1 -1
  19. package/dist/esm/instrumentation.js +237 -43
  20. package/dist/esm/instrumentation.js.map +1 -1
  21. package/dist/esm/instrumentations/getDefaultOTELInstrumentations.js +27 -21
  22. package/dist/esm/instrumentations/getDefaultOTELInstrumentations.js.map +1 -1
  23. package/dist/esm/instrumentations/instrumentationUtils.js +14 -0
  24. package/dist/esm/instrumentations/instrumentationUtils.js.map +1 -1
  25. package/dist/esm/processors/httpRequestMonitorSpanProcessor.js +27 -13
  26. package/dist/esm/processors/httpRequestMonitorSpanProcessor.js.map +1 -1
  27. package/dist/esm/types.js.map +1 -1
  28. package/dist/types/instrumentation.d.ts +12 -4
  29. package/dist/types/instrumentations/getDefaultOTELInstrumentations.d.ts +2 -0
  30. package/dist/types/instrumentations/instrumentationUtils.d.ts +2 -0
  31. package/dist/types/types.d.ts +4 -0
  32. package/package.json +13 -13
  33. package/src/exporters/faroTraceExporter.events.test.ts +90 -0
  34. package/src/exporters/faroTraceExporter.ts +2 -1
  35. package/src/exporters/faroTraceExporter.utils.ts +32 -0
  36. package/src/httpSemantics.test.ts +300 -0
  37. package/src/instrumentation.test.ts +740 -0
  38. package/src/instrumentation.ts +299 -67
  39. package/src/instrumentations/getDefaultOTELInstrumentations.test.ts +28 -1
  40. package/src/instrumentations/getDefaultOTELInstrumentations.ts +41 -32
  41. package/src/instrumentations/instrumentationUtils.ts +13 -0
  42. package/src/processors/httpRequestMonitorSpanProcessor.ts +27 -15
  43. package/src/types.ts +4 -0
@@ -17,13 +17,38 @@ import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION, SEMRESATTRS_DEPLOYMENT_ENVIRON
17
17
  import { BaseInstrumentation, getInternalFaroFromGlobalObject, VERSION } from '@grafana/faro-core';
18
18
  import { FaroTraceExporter } from './exporters/faroTraceExporter';
19
19
  import { getReactNativeDevServerIgnoreUrls } from './instrumentations/devServerIgnoreUrls';
20
- import { getDefaultOTELInstrumentations } from './instrumentations/getDefaultOTELInstrumentations';
20
+ import { getDefaultOTELInstrumentations, updateDefaultOTELInstrumentations, } from './instrumentations/getDefaultOTELInstrumentations';
21
21
  import { FaroMetaAttributesSpanProcessor } from './processors/faroMetaAttributesSpanProcessor';
22
22
  import { HttpRequestMonitorSpanProcessor } from './processors/httpRequestMonitorSpanProcessor';
23
23
  import { ATTR_APP_VERSION, ATTR_DEPLOYMENT_ENVIRONMENT_NAME, ATTR_DEVICE_BRAND, ATTR_DEVICE_LOCALE, ATTR_DEVICE_MODEL, ATTR_DEVICE_OS_VERSION, ATTR_DEVICE_PLATFORM, ATTR_PROCESS_RUNTIME_NAME, ATTR_PROCESS_RUNTIME_VERSION, ATTR_SERVICE_NAMESPACE, ATTR_TELEMETRY_DISTRO_NAME, ATTR_TELEMETRY_DISTRO_VERSION, } from './semconv';
24
24
  import { getSamplingDecision } from './utils/sampler';
25
- // Import React Native TracerProvider
26
- // Note: We use the base provider since React Native doesn't have a specific one
25
+ const detachedInstrumentations = new WeakSet();
26
+ /**
27
+ * Keeps a caller-supplied processor reusable across Faro remove/add cycles.
28
+ * Explicit TracingInstrumentation.shutdown() remains responsible for the
29
+ * processor's terminal shutdown.
30
+ */
31
+ class BorrowedSpanProcessor {
32
+ constructor(processor) {
33
+ this.processor = processor;
34
+ }
35
+ forceFlush() {
36
+ return this.processor.forceFlush();
37
+ }
38
+ onStart(span, parentContext) {
39
+ this.processor.onStart(span, parentContext);
40
+ }
41
+ onEnding(span) {
42
+ var _a, _b;
43
+ (_b = (_a = this.processor).onEnding) === null || _b === void 0 ? void 0 : _b.call(_a, span);
44
+ }
45
+ onEnd(span) {
46
+ this.processor.onEnd(span);
47
+ }
48
+ shutdown() {
49
+ return Promise.resolve();
50
+ }
51
+ }
27
52
  /**
28
53
  * TracingInstrumentation for React Native
29
54
  *
@@ -56,9 +81,11 @@ export class TracingInstrumentation extends BaseInstrumentation {
56
81
  this.options = options;
57
82
  this.name = '@grafana/faro-react-native-tracing';
58
83
  this.version = VERSION;
84
+ this.pendingShutdowns = new Set();
59
85
  }
60
86
  initialize() {
61
- var _a, _b, _c, _d, _e, _f;
87
+ var _a, _b, _c, _d, _e;
88
+ this.destroy();
62
89
  const options = this.options;
63
90
  const attributes = {};
64
91
  // App attributes
@@ -107,7 +134,7 @@ export class TracingInstrumentation extends BaseInstrumentation {
107
134
  Object.assign(attributes, options.resourceAttributes);
108
135
  const resource = defaultResource().merge(resourceFromAttributes(attributes));
109
136
  // Create tracer provider with span processors
110
- this.provider = new ReactNativeTracerProvider({
137
+ const provider = new ReactNativeTracerProvider({
111
138
  resource,
112
139
  sampler: {
113
140
  shouldSample: () => {
@@ -117,51 +144,88 @@ export class TracingInstrumentation extends BaseInstrumentation {
117
144
  },
118
145
  },
119
146
  spanProcessors: [
120
- (_b = options.spanProcessor) !== null && _b !== void 0 ? _b : new HttpRequestMonitorSpanProcessor(new FaroMetaAttributesSpanProcessor(new BatchSpanProcessor(new FaroTraceExporter({ api: this.api }), {
147
+ (_b = (options.spanProcessor && new BorrowedSpanProcessor(options.spanProcessor))) !== null && _b !== void 0 ? _b : new HttpRequestMonitorSpanProcessor(new FaroMetaAttributesSpanProcessor(new BatchSpanProcessor(new FaroTraceExporter({ api: this.api }), {
121
148
  scheduledDelayMillis: TracingInstrumentation.SCHEDULED_BATCH_DELAY_MS,
122
149
  maxExportBatchSize: 30,
123
150
  }), this.metas)),
124
151
  ],
125
152
  });
126
- // Register the provider as the global tracer provider
127
- // This is CRITICAL for the tracer to generate real trace IDs instead of all zeros
128
- trace.setGlobalTracerProvider(this.provider);
129
- // Register a global ContextManager. Without one, OTel falls back to the NoopContextManager,
130
- // which always returns ROOT_CONTEXT — so when `@opentelemetry/instrumentation-fetch` does
131
- // `context.with(setSpan(active(), createdSpan), () => _addHeaders(...))` the span set on the
132
- // wrapped context is invisible inside `_addHeaders` and `propagation.inject` writes nothing.
133
- // `StackContextManager` is pure JS (no DOM/Zone deps) and works in React Native.
134
- context.setGlobalContextManager((_c = options.contextManager) !== null && _c !== void 0 ? _c : new StackContextManager().enable());
135
- // Register the global text-map propagator. Without this, OTel falls back to a
136
- // NoopTextMapPropagator and `propagation.inject(...)` becomes a no-op, meaning
137
- // `traceparent` / `tracestate` (and `baggage`) headers are never written on the
138
- // outbound fetch/XHR — so the backend receives no context and starts a new trace.
139
- propagation.setGlobalPropagator((_d = options.propagator) !== null && _d !== void 0 ? _d : new CompositePropagator({
140
- propagators: [new W3CTraceContextPropagator(), new W3CBaggagePropagator()],
141
- }));
142
- const { enableFetchInstrumentation, enableXhrInstrumentation, propagateTraceHeaderCorsUrls, fetchInstrumentationOptions, xhrInstrumentationOptions, } = (_e = this.options.instrumentationOptions) !== null && _e !== void 0 ? _e : {};
143
- // Get ignore URLs from transports to prevent infinite loops
144
- const ignoreUrls = this.getIgnoreUrls();
145
- // Register instrumentations
146
- registerInstrumentations({
147
- instrumentations: (_f = options.instrumentations) !== null && _f !== void 0 ? _f : getDefaultOTELInstrumentations({
153
+ const registration = {
154
+ instrumentations: [],
155
+ ownsContextManager: false,
156
+ ownsContextManagerInstance: false,
157
+ ownsPropagator: false,
158
+ ownsTracerProvider: false,
159
+ provider,
160
+ };
161
+ this.activeRegistration = registration;
162
+ try {
163
+ // Register the provider as the global tracer provider
164
+ // This is CRITICAL for the tracer to generate real trace IDs instead of all zeros
165
+ if (!trace.setGlobalTracerProvider(provider)) {
166
+ throw new Error('Unable to register the Faro OpenTelemetry tracer provider. Remove the existing global tracer provider before initializing Faro tracing.');
167
+ }
168
+ registration.ownsTracerProvider = true;
169
+ // Register a global ContextManager. Without one, OTel falls back to the NoopContextManager,
170
+ // which always returns ROOT_CONTEXT — so when `@opentelemetry/instrumentation-fetch` does
171
+ // `context.with(setSpan(active(), createdSpan), () => _addHeaders(...))` the span set on the
172
+ // wrapped context is invisible inside `_addHeaders` and `propagation.inject` writes nothing.
173
+ // `StackContextManager` is pure JS (no DOM/Zone deps) and works in React Native.
174
+ const contextManager = ((_c = options.contextManager) !== null && _c !== void 0 ? _c : new StackContextManager()).enable();
175
+ registration.contextManager = contextManager;
176
+ registration.ownsContextManagerInstance = options.contextManager == null;
177
+ registration.ownsContextManager = context.setGlobalContextManager(contextManager);
178
+ // Register the global text-map propagator. Without this, OTel falls back to a
179
+ // NoopTextMapPropagator and `propagation.inject(...)` becomes a no-op, meaning
180
+ // `traceparent` / `tracestate` (and `baggage`) headers are never written on the
181
+ // outbound fetch/XHR — so the backend receives no context and starts a new trace.
182
+ registration.ownsPropagator = propagation.setGlobalPropagator((_d = options.propagator) !== null && _d !== void 0 ? _d : new CompositePropagator({
183
+ propagators: [new W3CTraceContextPropagator(), new W3CBaggagePropagator()],
184
+ }));
185
+ const { enableFetchInstrumentation, enableXhrInstrumentation, propagateTraceHeaderCorsUrls, fetchInstrumentationOptions, xhrInstrumentationOptions, } = (_e = this.options.instrumentationOptions) !== null && _e !== void 0 ? _e : {};
186
+ // Get ignore URLs from transports to prevent infinite loops
187
+ const ignoreUrls = this.getIgnoreUrls();
188
+ const defaultInstrumentationOptions = {
148
189
  ignoreUrls,
149
190
  enableFetchInstrumentation,
150
191
  enableXhrInstrumentation,
151
192
  propagateTraceHeaderCorsUrls,
152
193
  fetchInstrumentationOptions,
153
194
  xhrInstrumentationOptions,
154
- }),
155
- });
156
- // Expose OTEL API on the global Faro instance for manual span creation
157
- // This allows users to access trace and context APIs via faro.otel
158
- const globalFaroInstance = getInternalFaroFromGlobalObject();
159
- if (globalFaroInstance) {
160
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Extending Faro instance with OTEL API
161
- globalFaroInstance.otel = {
162
- trace,
163
- context,
164
195
  };
196
+ if (options.instrumentations) {
197
+ registration.instrumentations = options.instrumentations.flat();
198
+ }
199
+ else if (this.defaultInstrumentations) {
200
+ updateDefaultOTELInstrumentations(this.defaultInstrumentations, defaultInstrumentationOptions);
201
+ registration.instrumentations = this.defaultInstrumentations;
202
+ }
203
+ else {
204
+ this.defaultInstrumentations = getDefaultOTELInstrumentations(defaultInstrumentationOptions).flat();
205
+ registration.instrumentations = this.defaultInstrumentations;
206
+ }
207
+ const instrumentationsNeedingExplicitEnable = registration.instrumentations.filter((instrumentation) => detachedInstrumentations.has(instrumentation) && instrumentation.getConfig().enabled === true);
208
+ registration.unregisterInstrumentations = registerInstrumentations({
209
+ instrumentations: registration.instrumentations,
210
+ });
211
+ registration.instrumentations.forEach((instrumentation) => {
212
+ detachedInstrumentations.delete(instrumentation);
213
+ });
214
+ instrumentationsNeedingExplicitEnable.forEach((instrumentation) => instrumentation.enable());
215
+ // Expose OTEL API on the global Faro instance for manual span creation
216
+ // This allows users to access trace and context APIs via faro.otel
217
+ const globalFaroInstance = getInternalFaroFromGlobalObject();
218
+ if (globalFaroInstance) {
219
+ const faroOtel = { trace, context };
220
+ registration.faro = globalFaroInstance;
221
+ registration.faroOtel = faroOtel;
222
+ registration.previousFaroOtel = globalFaroInstance.otel;
223
+ globalFaroInstance.otel = faroOtel;
224
+ }
225
+ }
226
+ catch (error) {
227
+ this.destroy();
228
+ throw error;
165
229
  }
166
230
  }
167
231
  /**
@@ -186,14 +250,144 @@ export class TracingInstrumentation extends BaseInstrumentation {
186
250
  // Return dev-server, original transport URLs, and regex patterns for maximum coverage.
187
251
  return [...getReactNativeDevServerIgnoreUrls(), ...transportUrls, ...regexPatterns];
188
252
  }
189
- /**
190
- * Shutdown the tracer provider
191
- */
253
+ detachRegistration() {
254
+ const registration = this.activeRegistration;
255
+ if (!registration) {
256
+ return undefined;
257
+ }
258
+ this.activeRegistration = undefined;
259
+ registration.instrumentations.forEach((instrumentation) => detachedInstrumentations.add(instrumentation));
260
+ let unregistered = false;
261
+ if (registration.unregisterInstrumentations) {
262
+ try {
263
+ registration.unregisterInstrumentations();
264
+ unregistered = true;
265
+ }
266
+ catch (error) {
267
+ this.logCleanupError('unregister OpenTelemetry instrumentations', error);
268
+ }
269
+ }
270
+ if (!unregistered) {
271
+ registration.instrumentations.forEach((instrumentation) => {
272
+ this.runCleanup(`disable ${instrumentation.instrumentationName}`, () => instrumentation.disable());
273
+ });
274
+ }
275
+ const { faro, faroOtel } = registration;
276
+ if (faro && faroOtel && faro.otel === faroOtel) {
277
+ this.runCleanup('restore faro.otel', () => {
278
+ if (registration.previousFaroOtel === undefined) {
279
+ delete faro.otel;
280
+ }
281
+ else {
282
+ faro.otel = registration.previousFaroOtel;
283
+ }
284
+ });
285
+ }
286
+ if (registration.ownsPropagator) {
287
+ this.runCleanup('clear the OpenTelemetry propagator', () => propagation.disable());
288
+ }
289
+ if (registration.ownsContextManager) {
290
+ this.runCleanup('clear the OpenTelemetry context manager', () => context.disable());
291
+ }
292
+ else if (registration.ownsContextManagerInstance && registration.contextManager) {
293
+ this.runCleanup('disable the unused OpenTelemetry context manager', () => { var _a; return (_a = registration.contextManager) === null || _a === void 0 ? void 0 : _a.disable(); });
294
+ }
295
+ if (registration.ownsTracerProvider) {
296
+ this.runCleanup('clear the OpenTelemetry tracer provider', () => trace.disable());
297
+ }
298
+ return registration;
299
+ }
300
+ runCleanup(action, cleanup) {
301
+ try {
302
+ cleanup();
303
+ }
304
+ catch (error) {
305
+ this.logCleanupError(action, error);
306
+ }
307
+ }
308
+ logCleanupError(action, error) {
309
+ try {
310
+ this.logError(`Failed to ${action}:`, error);
311
+ }
312
+ catch (_loggingError) {
313
+ // Cleanup must not fail because a custom logger threw.
314
+ }
315
+ }
316
+ startProviderShutdown(registration) {
317
+ if (!registration.shutdownPromise) {
318
+ const shutdownPromise = Promise.resolve()
319
+ .then(() => registration.provider.forceFlush())
320
+ .catch((error) => {
321
+ this.logCleanupError('flush the OpenTelemetry tracer provider', error);
322
+ })
323
+ .then(() => registration.provider.shutdown());
324
+ registration.shutdownPromise = shutdownPromise;
325
+ this.pendingShutdowns.add(shutdownPromise);
326
+ void shutdownPromise.then(() => this.pendingShutdowns.delete(shutdownPromise), () => this.pendingShutdowns.delete(shutdownPromise));
327
+ }
328
+ return registration.shutdownPromise;
329
+ }
330
+ startSuppliedSpanProcessorShutdown() {
331
+ const spanProcessor = this.options.spanProcessor;
332
+ if (!spanProcessor) {
333
+ return undefined;
334
+ }
335
+ if (!this.suppliedSpanProcessorShutdown) {
336
+ try {
337
+ this.suppliedSpanProcessorShutdown = spanProcessor.shutdown();
338
+ }
339
+ catch (error) {
340
+ this.suppliedSpanProcessorShutdown = Promise.reject(error);
341
+ }
342
+ }
343
+ return this.suppliedSpanProcessorShutdown;
344
+ }
345
+ /** Detach request instrumentations and wait for the tracer provider to flush. */
192
346
  shutdown() {
193
347
  return __awaiter(this, void 0, void 0, function* () {
194
- if (this.provider) {
195
- yield this.provider.shutdown();
348
+ const pendingShutdowns = Array.from(this.pendingShutdowns);
349
+ const registration = this.detachRegistration();
350
+ if (registration) {
351
+ pendingShutdowns.push(this.startProviderShutdown(registration));
196
352
  }
353
+ let firstError;
354
+ let shutdownFailed = false;
355
+ for (const shutdownPromise of pendingShutdowns) {
356
+ try {
357
+ yield shutdownPromise;
358
+ }
359
+ catch (error) {
360
+ if (!shutdownFailed) {
361
+ firstError = error;
362
+ shutdownFailed = true;
363
+ }
364
+ }
365
+ }
366
+ const spanProcessorShutdown = this.startSuppliedSpanProcessorShutdown();
367
+ if (spanProcessorShutdown) {
368
+ try {
369
+ yield spanProcessorShutdown;
370
+ }
371
+ catch (error) {
372
+ if (!shutdownFailed) {
373
+ firstError = error;
374
+ shutdownFailed = true;
375
+ }
376
+ }
377
+ }
378
+ if (shutdownFailed) {
379
+ throw firstError;
380
+ }
381
+ });
382
+ }
383
+ /** Detach synchronously when Faro removes this instrumentation. */
384
+ destroy() {
385
+ const registration = this.detachRegistration();
386
+ if (!registration) {
387
+ return;
388
+ }
389
+ void this.startProviderShutdown(registration).then(undefined, (error) => {
390
+ this.logCleanupError('shut down the OpenTelemetry tracer provider', error);
197
391
  });
198
392
  }
199
393
  }
@@ -1 +1 @@
1
- {"version":3,"file":"instrumentation.js","sourceRoot":"","sources":["../../src/instrumentation.ts"],"names":[],"mappings":"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","sourcesContent":["import { context, propagation, trace } from '@opentelemetry/api';\nimport type { Attributes } from '@opentelemetry/api';\nimport { CompositePropagator, W3CBaggagePropagator, W3CTraceContextPropagator } from '@opentelemetry/core';\nimport { registerInstrumentations } from '@opentelemetry/instrumentation';\nimport { defaultResource, resourceFromAttributes } from '@opentelemetry/resources';\nimport { BatchSpanProcessor, BasicTracerProvider as ReactNativeTracerProvider } from '@opentelemetry/sdk-trace-base';\nimport type { BasicTracerProvider } from '@opentelemetry/sdk-trace-base';\nimport { StackContextManager } from '@opentelemetry/sdk-trace-web';\nimport {\n ATTR_SERVICE_NAME,\n ATTR_SERVICE_VERSION,\n SEMRESATTRS_DEPLOYMENT_ENVIRONMENT,\n} from '@opentelemetry/semantic-conventions';\n\nimport { BaseInstrumentation, getInternalFaroFromGlobalObject, VERSION } from '@grafana/faro-core';\nimport type { Transport } from '@grafana/faro-core';\n\nimport { FaroTraceExporter } from './exporters/faroTraceExporter';\nimport { getReactNativeDevServerIgnoreUrls } from './instrumentations/devServerIgnoreUrls';\nimport { getDefaultOTELInstrumentations } from './instrumentations/getDefaultOTELInstrumentations';\nimport { FaroMetaAttributesSpanProcessor } from './processors/faroMetaAttributesSpanProcessor';\nimport { HttpRequestMonitorSpanProcessor } from './processors/httpRequestMonitorSpanProcessor';\nimport {\n ATTR_APP_VERSION,\n ATTR_DEPLOYMENT_ENVIRONMENT_NAME,\n ATTR_DEVICE_BRAND,\n ATTR_DEVICE_LOCALE,\n ATTR_DEVICE_MODEL,\n ATTR_DEVICE_OS_VERSION,\n ATTR_DEVICE_PLATFORM,\n ATTR_PROCESS_RUNTIME_NAME,\n ATTR_PROCESS_RUNTIME_VERSION,\n ATTR_SERVICE_NAMESPACE,\n ATTR_TELEMETRY_DISTRO_NAME,\n ATTR_TELEMETRY_DISTRO_VERSION,\n} from './semconv';\nimport type { TracingInstrumentationOptions } from './types';\nimport { getSamplingDecision } from './utils/sampler';\n\n// Import React Native TracerProvider\n// Note: We use the base provider since React Native doesn't have a specific one\n\n/**\n * TracingInstrumentation for React Native\n *\n * Enables distributed tracing with OpenTelemetry for React Native applications.\n *\n * IMPORTANT: Infinite loop prevention\n * - Uses internalLogger for debugging instead of console\n * - Collector URLs are added to ignoreUrls in HTTP instrumentation\n * - BatchSpanProcessor delays span export to avoid blocking\n * - No console logging during trace export\n *\n * Example usage:\n * ```ts\n * import { initializeFaro } from '@grafana/faro-react-native';\n * import { TracingInstrumentation } from '@grafana/faro-react-native-tracing';\n *\n * initializeFaro({\n * // ... other config\n * instrumentations: [\n * new TracingInstrumentation({\n * propagateTraceHeaderCorsUrls: [/https:\\\\/\\\\/my-api\\\\.com/],\n * }),\n * ],\n * });\n * ```\n */\nexport class TracingInstrumentation extends BaseInstrumentation {\n name = '@grafana/faro-react-native-tracing';\n version = VERSION;\n\n static SCHEDULED_BATCH_DELAY_MS = 1000;\n\n private provider?: BasicTracerProvider;\n\n constructor(private options: TracingInstrumentationOptions = {}) {\n super();\n }\n\n initialize(): void {\n const options = this.options;\n const attributes: Attributes = {};\n\n // App attributes\n if (this.config.app.name) {\n attributes[ATTR_SERVICE_NAME] = this.config.app.name;\n }\n\n if (this.config.app.namespace) {\n attributes[ATTR_SERVICE_NAMESPACE] = this.config.app.namespace;\n }\n\n if (this.config.app.version) {\n attributes[ATTR_SERVICE_VERSION] = this.config.app.version;\n attributes[ATTR_APP_VERSION] = this.config.app.version;\n }\n\n if (this.config.app.environment) {\n attributes[ATTR_DEPLOYMENT_ENVIRONMENT_NAME] = this.config.app.environment;\n\n /**\n * @deprecated will be removed in the future and has been replaced by ATTR_DEPLOYMENT_ENVIRONMENT_NAME (deployment.environment.name)\n * We need to keep this for compatibility with some internal services for now.\n */\n attributes[SEMRESATTRS_DEPLOYMENT_ENVIRONMENT] = this.config.app.environment;\n }\n\n // Device/Platform attributes from React Native\n // Note: metas.value contains all meta providers, we need to check if device meta exists\n const allMetas = this.metas.value as Record<string, unknown>;\n const deviceMeta = allMetas['device'] as\n | {\n model?: string;\n brand?: string;\n osName?: string;\n osVersion?: string;\n locale?: string;\n }\n | undefined;\n\n if (deviceMeta?.model) {\n attributes[ATTR_DEVICE_MODEL] = deviceMeta.model;\n }\n\n if (deviceMeta?.brand) {\n attributes[ATTR_DEVICE_BRAND] = deviceMeta.brand;\n }\n\n if (deviceMeta?.osName) {\n attributes[ATTR_DEVICE_PLATFORM] = deviceMeta.osName;\n }\n\n if (deviceMeta?.osVersion) {\n attributes[ATTR_DEVICE_OS_VERSION] = deviceMeta.osVersion;\n }\n\n if (deviceMeta?.locale) {\n attributes[ATTR_DEVICE_LOCALE] = deviceMeta.locale;\n }\n\n attributes[ATTR_PROCESS_RUNTIME_NAME] = 'react-native';\n attributes[ATTR_PROCESS_RUNTIME_VERSION] = deviceMeta?.osVersion ?? 'unknown';\n\n attributes[ATTR_TELEMETRY_DISTRO_NAME] = 'faro-react-native-sdk';\n attributes[ATTR_TELEMETRY_DISTRO_VERSION] = VERSION;\n\n // Merge with user-provided attributes\n Object.assign(attributes, options.resourceAttributes);\n\n const resource = defaultResource().merge(resourceFromAttributes(attributes));\n\n // Create tracer provider with span processors\n this.provider = new ReactNativeTracerProvider({\n resource,\n sampler: {\n shouldSample: () => {\n return {\n decision: getSamplingDecision(this.api.getSession()),\n };\n },\n },\n spanProcessors: [\n options.spanProcessor ??\n new HttpRequestMonitorSpanProcessor(\n new FaroMetaAttributesSpanProcessor(\n new BatchSpanProcessor(new FaroTraceExporter({ api: this.api }), {\n scheduledDelayMillis: TracingInstrumentation.SCHEDULED_BATCH_DELAY_MS,\n maxExportBatchSize: 30,\n }),\n this.metas\n )\n ),\n ],\n });\n\n // Register the provider as the global tracer provider\n // This is CRITICAL for the tracer to generate real trace IDs instead of all zeros\n trace.setGlobalTracerProvider(this.provider);\n\n // Register a global ContextManager. Without one, OTel falls back to the NoopContextManager,\n // which always returns ROOT_CONTEXT — so when `@opentelemetry/instrumentation-fetch` does\n // `context.with(setSpan(active(), createdSpan), () => _addHeaders(...))` the span set on the\n // wrapped context is invisible inside `_addHeaders` and `propagation.inject` writes nothing.\n // `StackContextManager` is pure JS (no DOM/Zone deps) and works in React Native.\n context.setGlobalContextManager(options.contextManager ?? new StackContextManager().enable());\n\n // Register the global text-map propagator. Without this, OTel falls back to a\n // NoopTextMapPropagator and `propagation.inject(...)` becomes a no-op, meaning\n // `traceparent` / `tracestate` (and `baggage`) headers are never written on the\n // outbound fetch/XHR — so the backend receives no context and starts a new trace.\n propagation.setGlobalPropagator(\n options.propagator ??\n new CompositePropagator({\n propagators: [new W3CTraceContextPropagator(), new W3CBaggagePropagator()],\n })\n );\n\n const {\n enableFetchInstrumentation,\n enableXhrInstrumentation,\n propagateTraceHeaderCorsUrls,\n fetchInstrumentationOptions,\n xhrInstrumentationOptions,\n } = this.options.instrumentationOptions ?? {};\n\n // Get ignore URLs from transports to prevent infinite loops\n const ignoreUrls = this.getIgnoreUrls();\n\n // Register instrumentations\n registerInstrumentations({\n instrumentations:\n options.instrumentations ??\n getDefaultOTELInstrumentations({\n ignoreUrls,\n enableFetchInstrumentation,\n enableXhrInstrumentation,\n propagateTraceHeaderCorsUrls,\n fetchInstrumentationOptions,\n xhrInstrumentationOptions,\n }),\n });\n\n // Expose OTEL API on the global Faro instance for manual span creation\n // This allows users to access trace and context APIs via faro.otel\n const globalFaroInstance = getInternalFaroFromGlobalObject();\n if (globalFaroInstance) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Extending Faro instance with OTEL API\n (globalFaroInstance as any).otel = {\n trace,\n context,\n };\n }\n }\n\n /**\n * Get ignore URLs from all transports to avoid tracing collector requests\n * CRITICAL: This prevents infinite loops where trace exports trigger more traces\n */\n private getIgnoreUrls(): Array<string | RegExp> {\n // Get URLs from transports' getIgnoreUrls() method\n const transportUrls = this.transports.transports.flatMap((transport: Transport) => {\n return transport.getIgnoreUrls();\n });\n\n // Create regex patterns that match both with and without trailing slashes\n // This is critical because fetch() might add trailing slashes\n const regexPatterns = transportUrls.map((url) => {\n if (typeof url === 'string') {\n // Escape special regex characters and make trailing slash optional\n const escapedUrl = url.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n return new RegExp(`^${escapedUrl}/?$`);\n }\n return url;\n });\n\n // Return dev-server, original transport URLs, and regex patterns for maximum coverage.\n return [...getReactNativeDevServerIgnoreUrls(), ...transportUrls, ...regexPatterns];\n }\n\n /**\n * Shutdown the tracer provider\n */\n async shutdown(): Promise<void> {\n if (this.provider) {\n await this.provider.shutdown();\n }\n }\n}\n"]}
1
+ {"version":3,"file":"instrumentation.js","sourceRoot":"","sources":["../../src/instrumentation.ts"],"names":[],"mappings":"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","sourcesContent":["import { context, propagation, trace } from '@opentelemetry/api';\nimport type { Attributes, Context, ContextManager } from '@opentelemetry/api';\nimport { CompositePropagator, W3CBaggagePropagator, W3CTraceContextPropagator } from '@opentelemetry/core';\nimport { registerInstrumentations } from '@opentelemetry/instrumentation';\nimport type { Instrumentation } from '@opentelemetry/instrumentation';\nimport { defaultResource, resourceFromAttributes } from '@opentelemetry/resources';\nimport { BatchSpanProcessor, BasicTracerProvider as ReactNativeTracerProvider } from '@opentelemetry/sdk-trace-base';\nimport type { BasicTracerProvider, ReadableSpan, Span, SpanProcessor } from '@opentelemetry/sdk-trace-base';\nimport { StackContextManager } from '@opentelemetry/sdk-trace-web';\nimport {\n ATTR_SERVICE_NAME,\n ATTR_SERVICE_VERSION,\n SEMRESATTRS_DEPLOYMENT_ENVIRONMENT,\n} from '@opentelemetry/semantic-conventions';\n\nimport { BaseInstrumentation, getInternalFaroFromGlobalObject, VERSION } from '@grafana/faro-core';\nimport type { Faro, OTELApi, Transport } from '@grafana/faro-core';\n\nimport { FaroTraceExporter } from './exporters/faroTraceExporter';\nimport { getReactNativeDevServerIgnoreUrls } from './instrumentations/devServerIgnoreUrls';\nimport {\n getDefaultOTELInstrumentations,\n updateDefaultOTELInstrumentations,\n} from './instrumentations/getDefaultOTELInstrumentations';\nimport { FaroMetaAttributesSpanProcessor } from './processors/faroMetaAttributesSpanProcessor';\nimport { HttpRequestMonitorSpanProcessor } from './processors/httpRequestMonitorSpanProcessor';\nimport {\n ATTR_APP_VERSION,\n ATTR_DEPLOYMENT_ENVIRONMENT_NAME,\n ATTR_DEVICE_BRAND,\n ATTR_DEVICE_LOCALE,\n ATTR_DEVICE_MODEL,\n ATTR_DEVICE_OS_VERSION,\n ATTR_DEVICE_PLATFORM,\n ATTR_PROCESS_RUNTIME_NAME,\n ATTR_PROCESS_RUNTIME_VERSION,\n ATTR_SERVICE_NAMESPACE,\n ATTR_TELEMETRY_DISTRO_NAME,\n ATTR_TELEMETRY_DISTRO_VERSION,\n} from './semconv';\nimport type { TracingInstrumentationOptions } from './types';\nimport { getSamplingDecision } from './utils/sampler';\n\n// Import React Native TracerProvider\n// Note: We use the base provider since React Native doesn't have a specific one\n\ntype FaroWithOtel = Faro & { otel?: unknown };\nconst detachedInstrumentations = new WeakSet<Instrumentation>();\n\n/**\n * Keeps a caller-supplied processor reusable across Faro remove/add cycles.\n * Explicit TracingInstrumentation.shutdown() remains responsible for the\n * processor's terminal shutdown.\n */\nclass BorrowedSpanProcessor implements SpanProcessor {\n constructor(private readonly processor: SpanProcessor) {}\n\n forceFlush(): Promise<void> {\n return this.processor.forceFlush();\n }\n\n onStart(span: Span, parentContext: Context): void {\n this.processor.onStart(span, parentContext);\n }\n\n onEnding(span: Span): void {\n this.processor.onEnding?.(span);\n }\n\n onEnd(span: ReadableSpan): void {\n this.processor.onEnd(span);\n }\n\n shutdown(): Promise<void> {\n return Promise.resolve();\n }\n}\n\ninterface TracingRegistration {\n contextManager?: ContextManager;\n faro?: FaroWithOtel;\n faroOtel?: OTELApi;\n instrumentations: Instrumentation[];\n ownsContextManager: boolean;\n ownsContextManagerInstance: boolean;\n ownsPropagator: boolean;\n ownsTracerProvider: boolean;\n previousFaroOtel?: unknown;\n provider: BasicTracerProvider;\n shutdownPromise?: Promise<void>;\n unregisterInstrumentations?: VoidFunction;\n}\n\n/**\n * TracingInstrumentation for React Native\n *\n * Enables distributed tracing with OpenTelemetry for React Native applications.\n *\n * IMPORTANT: Infinite loop prevention\n * - Uses internalLogger for debugging instead of console\n * - Collector URLs are added to ignoreUrls in HTTP instrumentation\n * - BatchSpanProcessor delays span export to avoid blocking\n * - No console logging during trace export\n *\n * Example usage:\n * ```ts\n * import { initializeFaro } from '@grafana/faro-react-native';\n * import { TracingInstrumentation } from '@grafana/faro-react-native-tracing';\n *\n * initializeFaro({\n * // ... other config\n * instrumentations: [\n * new TracingInstrumentation({\n * propagateTraceHeaderCorsUrls: [/https:\\\\/\\\\/my-api\\\\.com/],\n * }),\n * ],\n * });\n * ```\n */\nexport class TracingInstrumentation extends BaseInstrumentation {\n name = '@grafana/faro-react-native-tracing';\n version = VERSION;\n\n static SCHEDULED_BATCH_DELAY_MS = 1000;\n\n private activeRegistration?: TracingRegistration;\n private defaultInstrumentations?: Instrumentation[];\n private pendingShutdowns = new Set<Promise<void>>();\n private suppliedSpanProcessorShutdown?: Promise<void>;\n\n constructor(private options: TracingInstrumentationOptions = {}) {\n super();\n }\n\n initialize(): void {\n this.destroy();\n\n const options = this.options;\n const attributes: Attributes = {};\n\n // App attributes\n if (this.config.app.name) {\n attributes[ATTR_SERVICE_NAME] = this.config.app.name;\n }\n\n if (this.config.app.namespace) {\n attributes[ATTR_SERVICE_NAMESPACE] = this.config.app.namespace;\n }\n\n if (this.config.app.version) {\n attributes[ATTR_SERVICE_VERSION] = this.config.app.version;\n attributes[ATTR_APP_VERSION] = this.config.app.version;\n }\n\n if (this.config.app.environment) {\n attributes[ATTR_DEPLOYMENT_ENVIRONMENT_NAME] = this.config.app.environment;\n\n /**\n * @deprecated will be removed in the future and has been replaced by ATTR_DEPLOYMENT_ENVIRONMENT_NAME (deployment.environment.name)\n * We need to keep this for compatibility with some internal services for now.\n */\n attributes[SEMRESATTRS_DEPLOYMENT_ENVIRONMENT] = this.config.app.environment;\n }\n\n // Device/Platform attributes from React Native\n // Note: metas.value contains all meta providers, we need to check if device meta exists\n const allMetas = this.metas.value as Record<string, unknown>;\n const deviceMeta = allMetas['device'] as\n | {\n model?: string;\n brand?: string;\n osName?: string;\n osVersion?: string;\n locale?: string;\n }\n | undefined;\n\n if (deviceMeta?.model) {\n attributes[ATTR_DEVICE_MODEL] = deviceMeta.model;\n }\n\n if (deviceMeta?.brand) {\n attributes[ATTR_DEVICE_BRAND] = deviceMeta.brand;\n }\n\n if (deviceMeta?.osName) {\n attributes[ATTR_DEVICE_PLATFORM] = deviceMeta.osName;\n }\n\n if (deviceMeta?.osVersion) {\n attributes[ATTR_DEVICE_OS_VERSION] = deviceMeta.osVersion;\n }\n\n if (deviceMeta?.locale) {\n attributes[ATTR_DEVICE_LOCALE] = deviceMeta.locale;\n }\n\n attributes[ATTR_PROCESS_RUNTIME_NAME] = 'react-native';\n attributes[ATTR_PROCESS_RUNTIME_VERSION] = deviceMeta?.osVersion ?? 'unknown';\n\n attributes[ATTR_TELEMETRY_DISTRO_NAME] = 'faro-react-native-sdk';\n attributes[ATTR_TELEMETRY_DISTRO_VERSION] = VERSION;\n\n // Merge with user-provided attributes\n Object.assign(attributes, options.resourceAttributes);\n\n const resource = defaultResource().merge(resourceFromAttributes(attributes));\n\n // Create tracer provider with span processors\n const provider = new ReactNativeTracerProvider({\n resource,\n sampler: {\n shouldSample: () => {\n return {\n decision: getSamplingDecision(this.api.getSession()),\n };\n },\n },\n spanProcessors: [\n (options.spanProcessor && new BorrowedSpanProcessor(options.spanProcessor)) ??\n new HttpRequestMonitorSpanProcessor(\n new FaroMetaAttributesSpanProcessor(\n new BatchSpanProcessor(new FaroTraceExporter({ api: this.api }), {\n scheduledDelayMillis: TracingInstrumentation.SCHEDULED_BATCH_DELAY_MS,\n maxExportBatchSize: 30,\n }),\n this.metas\n )\n ),\n ],\n });\n\n const registration: TracingRegistration = {\n instrumentations: [],\n ownsContextManager: false,\n ownsContextManagerInstance: false,\n ownsPropagator: false,\n ownsTracerProvider: false,\n provider,\n };\n this.activeRegistration = registration;\n\n try {\n // Register the provider as the global tracer provider\n // This is CRITICAL for the tracer to generate real trace IDs instead of all zeros\n if (!trace.setGlobalTracerProvider(provider)) {\n throw new Error(\n 'Unable to register the Faro OpenTelemetry tracer provider. Remove the existing global tracer provider before initializing Faro tracing.'\n );\n }\n registration.ownsTracerProvider = true;\n\n // Register a global ContextManager. Without one, OTel falls back to the NoopContextManager,\n // which always returns ROOT_CONTEXT — so when `@opentelemetry/instrumentation-fetch` does\n // `context.with(setSpan(active(), createdSpan), () => _addHeaders(...))` the span set on the\n // wrapped context is invisible inside `_addHeaders` and `propagation.inject` writes nothing.\n // `StackContextManager` is pure JS (no DOM/Zone deps) and works in React Native.\n const contextManager = (options.contextManager ?? new StackContextManager()).enable();\n registration.contextManager = contextManager;\n registration.ownsContextManagerInstance = options.contextManager == null;\n registration.ownsContextManager = context.setGlobalContextManager(contextManager);\n\n // Register the global text-map propagator. Without this, OTel falls back to a\n // NoopTextMapPropagator and `propagation.inject(...)` becomes a no-op, meaning\n // `traceparent` / `tracestate` (and `baggage`) headers are never written on the\n // outbound fetch/XHR — so the backend receives no context and starts a new trace.\n registration.ownsPropagator = propagation.setGlobalPropagator(\n options.propagator ??\n new CompositePropagator({\n propagators: [new W3CTraceContextPropagator(), new W3CBaggagePropagator()],\n })\n );\n\n const {\n enableFetchInstrumentation,\n enableXhrInstrumentation,\n propagateTraceHeaderCorsUrls,\n fetchInstrumentationOptions,\n xhrInstrumentationOptions,\n } = this.options.instrumentationOptions ?? {};\n\n // Get ignore URLs from transports to prevent infinite loops\n const ignoreUrls = this.getIgnoreUrls();\n\n const defaultInstrumentationOptions = {\n ignoreUrls,\n enableFetchInstrumentation,\n enableXhrInstrumentation,\n propagateTraceHeaderCorsUrls,\n fetchInstrumentationOptions,\n xhrInstrumentationOptions,\n };\n\n if (options.instrumentations) {\n registration.instrumentations = options.instrumentations.flat();\n } else if (this.defaultInstrumentations) {\n updateDefaultOTELInstrumentations(this.defaultInstrumentations, defaultInstrumentationOptions);\n registration.instrumentations = this.defaultInstrumentations;\n } else {\n this.defaultInstrumentations = getDefaultOTELInstrumentations(defaultInstrumentationOptions).flat();\n registration.instrumentations = this.defaultInstrumentations;\n }\n\n const instrumentationsNeedingExplicitEnable = registration.instrumentations.filter(\n (instrumentation) =>\n detachedInstrumentations.has(instrumentation) && instrumentation.getConfig().enabled === true\n );\n registration.unregisterInstrumentations = registerInstrumentations({\n instrumentations: registration.instrumentations,\n });\n registration.instrumentations.forEach((instrumentation) => {\n detachedInstrumentations.delete(instrumentation);\n });\n instrumentationsNeedingExplicitEnable.forEach((instrumentation) => instrumentation.enable());\n\n // Expose OTEL API on the global Faro instance for manual span creation\n // This allows users to access trace and context APIs via faro.otel\n const globalFaroInstance = getInternalFaroFromGlobalObject() as FaroWithOtel | undefined;\n if (globalFaroInstance) {\n const faroOtel: OTELApi = { trace, context };\n registration.faro = globalFaroInstance;\n registration.faroOtel = faroOtel;\n registration.previousFaroOtel = globalFaroInstance.otel;\n globalFaroInstance.otel = faroOtel;\n }\n } catch (error) {\n this.destroy();\n throw error;\n }\n }\n\n /**\n * Get ignore URLs from all transports to avoid tracing collector requests\n * CRITICAL: This prevents infinite loops where trace exports trigger more traces\n */\n private getIgnoreUrls(): Array<string | RegExp> {\n // Get URLs from transports' getIgnoreUrls() method\n const transportUrls = this.transports.transports.flatMap((transport: Transport) => {\n return transport.getIgnoreUrls();\n });\n\n // Create regex patterns that match both with and without trailing slashes\n // This is critical because fetch() might add trailing slashes\n const regexPatterns = transportUrls.map((url) => {\n if (typeof url === 'string') {\n // Escape special regex characters and make trailing slash optional\n const escapedUrl = url.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n return new RegExp(`^${escapedUrl}/?$`);\n }\n return url;\n });\n\n // Return dev-server, original transport URLs, and regex patterns for maximum coverage.\n return [...getReactNativeDevServerIgnoreUrls(), ...transportUrls, ...regexPatterns];\n }\n\n private detachRegistration(): TracingRegistration | undefined {\n const registration = this.activeRegistration;\n if (!registration) {\n return undefined;\n }\n this.activeRegistration = undefined;\n registration.instrumentations.forEach((instrumentation) => detachedInstrumentations.add(instrumentation));\n\n let unregistered = false;\n if (registration.unregisterInstrumentations) {\n try {\n registration.unregisterInstrumentations();\n unregistered = true;\n } catch (error) {\n this.logCleanupError('unregister OpenTelemetry instrumentations', error);\n }\n }\n if (!unregistered) {\n registration.instrumentations.forEach((instrumentation) => {\n this.runCleanup(`disable ${instrumentation.instrumentationName}`, () => instrumentation.disable());\n });\n }\n\n const { faro, faroOtel } = registration;\n if (faro && faroOtel && faro.otel === faroOtel) {\n this.runCleanup('restore faro.otel', () => {\n if (registration.previousFaroOtel === undefined) {\n delete faro.otel;\n } else {\n faro.otel = registration.previousFaroOtel;\n }\n });\n }\n\n if (registration.ownsPropagator) {\n this.runCleanup('clear the OpenTelemetry propagator', () => propagation.disable());\n }\n if (registration.ownsContextManager) {\n this.runCleanup('clear the OpenTelemetry context manager', () => context.disable());\n } else if (registration.ownsContextManagerInstance && registration.contextManager) {\n this.runCleanup('disable the unused OpenTelemetry context manager', () => registration.contextManager?.disable());\n }\n if (registration.ownsTracerProvider) {\n this.runCleanup('clear the OpenTelemetry tracer provider', () => trace.disable());\n }\n\n return registration;\n }\n\n private runCleanup(action: string, cleanup: VoidFunction): void {\n try {\n cleanup();\n } catch (error) {\n this.logCleanupError(action, error);\n }\n }\n\n private logCleanupError(action: string, error: unknown): void {\n try {\n this.logError(`Failed to ${action}:`, error);\n } catch (_loggingError) {\n // Cleanup must not fail because a custom logger threw.\n }\n }\n\n private startProviderShutdown(registration: TracingRegistration): Promise<void> {\n if (!registration.shutdownPromise) {\n const shutdownPromise = Promise.resolve()\n .then(() => registration.provider.forceFlush())\n .catch((error) => {\n this.logCleanupError('flush the OpenTelemetry tracer provider', error);\n })\n .then(() => registration.provider.shutdown());\n registration.shutdownPromise = shutdownPromise;\n this.pendingShutdowns.add(shutdownPromise);\n void shutdownPromise.then(\n () => this.pendingShutdowns.delete(shutdownPromise),\n () => this.pendingShutdowns.delete(shutdownPromise)\n );\n }\n return registration.shutdownPromise;\n }\n\n private startSuppliedSpanProcessorShutdown(): Promise<void> | undefined {\n const spanProcessor = this.options.spanProcessor;\n if (!spanProcessor) {\n return undefined;\n }\n if (!this.suppliedSpanProcessorShutdown) {\n try {\n this.suppliedSpanProcessorShutdown = spanProcessor.shutdown();\n } catch (error) {\n this.suppliedSpanProcessorShutdown = Promise.reject(error);\n }\n }\n return this.suppliedSpanProcessorShutdown;\n }\n\n /** Detach request instrumentations and wait for the tracer provider to flush. */\n async shutdown(): Promise<void> {\n const pendingShutdowns = Array.from(this.pendingShutdowns);\n const registration = this.detachRegistration();\n if (registration) {\n pendingShutdowns.push(this.startProviderShutdown(registration));\n }\n\n let firstError: unknown;\n let shutdownFailed = false;\n for (const shutdownPromise of pendingShutdowns) {\n try {\n await shutdownPromise;\n } catch (error) {\n if (!shutdownFailed) {\n firstError = error;\n shutdownFailed = true;\n }\n }\n }\n const spanProcessorShutdown = this.startSuppliedSpanProcessorShutdown();\n if (spanProcessorShutdown) {\n try {\n await spanProcessorShutdown;\n } catch (error) {\n if (!shutdownFailed) {\n firstError = error;\n shutdownFailed = true;\n }\n }\n }\n if (shutdownFailed) {\n throw firstError;\n }\n }\n\n /** Detach synchronously when Faro removes this instrumentation. */\n destroy(): void {\n const registration = this.detachRegistration();\n if (!registration) {\n return;\n }\n void this.startProviderShutdown(registration).then(undefined, (error) => {\n this.logCleanupError('shut down the OpenTelemetry tracer provider', error);\n });\n }\n}\n"]}
@@ -11,8 +11,7 @@ var __rest = (this && this.__rest) || function (s, e) {
11
11
  };
12
12
  import { FetchInstrumentation } from '@opentelemetry/instrumentation-fetch';
13
13
  import { XMLHttpRequestInstrumentation } from '@opentelemetry/instrumentation-xml-http-request';
14
- import { faro, UserActionState } from '@grafana/faro-core';
15
- import { fetchCustomAttributeFunctionWithDefaults, xhrCustomAttributeFunctionWithDefaults, } from './instrumentationUtils';
14
+ import { captureFetchUserAction, fetchCustomAttributeFunctionWithDefaults, xhrCustomAttributeFunctionWithDefaults, } from './instrumentationUtils';
16
15
  /**
17
16
  * Get default OTEL instrumentations for React Native
18
17
  *
@@ -29,37 +28,44 @@ import { fetchCustomAttributeFunctionWithDefaults, xhrCustomAttributeFunctionWit
29
28
  * @returns Array of OTEL instrumentations
30
29
  */
31
30
  export function getDefaultOTELInstrumentations(options = {}) {
32
- const { enableFetchInstrumentation = true, enableXhrInstrumentation = false, fetchInstrumentationOptions, xhrInstrumentationOptions } = options, sharedOptions = __rest(options, ["enableFetchInstrumentation", "enableXhrInstrumentation", "fetchInstrumentationOptions", "xhrInstrumentationOptions"]);
31
+ const { enableFetchInstrumentation, enableXhrInstrumentation, fetchConfig, xhrConfig } = resolveDefaultInstrumentationOptions(options);
33
32
  const instrumentations = [];
34
33
  if (enableFetchInstrumentation) {
35
- instrumentations.push(new FetchInstrumentation(createFetchInstrumentationOptions(fetchInstrumentationOptions, sharedOptions)));
34
+ instrumentations.push(new FetchInstrumentation(fetchConfig));
36
35
  }
37
36
  if (enableXhrInstrumentation) {
38
- instrumentations.push(new XMLHttpRequestInstrumentation(createXhrInstrumentationOptions(xhrInstrumentationOptions, sharedOptions)));
37
+ instrumentations.push(new XMLHttpRequestInstrumentation(xhrConfig));
39
38
  }
40
39
  return instrumentations;
41
40
  }
41
+ export function updateDefaultOTELInstrumentations(instrumentations, options = {}) {
42
+ const { fetchConfig, xhrConfig } = resolveDefaultInstrumentationOptions(options);
43
+ instrumentations.forEach((instrumentation) => {
44
+ if (instrumentation instanceof FetchInstrumentation) {
45
+ instrumentation.setConfig(fetchConfig);
46
+ }
47
+ else if (instrumentation instanceof XMLHttpRequestInstrumentation) {
48
+ instrumentation.setConfig(xhrConfig);
49
+ }
50
+ });
51
+ }
52
+ function resolveDefaultInstrumentationOptions(options) {
53
+ const { enableFetchInstrumentation = true, enableXhrInstrumentation = false, fetchInstrumentationOptions, xhrInstrumentationOptions } = options, sharedOptions = __rest(options, ["enableFetchInstrumentation", "enableXhrInstrumentation", "fetchInstrumentationOptions", "xhrInstrumentationOptions"]);
54
+ return {
55
+ enableFetchInstrumentation,
56
+ enableXhrInstrumentation,
57
+ fetchConfig: createFetchInstrumentationOptions(fetchInstrumentationOptions, sharedOptions),
58
+ xhrConfig: createXhrInstrumentationOptions(xhrInstrumentationOptions, sharedOptions),
59
+ };
60
+ }
42
61
  function createFetchInstrumentationOptions(fetchInstrumentationOptions, sharedOptions) {
43
62
  return Object.assign(Object.assign(Object.assign(Object.assign({}, sharedOptions), {
44
63
  // Ignore network performance events to avoid duplicates
45
- ignoreNetworkEvents: true }), fetchInstrumentationOptions), {
64
+ ignoreNetworkEvents: true }), fetchInstrumentationOptions), { semconvStabilityOptIn: 'http',
46
65
  // Always keep this function
47
66
  applyCustomAttributesOnSpan: fetchCustomAttributeFunctionWithDefaults(fetchInstrumentationOptions === null || fetchInstrumentationOptions === void 0 ? void 0 : fetchInstrumentationOptions.applyCustomAttributesOnSpan),
48
- // Request hook to add user action context
49
- requestHook: (span, _) => {
50
- try {
51
- const currentAction = faro.api.getActiveUserAction();
52
- if (currentAction &&
53
- (currentAction === null || currentAction === void 0 ? void 0 : currentAction.getState()) === UserActionState.Started) {
54
- span.setAttribute('faro.action.user.name', currentAction.name);
55
- span.setAttribute('faro.action.user.parentId', currentAction.parentId);
56
- }
57
- }
58
- catch (_error) {
59
- // Silently fail - don't log to avoid infinite loops
60
- // The span will just not have user action context
61
- }
62
- } });
67
+ // Also supports callers using a custom processor without the RN request monitor.
68
+ requestHook: captureFetchUserAction });
63
69
  }
64
70
  function createXhrInstrumentationOptions(xhrInstrumentationOptions, sharedOptions) {
65
71
  return Object.assign(Object.assign(Object.assign(Object.assign({}, sharedOptions), { ignoreNetworkEvents: true }), xhrInstrumentationOptions), { applyCustomAttributesOnSpan: xhrCustomAttributeFunctionWithDefaults(xhrInstrumentationOptions === null || xhrInstrumentationOptions === void 0 ? void 0 : xhrInstrumentationOptions.applyCustomAttributesOnSpan) });
@@ -1 +1 @@
1
- {"version":3,"file":"getDefaultOTELInstrumentations.js","sourceRoot":"","sources":["../../../src/instrumentations/getDefaultOTELInstrumentations.ts"],"names":[],"mappings":";;;;;;;;;;;AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AAC5E,OAAO,EAAE,6BAA6B,EAAE,MAAM,iDAAiD,CAAC;AAEhG,OAAO,EAAE,IAAI,EAAoC,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAI7F,OAAO,EACL,wCAAwC,EACxC,sCAAsC,GACvC,MAAM,wBAAwB,CAAC;AAEhC;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,8BAA8B,CAAC,UAA0C,EAAE;IACzF,MAAM,EACJ,0BAA0B,GAAG,IAAI,EACjC,wBAAwB,GAAG,KAAK,EAChC,2BAA2B,EAC3B,yBAAyB,KAEvB,OAAO,EADN,aAAa,UACd,OAAO,EANL,sHAML,CAAU,CAAC;IAEZ,MAAM,gBAAgB,GAA4B,EAAE,CAAC;IAErD,IAAI,0BAA0B,EAAE,CAAC;QAC/B,gBAAgB,CAAC,IAAI,CACnB,IAAI,oBAAoB,CAAC,iCAAiC,CAAC,2BAA2B,EAAE,aAAa,CAAC,CAAC,CACxG,CAAC;IACJ,CAAC;IAED,IAAI,wBAAwB,EAAE,CAAC;QAC7B,gBAAgB,CAAC,IAAI,CACnB,IAAI,6BAA6B,CAAC,+BAA+B,CAAC,yBAAyB,EAAE,aAAa,CAAC,CAAC,CAC7G,CAAC;IACJ,CAAC;IAED,OAAO,gBAAgB,CAAC;AAC1B,CAAC;AAED,SAAS,iCAAiC,CACxC,2BAA0F,EAC1F,aAAsC;IAEtC,mEACK,aAAa;QAChB,wDAAwD;QACxD,mBAAmB,EAAE,IAAI,KAEtB,2BAA2B;QAC9B,4BAA4B;QAC5B,2BAA2B,EAAE,wCAAwC,CACnE,2BAA2B,aAA3B,2BAA2B,uBAA3B,2BAA2B,CAAE,2BAA2B,CACzD;QACD,0CAA0C;QAC1C,WAAW,EAAE,CAAC,IAAU,EAAE,CAAwB,EAAE,EAAE;YACpD,IAAI,CAAC;gBACH,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,mBAAmB,EAAE,CAAC;gBACrD,IACE,aAAa;oBACb,CAAC,aAAwD,aAAxD,aAAa,uBAAb,aAAa,CAA6C,QAAQ,EAAE,MAAK,eAAe,CAAC,OAAO,EACjG,CAAC;oBACD,IAAI,CAAC,YAAY,CAAC,uBAAuB,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC;oBAC/D,IAAI,CAAC,YAAY,CAAC,2BAA2B,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;gBACzE,CAAC;YACH,CAAC;YAAC,OAAO,MAAM,EAAE,CAAC;gBAChB,oDAAoD;gBACpD,kDAAkD;YACpD,CAAC;QACH,CAAC,IACD;AACJ,CAAC;AAED,SAAS,+BAA+B,CACtC,yBAAsF,EACtF,aAAsC;IAEtC,mEACK,aAAa,KAChB,mBAAmB,EAAE,IAAI,KACtB,yBAAyB,KAC5B,2BAA2B,EAAE,sCAAsC,CACjE,yBAAyB,aAAzB,yBAAyB,uBAAzB,yBAAyB,CAAE,2BAA2B,CACvD,IACD;AACJ,CAAC","sourcesContent":["import type { Span } from '@opentelemetry/api';\nimport { FetchInstrumentation } from '@opentelemetry/instrumentation-fetch';\nimport { XMLHttpRequestInstrumentation } from '@opentelemetry/instrumentation-xml-http-request';\n\nimport { faro, type UserActionInternalInterface, UserActionState } from '@grafana/faro-core';\n\nimport type { DefaultInstrumentationsOptions, InstrumentationOption } from '../types';\n\nimport {\n fetchCustomAttributeFunctionWithDefaults,\n xhrCustomAttributeFunctionWithDefaults,\n} from './instrumentationUtils';\n\n/**\n * Get default OTEL instrumentations for React Native\n *\n * This function creates the default OpenTelemetry instrumentations for React Native:\n * - FetchInstrumentation: Traces fetch() API calls\n * - XMLHttpRequestInstrumentation: Optional for apps that use XHR/axios directly\n *\n * IMPORTANT: Infinite loop prevention\n * - ignoreUrls is used to exclude Faro collector URLs\n * - ignoreNetworkEvents is true to avoid duplicate events\n * - No console logging during instrumentation\n *\n * @param options - Configuration options\n * @returns Array of OTEL instrumentations\n */\nexport function getDefaultOTELInstrumentations(options: DefaultInstrumentationsOptions = {}): InstrumentationOption[] {\n const {\n enableFetchInstrumentation = true,\n enableXhrInstrumentation = false,\n fetchInstrumentationOptions,\n xhrInstrumentationOptions,\n ...sharedOptions\n } = options;\n\n const instrumentations: InstrumentationOption[] = [];\n\n if (enableFetchInstrumentation) {\n instrumentations.push(\n new FetchInstrumentation(createFetchInstrumentationOptions(fetchInstrumentationOptions, sharedOptions))\n );\n }\n\n if (enableXhrInstrumentation) {\n instrumentations.push(\n new XMLHttpRequestInstrumentation(createXhrInstrumentationOptions(xhrInstrumentationOptions, sharedOptions))\n );\n }\n\n return instrumentations;\n}\n\nfunction createFetchInstrumentationOptions(\n fetchInstrumentationOptions: DefaultInstrumentationsOptions['fetchInstrumentationOptions'],\n sharedOptions: Record<string, unknown>\n) {\n return {\n ...sharedOptions,\n // Ignore network performance events to avoid duplicates\n ignoreNetworkEvents: true,\n // Keep this here to overwrite the defaults above if provided by the users\n ...fetchInstrumentationOptions,\n // Always keep this function\n applyCustomAttributesOnSpan: fetchCustomAttributeFunctionWithDefaults(\n fetchInstrumentationOptions?.applyCustomAttributesOnSpan\n ),\n // Request hook to add user action context\n requestHook: (span: Span, _: Request | RequestInit) => {\n try {\n const currentAction = faro.api.getActiveUserAction();\n if (\n currentAction &&\n (currentAction as unknown as UserActionInternalInterface)?.getState() === UserActionState.Started\n ) {\n span.setAttribute('faro.action.user.name', currentAction.name);\n span.setAttribute('faro.action.user.parentId', currentAction.parentId);\n }\n } catch (_error) {\n // Silently fail - don't log to avoid infinite loops\n // The span will just not have user action context\n }\n },\n };\n}\n\nfunction createXhrInstrumentationOptions(\n xhrInstrumentationOptions: DefaultInstrumentationsOptions['xhrInstrumentationOptions'],\n sharedOptions: Record<string, unknown>\n) {\n return {\n ...sharedOptions,\n ignoreNetworkEvents: true,\n ...xhrInstrumentationOptions,\n applyCustomAttributesOnSpan: xhrCustomAttributeFunctionWithDefaults(\n xhrInstrumentationOptions?.applyCustomAttributesOnSpan\n ),\n };\n}\n"]}
1
+ {"version":3,"file":"getDefaultOTELInstrumentations.js","sourceRoot":"","sources":["../../../src/instrumentations/getDefaultOTELInstrumentations.ts"],"names":[],"mappings":";;;;;;;;;;;AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AAC5E,OAAO,EAAE,6BAA6B,EAAE,MAAM,iDAAiD,CAAC;AAIhG,OAAO,EACL,sBAAsB,EACtB,wCAAwC,EACxC,sCAAsC,GACvC,MAAM,wBAAwB,CAAC;AAEhC;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,8BAA8B,CAAC,UAA0C,EAAE;IACzF,MAAM,EAAE,0BAA0B,EAAE,wBAAwB,EAAE,WAAW,EAAE,SAAS,EAAE,GACpF,oCAAoC,CAAC,OAAO,CAAC,CAAC;IAEhD,MAAM,gBAAgB,GAA4B,EAAE,CAAC;IAErD,IAAI,0BAA0B,EAAE,CAAC;QAC/B,gBAAgB,CAAC,IAAI,CAAC,IAAI,oBAAoB,CAAC,WAAW,CAAC,CAAC,CAAC;IAC/D,CAAC;IAED,IAAI,wBAAwB,EAAE,CAAC;QAC7B,gBAAgB,CAAC,IAAI,CAAC,IAAI,6BAA6B,CAAC,SAAS,CAAC,CAAC,CAAC;IACtE,CAAC;IAED,OAAO,gBAAgB,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,iCAAiC,CAC/C,gBAAmC,EACnC,UAA0C,EAAE;IAE5C,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,GAAG,oCAAoC,CAAC,OAAO,CAAC,CAAC;IAEjF,gBAAgB,CAAC,OAAO,CAAC,CAAC,eAAe,EAAE,EAAE;QAC3C,IAAI,eAAe,YAAY,oBAAoB,EAAE,CAAC;YACpD,eAAe,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;QACzC,CAAC;aAAM,IAAI,eAAe,YAAY,6BAA6B,EAAE,CAAC;YACpE,eAAe,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QACvC,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,oCAAoC,CAAC,OAAuC;IACnF,MAAM,EACJ,0BAA0B,GAAG,IAAI,EACjC,wBAAwB,GAAG,KAAK,EAChC,2BAA2B,EAC3B,yBAAyB,KAEvB,OAAO,EADN,aAAa,UACd,OAAO,EANL,sHAML,CAAU,CAAC;IAEZ,OAAO;QACL,0BAA0B;QAC1B,wBAAwB;QACxB,WAAW,EAAE,iCAAiC,CAAC,2BAA2B,EAAE,aAAa,CAAC;QAC1F,SAAS,EAAE,+BAA+B,CAAC,yBAAyB,EAAE,aAAa,CAAC;KACrF,CAAC;AACJ,CAAC;AAED,SAAS,iCAAiC,CACxC,2BAA0F,EAC1F,aAAsC;IAEtC,mEACK,aAAa;QAChB,wDAAwD;QACxD,mBAAmB,EAAE,IAAI,KAEtB,2BAA2B,KAC9B,qBAAqB,EAAE,MAAM;QAC7B,4BAA4B;QAC5B,2BAA2B,EAAE,wCAAwC,CACnE,2BAA2B,aAA3B,2BAA2B,uBAA3B,2BAA2B,CAAE,2BAA2B,CACzD;QACD,iFAAiF;QACjF,WAAW,EAAE,sBAAsB,IACnC;AACJ,CAAC;AAED,SAAS,+BAA+B,CACtC,yBAAsF,EACtF,aAAsC;IAEtC,mEACK,aAAa,KAChB,mBAAmB,EAAE,IAAI,KACtB,yBAAyB,KAC5B,2BAA2B,EAAE,sCAAsC,CACjE,yBAAyB,aAAzB,yBAAyB,uBAAzB,yBAAyB,CAAE,2BAA2B,CACvD,IACD;AACJ,CAAC","sourcesContent":["import type { Instrumentation } from '@opentelemetry/instrumentation';\nimport { FetchInstrumentation } from '@opentelemetry/instrumentation-fetch';\nimport { XMLHttpRequestInstrumentation } from '@opentelemetry/instrumentation-xml-http-request';\n\nimport type { DefaultInstrumentationsOptions, InstrumentationOption } from '../types';\n\nimport {\n captureFetchUserAction,\n fetchCustomAttributeFunctionWithDefaults,\n xhrCustomAttributeFunctionWithDefaults,\n} from './instrumentationUtils';\n\n/**\n * Get default OTEL instrumentations for React Native\n *\n * This function creates the default OpenTelemetry instrumentations for React Native:\n * - FetchInstrumentation: Traces fetch() API calls\n * - XMLHttpRequestInstrumentation: Optional for apps that use XHR/axios directly\n *\n * IMPORTANT: Infinite loop prevention\n * - ignoreUrls is used to exclude Faro collector URLs\n * - ignoreNetworkEvents is true to avoid duplicate events\n * - No console logging during instrumentation\n *\n * @param options - Configuration options\n * @returns Array of OTEL instrumentations\n */\nexport function getDefaultOTELInstrumentations(options: DefaultInstrumentationsOptions = {}): InstrumentationOption[] {\n const { enableFetchInstrumentation, enableXhrInstrumentation, fetchConfig, xhrConfig } =\n resolveDefaultInstrumentationOptions(options);\n\n const instrumentations: InstrumentationOption[] = [];\n\n if (enableFetchInstrumentation) {\n instrumentations.push(new FetchInstrumentation(fetchConfig));\n }\n\n if (enableXhrInstrumentation) {\n instrumentations.push(new XMLHttpRequestInstrumentation(xhrConfig));\n }\n\n return instrumentations;\n}\n\nexport function updateDefaultOTELInstrumentations(\n instrumentations: Instrumentation[],\n options: DefaultInstrumentationsOptions = {}\n): void {\n const { fetchConfig, xhrConfig } = resolveDefaultInstrumentationOptions(options);\n\n instrumentations.forEach((instrumentation) => {\n if (instrumentation instanceof FetchInstrumentation) {\n instrumentation.setConfig(fetchConfig);\n } else if (instrumentation instanceof XMLHttpRequestInstrumentation) {\n instrumentation.setConfig(xhrConfig);\n }\n });\n}\n\nfunction resolveDefaultInstrumentationOptions(options: DefaultInstrumentationsOptions) {\n const {\n enableFetchInstrumentation = true,\n enableXhrInstrumentation = false,\n fetchInstrumentationOptions,\n xhrInstrumentationOptions,\n ...sharedOptions\n } = options;\n\n return {\n enableFetchInstrumentation,\n enableXhrInstrumentation,\n fetchConfig: createFetchInstrumentationOptions(fetchInstrumentationOptions, sharedOptions),\n xhrConfig: createXhrInstrumentationOptions(xhrInstrumentationOptions, sharedOptions),\n };\n}\n\nfunction createFetchInstrumentationOptions(\n fetchInstrumentationOptions: DefaultInstrumentationsOptions['fetchInstrumentationOptions'],\n sharedOptions: Record<string, unknown>\n) {\n return {\n ...sharedOptions,\n // Ignore network performance events to avoid duplicates\n ignoreNetworkEvents: true,\n // Keep this here to overwrite the defaults above if provided by the users\n ...fetchInstrumentationOptions,\n semconvStabilityOptIn: 'http',\n // Always keep this function\n applyCustomAttributesOnSpan: fetchCustomAttributeFunctionWithDefaults(\n fetchInstrumentationOptions?.applyCustomAttributesOnSpan\n ),\n // Also supports callers using a custom processor without the RN request monitor.\n requestHook: captureFetchUserAction,\n };\n}\n\nfunction createXhrInstrumentationOptions(\n xhrInstrumentationOptions: DefaultInstrumentationsOptions['xhrInstrumentationOptions'],\n sharedOptions: Record<string, unknown>\n) {\n return {\n ...sharedOptions,\n ignoreNetworkEvents: true,\n ...xhrInstrumentationOptions,\n applyCustomAttributesOnSpan: xhrCustomAttributeFunctionWithDefaults(\n xhrInstrumentationOptions?.applyCustomAttributesOnSpan\n ),\n };\n}\n"]}
@@ -1,5 +1,19 @@
1
1
  import { SpanStatusCode } from '@opentelemetry/api';
2
2
  import { faro, UserActionState } from '@grafana/faro-core';
3
+ /** Capture request ownership at start, before the monitor can halt the action. */
4
+ export function captureFetchUserAction(span) {
5
+ var _a, _b;
6
+ try {
7
+ const action = (_b = (_a = faro.api) === null || _a === void 0 ? void 0 : _a.getActiveUserAction) === null || _b === void 0 ? void 0 : _b.call(_a);
8
+ if (action && action.getState() === UserActionState.Started) {
9
+ span.setAttribute('faro.action.user.name', action.name);
10
+ span.setAttribute('faro.action.user.parentId', action.parentId);
11
+ }
12
+ }
13
+ catch (_c) {
14
+ // Instrumentation must not interrupt the request or log recursively.
15
+ }
16
+ }
3
17
  /**
4
18
  * Set span status to ERROR when fetch fails
5
19
  *
@@ -1 +1 @@
1
- {"version":3,"file":"instrumentationUtils.js","sourceRoot":"","sources":["../../../src/instrumentations/instrumentationUtils.ts"],"names":[],"mappings":"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","sourcesContent":["import { SpanStatusCode } from '@opentelemetry/api';\nimport type { Span } from '@opentelemetry/api';\nimport type { FetchCustomAttributeFunction } from '@opentelemetry/instrumentation-fetch';\nimport type { XHRCustomAttributeFunction } from '@opentelemetry/instrumentation-xml-http-request';\n\nimport { faro, type UserActionInternalInterface, UserActionState } from '@grafana/faro-core';\n\n/**\n * FetchError interface matching OpenTelemetry's internal type\n * Note: FetchError is not exported from @opentelemetry/instrumentation-fetch\n */\ninterface FetchError {\n status?: number;\n message: string;\n}\n\n/**\n * Set span status to ERROR when fetch fails\n *\n * This ensures that failed HTTP requests are marked as errors in traces.\n */\nexport function setSpanStatusOnFetchError(span: Span, error: Error | string): void {\n const message = typeof error === 'string' ? error : error.message;\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message,\n });\n}\n\n/**\n * Type guard to check if result is a FetchError\n */\nfunction isFetchError(result: Response | FetchError): result is FetchError {\n return 'message' in result && typeof (result as FetchError).message === 'string';\n}\n\n/**\n * Custom attribute function for fetch instrumentation with defaults\n *\n * Combines user-provided custom attributes with default handling.\n *\n * @param userFunction - Optional user-provided custom attribute function\n * @returns Combined custom attribute function\n */\nexport function fetchCustomAttributeFunctionWithDefaults(\n userFunction?: FetchCustomAttributeFunction\n): FetchCustomAttributeFunction {\n const fn: FetchCustomAttributeFunction = (\n span: Span,\n request: Request | RequestInit,\n result: Response | FetchError\n ) => {\n // Call user function first if provided\n if (userFunction) {\n userFunction(span, request, result);\n }\n\n // Add default error handling\n if (isFetchError(result)) {\n setSpanStatusOnFetchError(span, result.message);\n } else if (result instanceof Response && result.status >= 400 && result.status < 600) {\n setSpanStatusOnFetchError(span, `HTTP ${result.status}: ${result.statusText}`);\n }\n };\n return fn;\n}\n\n/**\n * Set span status to ERROR for XHR failures (status 0 or 4xx/5xx).\n */\nexport function setSpanStatusOnXMLHttpRequestError(span: Span, xhr: XMLHttpRequest): void {\n const status = xhr.status;\n if (status == null) return;\n if (status === 0 || (status >= 400 && status < 600)) {\n span.setStatus({ code: SpanStatusCode.ERROR });\n }\n}\n\n/**\n * Add user action context to span when active (for HTTP Errors column in user action table).\n */\nfunction addUserActionContextToSpan(span: Span): void {\n try {\n const currentAction = faro.api?.getActiveUserAction?.();\n const state = (currentAction as unknown as UserActionInternalInterface)?.getState?.();\n if (currentAction && (state === UserActionState.Started || state === UserActionState.Halted)) {\n span.setAttribute('faro.action.user.name', currentAction.name);\n span.setAttribute('faro.action.user.parentId', currentAction.parentId);\n }\n } catch (_) {\n // Silently fail - don't log to avoid instrumentation loops\n }\n}\n\n/**\n * Custom attribute function for XHR instrumentation with defaults.\n */\nexport function xhrCustomAttributeFunctionWithDefaults(\n userFunction?: XHRCustomAttributeFunction\n): XHRCustomAttributeFunction {\n return (span: Span, xhr: XMLHttpRequest) => {\n setSpanStatusOnXMLHttpRequestError(span, xhr);\n addUserActionContextToSpan(span);\n userFunction?.(span, xhr);\n };\n}\n"]}
1
+ {"version":3,"file":"instrumentationUtils.js","sourceRoot":"","sources":["../../../src/instrumentations/instrumentationUtils.ts"],"names":[],"mappings":"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","sourcesContent":["import { SpanStatusCode } from '@opentelemetry/api';\nimport type { Span } from '@opentelemetry/api';\nimport type { FetchCustomAttributeFunction } from '@opentelemetry/instrumentation-fetch';\nimport type { XHRCustomAttributeFunction } from '@opentelemetry/instrumentation-xml-http-request';\n\nimport { faro, type UserActionInternalInterface, UserActionState } from '@grafana/faro-core';\n\n/** Capture request ownership at start, before the monitor can halt the action. */\nexport function captureFetchUserAction(span: Span): void {\n try {\n const action = faro.api?.getActiveUserAction?.();\n if (action && (action as UserActionInternalInterface).getState() === UserActionState.Started) {\n span.setAttribute('faro.action.user.name', action.name);\n span.setAttribute('faro.action.user.parentId', action.parentId);\n }\n } catch {\n // Instrumentation must not interrupt the request or log recursively.\n }\n}\n\n/**\n * FetchError interface matching OpenTelemetry's internal type\n * Note: FetchError is not exported from @opentelemetry/instrumentation-fetch\n */\ninterface FetchError {\n status?: number;\n message: string;\n}\n\n/**\n * Set span status to ERROR when fetch fails\n *\n * This ensures that failed HTTP requests are marked as errors in traces.\n */\nexport function setSpanStatusOnFetchError(span: Span, error: Error | string): void {\n const message = typeof error === 'string' ? error : error.message;\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message,\n });\n}\n\n/**\n * Type guard to check if result is a FetchError\n */\nfunction isFetchError(result: Response | FetchError): result is FetchError {\n return 'message' in result && typeof (result as FetchError).message === 'string';\n}\n\n/**\n * Custom attribute function for fetch instrumentation with defaults\n *\n * Combines user-provided custom attributes with default handling.\n *\n * @param userFunction - Optional user-provided custom attribute function\n * @returns Combined custom attribute function\n */\nexport function fetchCustomAttributeFunctionWithDefaults(\n userFunction?: FetchCustomAttributeFunction\n): FetchCustomAttributeFunction {\n const fn: FetchCustomAttributeFunction = (\n span: Span,\n request: Request | RequestInit,\n result: Response | FetchError\n ) => {\n // Call user function first if provided\n if (userFunction) {\n userFunction(span, request, result);\n }\n\n // Add default error handling\n if (isFetchError(result)) {\n setSpanStatusOnFetchError(span, result.message);\n } else if (result instanceof Response && result.status >= 400 && result.status < 600) {\n setSpanStatusOnFetchError(span, `HTTP ${result.status}: ${result.statusText}`);\n }\n };\n return fn;\n}\n\n/**\n * Set span status to ERROR for XHR failures (status 0 or 4xx/5xx).\n */\nexport function setSpanStatusOnXMLHttpRequestError(span: Span, xhr: XMLHttpRequest): void {\n const status = xhr.status;\n if (status == null) return;\n if (status === 0 || (status >= 400 && status < 600)) {\n span.setStatus({ code: SpanStatusCode.ERROR });\n }\n}\n\n/**\n * Add user action context to span when active (for HTTP Errors column in user action table).\n */\nfunction addUserActionContextToSpan(span: Span): void {\n try {\n const currentAction = faro.api?.getActiveUserAction?.();\n const state = (currentAction as unknown as UserActionInternalInterface)?.getState?.();\n if (currentAction && (state === UserActionState.Started || state === UserActionState.Halted)) {\n span.setAttribute('faro.action.user.name', currentAction.name);\n span.setAttribute('faro.action.user.parentId', currentAction.parentId);\n }\n } catch (_) {\n // Silently fail - don't log to avoid instrumentation loops\n }\n}\n\n/**\n * Custom attribute function for XHR instrumentation with defaults.\n */\nexport function xhrCustomAttributeFunctionWithDefaults(\n userFunction?: XHRCustomAttributeFunction\n): XHRCustomAttributeFunction {\n return (span: Span, xhr: XMLHttpRequest) => {\n setSpanStatusOnXMLHttpRequestError(span, xhr);\n addUserActionContextToSpan(span);\n userFunction?.(span, xhr);\n };\n}\n"]}