@coralogix/react-native-plugin 0.10.1 → 0.10.2
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 +8 -0
- package/README.md +27 -8
- package/index.cjs.js +73 -6
- package/index.esm.js +73 -6
- package/package.json +1 -1
- package/src/model/Types.d.ts +11 -1
- package/src/utils.d.ts +18 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
## 0.10.2 (2026-08-25)
|
|
2
|
+
|
|
3
|
+
### 🩹 Fixes
|
|
4
|
+
|
|
5
|
+
- `sessionSampleRate` is now applied once instead of twice — the configured percentage was being rolled on both the JavaScript and native sides, so a rate of 1% collected roughly 0.01% of sessions
|
|
6
|
+
- A fractional `sessionSampleRate` such as `0.5` is now rounded to a whole percentage instead of being truncated to `0` on iOS, which silently sampled out every session
|
|
7
|
+
- `SessionReplay.init()` now resolves `false` instead of rejecting when the session was sampled out, and resolves a real boolean on both platforms
|
|
8
|
+
|
|
1
9
|
## 0.10.1 (2026-08-11)
|
|
2
10
|
|
|
3
11
|
### 🩹 Fixes
|
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ This package replaces the old `@coralogix/react-native-sdk` package.
|
|
|
12
12
|
|
|
13
13
|
To use Coralogix SDK, call `CoralogixRum.init(options)` at the soonest available moment after the app loads.
|
|
14
14
|
This will initialize the SDK based on the options you provided.
|
|
15
|
-
|
|
15
|
+
`init` is an `async` function.
|
|
16
16
|
|
|
17
17
|
```javascript
|
|
18
18
|
import { CoralogixRum } from '@coralogix/react-native-plugin'
|
|
@@ -32,6 +32,11 @@ await CoralogixRum.init({
|
|
|
32
32
|
});
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
+
`sessionSampleRate` is a whole percentage in `0`-`100` and is applied **once**. A
|
|
36
|
+
fractional value is rounded to an integer before it is forwarded (and a non-zero
|
|
37
|
+
rate is never rounded down to `0`), because the native bridges read the value as
|
|
38
|
+
an integer.
|
|
39
|
+
|
|
35
40
|
To provide contextual information or transmit manual logs, utilize the exported functions of `CoralogixRum`.
|
|
36
41
|
Keep in mind that these functions will remain inactive until you've invoked `CoralogixRum.init()`.
|
|
37
42
|
|
|
@@ -67,6 +72,7 @@ CoralogixRum.log(CoralogixLogSeverity.Error, 'this is a log', { key: 'value' });
|
|
|
67
72
|
CoralogixRum.error('this is a log with error severity', { key: 'value' });
|
|
68
73
|
```
|
|
69
74
|
|
|
75
|
+
<!-- split title="Logs, errors, and views" path="features/logs-errors-and-views.md" -->
|
|
70
76
|
### Custom Logs
|
|
71
77
|
|
|
72
78
|
Send structured logs with optional data and labels.
|
|
@@ -80,9 +86,10 @@ CoralogixRum.debug('this is a debug log', {key: 'value', pi: 3.14});
|
|
|
80
86
|
CoralogixRum.error('this is an error log', {error: 'yes', is_bad: 'no'});
|
|
81
87
|
```
|
|
82
88
|
|
|
83
|
-
>
|
|
84
|
-
>
|
|
85
|
-
>
|
|
89
|
+
> [!NOTE]
|
|
90
|
+
> Due to React Native limitations, not all value types are supported for the log data values.
|
|
91
|
+
> Our testing shows that React Native can't pass some types to the coralogix native layer; the ones we have identified as problematic are `Map`, `Set`, `Date` and `Function`.
|
|
92
|
+
> There could be more. For example:
|
|
86
93
|
> ```javascript
|
|
87
94
|
> // this would pass as an empty object to the coralogix native layer, same for Set and Date:
|
|
88
95
|
> CoralogixRum.debug('this will be a problem', {key: new Map().set(1, 2)});
|
|
@@ -90,7 +97,7 @@ CoralogixRum.error('this is an error log', {error: 'yes', is_bad: 'no'});
|
|
|
90
97
|
> // this would pass as null to the coralogix native layer
|
|
91
98
|
> CoralogixRum.debug('this will be a problem too', {key: () => {}});
|
|
92
99
|
> ```
|
|
93
|
-
>
|
|
100
|
+
> If you need to pass any of these types, stringify them before you pass them to the `log` method.
|
|
94
101
|
|
|
95
102
|
### Error Reporting
|
|
96
103
|
|
|
@@ -193,6 +200,8 @@ subsequent events belong to a fresh session with a new session id.
|
|
|
193
200
|
CoralogixRum.createNewSession();
|
|
194
201
|
```
|
|
195
202
|
|
|
203
|
+
<!-- /split -->
|
|
204
|
+
<!-- split title="Configuration options" path="configuration/options.md" -->
|
|
196
205
|
### Instrumentation's
|
|
197
206
|
|
|
198
207
|
Turn on/off specific instrumentation; defaults to true for all.
|
|
@@ -282,6 +291,8 @@ await CoralogixRum.init({
|
|
|
282
291
|
});
|
|
283
292
|
```
|
|
284
293
|
|
|
294
|
+
<!-- /split -->
|
|
295
|
+
<!-- split title="Custom instrumentation" path="features/custom-instrumentation.md" -->
|
|
285
296
|
### Custom Spans
|
|
286
297
|
|
|
287
298
|
Create manual RUM spans to instrument custom flows in your application. Requires `traceParentInHeader.enabled: true`.
|
|
@@ -331,7 +342,8 @@ Pass instrument names to prevent network requests, errors, or interactions fired
|
|
|
331
342
|
const tracer = CoralogixRum.getCustomTracer(['networkRequests', 'userInteractions', 'errors']);
|
|
332
343
|
```
|
|
333
344
|
|
|
334
|
-
>
|
|
345
|
+
> [!NOTE]
|
|
346
|
+
> Only one global span may be active at a time. `startGlobalSpan` returns `null` if a global span is already open.
|
|
335
347
|
|
|
336
348
|
### Time Measurement
|
|
337
349
|
|
|
@@ -357,6 +369,8 @@ CoralogixRum.endTimeMeasure('checkout');
|
|
|
357
369
|
- Unmatched `endTimeMeasure` calls are dropped silently by the native SDK.
|
|
358
370
|
- Calling `startTimeMeasure` again with an open `name` overwrites the previous start.
|
|
359
371
|
|
|
372
|
+
<!-- /split -->
|
|
373
|
+
<!-- split title="Exporting and networking" path="configuration/exporting-and-networking.md" -->
|
|
360
374
|
### Traces Exporter
|
|
361
375
|
|
|
362
376
|
Receive OTLP-formatted trace batches from the native SDK in your JavaScript code. Use this to forward spans to an OTLP-compatible backend (e.g. Jaeger, custom collector) alongside Coralogix.
|
|
@@ -400,7 +414,8 @@ The callback receives a `TraceExporterData` object following the OTLP JSON forma
|
|
|
400
414
|
}
|
|
401
415
|
```
|
|
402
416
|
|
|
403
|
-
>
|
|
417
|
+
> [!NOTE]
|
|
418
|
+
> The callback fires once per native export batch, which typically contains several spans rather than one per span.
|
|
404
419
|
|
|
405
420
|
### beforeSend
|
|
406
421
|
|
|
@@ -454,7 +469,8 @@ await CoralogixRum.init({
|
|
|
454
469
|
});
|
|
455
470
|
```
|
|
456
471
|
|
|
457
|
-
>
|
|
472
|
+
> [!NOTE]
|
|
473
|
+
> Always read it as `isSessionSampledIn ?? true`. The field is absent on
|
|
458
474
|
> native SDKs that predate it, and the SDK never invents a value it was not given.
|
|
459
475
|
|
|
460
476
|
`isSessionSampledIn` is read-only: it reports the SDK's sampling decision for the
|
|
@@ -515,6 +531,8 @@ await CoralogixRum.init({
|
|
|
515
531
|
});
|
|
516
532
|
```
|
|
517
533
|
|
|
534
|
+
<!-- /split -->
|
|
535
|
+
<!-- split title="Session Replay" path="features/session-replay.md" -->
|
|
518
536
|
### Session Replay
|
|
519
537
|
|
|
520
538
|
Session Replay allows you to record and replay user sessions to understand user behavior and debug issues.
|
|
@@ -616,6 +634,7 @@ import { SessionReplay } from '@coralogix/react-native-plugin';
|
|
|
616
634
|
The `SessionReplay.maskView` function accepts a `LayoutChangeEvent` and will mask the view in session replay recordings. It works on both the legacy and the New Architecture (Fabric).
|
|
617
635
|
|
|
618
636
|
|
|
637
|
+
<!-- /split -->
|
|
619
638
|
### Optional - Coralogix Gradle Plugin (Android)
|
|
620
639
|
|
|
621
640
|
The Coralogix Gradle Plugin automatically instruments all OkHttp clients in your app (including third-party SDKs) at build time.
|
package/index.cjs.js
CHANGED
|
@@ -577,7 +577,7 @@ function stopJsRefreshRateSampler() {
|
|
|
577
577
|
appStateSub = null;
|
|
578
578
|
}
|
|
579
579
|
|
|
580
|
-
var version = "0.10.
|
|
580
|
+
var version = "0.10.2";
|
|
581
581
|
var pkg = {
|
|
582
582
|
version: version};
|
|
583
583
|
|
|
@@ -766,9 +766,43 @@ const getUrlFragments = url => {
|
|
|
766
766
|
return url;
|
|
767
767
|
}
|
|
768
768
|
};
|
|
769
|
+
|
|
770
|
+
/**
|
|
771
|
+
* Rolls the session sampling dice.
|
|
772
|
+
*
|
|
773
|
+
* This is the only roll for a config without `excludeFromSampling`: `init` pins the
|
|
774
|
+
* rate it sends to native to 100 in that case, so native does not roll again. See the
|
|
775
|
+
* comment in `CoralogixRum.init` for why the exclude case is handled the other way round.
|
|
776
|
+
*/
|
|
769
777
|
function isSamplingOn(threshold) {
|
|
770
778
|
return threshold > 0 && Math.random() * 100 <= threshold;
|
|
771
779
|
}
|
|
780
|
+
|
|
781
|
+
/**
|
|
782
|
+
* Normalizes `sessionSampleRate` into the shape both native SDKs expect: an
|
|
783
|
+
* integer percentage in [0, 100].
|
|
784
|
+
*
|
|
785
|
+
* The bridges read the value as an integer (`NSNumber.intValue` on iOS,
|
|
786
|
+
* `ReadableMap.getInt` on Android), so a fractional rate such as `0.5` would be
|
|
787
|
+
* truncated to `0` on iOS — silently sampling every session out — and can throw
|
|
788
|
+
* on Android. Round instead, and never round a caller-requested non-zero rate
|
|
789
|
+
* down to `0`: `0` is the one value that means "emit nothing".
|
|
790
|
+
*/
|
|
791
|
+
function normalizeSessionSampleRate(rate) {
|
|
792
|
+
if (typeof rate !== 'number' || !Number.isFinite(rate)) {
|
|
793
|
+
logger.warn(`CoralogixRum: \`sessionSampleRate\` must be a finite number; received ${String(rate)}. Falling back to 100.`);
|
|
794
|
+
return 100;
|
|
795
|
+
}
|
|
796
|
+
if (rate <= 0) {
|
|
797
|
+
return 0;
|
|
798
|
+
}
|
|
799
|
+
if (rate >= 100) {
|
|
800
|
+
return 100;
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
// Keep a sub-1% request alive rather than truncating it to "emit nothing".
|
|
804
|
+
return Math.max(1, Math.round(rate));
|
|
805
|
+
}
|
|
772
806
|
function resolveCoralogixOtelWebConfig(config) {
|
|
773
807
|
var _config$sessionSample, _config$view_context;
|
|
774
808
|
const {
|
|
@@ -780,7 +814,7 @@ function resolveCoralogixOtelWebConfig(config) {
|
|
|
780
814
|
OPTIONS_DEFAULTS.ignoreUrls && resolvedIgnoreUrls.push(...OPTIONS_DEFAULTS.ignoreUrls);
|
|
781
815
|
return _extends({}, OPTIONS_DEFAULTS, config, {
|
|
782
816
|
ignoreUrls: resolvedIgnoreUrls,
|
|
783
|
-
sessionSampleRate: (_config$sessionSample = config.sessionSampleRate) != null ? _config$sessionSample : 100,
|
|
817
|
+
sessionSampleRate: normalizeSessionSampleRate((_config$sessionSample = config.sessionSampleRate) != null ? _config$sessionSample : 100),
|
|
784
818
|
debug,
|
|
785
819
|
view_context: (_config$view_context = config.view_context) != null ? _config$view_context : OPTIONS_DEFAULTS.view_context
|
|
786
820
|
});
|
|
@@ -1033,6 +1067,9 @@ function createErrorProxy(errorMessage) {
|
|
|
1033
1067
|
});
|
|
1034
1068
|
}
|
|
1035
1069
|
let isInited = false;
|
|
1070
|
+
// Whether native, rather than JS, rolled the sampling for this init. Only in that mode can
|
|
1071
|
+
// `CoralogixRum.isInited` be true while native has no RUM behind it.
|
|
1072
|
+
let nativeOwnsSamplingRoll = false;
|
|
1036
1073
|
let fetchInstrumentation;
|
|
1037
1074
|
function toSafeRecord(name, value) {
|
|
1038
1075
|
if (value == null) {
|
|
@@ -1049,7 +1086,7 @@ const CoralogixRum = {
|
|
|
1049
1086
|
return isInited;
|
|
1050
1087
|
},
|
|
1051
1088
|
init: async function (options) {
|
|
1052
|
-
var
|
|
1089
|
+
var _options$debug, _resolvedOptions$excl, _resolvedOptions$excl2;
|
|
1053
1090
|
if (isInited) {
|
|
1054
1091
|
console.warn('[Coralogix React Native SDK] - already initialized');
|
|
1055
1092
|
return;
|
|
@@ -1058,13 +1095,28 @@ const CoralogixRum = {
|
|
|
1058
1095
|
console.warn('[Coralogix React Native SDK] - `public_key` is required and must be a non-empty string; initialization aborted.');
|
|
1059
1096
|
return;
|
|
1060
1097
|
}
|
|
1098
|
+
|
|
1099
|
+
// Configure the logger first: resolving the options normalizes `sessionSampleRate`,
|
|
1100
|
+
// which warns about an invalid rate. Doing it the other way round swallowed that
|
|
1101
|
+
// warning on the first init — exactly when the caller needs to see it.
|
|
1102
|
+
logger.shouldLog = (_options$debug = options.debug) != null ? _options$debug : false;
|
|
1061
1103
|
const resolvedOptions = resolveCoralogixOtelWebConfig(options);
|
|
1062
|
-
|
|
1104
|
+
|
|
1105
|
+
// The rate has to be applied exactly *once*. Rolling it on both sides squared it:
|
|
1106
|
+
// `sessionSampleRate: 1` kept ~0.01% of sessions instead of 1%.
|
|
1107
|
+
//
|
|
1108
|
+
// Without `excludeFromSampling`, JS rolls and the rate sent to native is pinned to 100
|
|
1109
|
+
// so native does not roll again; a losing roll returns here, which also keeps JS
|
|
1110
|
+
// instrumentation off a session that would emit nothing. With `excludeFromSampling`,
|
|
1111
|
+
// only native can honour "sampled out, but still emit these categories", so JS does not
|
|
1112
|
+
// roll and forwards the real rate — pinning to 100 there would sample every session in.
|
|
1063
1113
|
const hasExcludeOverrides = ((_resolvedOptions$excl = (_resolvedOptions$excl2 = resolvedOptions.excludeFromSampling) == null ? void 0 : _resolvedOptions$excl2.length) != null ? _resolvedOptions$excl : 0) > 0;
|
|
1064
|
-
if (!isSamplingOn(resolvedOptions.sessionSampleRate)
|
|
1114
|
+
if (!hasExcludeOverrides && !isSamplingOn(resolvedOptions.sessionSampleRate)) {
|
|
1065
1115
|
logger.debug('CoralogixRum: Session tracking is disabled');
|
|
1066
1116
|
return;
|
|
1067
1117
|
}
|
|
1118
|
+
nativeOwnsSamplingRoll = hasExcludeOverrides;
|
|
1119
|
+
const nativeSessionSampleRate = hasExcludeOverrides ? resolvedOptions.sessionSampleRate : 100;
|
|
1068
1120
|
await registerCoralogixInstrumentations(resolvedOptions);
|
|
1069
1121
|
let finalOptions;
|
|
1070
1122
|
const lastNavRoute = getLastNavigationRouteDetected();
|
|
@@ -1095,6 +1147,7 @@ const CoralogixRum = {
|
|
|
1095
1147
|
});
|
|
1096
1148
|
}
|
|
1097
1149
|
await CxSdk.initialize(_extends({}, finalOptions, {
|
|
1150
|
+
sessionSampleRate: nativeSessionSampleRate,
|
|
1098
1151
|
frameworkVersion: pkg.version,
|
|
1099
1152
|
networkExtraConfig: finalOptions.networkExtraConfig ? serializeNetworkCaptureRules(finalOptions.networkExtraConfig) : undefined,
|
|
1100
1153
|
hasBeforeSend: !!finalOptions.beforeSend,
|
|
@@ -1280,7 +1333,21 @@ const SessionReplay = {
|
|
|
1280
1333
|
logger.warn("invalid options in SessionReplay.init: ", options);
|
|
1281
1334
|
return false;
|
|
1282
1335
|
}
|
|
1283
|
-
|
|
1336
|
+
try {
|
|
1337
|
+
// iOS resolves the string "initializeSessionReplay success" rather than a boolean,
|
|
1338
|
+
// so coerce instead of handing a truthy string back through a `Promise<boolean>`.
|
|
1339
|
+
return !!(await CxSdk.initializeSessionReplay(options));
|
|
1340
|
+
} catch (e) {
|
|
1341
|
+
// When native owns the sampling roll, a sampled-out session leaves no native RUM
|
|
1342
|
+
// behind and iOS rejects rather than resolving. That is an expected outcome, not a
|
|
1343
|
+
// failure, so report it as `false` like the guards above rather than surfacing an
|
|
1344
|
+
// unhandled rejection. Every other rejection is a real error and stays the caller's.
|
|
1345
|
+
if (!nativeOwnsSamplingRoll) {
|
|
1346
|
+
throw e;
|
|
1347
|
+
}
|
|
1348
|
+
logger.warn('SessionReplay.init: no native RUM for this session (sampled out); replay not started.', e);
|
|
1349
|
+
return false;
|
|
1350
|
+
}
|
|
1284
1351
|
},
|
|
1285
1352
|
shutdown: async () => {
|
|
1286
1353
|
logger.debug("session replay: shutdown called");
|
package/index.esm.js
CHANGED
|
@@ -575,7 +575,7 @@ function stopJsRefreshRateSampler() {
|
|
|
575
575
|
appStateSub = null;
|
|
576
576
|
}
|
|
577
577
|
|
|
578
|
-
var version = "0.10.
|
|
578
|
+
var version = "0.10.2";
|
|
579
579
|
var pkg = {
|
|
580
580
|
version: version};
|
|
581
581
|
|
|
@@ -764,9 +764,43 @@ const getUrlFragments = url => {
|
|
|
764
764
|
return url;
|
|
765
765
|
}
|
|
766
766
|
};
|
|
767
|
+
|
|
768
|
+
/**
|
|
769
|
+
* Rolls the session sampling dice.
|
|
770
|
+
*
|
|
771
|
+
* This is the only roll for a config without `excludeFromSampling`: `init` pins the
|
|
772
|
+
* rate it sends to native to 100 in that case, so native does not roll again. See the
|
|
773
|
+
* comment in `CoralogixRum.init` for why the exclude case is handled the other way round.
|
|
774
|
+
*/
|
|
767
775
|
function isSamplingOn(threshold) {
|
|
768
776
|
return threshold > 0 && Math.random() * 100 <= threshold;
|
|
769
777
|
}
|
|
778
|
+
|
|
779
|
+
/**
|
|
780
|
+
* Normalizes `sessionSampleRate` into the shape both native SDKs expect: an
|
|
781
|
+
* integer percentage in [0, 100].
|
|
782
|
+
*
|
|
783
|
+
* The bridges read the value as an integer (`NSNumber.intValue` on iOS,
|
|
784
|
+
* `ReadableMap.getInt` on Android), so a fractional rate such as `0.5` would be
|
|
785
|
+
* truncated to `0` on iOS — silently sampling every session out — and can throw
|
|
786
|
+
* on Android. Round instead, and never round a caller-requested non-zero rate
|
|
787
|
+
* down to `0`: `0` is the one value that means "emit nothing".
|
|
788
|
+
*/
|
|
789
|
+
function normalizeSessionSampleRate(rate) {
|
|
790
|
+
if (typeof rate !== 'number' || !Number.isFinite(rate)) {
|
|
791
|
+
logger.warn(`CoralogixRum: \`sessionSampleRate\` must be a finite number; received ${String(rate)}. Falling back to 100.`);
|
|
792
|
+
return 100;
|
|
793
|
+
}
|
|
794
|
+
if (rate <= 0) {
|
|
795
|
+
return 0;
|
|
796
|
+
}
|
|
797
|
+
if (rate >= 100) {
|
|
798
|
+
return 100;
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
// Keep a sub-1% request alive rather than truncating it to "emit nothing".
|
|
802
|
+
return Math.max(1, Math.round(rate));
|
|
803
|
+
}
|
|
770
804
|
function resolveCoralogixOtelWebConfig(config) {
|
|
771
805
|
var _config$sessionSample, _config$view_context;
|
|
772
806
|
const {
|
|
@@ -778,7 +812,7 @@ function resolveCoralogixOtelWebConfig(config) {
|
|
|
778
812
|
OPTIONS_DEFAULTS.ignoreUrls && resolvedIgnoreUrls.push(...OPTIONS_DEFAULTS.ignoreUrls);
|
|
779
813
|
return _extends({}, OPTIONS_DEFAULTS, config, {
|
|
780
814
|
ignoreUrls: resolvedIgnoreUrls,
|
|
781
|
-
sessionSampleRate: (_config$sessionSample = config.sessionSampleRate) != null ? _config$sessionSample : 100,
|
|
815
|
+
sessionSampleRate: normalizeSessionSampleRate((_config$sessionSample = config.sessionSampleRate) != null ? _config$sessionSample : 100),
|
|
782
816
|
debug,
|
|
783
817
|
view_context: (_config$view_context = config.view_context) != null ? _config$view_context : OPTIONS_DEFAULTS.view_context
|
|
784
818
|
});
|
|
@@ -1031,6 +1065,9 @@ function createErrorProxy(errorMessage) {
|
|
|
1031
1065
|
});
|
|
1032
1066
|
}
|
|
1033
1067
|
let isInited = false;
|
|
1068
|
+
// Whether native, rather than JS, rolled the sampling for this init. Only in that mode can
|
|
1069
|
+
// `CoralogixRum.isInited` be true while native has no RUM behind it.
|
|
1070
|
+
let nativeOwnsSamplingRoll = false;
|
|
1034
1071
|
let fetchInstrumentation;
|
|
1035
1072
|
function toSafeRecord(name, value) {
|
|
1036
1073
|
if (value == null) {
|
|
@@ -1047,7 +1084,7 @@ const CoralogixRum = {
|
|
|
1047
1084
|
return isInited;
|
|
1048
1085
|
},
|
|
1049
1086
|
init: async function (options) {
|
|
1050
|
-
var
|
|
1087
|
+
var _options$debug, _resolvedOptions$excl, _resolvedOptions$excl2;
|
|
1051
1088
|
if (isInited) {
|
|
1052
1089
|
console.warn('[Coralogix React Native SDK] - already initialized');
|
|
1053
1090
|
return;
|
|
@@ -1056,13 +1093,28 @@ const CoralogixRum = {
|
|
|
1056
1093
|
console.warn('[Coralogix React Native SDK] - `public_key` is required and must be a non-empty string; initialization aborted.');
|
|
1057
1094
|
return;
|
|
1058
1095
|
}
|
|
1096
|
+
|
|
1097
|
+
// Configure the logger first: resolving the options normalizes `sessionSampleRate`,
|
|
1098
|
+
// which warns about an invalid rate. Doing it the other way round swallowed that
|
|
1099
|
+
// warning on the first init — exactly when the caller needs to see it.
|
|
1100
|
+
logger.shouldLog = (_options$debug = options.debug) != null ? _options$debug : false;
|
|
1059
1101
|
const resolvedOptions = resolveCoralogixOtelWebConfig(options);
|
|
1060
|
-
|
|
1102
|
+
|
|
1103
|
+
// The rate has to be applied exactly *once*. Rolling it on both sides squared it:
|
|
1104
|
+
// `sessionSampleRate: 1` kept ~0.01% of sessions instead of 1%.
|
|
1105
|
+
//
|
|
1106
|
+
// Without `excludeFromSampling`, JS rolls and the rate sent to native is pinned to 100
|
|
1107
|
+
// so native does not roll again; a losing roll returns here, which also keeps JS
|
|
1108
|
+
// instrumentation off a session that would emit nothing. With `excludeFromSampling`,
|
|
1109
|
+
// only native can honour "sampled out, but still emit these categories", so JS does not
|
|
1110
|
+
// roll and forwards the real rate — pinning to 100 there would sample every session in.
|
|
1061
1111
|
const hasExcludeOverrides = ((_resolvedOptions$excl = (_resolvedOptions$excl2 = resolvedOptions.excludeFromSampling) == null ? void 0 : _resolvedOptions$excl2.length) != null ? _resolvedOptions$excl : 0) > 0;
|
|
1062
|
-
if (!isSamplingOn(resolvedOptions.sessionSampleRate)
|
|
1112
|
+
if (!hasExcludeOverrides && !isSamplingOn(resolvedOptions.sessionSampleRate)) {
|
|
1063
1113
|
logger.debug('CoralogixRum: Session tracking is disabled');
|
|
1064
1114
|
return;
|
|
1065
1115
|
}
|
|
1116
|
+
nativeOwnsSamplingRoll = hasExcludeOverrides;
|
|
1117
|
+
const nativeSessionSampleRate = hasExcludeOverrides ? resolvedOptions.sessionSampleRate : 100;
|
|
1066
1118
|
await registerCoralogixInstrumentations(resolvedOptions);
|
|
1067
1119
|
let finalOptions;
|
|
1068
1120
|
const lastNavRoute = getLastNavigationRouteDetected();
|
|
@@ -1093,6 +1145,7 @@ const CoralogixRum = {
|
|
|
1093
1145
|
});
|
|
1094
1146
|
}
|
|
1095
1147
|
await CxSdk.initialize(_extends({}, finalOptions, {
|
|
1148
|
+
sessionSampleRate: nativeSessionSampleRate,
|
|
1096
1149
|
frameworkVersion: pkg.version,
|
|
1097
1150
|
networkExtraConfig: finalOptions.networkExtraConfig ? serializeNetworkCaptureRules(finalOptions.networkExtraConfig) : undefined,
|
|
1098
1151
|
hasBeforeSend: !!finalOptions.beforeSend,
|
|
@@ -1278,7 +1331,21 @@ const SessionReplay = {
|
|
|
1278
1331
|
logger.warn("invalid options in SessionReplay.init: ", options);
|
|
1279
1332
|
return false;
|
|
1280
1333
|
}
|
|
1281
|
-
|
|
1334
|
+
try {
|
|
1335
|
+
// iOS resolves the string "initializeSessionReplay success" rather than a boolean,
|
|
1336
|
+
// so coerce instead of handing a truthy string back through a `Promise<boolean>`.
|
|
1337
|
+
return !!(await CxSdk.initializeSessionReplay(options));
|
|
1338
|
+
} catch (e) {
|
|
1339
|
+
// When native owns the sampling roll, a sampled-out session leaves no native RUM
|
|
1340
|
+
// behind and iOS rejects rather than resolving. That is an expected outcome, not a
|
|
1341
|
+
// failure, so report it as `false` like the guards above rather than surfacing an
|
|
1342
|
+
// unhandled rejection. Every other rejection is a real error and stays the caller's.
|
|
1343
|
+
if (!nativeOwnsSamplingRoll) {
|
|
1344
|
+
throw e;
|
|
1345
|
+
}
|
|
1346
|
+
logger.warn('SessionReplay.init: no native RUM for this session (sampled out); replay not started.', e);
|
|
1347
|
+
return false;
|
|
1348
|
+
}
|
|
1282
1349
|
},
|
|
1283
1350
|
shutdown: async () => {
|
|
1284
1351
|
logger.debug("session replay: shutdown called");
|
package/package.json
CHANGED
package/src/model/Types.d.ts
CHANGED
|
@@ -260,7 +260,17 @@ export interface CoralogixBrowserSdkConfig {
|
|
|
260
260
|
fpsSamplingSeconds?: number;
|
|
261
261
|
/** Sets a value for the `environment` attribute */
|
|
262
262
|
environment?: string;
|
|
263
|
-
/**
|
|
263
|
+
/**
|
|
264
|
+
* Percentage of overall sessions being tracked, defaults to 100%.
|
|
265
|
+
*
|
|
266
|
+
* The rate is applied exactly once. Without `excludeFromSampling` the plugin
|
|
267
|
+
* rolls it and the native SDK is told 100; with `excludeFromSampling` set the
|
|
268
|
+
* native SDK rolls it, since only native can emit the excluded categories for a
|
|
269
|
+
* sampled-out session.
|
|
270
|
+
*
|
|
271
|
+
* Expressed as a whole percentage in [0, 100]; a fractional value is rounded
|
|
272
|
+
* (never down to 0) because the native bridges read it as an integer.
|
|
273
|
+
*/
|
|
264
274
|
sessionSampleRate?: number;
|
|
265
275
|
/**
|
|
266
276
|
* Event categories that bypass session sampling. Events of these categories are
|
package/src/utils.d.ts
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
import { CoralogixBrowserSdkConfig } from './model/Types';
|
|
2
2
|
export declare const hrTimeToMilliseconds: ([seconds, nanoseconds]: [number, number]) => number;
|
|
3
3
|
export declare const getUrlFragments: (url: string) => string;
|
|
4
|
+
/**
|
|
5
|
+
* Rolls the session sampling dice.
|
|
6
|
+
*
|
|
7
|
+
* This is the only roll for a config without `excludeFromSampling`: `init` pins the
|
|
8
|
+
* rate it sends to native to 100 in that case, so native does not roll again. See the
|
|
9
|
+
* comment in `CoralogixRum.init` for why the exclude case is handled the other way round.
|
|
10
|
+
*/
|
|
4
11
|
export declare function isSamplingOn(threshold: number): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Normalizes `sessionSampleRate` into the shape both native SDKs expect: an
|
|
14
|
+
* integer percentage in [0, 100].
|
|
15
|
+
*
|
|
16
|
+
* The bridges read the value as an integer (`NSNumber.intValue` on iOS,
|
|
17
|
+
* `ReadableMap.getInt` on Android), so a fractional rate such as `0.5` would be
|
|
18
|
+
* truncated to `0` on iOS — silently sampling every session out — and can throw
|
|
19
|
+
* on Android. Round instead, and never round a caller-requested non-zero rate
|
|
20
|
+
* down to `0`: `0` is the one value that means "emit nothing".
|
|
21
|
+
*/
|
|
22
|
+
export declare function normalizeSessionSampleRate(rate: unknown): number;
|
|
5
23
|
export declare function resolveCoralogixOtelWebConfig(config: CoralogixBrowserSdkConfig): CoralogixBrowserSdkConfig;
|