-
Notifications
You must be signed in to change notification settings - Fork 1.3k
/
useTracer.ts
120 lines (109 loc) · 4.16 KB
/
useTracer.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
import {
CompositePropagator,
W3CBaggagePropagator,
W3CTraceContextPropagator,
} from "@opentelemetry/core";
import { WebTracerProvider } from "@opentelemetry/sdk-trace-web";
import {
BatchSpanProcessor,
SimpleSpanProcessor,
ConsoleSpanExporter,
} from "@opentelemetry/sdk-trace-base";
import { XMLHttpRequestInstrumentation } from "@opentelemetry/instrumentation-xml-http-request";
import { FetchInstrumentation } from "@opentelemetry/instrumentation-fetch";
import { registerInstrumentations } from "@opentelemetry/instrumentation";
import { Resource } from "@opentelemetry/resources";
import {
ATTR_DEVICE_ID,
ATTR_OS_NAME,
ATTR_OS_VERSION,
ATTR_SERVICE_NAME,
ATTR_SERVICE_VERSION,
} from "@opentelemetry/semantic-conventions/incubating";
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
import getLocalhost from "@/utils/Localhost";
import { useEffect, useState } from "react";
import {
getDeviceId,
getSystemVersion,
getVersion,
} from "react-native-device-info";
import { Platform } from "react-native";
import { SessionIdProcessor } from "@/utils/SessionIdProcessor";
const Tracer = async () => {
const localhost = await getLocalhost();
// TODO Should add a resource detector for React Native that provides this automatically
const resource = new Resource({
[ATTR_SERVICE_NAME]: "reactnativeapp",
[ATTR_OS_NAME]: Platform.OS,
[ATTR_OS_VERSION]: getSystemVersion(),
[ATTR_SERVICE_VERSION]: getVersion(),
[ATTR_DEVICE_ID]: getDeviceId(),
});
// TODO Not obvious that the WebTracerProvider can be used for React Native, might be useful to have a thin
// ReactNativeTracerProvider on top of it (or BasicTracerProvider) that makes this clear. Could also add some
// protection against browser specific functionality being added to WebTracerProvider that breaks functionality
// for React Native.
// Alternatively could offer a TracerProvider that exposed a JS interface on top of the OTEL Android and Swift SDKS,
// giving developers the option of collecting telemetry at the native mobile layer
const provider = new WebTracerProvider({
resource,
spanProcessors: [
new BatchSpanProcessor(
new OTLPTraceExporter({
url: `http://${localhost}:${process.env.EXPO_PUBLIC_FRONTEND_PROXY_PORT}/otlp-http/v1/traces`,
}),
{
scheduledDelayMillis: 500,
},
),
// TODO introduce a React Native session processor package that could be used here, taking into account mobile
// specific considerations for the session such as putting the app into the background
new SessionIdProcessor(),
// Helpful for debugging
new SimpleSpanProcessor(new ConsoleSpanExporter()),
],
});
provider.register({
propagator: new CompositePropagator({
propagators: [
new W3CBaggagePropagator(),
new W3CTraceContextPropagator(),
],
}),
});
registerInstrumentations({
instrumentations: [
new XMLHttpRequestInstrumentation(),
// TODO Some tiptoeing required here, propagateTraceHeaderCorsUrls is required to make the instrumentation
// work in the context of a mobile app even though we are not making CORS requests. `clearTimingResources` must
// be turned off to avoid using the web-only Performance API
// Overall wrapping or forking this and providing a React Native specific auto instrumentation will ease
// integration and make it less error-prone
new FetchInstrumentation({
propagateTraceHeaderCorsUrls: /.*/,
clearTimingResources: false,
}),
],
});
};
export interface TracerResult {
loaded: boolean;
}
// TODO providing a wrapper similar to this that uses hooks over the full JS OTEL API would be nice to have for both
// React Native and React development
export const useTracer = (): TracerResult => {
const [loaded, setLoaded] = useState<boolean>(false);
useEffect(() => {
if (!loaded) {
Tracer()
.catch(() => console.warn("failed to setup tracer"))
.finally(() => setLoaded(true));
}
}, [loaded]);
return {
loaded,
};
};