@grafana/faro-react-native-tracing 1.3.1 → 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.
- package/README.md +33 -0
- package/dist/cjs/exporters/faroTraceExporter.utils.js +33 -0
- package/dist/cjs/exporters/faroTraceExporter.utils.js.map +1 -1
- package/dist/cjs/instrumentation.js +259 -44
- package/dist/cjs/instrumentation.js.map +1 -1
- package/dist/cjs/instrumentations/getDefaultOTELInstrumentations.js +28 -20
- package/dist/cjs/instrumentations/getDefaultOTELInstrumentations.js.map +1 -1
- package/dist/cjs/instrumentations/instrumentationUtils.js +15 -0
- package/dist/cjs/instrumentations/instrumentationUtils.js.map +1 -1
- package/dist/cjs/processors/httpRequestMonitorSpanProcessor.js +27 -13
- package/dist/cjs/processors/httpRequestMonitorSpanProcessor.js.map +1 -1
- package/dist/cjs/types.js.map +1 -1
- package/dist/esm/exporters/faroTraceExporter.utils.js +32 -0
- package/dist/esm/exporters/faroTraceExporter.utils.js.map +1 -1
- package/dist/esm/instrumentation.js +237 -43
- package/dist/esm/instrumentation.js.map +1 -1
- package/dist/esm/instrumentations/getDefaultOTELInstrumentations.js +27 -21
- package/dist/esm/instrumentations/getDefaultOTELInstrumentations.js.map +1 -1
- package/dist/esm/instrumentations/instrumentationUtils.js +14 -0
- package/dist/esm/instrumentations/instrumentationUtils.js.map +1 -1
- package/dist/esm/processors/httpRequestMonitorSpanProcessor.js +27 -13
- package/dist/esm/processors/httpRequestMonitorSpanProcessor.js.map +1 -1
- package/dist/esm/types.js.map +1 -1
- package/dist/types/instrumentation.d.ts +12 -4
- package/dist/types/instrumentations/getDefaultOTELInstrumentations.d.ts +2 -0
- package/dist/types/instrumentations/instrumentationUtils.d.ts +2 -0
- package/dist/types/types.d.ts +4 -0
- package/package.json +3 -3
- package/src/exporters/faroTraceExporter.events.test.ts +90 -0
- package/src/exporters/faroTraceExporter.utils.ts +32 -0
- package/src/httpSemantics.test.ts +300 -0
- package/src/instrumentation.test.ts +740 -0
- package/src/instrumentation.ts +299 -67
- package/src/instrumentations/getDefaultOTELInstrumentations.test.ts +28 -1
- package/src/instrumentations/getDefaultOTELInstrumentations.ts +41 -32
- package/src/instrumentations/instrumentationUtils.ts +13 -0
- package/src/processors/httpRequestMonitorSpanProcessor.ts +27 -15
- package/src/types.ts +4 -0
package/README.md
CHANGED
|
@@ -41,6 +41,23 @@ const faro = initializeFaro({
|
|
|
41
41
|
|
|
42
42
|
That's it! HTTP requests via `fetch()` are now automatically traced (and correlated with user actions when user action tracking is enabled) and sent to your Faro collector.
|
|
43
43
|
|
|
44
|
+
## HTTP span and event conventions
|
|
45
|
+
|
|
46
|
+
Built-in fetch tracing uses OpenTelemetry's [stable HTTP conventions](https://opentelemetry.io/docs/specs/semconv/http/http-spans/#name),
|
|
47
|
+
with span names such as `GET` and `POST`. Attributes include `http.request.method`,
|
|
48
|
+
`url.full`, `server.address`, `server.port`, and `http.response.status_code`.
|
|
49
|
+
Successful responses leave status UNSET; ordinary 4xx/5xx responses set ERROR
|
|
50
|
+
and a string `error.type`. There is no fetch convention mode setting.
|
|
51
|
+
|
|
52
|
+
The `faro.tracing.fetch` event keeps `http.method`, `http.url`, `http.status_code`,
|
|
53
|
+
`http.host`, and `http.scheme`. Event attributes, including `duration_ns`, are
|
|
54
|
+
strings. Events retain session and trace/span context and use the shared event
|
|
55
|
+
pipeline for deduplication and transport hooks. Optional XHR tracing and custom
|
|
56
|
+
instrumentations use their own conventions.
|
|
57
|
+
|
|
58
|
+
Fetch spans capture the active user action at request start. A delayed fetch
|
|
59
|
+
event can still be associated with a later action through event buffering.
|
|
60
|
+
|
|
44
61
|
## Fetch vs XHR in React Native
|
|
45
62
|
|
|
46
63
|
By default, this package traces `fetch()` requests only.
|
|
@@ -209,6 +226,10 @@ new TracingInstrumentation({
|
|
|
209
226
|
});
|
|
210
227
|
```
|
|
211
228
|
|
|
229
|
+
A custom span processor remains reusable when Faro removes and later re-adds the tracing instrumentation. Removal
|
|
230
|
+
flushes the processor without shutting it down. Calling `TracingInstrumentation.shutdown()` shuts it down and is
|
|
231
|
+
terminal for that processor; use a new processor before initializing the instrumentation again.
|
|
232
|
+
|
|
212
233
|
## Usage Examples
|
|
213
234
|
|
|
214
235
|
### Automatic HTTP Tracing
|
|
@@ -665,6 +686,10 @@ const { trace } = faro.otel; // Error!
|
|
|
665
686
|
|
|
666
687
|
**Solution:** This should be automatic. If you're using a custom span processor or custom instrumentations, ensure you're not overriding the tracer provider registration.
|
|
667
688
|
|
|
689
|
+
If another global OpenTelemetry tracer provider is already registered, tracing initialization fails with a clear
|
|
690
|
+
error instead of installing request instrumentation that cannot export through Faro. Remove the duplicate provider
|
|
691
|
+
registration before initializing `TracingInstrumentation`.
|
|
692
|
+
|
|
668
693
|
### Spans missing user/session/device context
|
|
669
694
|
|
|
670
695
|
**Cause:** FaroMetaAttributesSpanProcessor is not wrapping your span processor.
|
|
@@ -727,9 +752,17 @@ class TracingInstrumentation extends BaseInstrumentation {
|
|
|
727
752
|
constructor(options?: TracingInstrumentationOptions);
|
|
728
753
|
initialize(): void;
|
|
729
754
|
shutdown(): Promise<void>;
|
|
755
|
+
destroy(): void;
|
|
730
756
|
}
|
|
731
757
|
```
|
|
732
758
|
|
|
759
|
+
`shutdown()` detaches HTTP instrumentation before waiting for the tracer provider to flush. Faro calls `destroy()`
|
|
760
|
+
when the instrumentation is removed; it detaches immediately and completes provider shutdown in the background.
|
|
761
|
+
Both methods are safe to call more than once.
|
|
762
|
+
|
|
763
|
+
When tracing is removed and later re-added, reuse the same `TracingInstrumentation` instance so the default fetch
|
|
764
|
+
and XHR patches are reused as well.
|
|
765
|
+
|
|
733
766
|
**Options:**
|
|
734
767
|
|
|
735
768
|
```typescript
|
|
@@ -5,6 +5,36 @@ var internal_types_1 = require("@opentelemetry/otlp-transformer/build/src/trace/
|
|
|
5
5
|
var faro_core_1 = require("@grafana/faro-core");
|
|
6
6
|
var internalLogger = (0, faro_core_1.createInternalLogger)();
|
|
7
7
|
var DURATION_NS_KEY = 'duration_ns';
|
|
8
|
+
/** Map stable OTel span attributes to Faro's fetch event contract. */
|
|
9
|
+
function projectFetchEventAttributes(attributes) {
|
|
10
|
+
var _a, _b, _c;
|
|
11
|
+
var fields = {
|
|
12
|
+
'http.request.method': 'http.method',
|
|
13
|
+
'url.full': 'http.url',
|
|
14
|
+
'http.response.status_code': 'http.status_code',
|
|
15
|
+
};
|
|
16
|
+
for (var _i = 0, _d = Object.entries(fields); _i < _d.length; _i++) {
|
|
17
|
+
var _e = _d[_i], spanField = _e[0], eventField = _e[1];
|
|
18
|
+
if (attributes[spanField] != null) {
|
|
19
|
+
attributes[eventField] = attributes[spanField];
|
|
20
|
+
delete attributes[spanField];
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
var url = attributes['http.url'];
|
|
24
|
+
if (url) {
|
|
25
|
+
try {
|
|
26
|
+
var parsed = new URL(url);
|
|
27
|
+
attributes['http.host'] = (_a = attributes['http.host']) !== null && _a !== void 0 ? _a : parsed.host;
|
|
28
|
+
attributes['http.scheme'] = (_b = attributes['http.scheme']) !== null && _b !== void 0 ? _b : parsed.protocol.replace(':', '');
|
|
29
|
+
}
|
|
30
|
+
catch (_f) {
|
|
31
|
+
// Keep the captured URL even if it cannot supply host/scheme metadata.
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
delete attributes['server.address'];
|
|
35
|
+
delete attributes['server.port'];
|
|
36
|
+
attributes['component'] = (_c = attributes['component']) !== null && _c !== void 0 ? _c : 'fetch';
|
|
37
|
+
}
|
|
8
38
|
/**
|
|
9
39
|
* Send Faro events for CLIENT spans (HTTP requests, navigation, etc.)
|
|
10
40
|
*
|
|
@@ -45,6 +75,9 @@ function sendFaroEvents(resourceSpans) {
|
|
|
45
75
|
var attribute = _g[_f];
|
|
46
76
|
faroEventAttributes[attribute.key] = String(Object.values(attribute.value)[0]);
|
|
47
77
|
}
|
|
78
|
+
if ((scope === null || scope === void 0 ? void 0 : scope.name) === '@opentelemetry/instrumentation-fetch') {
|
|
79
|
+
projectFetchEventAttributes(faroEventAttributes);
|
|
80
|
+
}
|
|
48
81
|
// Add span duration in nanoseconds
|
|
49
82
|
if (!Number.isNaN(span.endTimeUnixNano) && !Number.isNaN(span.startTimeUnixNano)) {
|
|
50
83
|
faroEventAttributes[DURATION_NS_KEY] = String(Number(span.endTimeUnixNano) - Number(span.startTimeUnixNano));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"faroTraceExporter.utils.js","sourceRoot":"","sources":["../../../src/exporters/faroTraceExporter.utils.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"faroTraceExporter.utils.js","sourceRoot":"","sources":["../../../src/exporters/faroTraceExporter.utils.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SpanContext } from '@opentelemetry/api';\nimport { ESpanKind, type IResourceSpans } from '@opentelemetry/otlp-transformer/build/src/trace/internal-types';\n\nimport { createInternalLogger, faro, unknownString } from '@grafana/faro-core';\nimport type { EventAttributes as FaroEventAttributes } from '@grafana/faro-core';\n\nconst internalLogger = createInternalLogger();\n\nconst DURATION_NS_KEY = 'duration_ns';\n/** Map stable OTel span attributes to Faro's fetch event contract. */\nfunction projectFetchEventAttributes(attributes: FaroEventAttributes): void {\n const fields = {\n 'http.request.method': 'http.method',\n 'url.full': 'http.url',\n 'http.response.status_code': 'http.status_code',\n };\n for (const [spanField, eventField] of Object.entries(fields)) {\n if (attributes[spanField] != null) {\n attributes[eventField] = attributes[spanField];\n delete attributes[spanField];\n }\n }\n\n const url = attributes['http.url'];\n if (url) {\n try {\n const parsed = new URL(url);\n attributes['http.host'] = attributes['http.host'] ?? parsed.host;\n attributes['http.scheme'] = attributes['http.scheme'] ?? parsed.protocol.replace(':', '');\n } catch {\n // Keep the captured URL even if it cannot supply host/scheme metadata.\n }\n }\n delete attributes['server.address'];\n delete attributes['server.port'];\n attributes['component'] = attributes['component'] ?? 'fetch';\n}\n\n/**\n * Send Faro events for CLIENT spans (HTTP requests, navigation, etc.)\n *\n * IMPORTANT: This function is called during trace export and must be careful to avoid infinite loops.\n *\n * Infinite loop prevention strategy:\n * 1. Only process SPAN_KIND_CLIENT spans (HTTP requests, etc.)\n * 2. Use faro.api.pushEvent which:\n * - Does NOT trigger console logs if ConsoleInstrumentation is configured properly\n * - Does NOT trigger HTTP instrumentation for collector URLs (they're ignored)\n * 3. Use internalLogger for debugging instead of console\n * 4. Never call console.log/warn/error in this function\n *\n * @param resourceSpans - OTLP resource spans from trace exporter\n */\nexport function sendFaroEvents(resourceSpans: IResourceSpans[] = []) {\n try {\n for (const resourceSpan of resourceSpans) {\n const { scopeSpans } = resourceSpan;\n\n for (const scopeSpan of scopeSpans) {\n const { scope, spans = [] } = scopeSpan;\n\n for (const span of spans) {\n // Only process CLIENT spans (HTTP requests, external calls)\n // This avoids processing internal spans which could cause loops\n if (span.kind !== ESpanKind.SPAN_KIND_CLIENT) {\n continue;\n }\n\n const spanContext: Pick<SpanContext, 'traceId' | 'spanId'> = {\n traceId: span.traceId.toString(),\n spanId: span.spanId.toString(),\n };\n\n const faroEventAttributes: FaroEventAttributes = {};\n for (const attribute of span.attributes) {\n faroEventAttributes[attribute.key] = String(Object.values(attribute.value)[0]);\n }\n\n if (scope?.name === '@opentelemetry/instrumentation-fetch') {\n projectFetchEventAttributes(faroEventAttributes);\n }\n\n // Add span duration in nanoseconds\n if (!Number.isNaN(span.endTimeUnixNano) && !Number.isNaN(span.startTimeUnixNano)) {\n faroEventAttributes[DURATION_NS_KEY] = String(\n Number(span.endTimeUnixNano) - Number(span.startTimeUnixNano)\n );\n }\n\n const index = (scope?.name ?? '').indexOf('-');\n let eventName = unknownString;\n\n if (scope?.name) {\n if (index === -1) {\n eventName = scope.name.split('/')[1] ?? scope.name;\n }\n\n if (index > -1) {\n eventName = scope?.name.substring(index + 1);\n }\n }\n\n // Push event to Faro\n // This should NOT cause infinite loops because:\n // 1. The collector URL is in ignoreUrls for HttpInstrumentation\n // 2. ConsoleInstrumentation won't log this event\n // 3. No console.log calls are made here\n faro.api.pushEvent(`faro.tracing.${eventName}`, faroEventAttributes, undefined, {\n spanContext,\n // Convert nanoseconds to milliseconds\n timestampOverwriteMs: Number(span.endTimeUnixNano) / 1_000_000,\n customPayloadTransformer: (payload) => {\n if (\n faroEventAttributes['faro.action.user.name'] != null &&\n faroEventAttributes['faro.action.user.parentId'] != null\n ) {\n payload.action = {\n name: faroEventAttributes['faro.action.user.name'],\n parentId: faroEventAttributes['faro.action.user.parentId'],\n };\n\n delete payload.attributes?.['faro.action.user.name'];\n delete payload.attributes?.['faro.action.user.parentId'];\n }\n\n return payload;\n },\n });\n }\n }\n }\n } catch (error) {\n // Only log critical errors using internal logger\n // Do NOT use console.log here as it could cause infinite loops\n internalLogger.error('sendFaroEvents: Failed to process spans', error);\n }\n}\n"]}
|
|
@@ -76,8 +76,34 @@ var faroMetaAttributesSpanProcessor_1 = require("./processors/faroMetaAttributes
|
|
|
76
76
|
var httpRequestMonitorSpanProcessor_1 = require("./processors/httpRequestMonitorSpanProcessor");
|
|
77
77
|
var semconv_1 = require("./semconv");
|
|
78
78
|
var sampler_1 = require("./utils/sampler");
|
|
79
|
-
|
|
80
|
-
|
|
79
|
+
var detachedInstrumentations = new WeakSet();
|
|
80
|
+
/**
|
|
81
|
+
* Keeps a caller-supplied processor reusable across Faro remove/add cycles.
|
|
82
|
+
* Explicit TracingInstrumentation.shutdown() remains responsible for the
|
|
83
|
+
* processor's terminal shutdown.
|
|
84
|
+
*/
|
|
85
|
+
var BorrowedSpanProcessor = /** @class */ (function () {
|
|
86
|
+
function BorrowedSpanProcessor(processor) {
|
|
87
|
+
this.processor = processor;
|
|
88
|
+
}
|
|
89
|
+
BorrowedSpanProcessor.prototype.forceFlush = function () {
|
|
90
|
+
return this.processor.forceFlush();
|
|
91
|
+
};
|
|
92
|
+
BorrowedSpanProcessor.prototype.onStart = function (span, parentContext) {
|
|
93
|
+
this.processor.onStart(span, parentContext);
|
|
94
|
+
};
|
|
95
|
+
BorrowedSpanProcessor.prototype.onEnding = function (span) {
|
|
96
|
+
var _a, _b;
|
|
97
|
+
(_b = (_a = this.processor).onEnding) === null || _b === void 0 ? void 0 : _b.call(_a, span);
|
|
98
|
+
};
|
|
99
|
+
BorrowedSpanProcessor.prototype.onEnd = function (span) {
|
|
100
|
+
this.processor.onEnd(span);
|
|
101
|
+
};
|
|
102
|
+
BorrowedSpanProcessor.prototype.shutdown = function () {
|
|
103
|
+
return Promise.resolve();
|
|
104
|
+
};
|
|
105
|
+
return BorrowedSpanProcessor;
|
|
106
|
+
}());
|
|
81
107
|
/**
|
|
82
108
|
* TracingInstrumentation for React Native
|
|
83
109
|
*
|
|
@@ -112,11 +138,13 @@ var TracingInstrumentation = /** @class */ (function (_super) {
|
|
|
112
138
|
_this.options = options;
|
|
113
139
|
_this.name = '@grafana/faro-react-native-tracing';
|
|
114
140
|
_this.version = faro_core_1.VERSION;
|
|
141
|
+
_this.pendingShutdowns = new Set();
|
|
115
142
|
return _this;
|
|
116
143
|
}
|
|
117
144
|
TracingInstrumentation.prototype.initialize = function () {
|
|
118
145
|
var _this = this;
|
|
119
|
-
var _a, _b, _c, _d, _e
|
|
146
|
+
var _a, _b, _c, _d, _e;
|
|
147
|
+
this.destroy();
|
|
120
148
|
var options = this.options;
|
|
121
149
|
var attributes = {};
|
|
122
150
|
// App attributes
|
|
@@ -165,7 +193,7 @@ var TracingInstrumentation = /** @class */ (function (_super) {
|
|
|
165
193
|
Object.assign(attributes, options.resourceAttributes);
|
|
166
194
|
var resource = (0, resources_1.defaultResource)().merge((0, resources_1.resourceFromAttributes)(attributes));
|
|
167
195
|
// Create tracer provider with span processors
|
|
168
|
-
|
|
196
|
+
var provider = new sdk_trace_base_1.BasicTracerProvider({
|
|
169
197
|
resource: resource,
|
|
170
198
|
sampler: {
|
|
171
199
|
shouldSample: function () {
|
|
@@ -175,51 +203,90 @@ var TracingInstrumentation = /** @class */ (function (_super) {
|
|
|
175
203
|
},
|
|
176
204
|
},
|
|
177
205
|
spanProcessors: [
|
|
178
|
-
(_b = options.spanProcessor) !== null && _b !== void 0 ? _b : new httpRequestMonitorSpanProcessor_1.HttpRequestMonitorSpanProcessor(new faroMetaAttributesSpanProcessor_1.FaroMetaAttributesSpanProcessor(new sdk_trace_base_1.BatchSpanProcessor(new faroTraceExporter_1.FaroTraceExporter({ api: this.api }), {
|
|
206
|
+
(_b = (options.spanProcessor && new BorrowedSpanProcessor(options.spanProcessor))) !== null && _b !== void 0 ? _b : new httpRequestMonitorSpanProcessor_1.HttpRequestMonitorSpanProcessor(new faroMetaAttributesSpanProcessor_1.FaroMetaAttributesSpanProcessor(new sdk_trace_base_1.BatchSpanProcessor(new faroTraceExporter_1.FaroTraceExporter({ api: this.api }), {
|
|
179
207
|
scheduledDelayMillis: TracingInstrumentation.SCHEDULED_BATCH_DELAY_MS,
|
|
180
208
|
maxExportBatchSize: 30,
|
|
181
209
|
}), this.metas)),
|
|
182
210
|
],
|
|
183
211
|
});
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
212
|
+
var registration = {
|
|
213
|
+
instrumentations: [],
|
|
214
|
+
ownsContextManager: false,
|
|
215
|
+
ownsContextManagerInstance: false,
|
|
216
|
+
ownsPropagator: false,
|
|
217
|
+
ownsTracerProvider: false,
|
|
218
|
+
provider: provider,
|
|
219
|
+
};
|
|
220
|
+
this.activeRegistration = registration;
|
|
221
|
+
try {
|
|
222
|
+
// Register the provider as the global tracer provider
|
|
223
|
+
// This is CRITICAL for the tracer to generate real trace IDs instead of all zeros
|
|
224
|
+
if (!api_1.trace.setGlobalTracerProvider(provider)) {
|
|
225
|
+
throw new Error('Unable to register the Faro OpenTelemetry tracer provider. Remove the existing global tracer provider before initializing Faro tracing.');
|
|
226
|
+
}
|
|
227
|
+
registration.ownsTracerProvider = true;
|
|
228
|
+
// Register a global ContextManager. Without one, OTel falls back to the NoopContextManager,
|
|
229
|
+
// which always returns ROOT_CONTEXT — so when `@opentelemetry/instrumentation-fetch` does
|
|
230
|
+
// `context.with(setSpan(active(), createdSpan), () => _addHeaders(...))` the span set on the
|
|
231
|
+
// wrapped context is invisible inside `_addHeaders` and `propagation.inject` writes nothing.
|
|
232
|
+
// `StackContextManager` is pure JS (no DOM/Zone deps) and works in React Native.
|
|
233
|
+
var contextManager = ((_c = options.contextManager) !== null && _c !== void 0 ? _c : new sdk_trace_web_1.StackContextManager()).enable();
|
|
234
|
+
registration.contextManager = contextManager;
|
|
235
|
+
registration.ownsContextManagerInstance = options.contextManager == null;
|
|
236
|
+
registration.ownsContextManager = api_1.context.setGlobalContextManager(contextManager);
|
|
237
|
+
// Register the global text-map propagator. Without this, OTel falls back to a
|
|
238
|
+
// NoopTextMapPropagator and `propagation.inject(...)` becomes a no-op, meaning
|
|
239
|
+
// `traceparent` / `tracestate` (and `baggage`) headers are never written on the
|
|
240
|
+
// outbound fetch/XHR — so the backend receives no context and starts a new trace.
|
|
241
|
+
registration.ownsPropagator = api_1.propagation.setGlobalPropagator((_d = options.propagator) !== null && _d !== void 0 ? _d : new core_1.CompositePropagator({
|
|
242
|
+
propagators: [new core_1.W3CTraceContextPropagator(), new core_1.W3CBaggagePropagator()],
|
|
243
|
+
}));
|
|
244
|
+
var _f = (_e = this.options.instrumentationOptions) !== null && _e !== void 0 ? _e : {}, enableFetchInstrumentation = _f.enableFetchInstrumentation, enableXhrInstrumentation = _f.enableXhrInstrumentation, propagateTraceHeaderCorsUrls = _f.propagateTraceHeaderCorsUrls, fetchInstrumentationOptions = _f.fetchInstrumentationOptions, xhrInstrumentationOptions = _f.xhrInstrumentationOptions;
|
|
245
|
+
// Get ignore URLs from transports to prevent infinite loops
|
|
246
|
+
var ignoreUrls = this.getIgnoreUrls();
|
|
247
|
+
var defaultInstrumentationOptions = {
|
|
206
248
|
ignoreUrls: ignoreUrls,
|
|
207
249
|
enableFetchInstrumentation: enableFetchInstrumentation,
|
|
208
250
|
enableXhrInstrumentation: enableXhrInstrumentation,
|
|
209
251
|
propagateTraceHeaderCorsUrls: propagateTraceHeaderCorsUrls,
|
|
210
252
|
fetchInstrumentationOptions: fetchInstrumentationOptions,
|
|
211
253
|
xhrInstrumentationOptions: xhrInstrumentationOptions,
|
|
212
|
-
}),
|
|
213
|
-
});
|
|
214
|
-
// Expose OTEL API on the global Faro instance for manual span creation
|
|
215
|
-
// This allows users to access trace and context APIs via faro.otel
|
|
216
|
-
var globalFaroInstance = (0, faro_core_1.getInternalFaroFromGlobalObject)();
|
|
217
|
-
if (globalFaroInstance) {
|
|
218
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Extending Faro instance with OTEL API
|
|
219
|
-
globalFaroInstance.otel = {
|
|
220
|
-
trace: api_1.trace,
|
|
221
|
-
context: api_1.context,
|
|
222
254
|
};
|
|
255
|
+
if (options.instrumentations) {
|
|
256
|
+
registration.instrumentations = options.instrumentations.flat();
|
|
257
|
+
}
|
|
258
|
+
else if (this.defaultInstrumentations) {
|
|
259
|
+
(0, getDefaultOTELInstrumentations_1.updateDefaultOTELInstrumentations)(this.defaultInstrumentations, defaultInstrumentationOptions);
|
|
260
|
+
registration.instrumentations = this.defaultInstrumentations;
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
this.defaultInstrumentations = (0, getDefaultOTELInstrumentations_1.getDefaultOTELInstrumentations)(defaultInstrumentationOptions).flat();
|
|
264
|
+
registration.instrumentations = this.defaultInstrumentations;
|
|
265
|
+
}
|
|
266
|
+
var instrumentationsNeedingExplicitEnable = registration.instrumentations.filter(function (instrumentation) {
|
|
267
|
+
return detachedInstrumentations.has(instrumentation) && instrumentation.getConfig().enabled === true;
|
|
268
|
+
});
|
|
269
|
+
registration.unregisterInstrumentations = (0, instrumentation_1.registerInstrumentations)({
|
|
270
|
+
instrumentations: registration.instrumentations,
|
|
271
|
+
});
|
|
272
|
+
registration.instrumentations.forEach(function (instrumentation) {
|
|
273
|
+
detachedInstrumentations.delete(instrumentation);
|
|
274
|
+
});
|
|
275
|
+
instrumentationsNeedingExplicitEnable.forEach(function (instrumentation) { return instrumentation.enable(); });
|
|
276
|
+
// Expose OTEL API on the global Faro instance for manual span creation
|
|
277
|
+
// This allows users to access trace and context APIs via faro.otel
|
|
278
|
+
var globalFaroInstance = (0, faro_core_1.getInternalFaroFromGlobalObject)();
|
|
279
|
+
if (globalFaroInstance) {
|
|
280
|
+
var faroOtel = { trace: api_1.trace, context: api_1.context };
|
|
281
|
+
registration.faro = globalFaroInstance;
|
|
282
|
+
registration.faroOtel = faroOtel;
|
|
283
|
+
registration.previousFaroOtel = globalFaroInstance.otel;
|
|
284
|
+
globalFaroInstance.otel = faroOtel;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
catch (error) {
|
|
288
|
+
this.destroy();
|
|
289
|
+
throw error;
|
|
223
290
|
}
|
|
224
291
|
};
|
|
225
292
|
/**
|
|
@@ -244,24 +311,172 @@ var TracingInstrumentation = /** @class */ (function (_super) {
|
|
|
244
311
|
// Return dev-server, original transport URLs, and regex patterns for maximum coverage.
|
|
245
312
|
return __spreadArray(__spreadArray(__spreadArray([], (0, devServerIgnoreUrls_1.getReactNativeDevServerIgnoreUrls)(), true), transportUrls, true), regexPatterns, true);
|
|
246
313
|
};
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
314
|
+
TracingInstrumentation.prototype.detachRegistration = function () {
|
|
315
|
+
var _this = this;
|
|
316
|
+
var registration = this.activeRegistration;
|
|
317
|
+
if (!registration) {
|
|
318
|
+
return undefined;
|
|
319
|
+
}
|
|
320
|
+
this.activeRegistration = undefined;
|
|
321
|
+
registration.instrumentations.forEach(function (instrumentation) { return detachedInstrumentations.add(instrumentation); });
|
|
322
|
+
var unregistered = false;
|
|
323
|
+
if (registration.unregisterInstrumentations) {
|
|
324
|
+
try {
|
|
325
|
+
registration.unregisterInstrumentations();
|
|
326
|
+
unregistered = true;
|
|
327
|
+
}
|
|
328
|
+
catch (error) {
|
|
329
|
+
this.logCleanupError('unregister OpenTelemetry instrumentations', error);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
if (!unregistered) {
|
|
333
|
+
registration.instrumentations.forEach(function (instrumentation) {
|
|
334
|
+
_this.runCleanup("disable ".concat(instrumentation.instrumentationName), function () { return instrumentation.disable(); });
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
var faro = registration.faro, faroOtel = registration.faroOtel;
|
|
338
|
+
if (faro && faroOtel && faro.otel === faroOtel) {
|
|
339
|
+
this.runCleanup('restore faro.otel', function () {
|
|
340
|
+
if (registration.previousFaroOtel === undefined) {
|
|
341
|
+
delete faro.otel;
|
|
342
|
+
}
|
|
343
|
+
else {
|
|
344
|
+
faro.otel = registration.previousFaroOtel;
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
if (registration.ownsPropagator) {
|
|
349
|
+
this.runCleanup('clear the OpenTelemetry propagator', function () { return api_1.propagation.disable(); });
|
|
350
|
+
}
|
|
351
|
+
if (registration.ownsContextManager) {
|
|
352
|
+
this.runCleanup('clear the OpenTelemetry context manager', function () { return api_1.context.disable(); });
|
|
353
|
+
}
|
|
354
|
+
else if (registration.ownsContextManagerInstance && registration.contextManager) {
|
|
355
|
+
this.runCleanup('disable the unused OpenTelemetry context manager', function () { var _a; return (_a = registration.contextManager) === null || _a === void 0 ? void 0 : _a.disable(); });
|
|
356
|
+
}
|
|
357
|
+
if (registration.ownsTracerProvider) {
|
|
358
|
+
this.runCleanup('clear the OpenTelemetry tracer provider', function () { return api_1.trace.disable(); });
|
|
359
|
+
}
|
|
360
|
+
return registration;
|
|
361
|
+
};
|
|
362
|
+
TracingInstrumentation.prototype.runCleanup = function (action, cleanup) {
|
|
363
|
+
try {
|
|
364
|
+
cleanup();
|
|
365
|
+
}
|
|
366
|
+
catch (error) {
|
|
367
|
+
this.logCleanupError(action, error);
|
|
368
|
+
}
|
|
369
|
+
};
|
|
370
|
+
TracingInstrumentation.prototype.logCleanupError = function (action, error) {
|
|
371
|
+
try {
|
|
372
|
+
this.logError("Failed to ".concat(action, ":"), error);
|
|
373
|
+
}
|
|
374
|
+
catch (_loggingError) {
|
|
375
|
+
// Cleanup must not fail because a custom logger threw.
|
|
376
|
+
}
|
|
377
|
+
};
|
|
378
|
+
TracingInstrumentation.prototype.startProviderShutdown = function (registration) {
|
|
379
|
+
var _this = this;
|
|
380
|
+
if (!registration.shutdownPromise) {
|
|
381
|
+
var shutdownPromise_1 = Promise.resolve()
|
|
382
|
+
.then(function () { return registration.provider.forceFlush(); })
|
|
383
|
+
.catch(function (error) {
|
|
384
|
+
_this.logCleanupError('flush the OpenTelemetry tracer provider', error);
|
|
385
|
+
})
|
|
386
|
+
.then(function () { return registration.provider.shutdown(); });
|
|
387
|
+
registration.shutdownPromise = shutdownPromise_1;
|
|
388
|
+
this.pendingShutdowns.add(shutdownPromise_1);
|
|
389
|
+
void shutdownPromise_1.then(function () { return _this.pendingShutdowns.delete(shutdownPromise_1); }, function () { return _this.pendingShutdowns.delete(shutdownPromise_1); });
|
|
390
|
+
}
|
|
391
|
+
return registration.shutdownPromise;
|
|
392
|
+
};
|
|
393
|
+
TracingInstrumentation.prototype.startSuppliedSpanProcessorShutdown = function () {
|
|
394
|
+
var spanProcessor = this.options.spanProcessor;
|
|
395
|
+
if (!spanProcessor) {
|
|
396
|
+
return undefined;
|
|
397
|
+
}
|
|
398
|
+
if (!this.suppliedSpanProcessorShutdown) {
|
|
399
|
+
try {
|
|
400
|
+
this.suppliedSpanProcessorShutdown = spanProcessor.shutdown();
|
|
401
|
+
}
|
|
402
|
+
catch (error) {
|
|
403
|
+
this.suppliedSpanProcessorShutdown = Promise.reject(error);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
return this.suppliedSpanProcessorShutdown;
|
|
407
|
+
};
|
|
408
|
+
/** Detach request instrumentations and wait for the tracer provider to flush. */
|
|
250
409
|
TracingInstrumentation.prototype.shutdown = function () {
|
|
251
410
|
return __awaiter(this, void 0, void 0, function () {
|
|
411
|
+
var pendingShutdowns, registration, firstError, shutdownFailed, _i, pendingShutdowns_1, shutdownPromise, error_1, spanProcessorShutdown, error_2;
|
|
252
412
|
return __generator(this, function (_a) {
|
|
253
413
|
switch (_a.label) {
|
|
254
414
|
case 0:
|
|
255
|
-
|
|
256
|
-
|
|
415
|
+
pendingShutdowns = Array.from(this.pendingShutdowns);
|
|
416
|
+
registration = this.detachRegistration();
|
|
417
|
+
if (registration) {
|
|
418
|
+
pendingShutdowns.push(this.startProviderShutdown(registration));
|
|
419
|
+
}
|
|
420
|
+
shutdownFailed = false;
|
|
421
|
+
_i = 0, pendingShutdowns_1 = pendingShutdowns;
|
|
422
|
+
_a.label = 1;
|
|
257
423
|
case 1:
|
|
258
|
-
|
|
424
|
+
if (!(_i < pendingShutdowns_1.length)) return [3 /*break*/, 6];
|
|
425
|
+
shutdownPromise = pendingShutdowns_1[_i];
|
|
259
426
|
_a.label = 2;
|
|
260
|
-
case 2:
|
|
427
|
+
case 2:
|
|
428
|
+
_a.trys.push([2, 4, , 5]);
|
|
429
|
+
return [4 /*yield*/, shutdownPromise];
|
|
430
|
+
case 3:
|
|
431
|
+
_a.sent();
|
|
432
|
+
return [3 /*break*/, 5];
|
|
433
|
+
case 4:
|
|
434
|
+
error_1 = _a.sent();
|
|
435
|
+
if (!shutdownFailed) {
|
|
436
|
+
firstError = error_1;
|
|
437
|
+
shutdownFailed = true;
|
|
438
|
+
}
|
|
439
|
+
return [3 /*break*/, 5];
|
|
440
|
+
case 5:
|
|
441
|
+
_i++;
|
|
442
|
+
return [3 /*break*/, 1];
|
|
443
|
+
case 6:
|
|
444
|
+
spanProcessorShutdown = this.startSuppliedSpanProcessorShutdown();
|
|
445
|
+
if (!spanProcessorShutdown) return [3 /*break*/, 10];
|
|
446
|
+
_a.label = 7;
|
|
447
|
+
case 7:
|
|
448
|
+
_a.trys.push([7, 9, , 10]);
|
|
449
|
+
return [4 /*yield*/, spanProcessorShutdown];
|
|
450
|
+
case 8:
|
|
451
|
+
_a.sent();
|
|
452
|
+
return [3 /*break*/, 10];
|
|
453
|
+
case 9:
|
|
454
|
+
error_2 = _a.sent();
|
|
455
|
+
if (!shutdownFailed) {
|
|
456
|
+
firstError = error_2;
|
|
457
|
+
shutdownFailed = true;
|
|
458
|
+
}
|
|
459
|
+
return [3 /*break*/, 10];
|
|
460
|
+
case 10:
|
|
461
|
+
if (shutdownFailed) {
|
|
462
|
+
throw firstError;
|
|
463
|
+
}
|
|
464
|
+
return [2 /*return*/];
|
|
261
465
|
}
|
|
262
466
|
});
|
|
263
467
|
});
|
|
264
468
|
};
|
|
469
|
+
/** Detach synchronously when Faro removes this instrumentation. */
|
|
470
|
+
TracingInstrumentation.prototype.destroy = function () {
|
|
471
|
+
var _this = this;
|
|
472
|
+
var registration = this.detachRegistration();
|
|
473
|
+
if (!registration) {
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
void this.startProviderShutdown(registration).then(undefined, function (error) {
|
|
477
|
+
_this.logCleanupError('shut down the OpenTelemetry tracer provider', error);
|
|
478
|
+
});
|
|
479
|
+
};
|
|
265
480
|
TracingInstrumentation.SCHEDULED_BATCH_DELAY_MS = 1000;
|
|
266
481
|
return TracingInstrumentation;
|
|
267
482
|
}(faro_core_1.BaseInstrumentation));
|
|
@@ -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"]}
|