@coralogix/react-native-plugin 0.1.5 → 0.1.6

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,12 @@
1
+ ## 0.1.6 (2025-10-26)
2
+ ### Patch
3
+ - Bump android native version to 2.5.51
4
+ - Bump ios native version to 1.3.0
5
+
6
+ ### 🚀 Features
7
+ - Integrate support for the Coralogix Gradle Plugin for automatic network instrumentation
8
+ - Added granular control for disabling only specific mobile vitals detectors
9
+
1
10
  ## 0.1.5 (2025-10-13)
2
11
 
3
12
  ### 🩹 Fixes
package/CxSdk.podspec CHANGED
@@ -16,8 +16,8 @@ Pod::Spec.new do |s|
16
16
 
17
17
  s.source_files = "ios/**/*.{h,m,mm,swift}"
18
18
 
19
- s.dependency 'Coralogix','1.2.3'
20
- s.dependency 'CoralogixInternal','1.2.3'
19
+ s.dependency 'Coralogix','1.3.0'
20
+ s.dependency 'CoralogixInternal','1.3.0'
21
21
 
22
22
 
23
23
  # Use install_modules_dependencies helper to install the dependencies if React Native version >=0.71.0.
package/README.md CHANGED
@@ -112,6 +112,24 @@ await CoralogixRum.init({
112
112
  });
113
113
  ```
114
114
 
115
+ ### Mobile Vital Detectors
116
+
117
+ Disable specific mobile vitals detection and collection
118
+
119
+ ```javascript
120
+ await CoralogixRum.init({
121
+ // ...
122
+ mobileVitals: {
123
+ warm: true,
124
+ cold: true,
125
+ cpu: true,
126
+ memory: true,
127
+ rendering: true,
128
+ slowFrozenFrames: true,
129
+ }
130
+ });
131
+ ```
132
+
115
133
  ### Ignore Errors
116
134
 
117
135
  The ignoreErrors option allows you to exclude errors that meet specific criteria.
@@ -177,6 +195,52 @@ await CoralogixRum.init({
177
195
  });
178
196
  ```
179
197
 
198
+ ### Optional - Coralogix Gradle Plugin (Android)
199
+
200
+ The Coralogix Gradle Plugin automatically instruments all OkHttp clients in your app (including third-party SDKs) at build time.
201
+ This ensures that all network traffic is automatically traced and reported to Coralogix, with no manual setup or code changes required.
202
+ This plugin is especially useful for instrumenting networking libraries that create their own OkHttpClient instances internally and would otherwise be impossible to monitor.
203
+
204
+ #### Apply the plugin
205
+
206
+ 1. Add the plugin to your project classpath <br /> In your project-level `build.gradle` file:
207
+ ```groovy
208
+ buildscript {
209
+ dependencies {
210
+ classpath "com.coralogix.gradle.plugin:gradle-plugin:0.0.2"
211
+ }
212
+ }
213
+ ```
214
+
215
+ 2. Apply the plugin in your app module <br /> At the top of your app-level build.gradle file:
216
+
217
+ ```groovy
218
+ apply plugin: "com.coralogix.gradle.plugin"
219
+ ```
220
+
221
+ #### Configure the plugin
222
+
223
+ The plugin exposes a simple Gradle extension you can use in your app module:
224
+
225
+ ```groovy
226
+ coralogix {
227
+ // Enable or disable instrumentation (default: true)
228
+ enabled = true
229
+
230
+ // Print debug logs during the build process (default: false)
231
+ log = false
232
+ }
233
+ ```
234
+
235
+ If the default configuration suits your needs, you can safely omit this block — the defaults will apply automatically.
236
+
237
+ #### Note
238
+
239
+ This plugin is optional.
240
+ Regular JavaScript `fetch` calls and standard network requests will still be instrumented without it.
241
+
242
+ However, the plugin is the only way to capture network activity from third-party libraries or SDKs that use their own `OkHttpClient` instances internally.
243
+
180
244
  ### Troubleshooting
