@coralogix/react-native-plugin 0.1.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/CHANGELOG.md +17 -0
- package/CxSdk.podspec +45 -0
- package/LICENSE +201 -0
- package/README.md +187 -0
- package/android/build.gradle +87 -0
- package/android/gradle.properties +5 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/com/cxsdk/CxSdkModule.kt +457 -0
- package/android/src/main/java/com/cxsdk/CxSdkPackage.kt +16 -0
- package/android/src/main/java/com/cxsdk/ICxSdkModule.kt +24 -0
- package/index.cjs.js +682 -0
- package/index.d.ts +1 -0
- package/index.esm.js +678 -0
- package/ios/CxSdk-Bridging-Header.h +2 -0
- package/ios/CxSdk.mm +81 -0
- package/ios/CxSdk.swift +371 -0
- package/package.json +34 -0
- package/src/CoralogixPropgator.d.ts +2 -0
- package/src/consts.d.ts +23 -0
- package/src/index.d.ts +10 -0
- package/src/instrumentations/error/ErrorInstrumentation.d.ts +18 -0
- package/src/instrumentations/error/error.consts.d.ts +7 -0
- package/src/instrumentations/error/error.enums.d.ts +4 -0
- package/src/instrumentations/mobile-vitals/JsRefreshRateSamplerInstrumentation.d.ts +8 -0
- package/src/instrumentations/mobile-vitals/loopDetectorInstrumentation.d.ts +16 -0
- package/src/instrumentations/network/FetchInstrumentation.d.ts +5 -0
- package/src/instrumentations/network/network.enums.d.ts +10 -0
- package/src/logger.d.ts +16 -0
- package/src/model/ApplicationContextConfig.d.ts +4 -0
- package/src/model/CoralogixDomain.d.ts +10 -0
- package/src/model/CoralogixOtelWebOptionsInstrumentations.d.ts +9 -0
- package/src/model/CoralogixOtelWebType.d.ts +49 -0
- package/src/model/CoralogixRumLabels.d.ts +1 -0
- package/src/model/CustomMeasurement.d.ts +4 -0
- package/src/model/NetworkRequestDetails.d.ts +14 -0
- package/src/model/SendLog.d.ts +10 -0
- package/src/model/Types.d.ts +209 -0
- package/src/model/UserContextConfig.d.ts +8 -0
- package/src/model/ViewContextConfig.d.ts +3 -0
- package/src/utils.d.ts +5 -0
package/index.esm.js
ADDED
|
@@ -0,0 +1,678 @@
|
|
|
1
|
+
import { AppState, Platform, NativeModules, NativeEventEmitter } from 'react-native';
|
|
2
|
+
import { FetchInstrumentation } from '@opentelemetry/instrumentation-fetch';
|
|
3
|
+
import { InstrumentationBase, registerInstrumentations } from '@opentelemetry/instrumentation';
|
|
4
|
+
import { WebTracerProvider } from '@opentelemetry/sdk-trace-web';
|
|
5
|
+
|
|
6
|
+
function _extends() {
|
|
7
|
+
return _extends = Object.assign ? Object.assign.bind() : function (n) {
|
|
8
|
+
for (var e = 1; e < arguments.length; e++) {
|
|
9
|
+
var t = arguments[e];
|
|
10
|
+
for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]);
|
|
11
|
+
}
|
|
12
|
+
return n;
|
|
13
|
+
}, _extends.apply(null, arguments);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
let CoralogixLogSeverity = /*#__PURE__*/function (CoralogixLogSeverity) {
|
|
17
|
+
CoralogixLogSeverity[CoralogixLogSeverity["Debug"] = 1] = "Debug";
|
|
18
|
+
CoralogixLogSeverity[CoralogixLogSeverity["Verbose"] = 2] = "Verbose";
|
|
19
|
+
CoralogixLogSeverity[CoralogixLogSeverity["Info"] = 3] = "Info";
|
|
20
|
+
CoralogixLogSeverity[CoralogixLogSeverity["Warn"] = 4] = "Warn";
|
|
21
|
+
CoralogixLogSeverity[CoralogixLogSeverity["Error"] = 5] = "Error";
|
|
22
|
+
CoralogixLogSeverity[CoralogixLogSeverity["Critical"] = 6] = "Critical";
|
|
23
|
+
return CoralogixLogSeverity;
|
|
24
|
+
}({});
|
|
25
|
+
|
|
26
|
+
let ErrorSource = /*#__PURE__*/function (ErrorSource) {
|
|
27
|
+
ErrorSource["CONSOLE"] = "console";
|
|
28
|
+
ErrorSource["GLOBAL"] = "global";
|
|
29
|
+
return ErrorSource;
|
|
30
|
+
}({});
|
|
31
|
+
|
|
32
|
+
const ERROR_INSTRUMENTATION_NAME = 'errors';
|
|
33
|
+
const ERROR_INSTRUMENTATION_VERSION = '1';
|
|
34
|
+
|
|
35
|
+
let defaultConsoleError = (..._params) => {};
|
|
36
|
+
const MESSAGE_LIMIT = 1024;
|
|
37
|
+
const getCircularReplacer = () => {
|
|
38
|
+
const seen = new WeakSet();
|
|
39
|
+
return (_key, value) => {
|
|
40
|
+
if (typeof value === 'object' && value !== null) {
|
|
41
|
+
if (seen.has(value)) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
seen.add(value);
|
|
45
|
+
}
|
|
46
|
+
return value;
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
class CoralogixErrorInstrumentation extends InstrumentationBase {
|
|
50
|
+
constructor(config) {
|
|
51
|
+
super(ERROR_INSTRUMENTATION_NAME, ERROR_INSTRUMENTATION_VERSION, config);
|
|
52
|
+
this.parseErrorObject = obj => {
|
|
53
|
+
var _obj$message;
|
|
54
|
+
return (_obj$message = obj == null ? void 0 : obj.message) != null ? _obj$message : JSON.stringify(obj, getCircularReplacer());
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
init() {}
|
|
58
|
+
listenToConsoleError() {
|
|
59
|
+
const onConsoleError = (...params) => {
|
|
60
|
+
defaultConsoleError.apply(console, params);
|
|
61
|
+
this.report(ErrorSource.CONSOLE, params);
|
|
62
|
+
};
|
|
63
|
+
defaultConsoleError = console.error;
|
|
64
|
+
console.error = onConsoleError;
|
|
65
|
+
}
|
|
66
|
+
report(source, arg) {
|
|
67
|
+
if (Array.isArray(arg)) {
|
|
68
|
+
if (arg.length === 0) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (arg instanceof Error) {
|
|
73
|
+
this.reportError(arg);
|
|
74
|
+
} else if (typeof arg === 'string') {
|
|
75
|
+
this.reportString(arg);
|
|
76
|
+
} else if (Array.isArray(arg)) {
|
|
77
|
+
// if any arguments are Errors then add the stack trace even though the message is handled differently
|
|
78
|
+
const firstError = arg.find(x => x instanceof Error);
|
|
79
|
+
const message = arg.map(msg => typeof msg === 'string' ? msg : this.parseErrorObject(msg)).join(' ');
|
|
80
|
+
this.reportString(message, firstError);
|
|
81
|
+
} else {
|
|
82
|
+
this.reportString(typeof arg === 'string' ? arg : this.getPossibleEventMessage(arg));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
reportError(err) {
|
|
86
|
+
CoralogixRum.reportError(err, false);
|
|
87
|
+
}
|
|
88
|
+
reportString(message, firstError) {
|
|
89
|
+
const truncatedMessage = (message == null ? void 0 : message.substring(0, MESSAGE_LIMIT)) || '';
|
|
90
|
+
CoralogixRum.reportError({
|
|
91
|
+
name: (firstError == null ? void 0 : firstError.name) || 'CONSOLE',
|
|
92
|
+
message: truncatedMessage,
|
|
93
|
+
stack: firstError == null ? void 0 : firstError.stack
|
|
94
|
+
}, false);
|
|
95
|
+
}
|
|
96
|
+
getPossibleEventMessage(event) {
|
|
97
|
+
const {
|
|
98
|
+
message,
|
|
99
|
+
statusMessage
|
|
100
|
+
} = event || {};
|
|
101
|
+
if (message && typeof message === 'string') {
|
|
102
|
+
return message;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// GrpcStatusEvent
|
|
106
|
+
if (statusMessage && typeof statusMessage === 'string') {
|
|
107
|
+
return statusMessage;
|
|
108
|
+
}
|
|
109
|
+
return JSON.stringify(event);
|
|
110
|
+
}
|
|
111
|
+
enable() {
|
|
112
|
+
const defaultHandler = ErrorUtils.getGlobalHandler();
|
|
113
|
+
ErrorUtils.setGlobalHandler((error, isFatal) => {
|
|
114
|
+
this.report(ErrorSource.GLOBAL, error);
|
|
115
|
+
if (defaultHandler) {
|
|
116
|
+
setTimeout(() => {
|
|
117
|
+
defaultHandler(error, isFatal);
|
|
118
|
+
}, 2500);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
this.listenToConsoleError();
|
|
122
|
+
}
|
|
123
|
+
disable() {}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const DEFAULT_SAMPLE_DURATION_MS = 5000;
|
|
127
|
+
const DEFAULT_SAMPLE_INTERVAL_MS = 60000;
|
|
128
|
+
let isSampling = false;
|
|
129
|
+
let rafId = null;
|
|
130
|
+
let intervalTimer = null;
|
|
131
|
+
let appState = 'active';
|
|
132
|
+
let appStateSub = null;
|
|
133
|
+
function startJsRefreshRateSampler({
|
|
134
|
+
sampleDurationMs = DEFAULT_SAMPLE_DURATION_MS,
|
|
135
|
+
sampleIntervalMs = DEFAULT_SAMPLE_INTERVAL_MS,
|
|
136
|
+
onSample
|
|
137
|
+
}) {
|
|
138
|
+
var _AppState$currentStat;
|
|
139
|
+
if (isSampling) return;
|
|
140
|
+
isSampling = true;
|
|
141
|
+
let firstTimestamp = null;
|
|
142
|
+
let lastTimestamp = null;
|
|
143
|
+
let frameCount = 0;
|
|
144
|
+
const requestNext = () => {
|
|
145
|
+
rafId = requestAnimationFrame(loop);
|
|
146
|
+
};
|
|
147
|
+
const loop = t => {
|
|
148
|
+
if (appState === 'active') {
|
|
149
|
+
if (firstTimestamp === null) firstTimestamp = t;
|
|
150
|
+
lastTimestamp = t;
|
|
151
|
+
frameCount += 1;
|
|
152
|
+
}
|
|
153
|
+
requestNext();
|
|
154
|
+
};
|
|
155
|
+
const stopRaf = () => {
|
|
156
|
+
if (rafId !== null) {
|
|
157
|
+
cancelAnimationFrame(rafId);
|
|
158
|
+
rafId = null;
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
const resetCounters = () => {
|
|
162
|
+
firstTimestamp = null;
|
|
163
|
+
lastTimestamp = null;
|
|
164
|
+
frameCount = 0;
|
|
165
|
+
};
|
|
166
|
+
const getElapsedMs = () => {
|
|
167
|
+
if (firstTimestamp == null || lastTimestamp == null) return 0;
|
|
168
|
+
return Math.max(0, lastTimestamp - firstTimestamp);
|
|
169
|
+
};
|
|
170
|
+
const computeAverageRafRate = () => {
|
|
171
|
+
const elapsedMs = getElapsedMs();
|
|
172
|
+
if (elapsedMs === 0) return 0;
|
|
173
|
+
return (frameCount - 1) * 1000 / elapsedMs;
|
|
174
|
+
};
|
|
175
|
+
const runSample = () => {
|
|
176
|
+
if (!isSampling) return;
|
|
177
|
+
if (appState !== 'active') {
|
|
178
|
+
scheduleNextSample();
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
resetCounters();
|
|
182
|
+
requestNext();
|
|
183
|
+
setTimeout(() => {
|
|
184
|
+
stopRaf();
|
|
185
|
+
const rafRate = computeAverageRafRate();
|
|
186
|
+
onSample(rafRate);
|
|
187
|
+
scheduleNextSample();
|
|
188
|
+
}, sampleDurationMs);
|
|
189
|
+
};
|
|
190
|
+
const scheduleNextSample = () => {
|
|
191
|
+
if (!isSampling) return;
|
|
192
|
+
intervalTimer = setTimeout(runSample, sampleIntervalMs);
|
|
193
|
+
};
|
|
194
|
+
const handleAppStateChange = next => {
|
|
195
|
+
appState = next;
|
|
196
|
+
if (next !== 'active') {
|
|
197
|
+
stopRaf();
|
|
198
|
+
resetCounters();
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
appState = (_AppState$currentStat = AppState.currentState) != null ? _AppState$currentStat : 'active';
|
|
202
|
+
appStateSub = AppState.addEventListener('change', handleAppStateChange);
|
|
203
|
+
runSample();
|
|
204
|
+
}
|
|
205
|
+
function stopJsRefreshRateSampler() {
|
|
206
|
+
var _appStateSub;
|
|
207
|
+
isSampling = false;
|
|
208
|
+
if (intervalTimer) {
|
|
209
|
+
clearTimeout(intervalTimer);
|
|
210
|
+
intervalTimer = null;
|
|
211
|
+
}
|
|
212
|
+
if (rafId !== null) {
|
|
213
|
+
cancelAnimationFrame(rafId);
|
|
214
|
+
rafId = null;
|
|
215
|
+
}
|
|
216
|
+
(_appStateSub = appStateSub) == null || _appStateSub.remove();
|
|
217
|
+
appStateSub = null;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
var version = "0.1.0";
|
|
221
|
+
var pkg = {
|
|
222
|
+
version: version};
|
|
223
|
+
|
|
224
|
+
class Logger {
|
|
225
|
+
constructor(config = {}) {
|
|
226
|
+
var _config$shouldLog, _config$prefix;
|
|
227
|
+
this._shouldLog = void 0;
|
|
228
|
+
this._prefix = void 0;
|
|
229
|
+
this._shouldLog = (_config$shouldLog = config.shouldLog) != null ? _config$shouldLog : false;
|
|
230
|
+
this._prefix = (_config$prefix = config.prefix) != null ? _config$prefix : '[Coralogix React Native SDK] - ';
|
|
231
|
+
}
|
|
232
|
+
set shouldLog(value) {
|
|
233
|
+
this._shouldLog = value;
|
|
234
|
+
}
|
|
235
|
+
debug(message, ...args) {
|
|
236
|
+
if (this._shouldLog) {
|
|
237
|
+
console.debug(`${this._prefix} ${message}`, ...args);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
info(message, ...args) {
|
|
241
|
+
if (this._shouldLog) {
|
|
242
|
+
console.info(`${this._prefix} ${message}`, ...args);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
warn(message, ...args) {
|
|
246
|
+
if (this._shouldLog) {
|
|
247
|
+
console.warn(`${this._prefix} ${message}`, ...args);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
error(message, ...args) {
|
|
251
|
+
if (this._shouldLog) {
|
|
252
|
+
console.error(`${this._prefix} ${message}`, ...args);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
const logger = new Logger();
|
|
257
|
+
|
|
258
|
+
const propagateTraceHeaderCorsUrls = config => {
|
|
259
|
+
var _traceParentInHeader$;
|
|
260
|
+
const {
|
|
261
|
+
traceParentInHeader
|
|
262
|
+
} = config;
|
|
263
|
+
const propagateCorsUrls = traceParentInHeader == null || (_traceParentInHeader$ = traceParentInHeader.options) == null ? void 0 : _traceParentInHeader$.propagateTraceHeaderCorsUrls;
|
|
264
|
+
if (traceParentInHeader != null && traceParentInHeader.enabled && propagateCorsUrls) {
|
|
265
|
+
config.propagateTraceHeaderCorsUrls = propagateCorsUrls;
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
const CORALOGIX_LOGS_URL_SUFFIX = '/browser/v1beta/logs';
|
|
270
|
+
const CORALOGIX_RECORDING_URL_SUFFIX = '/sessionrecording';
|
|
271
|
+
const OPTIONS_DEFAULTS = {
|
|
272
|
+
ignoreUrls: [new RegExp(CORALOGIX_LOGS_URL_SUFFIX), new RegExp(CORALOGIX_RECORDING_URL_SUFFIX)],
|
|
273
|
+
user_context: {
|
|
274
|
+
user_id: '',
|
|
275
|
+
user_name: ''
|
|
276
|
+
},
|
|
277
|
+
labels: {},
|
|
278
|
+
view_context: {
|
|
279
|
+
view: ''
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
const hrTimeToMilliseconds = ([seconds, nanoseconds]) => seconds * 1000 + Math.round(nanoseconds / 1e6);
|
|
284
|
+
const getUrlFragments = url => {
|
|
285
|
+
if (!url) {
|
|
286
|
+
return '';
|
|
287
|
+
}
|
|
288
|
+
try {
|
|
289
|
+
if (url.startsWith('blob:')) {
|
|
290
|
+
return url;
|
|
291
|
+
}
|
|
292
|
+
return new URL(url).pathname.substring(1) || '/';
|
|
293
|
+
} catch (err) {
|
|
294
|
+
logger.warn('Error parsing URL', err);
|
|
295
|
+
return url;
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
function isSamplingOn(threshold) {
|
|
299
|
+
return threshold > 0 && Math.random() * 100 <= threshold;
|
|
300
|
+
}
|
|
301
|
+
function resolveCoralogixOtelWebConfig(config) {
|
|
302
|
+
var _config$sessionSample, _config$view_context;
|
|
303
|
+
const {
|
|
304
|
+
ignoreUrls,
|
|
305
|
+
debug
|
|
306
|
+
} = config;
|
|
307
|
+
const resolvedIgnoreUrls = [];
|
|
308
|
+
ignoreUrls && resolvedIgnoreUrls.push(...ignoreUrls);
|
|
309
|
+
OPTIONS_DEFAULTS.ignoreUrls && resolvedIgnoreUrls.push(...OPTIONS_DEFAULTS.ignoreUrls);
|
|
310
|
+
return _extends({}, OPTIONS_DEFAULTS, config, {
|
|
311
|
+
ignoreUrls: resolvedIgnoreUrls,
|
|
312
|
+
sessionSampleRate: (_config$sessionSample = config.sessionSampleRate) != null ? _config$sessionSample : 100,
|
|
313
|
+
debug,
|
|
314
|
+
view_context: (_config$view_context = config.view_context) != null ? _config$view_context : OPTIONS_DEFAULTS.view_context
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
let OtelNetworkAttrs = /*#__PURE__*/function (OtelNetworkAttrs) {
|
|
319
|
+
OtelNetworkAttrs["METHOD"] = "http.method";
|
|
320
|
+
OtelNetworkAttrs["URL"] = "http.url";
|
|
321
|
+
OtelNetworkAttrs["STATUS_CODE"] = "http.status_code";
|
|
322
|
+
OtelNetworkAttrs["HOST"] = "http.host";
|
|
323
|
+
OtelNetworkAttrs["SCHEME"] = "http.scheme";
|
|
324
|
+
OtelNetworkAttrs["STATUS_TEXT"] = "http.status_text";
|
|
325
|
+
OtelNetworkAttrs["RESPONSE_CONTENT_LENGTH"] = "http.response_content_length";
|
|
326
|
+
OtelNetworkAttrs["OtelNetworkAttrs"] = "OtelNetworkAttrs";
|
|
327
|
+
return OtelNetworkAttrs;
|
|
328
|
+
}({});
|
|
329
|
+
|
|
330
|
+
class CoralogixFetchInstrumentation extends FetchInstrumentation {
|
|
331
|
+
constructor(config) {
|
|
332
|
+
propagateTraceHeaderCorsUrls(config);
|
|
333
|
+
config.applyCustomAttributesOnSpan = (span, request, result) => {
|
|
334
|
+
span.end();
|
|
335
|
+
const readableSpan = span;
|
|
336
|
+
const attrs = readableSpan.attributes;
|
|
337
|
+
const method = attrs[OtelNetworkAttrs.METHOD];
|
|
338
|
+
const url = attrs[OtelNetworkAttrs.URL];
|
|
339
|
+
const statusCode = result.status;
|
|
340
|
+
const statusText = attrs[OtelNetworkAttrs.STATUS_TEXT];
|
|
341
|
+
const responseContentLength = attrs[OtelNetworkAttrs.RESPONSE_CONTENT_LENGTH] || 0;
|
|
342
|
+
const duration = hrTimeToMilliseconds(readableSpan.duration);
|
|
343
|
+
const fragments = getUrlFragments(url);
|
|
344
|
+
const errorMessage = result.message;
|
|
345
|
+
const customTraceId = readableSpan.spanContext().traceId;
|
|
346
|
+
const customSpanId = readableSpan.spanContext().spanId;
|
|
347
|
+
const parsed = new URL(url);
|
|
348
|
+
const host = parsed.host; // e.g. "example.com:443"
|
|
349
|
+
const schema = parsed.protocol.replace(":", ""); // e.g. "https"
|
|
350
|
+
|
|
351
|
+
const details = {
|
|
352
|
+
method,
|
|
353
|
+
statusCode,
|
|
354
|
+
url,
|
|
355
|
+
fragments,
|
|
356
|
+
host,
|
|
357
|
+
schema,
|
|
358
|
+
statusText,
|
|
359
|
+
duration,
|
|
360
|
+
responseContentLength,
|
|
361
|
+
errorMessage,
|
|
362
|
+
customTraceId,
|
|
363
|
+
customSpanId
|
|
364
|
+
};
|
|
365
|
+
CoralogixRum.reportNetworkRequest(details);
|
|
366
|
+
};
|
|
367
|
+
super(config);
|
|
368
|
+
}
|
|
369
|
+
enable() {
|
|
370
|
+
super.enable();
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
let CoralogixDomain = /*#__PURE__*/function (CoralogixDomain) {
|
|
375
|
+
CoralogixDomain["EU1"] = "EU1";
|
|
376
|
+
CoralogixDomain["EU2"] = "EU2";
|
|
377
|
+
CoralogixDomain["US1"] = "US1";
|
|
378
|
+
CoralogixDomain["US2"] = "US2";
|
|
379
|
+
CoralogixDomain["AP1"] = "AP1";
|
|
380
|
+
CoralogixDomain["AP2"] = "AP2";
|
|
381
|
+
CoralogixDomain["AP3"] = "AP3";
|
|
382
|
+
CoralogixDomain["STAGING"] = "staging";
|
|
383
|
+
return CoralogixDomain;
|
|
384
|
+
}({});
|
|
385
|
+
|
|
386
|
+
const LINKING_ERROR = `The package 'cx-plugin' doesn't seem to be linked. Make sure: \n\n` + Platform.select({
|
|
387
|
+
ios: "- You have run 'pod install'\n",
|
|
388
|
+
default: ''
|
|
389
|
+
}) + '- You rebuilt the app after installing the package\n' + '- You are not using Expo Go\n';
|
|
390
|
+
let beforeSendCallback;
|
|
391
|
+
let _deregisterInstrumentations;
|
|
392
|
+
const CxSdk = NativeModules.CxSdk ? NativeModules.CxSdk : createErrorProxy(LINKING_ERROR);
|
|
393
|
+
function createErrorProxy(errorMessage) {
|
|
394
|
+
return new Proxy({}, {
|
|
395
|
+
get() {
|
|
396
|
+
throw new Error(errorMessage);
|
|
397
|
+
}
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
let isInited = false;
|
|
401
|
+
let fetchInstrumentation;
|
|
402
|
+
const CoralogixRum = {
|
|
403
|
+
get isInited() {
|
|
404
|
+
return isInited;
|
|
405
|
+
},
|
|
406
|
+
init: function (options) {
|
|
407
|
+
var _resolvedOptions$debu;
|
|
408
|
+
if (isInited) {
|
|
409
|
+
console.warn('[Coralogix React Native SDK] - already initialized');
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
const resolvedOptions = resolveCoralogixOtelWebConfig(options);
|
|
413
|
+
logger.shouldLog = (_resolvedOptions$debu = resolvedOptions.debug) != null ? _resolvedOptions$debu : false;
|
|
414
|
+
if (!isSamplingOn(resolvedOptions.sessionSampleRate)) {
|
|
415
|
+
logger.debug('CoralogixRum: Session tracking is disabled');
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
registerCoralogixInstrumentations(resolvedOptions);
|
|
419
|
+
CxSdk.initialize(_extends({}, resolvedOptions, {
|
|
420
|
+
frameworkVersion: pkg.version
|
|
421
|
+
}));
|
|
422
|
+
isInited = true;
|
|
423
|
+
},
|
|
424
|
+
shutdown: () => {
|
|
425
|
+
if (!isInited) {
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
CxSdk.shutdown();
|
|
429
|
+
if (subscription) {
|
|
430
|
+
subscription.remove();
|
|
431
|
+
}
|
|
432
|
+
isInited = false;
|
|
433
|
+
_deregisterInstrumentations == null || _deregisterInstrumentations();
|
|
434
|
+
_deregisterInstrumentations = undefined;
|
|
435
|
+
cleanupResources();
|
|
436
|
+
},
|
|
437
|
+
setApplicationContext: applicationContext => {
|
|
438
|
+
if (!isInited) {
|
|
439
|
+
logger.debug('CoralogixRum must be initiated before setting application context');
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
442
|
+
CxSdk.setApplicationContext(applicationContext);
|
|
443
|
+
},
|
|
444
|
+
setUserContext: userContext => {
|
|
445
|
+
if (!isInited) {
|
|
446
|
+
logger.debug('CoralogixRum must be initiated before setting user context');
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
449
|
+
CxSdk.setUserContext(userContext);
|
|
450
|
+
},
|
|
451
|
+
setViewContext(viewContext) {
|
|
452
|
+
if (!isInited) {
|
|
453
|
+
logger.debug('CoralogixRum must be initiated before setting view context');
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
CxSdk.setViewContext(viewContext.view);
|
|
457
|
+
},
|
|
458
|
+
getUserContext: async () => {
|
|
459
|
+
if (!isInited) {
|
|
460
|
+
logger.debug('CoralogixRum must be initiated before getting user context');
|
|
461
|
+
return undefined;
|
|
462
|
+
}
|
|
463
|
+
const result = await CxSdk.getUserContext();
|
|
464
|
+
if (!result || typeof result !== 'object') {
|
|
465
|
+
return undefined;
|
|
466
|
+
}
|
|
467
|
+
return {
|
|
468
|
+
user_id: result.user_id || '',
|
|
469
|
+
user_name: result.user_name || '',
|
|
470
|
+
user_email: result.user_email || '',
|
|
471
|
+
user_metadata: result.user_metadata || {}
|
|
472
|
+
};
|
|
473
|
+
},
|
|
474
|
+
setLabels: labels => {
|
|
475
|
+
if (!isInited) {
|
|
476
|
+
logger.debug('CoralogixRum must be initiated before setting labels');
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
CxSdk.setLabels(labels);
|
|
480
|
+
},
|
|
481
|
+
getLabels: async () => {
|
|
482
|
+
if (!isInited) {
|
|
483
|
+
logger.debug('CoralogixRum must be initiated before getting labels');
|
|
484
|
+
return {};
|
|
485
|
+
}
|
|
486
|
+
return await CxSdk.getLabels();
|
|
487
|
+
},
|
|
488
|
+
getSessionId: async () => {
|
|
489
|
+
if (!isInited) {
|
|
490
|
+
logger.debug('CoralogixRum must be initiated before getting session id');
|
|
491
|
+
return '';
|
|
492
|
+
}
|
|
493
|
+
return CxSdk.getSessionId();
|
|
494
|
+
},
|
|
495
|
+
log: (severity, message, data) => {
|
|
496
|
+
if (!isInited) {
|
|
497
|
+
logger.debug('CoralogixRum must be initiated before using log');
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
CxSdk.log(severity, message, data != null ? data : {});
|
|
501
|
+
},
|
|
502
|
+
debug(message, data) {
|
|
503
|
+
this.log(CoralogixLogSeverity.Debug, message, data);
|
|
504
|
+
},
|
|
505
|
+
verbose(message, data) {
|
|
506
|
+
this.log(CoralogixLogSeverity.Verbose, message, data);
|
|
507
|
+
},
|
|
508
|
+
info(message, data) {
|
|
509
|
+
this.log(CoralogixLogSeverity.Info, message, data);
|
|
510
|
+
},
|
|
511
|
+
warn(message, data) {
|
|
512
|
+
this.log(CoralogixLogSeverity.Warn, message, data);
|
|
513
|
+
},
|
|
514
|
+
error(message, data) {
|
|
515
|
+
this.log(CoralogixLogSeverity.Error, message, data);
|
|
516
|
+
},
|
|
517
|
+
critical(message, data) {
|
|
518
|
+
this.log(CoralogixLogSeverity.Critical, message, data);
|
|
519
|
+
},
|
|
520
|
+
reportNetworkRequest: details => {
|
|
521
|
+
CxSdk.reportNetworkRequest(details);
|
|
522
|
+
},
|
|
523
|
+
sendCustomMeasurement: measurement => {
|
|
524
|
+
if (!isInited) {
|
|
525
|
+
logger.debug('CoralogixRum must be initiated before sending custom measurements');
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
CxSdk.sendCustomMeasurement(measurement);
|
|
529
|
+
},
|
|
530
|
+
reportError: (error, isCrash) => {
|
|
531
|
+
if (!isInited) {
|
|
532
|
+
logger.debug('CoralogixRum must be initiated before error reporting');
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
const errorDetails = {
|
|
536
|
+
error_type: error.name,
|
|
537
|
+
error_message: error.message,
|
|
538
|
+
stack_trace: parseErrorStack(error),
|
|
539
|
+
is_crash: isCrash
|
|
540
|
+
};
|
|
541
|
+
CxSdk.reportError(errorDetails);
|
|
542
|
+
}
|
|
543
|
+
};
|
|
544
|
+
function trackMobileVitals(options) {
|
|
545
|
+
startJsRefreshRateSampler(_extends({}, options.jsRefreshRateSampleRate, {
|
|
546
|
+
onSample: jsRefreshRate => {
|
|
547
|
+
CxSdk.reportMobileVitalsMeasurement('js_refresh_rate', Math.round(jsRefreshRate), 'fps');
|
|
548
|
+
}
|
|
549
|
+
}));
|
|
550
|
+
|
|
551
|
+
// startJSLoopDetector({
|
|
552
|
+
// ...options.jsLoopDetection,
|
|
553
|
+
// onFrameDrop: (event) => {
|
|
554
|
+
// CxSdk.reportMobileVitalsMeasurementSet('js_loop', [
|
|
555
|
+
// {
|
|
556
|
+
// name: 'stall',
|
|
557
|
+
// value: event.stall,
|
|
558
|
+
// units: 'ms',
|
|
559
|
+
// },
|
|
560
|
+
// {
|
|
561
|
+
// name: 'delta',
|
|
562
|
+
// value: event.delta,
|
|
563
|
+
// units: 'ms',
|
|
564
|
+
// },
|
|
565
|
+
// ]);
|
|
566
|
+
// },
|
|
567
|
+
// onError: (error) => {
|
|
568
|
+
// logger.debug('[JSLoopDetector] Error:', { error });
|
|
569
|
+
// },
|
|
570
|
+
// });
|
|
571
|
+
}
|
|
572
|
+
function cleanupResources() {
|
|
573
|
+
stopJsRefreshRateSampler();
|
|
574
|
+
// stopJSLoopDetector();
|
|
575
|
+
}
|
|
576
|
+
function registerCoralogixInstrumentations(options) {
|
|
577
|
+
if (options.beforeSend) {
|
|
578
|
+
beforeSendCallback = options.beforeSend;
|
|
579
|
+
}
|
|
580
|
+
const tracerProvider = new WebTracerProvider();
|
|
581
|
+
const instrumentations = [];
|
|
582
|
+
const instrumentationsOptions = options.instrumentations;
|
|
583
|
+
|
|
584
|
+
// disable network for ios, since swizzle will capture the fetch requests
|
|
585
|
+
const shouldInterceptNetowrk = Platform.OS === 'android' && (!instrumentationsOptions || instrumentationsOptions.network !== false);
|
|
586
|
+
const shouldInterceptErrors = !instrumentationsOptions || instrumentationsOptions.errors !== false;
|
|
587
|
+
const shouldInterceptMobileVitals = !instrumentationsOptions || instrumentationsOptions.mobile_vitals !== false;
|
|
588
|
+
|
|
589
|
+
// Fetch instrumentation
|
|
590
|
+
if (shouldInterceptNetowrk) {
|
|
591
|
+
fetchInstrumentation = new CoralogixFetchInstrumentation(options);
|
|
592
|
+
instrumentations.push(fetchInstrumentation);
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
// Errors instrumentation
|
|
596
|
+
if (shouldInterceptErrors) {
|
|
597
|
+
const errorInstrumentation = new CoralogixErrorInstrumentation(options);
|
|
598
|
+
instrumentations.push(errorInstrumentation);
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
// Mobile vitals instrumentation
|
|
602
|
+
if (shouldInterceptMobileVitals) {
|
|
603
|
+
trackMobileVitals(options);
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
// Register Instrumentations
|
|
607
|
+
_deregisterInstrumentations = registerInstrumentations({
|
|
608
|
+
tracerProvider,
|
|
609
|
+
instrumentations
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
const parseErrorStack = error => {
|
|
613
|
+
if (!error.stack) {
|
|
614
|
+
return [];
|
|
615
|
+
}
|
|
616
|
+
const stackLines = error.stack.split('\n').slice(1); // Ignore the first line (error message)
|
|
617
|
+
return stackLines.map(line => {
|
|
618
|
+
const match = line.match(/\s*at\s+(.*)\s+\((.*):(\d+):(\d+)\)/) ||
|
|
619
|
+
// Matches function name, file, line, column
|
|
620
|
+
line.match(/\s*at\s+(.*):(\d+):(\d+)/); // Matches anonymous function calls
|
|
621
|
+
|
|
622
|
+
if (match) {
|
|
623
|
+
var _match$, _match$2;
|
|
624
|
+
return {
|
|
625
|
+
functionName: match[1] || '<anonymous>',
|
|
626
|
+
fileName: match[2],
|
|
627
|
+
lineNumber: parseInt((_match$ = match[3]) != null ? _match$ : '-1', 10),
|
|
628
|
+
columnNumber: parseInt((_match$2 = match[4]) != null ? _match$2 : '-1', 10)
|
|
629
|
+
};
|
|
630
|
+
}
|
|
631
|
+
return null;
|
|
632
|
+
}).filter(frame => frame !== null);
|
|
633
|
+
};
|
|
634
|
+
|
|
635
|
+
// Create event emitter
|
|
636
|
+
const eventEmitter = new NativeEventEmitter(CxSdk);
|
|
637
|
+
|
|
638
|
+
// Subscribe to beforeSend events
|
|
639
|
+
const subscription = eventEmitter.addListener('onBeforeSend', events => {
|
|
640
|
+
// logger.log("📨 onBeforeSend triggered with events: ", events)
|
|
641
|
+
// events is an array of events [[String: Any]]
|
|
642
|
+
// Skip processing if SDK is not initialized or events is empty
|
|
643
|
+
if (!CoralogixRum.isInited || !events || !Array.isArray(events)) {
|
|
644
|
+
logger.debug('⚠️ Skipping event processing - SDK not initialized or events invalid');
|
|
645
|
+
return;
|
|
646
|
+
}
|
|
647
|
+
logger.debug('🔄 Processing events with beforeSendCallback');
|
|
648
|
+
// Process event with beforeSendCallback if available
|
|
649
|
+
if (beforeSendCallback) {
|
|
650
|
+
try {
|
|
651
|
+
// Process each event in the array
|
|
652
|
+
const results = [];
|
|
653
|
+
for (const fullEvent of events) {
|
|
654
|
+
const event = fullEvent.text.cx_rum;
|
|
655
|
+
const res = beforeSendCallback(event);
|
|
656
|
+
if (!res) {
|
|
657
|
+
continue;
|
|
658
|
+
}
|
|
659
|
+
// Merge the result from each event
|
|
660
|
+
const mergeEvent = _extends({}, fullEvent, {
|
|
661
|
+
text: _extends({}, fullEvent.text, {
|
|
662
|
+
cx_rum: _extends({}, fullEvent.text.cx_rum, res)
|
|
663
|
+
})
|
|
664
|
+
});
|
|
665
|
+
results.push(mergeEvent);
|
|
666
|
+
}
|
|
667
|
+
if (results.length) {
|
|
668
|
+
CxSdk.sendCxSpanData(results);
|
|
669
|
+
}
|
|
670
|
+
} catch (error) {
|
|
671
|
+
logger.debug('❌ Error in beforeSend callback:', error);
|
|
672
|
+
}
|
|
673
|
+
} else {
|
|
674
|
+
logger.debug('⚠️ No beforeSendCallback available');
|
|
675
|
+
}
|
|
676
|
+
});
|
|
677
|
+
|
|
678
|
+
export { CoralogixDomain, CoralogixLogSeverity, CoralogixRum };
|