@coralogix/react-native-plugin 0.1.6 → 0.1.8

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 CHANGED
@@ -1,3 +1,18 @@
1
+ ## 0.1.8 (2025-11-04)
2
+
3
+ ### 🩹 Fixes
4
+
5
+ - the log can now get any type for the data and labels map parameters
6
+
7
+ ## 0.1.7 (2025-11-02)
8
+
9
+ ### 🚀 Features
10
+
11
+ - added automatic navigation detection using the @react-navigation/native package
12
+
13
+ ### Patch
14
+ - Bump android native version to 2.5.6
15
+
1
16
  ## 0.1.6 (2025-10-26)
2
17
  ### Patch
3
18
  - Bump android native version to 2.5.51
package/README.md CHANGED
@@ -67,6 +67,31 @@ CoralogixRum.log(CoralogixLogSeverity.Error, 'this is a log', { key: 'value' });
67
67
  CoralogixRum.error('this is a log with error severity', { key: 'value' });
68
68
  ```
69
69
 
70
+ ### Custom Logs
71
+
72
+ Send structured logs with optional data and labels.
73
+ ```javascript
74
+ CoralogixRum.log(CoralogixLogSeverity.Error, 'this is a log', { key: 'value' });
75
+ ```
76
+
77
+ Shorthand signatures exists for all log severities:
78
+ ```javascript
79
+ CoralogixRum.debug('this is a debug log', {key: 'value', pi: 3.14});
80
+ CoralogixRum.error('this is an error log', {error: 'yes', is_bad: 'no'});
81
+ ```
82
+
83
+ > **Note:** Due to ReactNative limitations, not all value types are supported for the log data values,
84
+ > our testing shows that ReactNative can't pass some types to the coralogix native layer, types we have identified as problematic are `Map`, `Set`, `Date` and `Function`
85
+ > please note that there could be more, so for example:
86
+ > ```javascript
87
+ > // this would pass as an empty object to the coralogix native layer, same for Set and Date:
88
+ > CoralogixRum.debug('this will be a problem', {key: new Map().set(1, 2)});
89
+ >
90
+ > // this would pass as null to the coralogix native layer
91
+ > CoralogixRum.debug('this will be a problem too', {key: () => {}});
92
+ > ```
93
+ > in the event that you need to use any of these types please stringify them before you pass it to the `log` method
94
+
70
95
  ### View Tracking
71
96
 
72
97
  To track views, set the view context whenever a view changes.
@@ -78,15 +103,16 @@ CoralogixRum.setViewContext({
78
103
  ```
79
104
 