181
245
 
182
246
  #### URL.origin is not implemented
@@ -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.2"
78
+ implementation "com.coralogix:android-sdk:2.5.51"
79
79
  }
80
80
 
81
81
  react {
@@ -15,6 +15,7 @@ import com.coralogix.android.sdk.model.CoralogixOptions
15
15
  import com.coralogix.android.sdk.model.Framework
16
16
  import com.coralogix.android.sdk.model.HybridMetric
17
17
  import com.coralogix.android.sdk.model.Instrumentation
18
+ import com.coralogix.android.sdk.model.MobileVitalType
18
19
  import com.coralogix.android.sdk.model.UserContext
19
20
  import com.coralogix.android.sdk.model.ViewContext
20
21
  import com.facebook.react.bridge.Arguments
@@ -171,6 +172,12 @@ class CxSdkModule(reactContext: ReactApplicationContext) :
171
172
  CoralogixRum.reportMobileVitalsMeasurement(type, list)
172
173
  }
173
174
 
175
+ @ReactMethod
176
+ override fun isCoralogixGradlePluginApplied(promise: Promise) {
177
+ val applied = CoralogixRum.isCoralogixGradlePluginApplied(reactApplicationContext)
178
+ promise.resolve(applied)
179
+ }
180
+
174
181
  @ReactMethod
175
182
  override fun shutdown(promise: Promise) {
176
183
  Handler(Looper.getMainLooper()).post {
@@ -222,11 +229,11 @@ class CxSdkModule(reactContext: ReactApplicationContext) :
222
229
  userContext = getMap("user_context")?.toUserContext() ?: UserContext(),
223
230
  viewContext = ViewContext(getMap("view_context")?.getString("view") ?: ""),
224
231
  instrumentations = getMap("instrumentations")?.toInstrumentationMap() ?: mapOf(),
232
+ mobileVitalsOptions = getMap("mobileVitals")?.toMobileVitalsOptions() ?: mapOf(),
225
233
  ignoreUrls = getArray("ignoreUrls")?.handleStringOrRegexList() ?: listOf(),
226
234
  ignoreErrors = getArray("ignoreErrors")?.handleStringOrRegexList() ?: listOf(),
227
235
  sessionSampleRate = 100,
228
236
  traceParentInHeader = isTraceParentInHeaderEnabled,
229
- fpsSamplingSeconds = if (hasKey("fpsSamplingSeconds")) getLong("fpsSamplingSeconds") else 300,
230
237
  debug = if (hasKey("debug")) getBoolean("debug") else false,
231
238
  proxyUrl = getString("proxyUrl"),
232
239
  beforeSendCallback = ::beforeSendCallback,
@@ -234,6 +241,25 @@ class CxSdkModule(reactContext: ReactApplicationContext) :
234
241
  )
235
242
  }
236
243
 
244
+ private fun ReadableMap.toMobileVitalsOptions(): Map<MobileVitalType, Boolean> {
245
+ val mapping = mapOf(
246
+ "cold" to MobileVitalType.ColdStartTime,
247
+ "warm" to MobileVitalType.WarmStartTime,
248
+ "cpu" to MobileVitalType.CpuUsage,
249
+ "memory" to MobileVitalType.MemoryUsage,
250
+ "slowFrozenFrames" to MobileVitalType.SlowFrozenFrames,
251
+ "rendering" to MobileVitalType.Fps
252
+ )
253
+
254
+ return buildMap {
255
+ for ((key, type) in mapping) {
256
+ if (hasKey(key) && !isNull(key)) {
257
+ put(type, getBoolean(key))
258
+ }
259
+ }
260
+ }
261
+ }
262
+
237
263
  private fun beforeSendCallback(data: List<Map<String, Any?>>) {
238
264
  val args = convertAnyListToWritableArray(data)
239
265
  if (!reactApplicationContext.hasActiveReactInstance()) return
@@ -20,5 +20,6 @@ interface ICxSdkModule {
20
20
  fun sendCxSpanData(results: ReadableArray)
21
21
  fun reportMobileVitalsMeasurement(type: String, value: Double, units: String)
22
22
  fun reportMobileVitalsMeasurementSet(type: String, metrics: ReadableArray)
23
+ fun isCoralogixGradlePluginApplied(promise: Promise)
23
24
  fun shutdown(promise: Promise)
24
25
  }
package/index.cjs.js CHANGED
@@ -219,7 +219,7 @@ function stopJsRefreshRateSampler() {
219
219
  appStateSub = null;
220
220
  }
221
221
 
222
- var version = "0.1.5";
222
+ var version = "0.1.6";
223
223
  var pkg = {
224
224
  version: version};
225
225
 
@@ -417,7 +417,7 @@ const CoralogixRum = {
417
417
  logger.debug('CoralogixRum: Session tracking is disabled');
418
418
  return;
419
419
  }
420
- registerCoralogixInstrumentations(resolvedOptions);
420
+ await registerCoralogixInstrumentations(resolvedOptions);
421
421
  await CxSdk.initialize(_extends({}, resolvedOptions, {
422
422
  frameworkVersion: pkg.version
423
423
  }));
@@ -544,11 +544,15 @@ const CoralogixRum = {
544
544
  }
545
545
  };