80
105
  You can automatically track view changes by using [react-navigation](https://reactnavigation.org/docs/navigation-container/#onstatechange).
106
+ Wrap your navigation ref with our `attachReactNavigationObserver` hook like so:
81
107
 
82
108
  ```javascript
109
+ const navigationRef = createNavigationContainerRef();
110
+ const navHooks = attachReactNavigationObserver(navigationRef);
111
+
83
112
  <NavigationContainer
84
113
  ref={navigationRef}
85
- onStateChange={() => {
86
- const currentRouteName = navigationRef.current.getCurrentRoute().name;
87
-
88
- CoralogixRum.setViewContext({ view: currentRouteName });
89
- }}
114
+ onReady={navHooks.onReady}
115
+ onStateChange={navHooks.onStateChange}
90
116
  >
91
117
  >{/* ... */}
92
118
  </NavigationContainer>
@@ -75,7 +75,7 @@ dependencies {
75
75
  implementation "com.facebook.react:react-android"
76
76
  implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
77
77
 
78
- implementation "com.coralogix:android-sdk:2.5.51"
78
+ implementation "com.coralogix:android-sdk:2.5.6"
79
79
  }
80
80
 
81
81
  react {
@@ -29,6 +29,8 @@ import com.facebook.react.bridge.ReadableType
29
29
  import com.facebook.react.bridge.WritableArray
30
30
  import com.facebook.react.bridge.WritableMap
31
31
  import com.facebook.react.modules.core.DeviceEventManagerModule
32
+ import org.json.JSONArray
33
+ import org.json.JSONObject
32
34
  import java.lang.Long.getLong
33
35
 
34
36
  class CxSdkModule(reactContext: ReactApplicationContext) :
@@ -425,13 +427,65 @@ class CxSdkModule(reactContext: ReactApplicationContext) :
425
427
  }
426
428
 
427
429
  private fun ReadableMap.toStringMap(): Map<String, String> {
428
- val map = mutableMapOf<String, String>()
430
+ val result = mutableMapOf<String, String>()
429
431
  val iterator = keySetIterator()
430
432
  while (iterator.hasNextKey()) {
431
433
  val key = iterator.nextKey()
432
- getString(key)?.let { map[key] = it }
434
+ val jsonValue = when (getType(key)) {
435
+ ReadableType.Null -> JSONObject.NULL
436
+ ReadableType.Boolean -> getBoolean(key)
437
+ ReadableType.Number -> getDouble(key)
438
+ ReadableType.String -> getString(key)
439
+ ReadableType.Map -> getMap(key)?.toJsonObject()
440
+ ReadableType.Array -> getArray(key)?.toJsonArray()
441
+ else -> JSONObject.NULL
442
+ }
443
+
444
+ // Always serialize as JSON string
445
+ result[key] = when (jsonValue) {
446
+ is JSONObject, is JSONArray -> jsonValue.toString()
447
+ JSONObject.NULL -> "null"
448
+ else -> JSONObject.wrap(jsonValue)?.toString() ?: "null"
449
+ }
433
450
  }
434
- return map
451
+
452
+ return result
453
+ }
454
+
455
+ private fun ReadableMap.toJsonObject(): JSONObject {
456
+ val obj = JSONObject()
457
+ val iterator = keySetIterator()
458
+ while (iterator.hasNextKey()) {
459
+ val key = iterator.nextKey()
460
+ val value = when (getType(key)) {
461
+ ReadableType.Null -> JSONObject.NULL
462
+ ReadableType.Boolean -> getBoolean(key)
463
+ ReadableType.Number -> getDouble(key)
464
+ ReadableType.String -> getString(key)
465
+ ReadableType.Map -> getMap(key)?.toJsonObject()
466
+ ReadableType.Array -> getArray(key)?.toJsonArray()
467
+ else -> JSONObject.NULL
468
+ }
469
+ obj.put(key, value)
470
+ }
471
+ return obj
472
+ }
473
+
474
+ private fun ReadableArray.toJsonArray(): JSONArray {
475
+ val arr = JSONArray()
476
+ for (i in 0 until size()) {
477
+ val value = when (getType(i)) {
478
+ ReadableType.Null -> JSONObject.NULL
479
+ ReadableType.Boolean -> getBoolean(i)
480
+ ReadableType.Number -> getDouble(i)
481
+ ReadableType.String -> getString(i)
482
+ ReadableType.Map -> getMap(i)?.toJsonObject()
483
+ ReadableType.Array -> getArray(i)?.toJsonArray()
484
+ else -> JSONObject.NULL
485
+ }
486
+ arr.put(value)
487
+ }
488
+ return arr
435
489
  }
436
490
 
437
491
  private fun Map<String, String>.toWritableMap(): WritableMap {
package/index.cjs.js CHANGED
@@ -219,7 +219,7 @@ function stopJsRefreshRateSampler() {
219
219
  appStateSub = null;
220
220
  }
221
221
 
222
- var version = "0.1.6";
222
+ var version = "0.1.8";
223
223
  var pkg = {
224
224
  version: version};
225
225
 
@@ -373,6 +373,34 @@ class CoralogixFetchInstrumentation extends instrumentationFetch.FetchInstrument
373
373
  }
374
374
  }
375
375
 
376
+ let lastRouteName;
377
+ function getLastNavigationRouteDetected() {
378
+ return lastRouteName;
379
+ }
380
+ function attachReactNavigationObserver(ref) {
381
+ const report = () => {
382
+ const route = ref.getCurrentRoute();
383
+ if (!route) return;
384
+ const name = route.name;
385
+ if (name !== lastRouteName) {
386
+ if (CoralogixRum.isInited) {
387
+ CoralogixRum.setViewContext({
388
+ view: name
389
+ });
390
+ }
391
+ lastRouteName = name;
392
+ }
393
+ };
394
+ const onReady = () => {
395
+ // Wait a tick to ensure the route is initialized
396
+ setTimeout(report, 0);
397
+ };
398
+ return {
399
+ onReady,
400
+ onStateChange: report
401
+ };
402
+ }
403
+
376
404
  let CoralogixDomain = /*#__PURE__*/function (CoralogixDomain) {
377
405
  CoralogixDomain["EU1"] = "EU1";
378
406
  CoralogixDomain["EU2"] = "EU2";
@@ -418,7 +446,18 @@ const CoralogixRum = {
418
446
  return;
419
447
  }
420
448
  await registerCoralogixInstrumentations(resolvedOptions);
421
- await CxSdk.initialize(_extends({}, resolvedOptions, {
449
+ let finalOptions;
450
+ const lastNavRoute = getLastNavigationRouteDetected();
451
+ if (lastNavRoute) {
452
+ finalOptions = _extends({}, resolvedOptions, {
453
+ view_context: {
454
+ view: lastNavRoute
455
+ }
456
+ });
457
+ } else {
458
+ finalOptions = resolvedOptions;
459
+ }
460
+ await CxSdk.initialize(_extends({}, finalOptions, {
422
461
  frameworkVersion: pkg.version
423
462
  }));
424
463
  isInited = true;
@@ -690,3 +729,4 @@ const subscription = eventEmitter.addListener('onBeforeSend', events => {
690
729
  exports.CoralogixDomain = CoralogixDomain;
691
730
  exports.CoralogixLogSeverity = CoralogixLogSeverity;
692
731
  exports.CoralogixRum = CoralogixRum;
732
+ exports.attachReactNavigationObserver = attachReactNavigationObserver;
package/index.esm.js CHANGED
@@ -217,7 +217,7 @@ function stopJsRefreshRateSampler() {
217
217
  appStateSub = null;
218
218
  }
219
219
 
220
- var version = "0.1.6";
220
+ var version = "0.1.8";
221
221
  var pkg = {
222
222
  version: version};
223
223
 
@@ -371,6 +371,34 @@ class CoralogixFetchInstrumentation extends FetchInstrumentation {
371
371
  }
372
372
  }
373
373
 
374
+ let lastRouteName;
375
+ function getLastNavigationRouteDetected() {
376
+ return lastRouteName;
377
+ }
378
+ function attachReactNavigationObserver(ref) {
379
+ const report = () => {
380
+ const route = ref.getCurrentRoute();
381
+ if (!route) return;
382
+ const name = route.name;
383
+ if (name !== lastRouteName) {
384
+ if (CoralogixRum.isInited) {
385
+ CoralogixRum.setViewContext({
386
+ view: name
387
+ });
388
+ }
389
+ lastRouteName = name;
390
+ }
391
+ };
392
+ const onReady = () => {
393
+ // Wait a tick to ensure the route is initialized
394
+ setTimeout(report, 0);
395
+ };
396
+ return {
397
+ onReady,
398
+ onStateChange: report
399
+ };
400
+ }
401
+
374
402
  let CoralogixDomain = /*#__PURE__*/function (CoralogixDomain) {
375
403
  CoralogixDomain["EU1"] = "EU1";
376
404
  CoralogixDomain["EU2"] = "EU2";
@@ -416,7 +444,18 @@ const CoralogixRum = {
416
444
  return;
417
445
  }
418
446
  await registerCoralogixInstrumentations(resolvedOptions);
419
- await CxSdk.initialize(_extends({}, resolvedOptions, {
447
+ let finalOptions;
448
+ const lastNavRoute = getLastNavigationRouteDetected();
449
+ if (lastNavRoute) {
450
+ finalOptions = _extends({}, resolvedOptions, {
451
+ view_context: {
452
+ view: lastNavRoute
453
+ }
454
+ });
455
+ } else {
456
+ finalOptions = resolvedOptions;
457
+ }
458
+ await CxSdk.initialize(_extends({}, finalOptions, {
420
459
  frameworkVersion: pkg.version
421
460
  }));
422
461
  isInited = true;
@@ -685,4 +724,4 @@ const subscription = eventEmitter.addListener('onBeforeSend', events => {
685
724
  }
686
725
  });
687
726
 
688
- export { CoralogixDomain, CoralogixLogSeverity, CoralogixRum };
727
+ export { CoralogixDomain, CoralogixLogSeverity, CoralogixRum, attachReactNavigationObserver };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coralogix/react-native-plugin",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "description": "Official Coralogix React Native plugin",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Coralogix",
@@ -25,8 +25,8 @@
25
25
  },
26
26
  "main": "./index.cjs.js",
27
27
  "dependencies": {
28
- "@opentelemetry/instrumentation-fetch": "0.203.0",
29
28
  "@opentelemetry/instrumentation": "0.48.0",
29
+ "@opentelemetry/instrumentation-fetch": "0.203.0",
30
30
  "@opentelemetry/sdk-trace-web": "1.30.1"
31
31
  },
32
32
  "module": "./index.esm.js",
package/src/index.d.ts CHANGED
@@ -9,3 +9,4 @@ export { type CoralogixOtelWebOptionsInstrumentations } from './model/CoralogixO
9
9
  export { type CustomMeasurement } from './model/CustomMeasurement';
10
10
  export { type NetworkRequestDetails } from './model/NetworkRequestDetails';
11
11
  export { type CoralogixMobileVitals } from './model/CoralogixMobileVitals';
12
+ export { attachReactNavigationObserver } from './instrumentations/navigation/NavigationInstrumentation';
@@ -0,0 +1,8 @@
1
+ export declare function getLastNavigationRouteDetected(): string | undefined;
2
+ export type CurrentRouteProvider = {
3
+ getCurrentRoute: any;
4
+ };
5
+ export declare function attachReactNavigationObserver(ref: CurrentRouteProvider): {
6
+ onReady: () => void;
7
+ onStateChange: () => void;
8
+ };