546
546
  function trackMobileVitals(options) {
547
- startJsRefreshRateSampler(_extends({}, options.jsRefreshRateSampleRate, {
548
- onSample: jsRefreshRate => {
549
- CxSdk.reportMobileVitalsMeasurement('js_refresh_rate', Math.round(jsRefreshRate), 'fps');
550
- }
551
- }));
547
+ var _options$mobileVitals;
548
+ const shouldEnableJsRefreshRateDetector = ((_options$mobileVitals = options.mobileVitals) == null ? void 0 : _options$mobileVitals.jsRefreshRate) !== false;
549
+ if (shouldEnableJsRefreshRateDetector) {
550
+ startJsRefreshRateSampler(_extends({}, options.jsRefreshRateSampleRate, {
551
+ onSample: jsRefreshRate => {
552
+ CxSdk.reportMobileVitalsMeasurement('js_refresh_rate', Math.round(jsRefreshRate), 'fps');
553
+ }
554
+ }));
555
+ }
552
556
 
553
557
  // startJSLoopDetector({
554
558
  // ...options.jsLoopDetection,
@@ -575,7 +579,7 @@ function cleanupResources() {
575
579
  stopJsRefreshRateSampler();
576
580
  // stopJSLoopDetector();
577
581
  }
578
- function registerCoralogixInstrumentations(options) {
582
+ async function registerCoralogixInstrumentations(options) {
579
583
  if (options.beforeSend) {
580
584
  beforeSendCallback = options.beforeSend;
581
585
  }
@@ -583,8 +587,13 @@ function registerCoralogixInstrumentations(options) {
583
587
  const instrumentations = [];
584
588
  const instrumentationsOptions = options.instrumentations;
585
589
 
586
- // disable network for ios, since swizzle will capture the fetch requests
587
- const shouldInterceptNetowrk = reactNative.Platform.OS === 'android' && (!instrumentationsOptions || instrumentationsOptions.network !== false);
590
+ // disable network for ios, since swizzle will capture the fetch requests, and for android if gradle plugin is applied
591
+ const isAndroid = reactNative.Platform.OS === 'android';
592
+ let pluginApplied = false;
593
+ if (isAndroid) {
594
+ pluginApplied = await CxSdk.isCoralogixGradlePluginApplied();
595
+ }
596
+ const shouldInterceptNetowrk = isAndroid && !pluginApplied && (!instrumentationsOptions || instrumentationsOptions.network !== false);
588
597
  const shouldInterceptErrors = !instrumentationsOptions || instrumentationsOptions.errors !== false;
589
598
  const shouldInterceptMobileVitals = !instrumentationsOptions || instrumentationsOptions.mobile_vitals !== false;
590
599
 
package/index.esm.js CHANGED
@@ -217,7 +217,7 @@ function stopJsRefreshRateSampler() {
217
217
  appStateSub = null;
218
218
  }
219
219
 
220
- var version = "0.1.5";
220
+ var version = "0.1.6";
221
221
  var pkg = {
222
222
  version: version};
223
223
 
@@ -415,7 +415,7 @@ const CoralogixRum = {
415
415
  logger.debug('CoralogixRum: Session tracking is disabled');
416
416
  return;
417
417
  }
418
- registerCoralogixInstrumentations(resolvedOptions);
418
+ await registerCoralogixInstrumentations(resolvedOptions);
419
419
  await CxSdk.initialize(_extends({}, resolvedOptions, {
420
420
  frameworkVersion: pkg.version
421
421
  }));
@@ -542,11 +542,15 @@ const CoralogixRum = {
542
542
  }
543
543
  };
544
544
  function trackMobileVitals(options) {
545
- startJsRefreshRateSampler(_extends({}, options.jsRefreshRateSampleRate, {
546
- onSample: jsRefreshRate => {
547
- CxSdk.reportMobileVitalsMeasurement('js_refresh_rate', Math.round(jsRefreshRate), 'fps');
548
- }
549
- }));
545
+ var _options$mobileVitals;
546
+ const shouldEnableJsRefreshRateDetector = ((_options$mobileVitals = options.mobileVitals) == null ? void 0 : _options$mobileVitals.jsRefreshRate) !== false;
547
+ if (shouldEnableJsRefreshRateDetector) {
548
+ startJsRefreshRateSampler(_extends({}, options.jsRefreshRateSampleRate, {
549
+ onSample: jsRefreshRate => {
550
+ CxSdk.reportMobileVitalsMeasurement('js_refresh_rate', Math.round(jsRefreshRate), 'fps');
551
+ }
552
+ }));
553
+ }
550
554
 
551
555
  // startJSLoopDetector({
552
556
  // ...options.jsLoopDetection,
@@ -573,7 +577,7 @@ function cleanupResources() {
573
577
  stopJsRefreshRateSampler();
574
578
  // stopJSLoopDetector();
575
579
  }
576
- function registerCoralogixInstrumentations(options) {
580
+ async function registerCoralogixInstrumentations(options) {
577
581
  if (options.beforeSend) {
578
582
  beforeSendCallback = options.beforeSend;
579
583
  }
@@ -581,8 +585,13 @@ function registerCoralogixInstrumentations(options) {
581
585
  const instrumentations = [];
582
586
  const instrumentationsOptions = options.instrumentations;
583
587
 
584
- // disable network for ios, since swizzle will capture the fetch requests
585
- const shouldInterceptNetowrk = Platform.OS === 'android' && (!instrumentationsOptions || instrumentationsOptions.network !== false);
588
+ // disable network for ios, since swizzle will capture the fetch requests, and for android if gradle plugin is applied
589
+ const isAndroid = Platform.OS === 'android';
590
+ let pluginApplied = false;
591
+ if (isAndroid) {
592
+ pluginApplied = await CxSdk.isCoralogixGradlePluginApplied();
593
+ }
594
+ const shouldInterceptNetowrk = isAndroid && !pluginApplied && (!instrumentationsOptions || instrumentationsOptions.network !== false);
586
595
  const shouldInterceptErrors = !instrumentationsOptions || instrumentationsOptions.errors !== false;
587
596
  const shouldInterceptMobileVitals = !instrumentationsOptions || instrumentationsOptions.mobile_vitals !== false;
588
597
 
package/ios/CxSdk.swift CHANGED
@@ -63,7 +63,7 @@ class CxSdk: RCTEventEmitter {
63
63
  @objc(getUserContext:withRejecter:)
64
64
  func getUserContext(resolve: @escaping RCTPromiseResolveBlock,
65
65
  reject: @escaping RCTPromiseRejectBlock) {
66
- let userContext = coralogixRum?.getUserContext()
66
+ let userContext = coralogixRum?.userContext
67
67
  resolve(userContext?.getDictionary())
68
68
  }
69
69
 
@@ -72,13 +72,13 @@ class CxSdk: RCTEventEmitter {
72
72
  resolve:RCTPromiseResolveBlock,
73
73
  reject:RCTPromiseRejectBlock) -> Void {
74
74
  let labels = labelsMap as? [String: String] ?? [String: String]()
75
- resolve(coralogixRum?.setLabels(labels: labels))
75
+ resolve(coralogixRum?.set(labels: labels))
76
76
  }
77
77
 
78
78
  @objc(getLabels:withRejecter:)
79
79
  func getLabels(resolve: @escaping RCTPromiseResolveBlock,
80
80
  reject: @escaping RCTPromiseRejectBlock) {
81
- if let labels = coralogixRum?.getLabels() {
81
+ if let labels = coralogixRum?.labels {
82
82
  resolve(labels) // Assuming labels is a Dictionary or Array
83
83
  } else {
84
84
  reject("GET_LABELS_ERROR", "Failed to retrieve labels", nil)
@@ -100,7 +100,7 @@ class CxSdk: RCTEventEmitter {
100
100
  @objc(isInited:withRejecter:)
101
101
  func isInited(resolve: @escaping RCTPromiseResolveBlock,
102
102
  reject: @escaping RCTPromiseRejectBlock) {
103
- if let isInit = coralogixRum?.isInitialized() {
103
+ if let isInit = coralogixRum?.isInitialized {
104
104
  resolve(isInit)
105
105
  } else {
106
106
  reject("IS_INITED", "Failed to retrieve isInited", nil)
@@ -149,7 +149,7 @@ class CxSdk: RCTEventEmitter {
149
149
  @objc(getSessionId:withRejecter:)
150
150
  func getSessionId(resolve: @escaping RCTPromiseResolveBlock,
151
151
  reject: @escaping RCTPromiseRejectBlock) -> Void {
152
- let sessionId = coralogixRum?.getSessionId()
152
+ let sessionId = coralogixRum?.getSessionId
153
153
  resolve(sessionId)
154
154
  }
155
155
 
@@ -199,7 +199,7 @@ class CxSdk: RCTEventEmitter {
199
199
  reject("Invalid sendBeforeSendData", "sendBeforeSendData is not a dictionary", nil)
200
200
  return
201
201
  }
202
- coralogixRum?.sendBeforeSendData(data: beforeSendResults)
202
+ coralogixRum?.sendBeforeSendData(beforeSendResults)
203
203
  resolve("sendBeforeSendData success")
204
204
  }
205
205
 
@@ -270,6 +270,14 @@ class CxSdk: RCTEventEmitter {
270
270
  }
271
271
  }
272
272
 
273
+ let mobileVitals = parameter["mobileVitals"] as? [String: Int] ?? [String: Int]()
274
+ var mobileVitalsDict: [CoralogixExporterOptions.MobileVitalsType: Bool] = [:]
275
+ for (key, value) in mobileVitals {
276
+ if let mobileVitalsKey = mobileVitalsType(from: key) {
277
+ mobileVitalsDict[mobileVitalsKey] = value == 0 ? false : true
278
+ }
279
+ }
280
+
273
281
  let userContext = parameter["user_context"] as? [String: Any]
274
282
  let userMetadata = userContext?["user_metadata"] as? [String: String] ?? [String: String]()
275
283
  let coralogixUser = UserContext(userId: userContext?["user_id"] as? String ?? "",
@@ -287,12 +295,12 @@ class CxSdk: RCTEventEmitter {
287
295
  ignoreUrls: ignoreUrls,
288
296
  ignoreErrors: ignoreError,
289
297
  labels: labels,
290
- sampleRate: 100,
291
- mobileVitalsFPSSamplingRate: parameter["fpsSamplingSeconds"] as? Int ?? 300,
298
+ fpsSampleRate: parameter["fpsSamplingSeconds"] as? TimeInterval ?? 300,
292
299
  instrumentations: instrumentationDict,
293
300
  collectIPData: parameter["collectIPData"] as? Bool ?? true,
294
301
  proxyUrl: parameter["proxyUrl"] as? String ?? nil,
295
302
  traceParentInHeader: parameter["traceParentInHeader"] as? [String: Any] ?? nil,
303
+ mobileVitals: mobileVitalsDict,
296
304
  debug: parameter["debug"] as? Bool ?? true)
297
305
 
298
306
  return options
@@ -326,6 +334,25 @@ class CxSdk: RCTEventEmitter {
326
334
  userMetadata: userMetadata)
327
335
  }
328
336
 
337
+ private func mobileVitalsType(from string: String) -> CoralogixExporterOptions.MobileVitalsType? {
338
+ switch string {
339
+ case "warm":
340
+ return .warmDetector
341
+ case "cold":
342
+ return .coldDetector
343
+ case "rendering":
344
+ return .renderingDetector
345
+ case "cpu":
346
+ return .cpuDetector
347
+ case "memory":
348
+ return .memoryDetector
349
+ case "slowFrozenFrames":
350
+ return .slowFrozenFramesDetector
351
+ default:
352
+ return nil
353
+ }
354
+ }
355
+
329
356
  private func instrumentationType(from string: String) -> CoralogixExporterOptions.InstrumentationType? {
330
357
  switch string {
331
358
  case "mobile_vitals":
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coralogix/react-native-plugin",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "Official Coralogix React Native plugin",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Coralogix",
package/src/index.d.ts CHANGED
@@ -8,3 +8,4 @@ export { type CoralogixBrowserSdkConfig, CoralogixLogSeverity, } from './model/T
8
8
  export { type CoralogixOtelWebOptionsInstrumentations } from './model/CoralogixOtelWebOptionsInstrumentations';
9
9
  export { type CustomMeasurement } from './model/CustomMeasurement';
10
10
  export { type NetworkRequestDetails } from './model/NetworkRequestDetails';
11
+ export { type CoralogixMobileVitals } from './model/CoralogixMobileVitals';
@@ -0,0 +1,9 @@
1
+ export interface CoralogixMobileVitals {
2
+ warm?: boolean;
3
+ cold?: boolean;
4
+ cpu?: boolean;
5
+ memory?: boolean;
6
+ rendering?: boolean;
7
+ slowFrozenFrames?: boolean;
8
+ jsRefreshRate?: boolean;
9
+ }
@@ -3,6 +3,7 @@ import type { CoralogixOtelWebOptionsInstrumentations } from './CoralogixOtelWeb
3
3
  import { CoralogixDomain } from './CoralogixDomain';
4
4
  import { UserContextConfig } from './UserContextConfig';
5
5
  import { ViewContextConfig } from './ViewContextConfig';
6
+ import type { CoralogixMobileVitals } from './CoralogixMobileVitals.ts';
6
7
  export interface CxSpan {
7
8
  version_metadata: VersionMetaData;
8
9
  applicationName: string;
@@ -200,6 +201,7 @@ export interface CoralogixBrowserSdkConfig {
200
201
  /** Interval between FPS measurements in milliseconds (default: 300000 = 5 minutes) */
201
202
  sampleIntervalMs?: number;
202
203
  };
204
+ mobileVitals?: CoralogixMobileVitals;
203
205
  }
204
206
  export type HybridMetric = {
205
207
  name: string;