@coralogix/react-native-plugin 0.3.2 → 0.4.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 +16 -0
- package/CxSdk.podspec +3 -3
- package/README.md +96 -0
- package/android/build.gradle +13 -1
- package/android/src/main/java/com/cxsdk/CxSdkModule.kt +113 -3
- package/android/src/main/java/com/cxsdk/RUMClient.kt +5 -0
- package/android/src/test/kotlin/com/cxsdk/ExtractOtelIdsTest.kt +49 -0
- package/index.cjs.js +172 -2
- package/index.esm.js +170 -3
- package/ios/CxSdk.mm +16 -0
- package/ios/CxSdk.swift +90 -1
- package/package.json +1 -1
- package/src/custom-spans/CoralogixCustomSpan.d.ts +9 -0
- package/src/custom-spans/CoralogixCustomTracer.d.ts +18 -0
- package/src/custom-spans/CoralogixGlobalSpan.d.ts +20 -0
- package/src/custom-spans/CustomSpanBridge.d.ts +11 -0
- package/src/custom-spans/CustomSpanRegistry.d.ts +12 -0
- package/src/index.d.ts +14 -1
- package/src/model/CoralogixDomain.d.ts +1 -0
- package/src/model/CoralogixOtelWebType.d.ts +7 -1
- package/src/model/Types.d.ts +12 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
## 0.4.0 (2026-05-03)
|
|
2
|
+
|
|
3
|
+
### 🚀 Features
|
|
4
|
+
|
|
5
|
+
- Custom Spans & Traces Exporter (CX-36055)
|
|
6
|
+
|
|
7
|
+
### 🩹 Fixes
|
|
8
|
+
|
|
9
|
+
- import CoralogixIgnoredInstrument in index.ts for rollup build
|
|
10
|
+
|
|
11
|
+
## 0.3.3 (2026-04-05)
|
|
12
|
+
|
|
13
|
+
### 🩹 Fixes
|
|
14
|
+
|
|
15
|
+
- bump Android SDK to 2.9.5 to fix ClassCastException with react-native-skia
|
|
16
|
+
|
|
1
17
|
## 0.3.2 (2026-03-29)
|
|
2
18
|
|
|
3
19
|
### 🩹 Patch
|
package/CxSdk.podspec
CHANGED
|
@@ -16,9 +16,9 @@ Pod::Spec.new do |s|
|
|
|
16
16
|
|
|
17
17
|
s.source_files = "ios/**/*.{h,m,mm,swift}"
|
|
18
18
|
|
|
19
|
-
s.dependency 'Coralogix','2.
|
|
20
|
-
s.dependency 'CoralogixInternal','2.
|
|
21
|
-
s.dependency 'SessionReplay','2.
|
|
19
|
+
s.dependency 'Coralogix','2.6.2'
|
|
20
|
+
s.dependency 'CoralogixInternal','2.6.2'
|
|
21
|
+
s.dependency 'SessionReplay','2.6.2'
|
|
22
22
|
|
|
23
23
|
# Use install_modules_dependencies helper to install the dependencies if React Native version >=0.71.0.
|
|
24
24
|
# See https://github.com/facebook/react-native/blob/febf6b7f33fdb4904669f99d795eba4c0f95d7bf/scripts/cocoapods/new_architecture.rb#L79.
|
package/README.md
CHANGED
|
@@ -184,6 +184,102 @@ await CoralogixRum.init({
|
|
|
184
184
|
});
|
|
185
185
|
```
|
|
186
186
|
|
|
187
|
+
### Custom Spans
|
|
188
|
+
|
|
189
|
+
Create manual RUM spans to instrument custom flows in your application. Requires `traceParentInHeader.enabled: true`.
|
|
190
|
+
|
|
191
|
+
**Prerequisite:**
|
|
192
|
+
```javascript
|
|
193
|
+
await CoralogixRum.init({
|
|
194
|
+
// ...
|
|
195
|
+
traceParentInHeader: { enabled: true },
|
|
196
|
+
});
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
**Basic usage — global span with a child:**
|
|
200
|
+
```javascript
|
|
201
|
+
import { CoralogixRum } from '@coralogix/react-native-plugin';
|
|
202
|
+
|
|
203
|
+
const tracer = CoralogixRum.getCustomTracer();
|
|
204
|
+
|
|
205
|
+
const globalSpan = await tracer.startGlobalSpan('checkout', { step: 'start' });
|
|
206
|
+
if (!globalSpan) return; // another global span is already active
|
|
207
|
+
|
|
208
|
+
const childSpan = await globalSpan.startCustomSpan('validate-cart');
|
|
209
|
+
await childSpan?.endSpan();
|
|
210
|
+
|
|
211
|
+
await globalSpan.endSpan();
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
**Linking network requests with `withContext`:**
|
|
215
|
+
|
|
216
|
+
When you call `fetch` inside `withContext`, the network request is automatically linked to the active global span's trace.
|
|
217
|
+
|
|
218
|
+
```javascript
|
|
219
|
+
const globalSpan = await tracer.startGlobalSpan('checkout');
|
|
220
|
+
|
|
221
|
+
await globalSpan.withContext(async () => {
|
|
222
|
+
await fetch('https://api.example.com/cart'); // linked to globalSpan's traceId
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
await globalSpan.endSpan();
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
**`ignoredInstruments` — exclude auto-instrumentation from the trace:**
|
|
229
|
+
|
|
230
|
+
Pass instrument names to prevent network requests, errors, or interactions fired during this tracer's spans from being linked to your custom trace.
|
|
231
|
+
|
|
232
|
+
```javascript
|
|
233
|
+
const tracer = CoralogixRum.getCustomTracer(['networkRequests', 'userInteractions', 'errors']);
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
> **Note:** Only one global span may be active at a time. `startGlobalSpan` returns `null` if a global span is already open.
|
|
237
|
+
|
|
238
|
+
### Traces Exporter
|
|
239
|
+
|
|
240
|
+
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.
|
|
241
|
+
|
|
242
|
+
```javascript
|
|
243
|
+
await CoralogixRum.init({
|
|
244
|
+
// ...
|
|
245
|
+
tracesExporter: (data) => {
|
|
246
|
+
// data.resource_spans contains OTLP JSON-format span data
|
|
247
|
+
sendToMyOtlpBackend(JSON.stringify(data));
|
|
248
|
+
},
|
|
249
|
+
});
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
The callback receives a `TraceExporterData` object following the OTLP JSON format:
|
|
253
|
+
|
|
254
|
+
```typescript
|
|
255
|
+
{
|
|
256
|
+
resource_spans: [
|
|
257
|
+
{
|
|
258
|
+
resource: { attributes: [{ key: string, value: { string_value: string } }] },
|
|
259
|
+
scope_spans: [
|
|
260
|
+
{
|
|
261
|
+
scope: { name: string, version?: string },
|
|
262
|
+
spans: [
|
|
263
|
+
{
|
|
264
|
+
trace_id: string,
|
|
265
|
+
span_id: string,
|
|
266
|
+
parent_span_id?: string,
|
|
267
|
+
name: string,
|
|
268
|
+
start_time_unix_nano: string,
|
|
269
|
+
end_time_unix_nano: string,
|
|
270
|
+
attributes: [{ key: string, value: {...} }],
|
|
271
|
+
status: { code: string },
|
|
272
|
+
}
|
|
273
|
+
]
|
|
274
|
+
}
|
|
275
|
+
]
|
|
276
|
+
}
|
|
277
|
+
]
|
|
278
|
+
}
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
> **Note:** The callback fires once per native export batch, which typically contains several spans rather than one per span.
|
|
282
|
+
|
|
187
283
|
### beforeSend
|
|
188
284
|
|
|
189
285
|
Enable event access and modification before sending to Coralogix, supporting content modification, and event discarding.
|
package/android/build.gradle
CHANGED
|
@@ -61,6 +61,15 @@ android {
|
|
|
61
61
|
"generated/jni"
|
|
62
62
|
]
|
|
63
63
|
}
|
|
64
|
+
test {
|
|
65
|
+
java.srcDirs += ["src/test/kotlin"]
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
testOptions {
|
|
70
|
+
unitTests.all {
|
|
71
|
+
useJUnitPlatform()
|
|
72
|
+
}
|
|
64
73
|
}
|
|
65
74
|
}
|
|
66
75
|
|
|
@@ -75,7 +84,10 @@ dependencies {
|
|
|
75
84
|
implementation "com.facebook.react:react-android"
|
|
76
85
|
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
|
77
86
|
|
|
78
|
-
implementation "com.coralogix:android-sdk:2.
|
|
87
|
+
implementation "com.coralogix:android-sdk:2.11.2"
|
|
88
|
+
|
|
89
|
+
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
|
90
|
+
testImplementation "org.mockito:mockito-core:5.12.0"
|
|
79
91
|
}
|
|
80
92
|
|
|
81
93
|
react {
|
|
@@ -5,6 +5,10 @@ import android.os.Handler
|
|
|
5
5
|
import android.os.Looper
|
|
6
6
|
import android.util.Log
|
|
7
7
|
import com.coralogix.android.sdk.CoralogixRum
|
|
8
|
+
import com.coralogix.android.sdk.customspans.CoralogixCustomSpan
|
|
9
|
+
import com.coralogix.android.sdk.customspans.CoralogixGlobalSpan
|
|
10
|
+
import com.coralogix.android.sdk.customspans.CoralogixIgnoredInstrument
|
|
11
|
+
import com.coralogix.android.sdk.traceexporter.CoralogixTraceExporterData
|
|
8
12
|
import com.coralogix.android.sdk.internal.features.instrumentations.error.CoralogixErrorDecorator
|
|
9
13
|
import com.coralogix.android.sdk.internal.features.instrumentations.network.NetworkRequestDetails
|
|
10
14
|
import com.coralogix.android.sdk.internal.infrastructure.threaddump.CoralogixJsStackFrame
|
|
@@ -39,10 +43,14 @@ import com.facebook.react.modules.core.DeviceEventManagerModule
|
|
|
39
43
|
import org.json.JSONArray
|
|
40
44
|
import org.json.JSONObject
|
|
41
45
|
import com.facebook.react.uimanager.UIManagerModule
|
|
46
|
+
import java.util.concurrent.ConcurrentHashMap
|
|
42
47
|
|
|
43
48
|
class CxSdkModule(reactContext: ReactApplicationContext) :
|
|
44
49
|
ReactContextBaseJavaModule(reactContext), RUMClient, SessionReplayClient {
|
|
45
50
|
|
|
51
|
+
private val globalSpans = ConcurrentHashMap<String, CoralogixGlobalSpan>()
|
|
52
|
+
private val customSpans = ConcurrentHashMap<String, CoralogixCustomSpan>()
|
|
53
|
+
|
|
46
54
|
override fun getName(): String {
|
|
47
55
|
return NAME
|
|
48
56
|
}
|
|
@@ -290,10 +298,73 @@ class CxSdkModule(reactContext: ReactApplicationContext) :
|
|
|
290
298
|
}
|
|
291
299
|
// endregion
|
|
292
300
|
|
|
301
|
+
// region - Custom Spans
|
|
302
|
+
|
|
303
|
+
@ReactMethod
|
|
304
|
+
override fun startGlobalSpan(name: String, labels: ReadableMap?, ignoredInstruments: ReadableArray?, promise: Promise) {
|
|
305
|
+
val ignoredSet = ignoredInstruments?.toIgnoredInstrumentSet() ?: emptySet()
|
|
306
|
+
val tracer = CoralogixRum.getCustomTracer(ignoredSet)
|
|
307
|
+
if (tracer == null) {
|
|
308
|
+
promise.resolve(null)
|
|
309
|
+
return
|
|
310
|
+
}
|
|
311
|
+
val globalSpan = tracer.startGlobalSpan(name, labels?.toStringAnyMap())
|
|
312
|
+
if (globalSpan == null) {
|
|
313
|
+
promise.resolve(null)
|
|
314
|
+
return
|
|
315
|
+
}
|
|
316
|
+
globalSpans[globalSpan.spanId] = globalSpan
|
|
317
|
+
val result = Arguments.createMap()
|
|
318
|
+
result.putString("spanId", globalSpan.spanId)
|
|
319
|
+
result.putString("traceId", globalSpan.traceId)
|
|
320
|
+
promise.resolve(result)
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
@ReactMethod
|
|
324
|
+
override fun startCustomSpan(parentSpanId: String, name: String, labels: ReadableMap?, promise: Promise) {
|
|
325
|
+
val globalSpan = globalSpans[parentSpanId]
|
|
326
|
+
if (globalSpan == null) {
|
|
327
|
+
promise.resolve(null)
|
|
328
|
+
return
|
|
329
|
+
}
|
|
330
|
+
val customSpan = globalSpan.startCustomSpan(name, labels?.toStringAnyMap())
|
|
331
|
+
val otelIds = extractOtelIds(customSpan)
|
|
332
|
+
if (otelIds == null) {
|
|
333
|
+
Log.e(NAME, "startCustomSpan: failed to extract OTel IDs via reflection — resolving null")
|
|
334
|
+
promise.resolve(null)
|
|
335
|
+
return
|
|
336
|
+
}
|
|
337
|
+
customSpans[otelIds.first] = customSpan
|
|
338
|
+
val result = Arguments.createMap()
|
|
339
|
+
result.putString("spanId", otelIds.first)
|
|
340
|
+
result.putString("traceId", otelIds.second)
|
|
341
|
+
promise.resolve(result)
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
@ReactMethod
|
|
346
|
+
override fun endSpan(spanId: String, promise: Promise) {
|
|
347
|
+
globalSpans.remove(spanId)?.let {
|
|
348
|
+
it.endSpan()
|
|
349
|
+
promise.resolve(null)
|
|
350
|
+
return
|
|
351
|
+
}
|
|
352
|
+
customSpans.remove(spanId)?.let {
|
|
353
|
+
it.endSpan()
|
|
354
|
+
promise.resolve(null)
|
|
355
|
+
return
|
|
356
|
+
}
|
|
357
|
+
Log.w(NAME, "endSpan: unknown spanId $spanId")
|
|
358
|
+
promise.resolve(null)
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// endregion
|
|
362
|
+
|
|
293
363
|
// region - utils
|
|
294
364
|
override fun invalidate() {
|
|
295
365
|
super.invalidate()
|
|
296
|
-
|
|
366
|
+
globalSpans.clear()
|
|
367
|
+
customSpans.clear()
|
|
297
368
|
Handler(Looper.getMainLooper()).post {
|
|
298
369
|
Log.d("CxSdkModule", "Bridge destroyed — shutting down CoralogixRum")
|
|
299
370
|
CoralogixRum.shutdown()
|
|
@@ -373,7 +444,16 @@ class CxSdkModule(reactContext: ReactApplicationContext) :
|
|
|
373
444
|
proxyUrl = getString("proxyUrl"),
|
|
374
445
|
beforeSendCallback = if (hasKey("hasBeforeSend") && getBoolean("hasBeforeSend")) ::beforeSendCallback else null,
|
|
375
446
|
collectIPData = collectIpData,
|
|
376
|
-
networkCaptureConfig = networkExtraConfig
|
|
447
|
+
networkCaptureConfig = networkExtraConfig,
|
|
448
|
+
tracesExporter = if (hasKey("hasTracesExporter") && getBoolean("hasTracesExporter")) {
|
|
449
|
+
{ data: CoralogixTraceExporterData ->
|
|
450
|
+
if (reactApplicationContext.hasActiveReactInstance()) {
|
|
451
|
+
reactApplicationContext
|
|
452
|
+
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
|
|
453
|
+
.emit("onTracesExport", data.toJson())
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
} else null
|
|
377
457
|
)
|
|
378
458
|
}
|
|
379
459
|
|
|
@@ -523,8 +603,9 @@ class CxSdkModule(reactContext: ReactApplicationContext) :
|
|
|
523
603
|
"AP1" -> CoralogixDomain.AP1
|
|
524
604
|
"AP2" -> CoralogixDomain.AP2
|
|
525
605
|
"AP3" -> CoralogixDomain.AP3
|
|
606
|
+
"US3" -> CoralogixDomain.US3
|
|
526
607
|
"STAGING" -> CoralogixDomain.STAGING
|
|
527
|
-
else -> throw IllegalArgumentException("Invalid coralogixDomain: $this. Must be one of [EU1, EU2, US1, US2, AP1, AP2, AP3, STAGING]")
|
|
608
|
+
else -> throw IllegalArgumentException("Invalid coralogixDomain: $this. Must be one of [EU1, EU2, US1, US2, US3, AP1, AP2, AP3, STAGING]")
|
|
528
609
|
}
|
|
529
610
|
}
|
|
530
611
|
|
|
@@ -758,6 +839,18 @@ class CxSdkModule(reactContext: ReactApplicationContext) :
|
|
|
758
839
|
return result
|
|
759
840
|
}
|
|
760
841
|
|
|
842
|
+
private fun ReadableArray.toIgnoredInstrumentSet(): Set<CoralogixIgnoredInstrument> {
|
|
843
|
+
val set = mutableSetOf<CoralogixIgnoredInstrument>()
|
|
844
|
+
for (i in 0 until size()) {
|
|
845
|
+
when (getString(i)) {
|
|
846
|
+
"networkRequests" -> set.add(CoralogixIgnoredInstrument.NETWORK_REQUESTS)
|
|
847
|
+
"userInteractions" -> set.add(CoralogixIgnoredInstrument.USER_INTERACTIONS)
|
|
848
|
+
"errors" -> set.add(CoralogixIgnoredInstrument.ERRORS)
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
return set
|
|
852
|
+
}
|
|
853
|
+
|
|
761
854
|
private fun ReadableArray.toHybridMetricList(): List<HybridMetric> {
|
|
762
855
|
val out = ArrayList<HybridMetric>(size())
|
|
763
856
|
for (i in 0 until size()) {
|
|
@@ -778,5 +871,22 @@ class CxSdkModule(reactContext: ReactApplicationContext) :
|
|
|
778
871
|
|
|
779
872
|
companion object {
|
|
780
873
|
const val NAME = "CxSdk"
|
|
874
|
+
|
|
875
|
+
// TODO: replace reflection with a public accessor once the Coralogix Android SDK exposes one —
|
|
876
|
+
// 'getSpan$library_release' is a Kotlin-internal name that may be renamed in a future SDK version.
|
|
877
|
+
internal fun extractOtelIds(child: CoralogixCustomSpan): Pair<String, String>? =
|
|
878
|
+
extractOtelIds(child, "getSpan\$library_release")
|
|
879
|
+
|
|
880
|
+
internal fun extractOtelIds(child: CoralogixCustomSpan, accessorName: String): Pair<String, String>? = try {
|
|
881
|
+
val span = child.javaClass.getMethod(accessorName).invoke(child) ?: return null
|
|
882
|
+
val ctx = span.javaClass.getMethod("getSpanContext").invoke(span) ?: return null
|
|
883
|
+
val spanId = ctx.javaClass.getMethod("getSpanId").invoke(ctx) as? String
|
|
884
|
+
val traceId = ctx.javaClass.getMethod("getTraceId").invoke(ctx) as? String
|
|
885
|
+
if (spanId.isNullOrEmpty() || traceId.isNullOrEmpty()) null
|
|
886
|
+
else Pair(spanId, traceId)
|
|
887
|
+
} catch (e: Throwable) {
|
|
888
|
+
Log.w(NAME, "extractOtelIds: reflection failed — $e")
|
|
889
|
+
null
|
|
890
|
+
}
|
|
781
891
|
}
|
|
782
892
|
}
|
|
@@ -22,4 +22,9 @@ interface RUMClient {
|
|
|
22
22
|
fun reportMobileVitalsMeasurementSet(type: String, metrics: ReadableArray)
|
|
23
23
|
fun isCoralogixGradlePluginApplied(promise: Promise)
|
|
24
24
|
fun shutdown(promise: Promise)
|
|
25
|
+
|
|
26
|
+
// custom spans
|
|
27
|
+
fun startGlobalSpan(name: String, labels: ReadableMap?, ignoredInstruments: ReadableArray?, promise: Promise)
|
|
28
|
+
fun startCustomSpan(parentSpanId: String, name: String, labels: ReadableMap?, promise: Promise)
|
|
29
|
+
fun endSpan(spanId: String, promise: Promise)
|
|
25
30
|
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
package com.cxsdk
|
|
2
|
+
|
|
3
|
+
import com.coralogix.android.sdk.customspans.CoralogixCustomSpan
|
|
4
|
+
import io.opentelemetry.api.trace.Span
|
|
5
|
+
import io.opentelemetry.api.trace.SpanContext
|
|
6
|
+
import io.opentelemetry.api.trace.TraceFlags
|
|
7
|
+
import io.opentelemetry.api.trace.TraceState
|
|
8
|
+
import org.mockito.Mockito.mock
|
|
9
|
+
import org.mockito.Mockito.`when`
|
|
10
|
+
import kotlin.test.Test
|
|
11
|
+
import kotlin.test.assertEquals
|
|
12
|
+
import kotlin.test.assertNull
|
|
13
|
+
|
|
14
|
+
class ExtractOtelIdsTest {
|
|
15
|
+
|
|
16
|
+
@Test
|
|
17
|
+
fun `extractOtelIds returns correct spanId and traceId via reflection`() {
|
|
18
|
+
val spanId = "1234567890abcdef"
|
|
19
|
+
val traceId = "abcdef1234567890abcdef1234567890"
|
|
20
|
+
|
|
21
|
+
val mockSpan = mock(Span::class.java)
|
|
22
|
+
`when`(mockSpan.spanContext).thenReturn(
|
|
23
|
+
SpanContext.create(traceId, spanId, TraceFlags.getDefault(), TraceState.getDefault())
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
val result = CxSdkModule.extractOtelIds(CoralogixCustomSpan(mockSpan))
|
|
27
|
+
|
|
28
|
+
assertEquals(Pair(spanId, traceId), result)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
@Test
|
|
32
|
+
fun `extractOtelIds returns null when spanContext returns null`() {
|
|
33
|
+
val mockSpan = mock(Span::class.java)
|
|
34
|
+
`when`(mockSpan.spanContext).thenReturn(null)
|
|
35
|
+
|
|
36
|
+
val result = CxSdkModule.extractOtelIds(CoralogixCustomSpan(mockSpan))
|
|
37
|
+
|
|
38
|
+
assertNull(result)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@Test
|
|
42
|
+
fun `extractOtelIds returns null when accessor method does not exist`() {
|
|
43
|
+
val mockSpan = mock(Span::class.java)
|
|
44
|
+
|
|
45
|
+
val result = CxSdkModule.extractOtelIds(CoralogixCustomSpan(mockSpan), "nonExistentMethod")
|
|
46
|
+
|
|
47
|
+
assertNull(result)
|
|
48
|
+
}
|
|
49
|
+
}
|
package/index.cjs.js
CHANGED
|
@@ -27,6 +27,14 @@ let CoralogixLogSeverity = /*#__PURE__*/function (CoralogixLogSeverity) {
|
|
|
27
27
|
return CoralogixLogSeverity;
|
|
28
28
|
}({});
|
|
29
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Instrumentation names that can be excluded from a custom tracer's span context.
|
|
32
|
+
* Pass one or more values to `getCustomTracer()` to prevent those event types from
|
|
33
|
+
* being linked to spans created by that tracer.
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
/** OTLP JSON-format trace data delivered to the `tracesExporter` callback. */
|
|
37
|
+
|
|
30
38
|
const ERROR_INSTRUMENTATION_NAME = 'errors';
|
|
31
39
|
const ERROR_INSTRUMENTATION_VERSION = '1';
|
|
32
40
|
|
|
@@ -523,7 +531,7 @@ function stopJsRefreshRateSampler() {
|
|
|
523
531
|
appStateSub = null;
|
|
524
532
|
}
|
|
525
533
|
|
|
526
|
-
var version = "0.
|
|
534
|
+
var version = "0.4.0";
|
|
527
535
|
var pkg = {
|
|
528
536
|
version: version};
|
|
529
537
|
|
|
@@ -561,6 +569,128 @@ class Logger {
|
|
|
561
569
|
}
|
|
562
570
|
const logger = new Logger();
|
|
563
571
|
|
|
572
|
+
let activeGlobalSpanId = null;
|
|
573
|
+
const spanTraceIds = new Map();
|
|
574
|
+
let ignoredInstruments = new Set();
|
|
575
|
+
const CustomSpanRegistry = {
|
|
576
|
+
getActive: () => activeGlobalSpanId,
|
|
577
|
+
setActive: id => {
|
|
578
|
+
activeGlobalSpanId = id;
|
|
579
|
+
},
|
|
580
|
+
clearActive: () => {
|
|
581
|
+
activeGlobalSpanId = null;
|
|
582
|
+
},
|
|
583
|
+
registerSpan: (spanId, traceId) => {
|
|
584
|
+
spanTraceIds.set(spanId, traceId);
|
|
585
|
+
},
|
|
586
|
+
unregisterSpan: spanId => {
|
|
587
|
+
spanTraceIds.delete(spanId);
|
|
588
|
+
},
|
|
589
|
+
getTraceId: spanId => spanTraceIds.get(spanId),
|
|
590
|
+
setIgnoredInstruments: set => {
|
|
591
|
+
ignoredInstruments = set;
|
|
592
|
+
},
|
|
593
|
+
getIgnoredInstruments: () => ignoredInstruments,
|
|
594
|
+
clear: () => {
|
|
595
|
+
activeGlobalSpanId = null;
|
|
596
|
+
spanTraceIds.clear();
|
|
597
|
+
ignoredInstruments.clear();
|
|
598
|
+
}
|
|
599
|
+
};
|
|
600
|
+
|
|
601
|
+
/** A child span nested under a {@link CoralogixGlobalSpan}. */
|
|
602
|
+
class CoralogixCustomSpan {
|
|
603
|
+
constructor(spanId, traceId, bridge) {
|
|
604
|
+
this.spanId = void 0;
|
|
605
|
+
this.traceId = void 0;
|
|
606
|
+
this.bridge = void 0;
|
|
607
|
+
this.spanId = spanId;
|
|
608
|
+
this.traceId = traceId;
|
|
609
|
+
this.bridge = bridge;
|
|
610
|
+
}
|
|
611
|
+
async endSpan() {
|
|
612
|
+
CustomSpanRegistry.unregisterSpan(this.spanId);
|
|
613
|
+
await this.bridge.endSpan(this.spanId);
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
/** A root-level custom span. All child spans and `withContext` network calls share its traceId. */
|
|
618
|
+
class CoralogixGlobalSpan {
|
|
619
|
+
constructor(spanId, traceId, bridge) {
|
|
620
|
+
this.spanId = void 0;
|
|
621
|
+
this.traceId = void 0;
|
|
622
|
+
this.bridge = void 0;
|
|
623
|
+
this.spanId = spanId;
|
|
624
|
+
this.traceId = traceId;
|
|
625
|
+
this.bridge = bridge;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
/** Creates a child span nested under this global span. */
|
|
629
|
+
async startCustomSpan(name, labels) {
|
|
630
|
+
const raw = await this.bridge.startCustomSpan(this.spanId, name, labels != null ? labels : null);
|
|
631
|
+
if (!raw) return null;
|
|
632
|
+
CustomSpanRegistry.registerSpan(raw.spanId, raw.traceId);
|
|
633
|
+
return new CoralogixCustomSpan(raw.spanId, raw.traceId, this.bridge);
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
/**
|
|
637
|
+
* Runs fn() with this span set as the active global span for the duration of
|
|
638
|
+
* the returned promise. The active span ID remains set throughout the full
|
|
639
|
+
* async chain — including code after intermediate awaits — because we await
|
|
640
|
+
* fn() before clearing. Only detached callbacks (e.g. setTimeout) that fire
|
|
641
|
+
* after withContext resolves won't be linked.
|
|
642
|
+
*/
|
|
643
|
+
async withContext(fn) {
|
|
644
|
+
const prev = CustomSpanRegistry.getActive();
|
|
645
|
+
CustomSpanRegistry.setActive(this.spanId);
|
|
646
|
+
try {
|
|
647
|
+
return await fn();
|
|
648
|
+
} finally {
|
|
649
|
+
if (prev !== null) {
|
|
650
|
+
CustomSpanRegistry.setActive(prev);
|
|
651
|
+
} else {
|
|
652
|
+
CustomSpanRegistry.clearActive();
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
async endSpan() {
|
|
657
|
+
CustomSpanRegistry.unregisterSpan(this.spanId);
|
|
658
|
+
if (CustomSpanRegistry.getActive() === this.spanId) {
|
|
659
|
+
CustomSpanRegistry.clearActive();
|
|
660
|
+
}
|
|
661
|
+
await this.bridge.endSpan(this.spanId);
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
/**
|
|
666
|
+
* Entry point for manual RUM tracing. Obtain an instance via `CoralogixRum.getCustomTracer()`.
|
|
667
|
+
* The `ignoredInstruments` list controls which auto-instrumented events are NOT linked to spans
|
|
668
|
+
* created by this tracer (e.g. passing `['networkRequests']` keeps network spans independent).
|
|
669
|
+
*/
|
|
670
|
+
class CoralogixCustomTracer {
|
|
671
|
+
constructor(ignoredInstruments, bridge) {
|
|
672
|
+
this.ignoredInstruments = void 0;
|
|
673
|
+
this.bridge = void 0;
|
|
674
|
+
this.ignoredInstruments = ignoredInstruments;
|
|
675
|
+
this.bridge = bridge;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
/**
|
|
679
|
+
* Starts a new global (root) span. Returns `null` if a global span is already active —
|
|
680
|
+
* only one global span may exist at a time across the entire app.
|
|
681
|
+
*/
|
|
682
|
+
async startGlobalSpan(name, labels) {
|
|
683
|
+
const raw = await this.bridge.startGlobalSpan(name, labels != null ? labels : null, this.ignoredInstruments);
|
|
684
|
+
if (!raw) {
|
|
685
|
+
logger.debug('CoralogixCustomTracer: startGlobalSpan returned null — check that the SDK is initialized, traceParentInHeader is enabled, and no other global span is already active');
|
|
686
|
+
return null;
|
|
687
|
+
}
|
|
688
|
+
CustomSpanRegistry.registerSpan(raw.spanId, raw.traceId);
|
|
689
|
+
CustomSpanRegistry.setIgnoredInstruments(new Set(this.ignoredInstruments));
|
|
690
|
+
return new CoralogixGlobalSpan(raw.spanId, raw.traceId, this.bridge);
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
|
|
564
694
|
const CORALOGIX_LOGS_URL_SUFFIX = '/browser/v1beta/logs';
|
|
565
695
|
const CORALOGIX_RECORDING_URL_SUFFIX = '/sessionrecording';
|
|
566
696
|
const OPTIONS_DEFAULTS = {
|
|
@@ -838,6 +968,7 @@ let CoralogixDomain = /*#__PURE__*/function (CoralogixDomain) {
|
|
|
838
968
|
CoralogixDomain["AP1"] = "AP1";
|
|
839
969
|
CoralogixDomain["AP2"] = "AP2";
|
|
840
970
|
CoralogixDomain["AP3"] = "AP3";
|
|
971
|
+
CoralogixDomain["US3"] = "US3";
|
|
841
972
|
CoralogixDomain["STAGING"] = "staging";
|
|
842
973
|
return CoralogixDomain;
|
|
843
974
|
}({});
|
|
@@ -847,6 +978,7 @@ const LINKING_ERROR = `The package 'cx-plugin' doesn't seem to be linked. Make s
|
|
|
847
978
|
default: ''
|
|
848
979
|
}) + '- You rebuilt the app after installing the package\n' + '- You are not using Expo Go\n';
|
|
849
980
|
let beforeSendCallback;
|
|
981
|
+
let tracesExporterSubscription;
|
|
850
982
|
let _deregisterInstrumentations;
|
|
851
983
|
const CxSdk = reactNative.NativeModules.CxSdk ? reactNative.NativeModules.CxSdk : createErrorProxy(LINKING_ERROR);
|
|
852
984
|
function createErrorProxy(errorMessage) {
|
|
@@ -886,10 +1018,28 @@ const CoralogixRum = {
|
|
|
886
1018
|
} else {
|
|
887
1019
|
finalOptions = resolvedOptions;
|
|
888
1020
|
}
|
|
1021
|
+
if (finalOptions.tracesExporter) {
|
|
1022
|
+
const callback = finalOptions.tracesExporter;
|
|
1023
|
+
tracesExporterSubscription = eventEmitter.addListener('onTracesExport', jsonString => {
|
|
1024
|
+
let data;
|
|
1025
|
+
try {
|
|
1026
|
+
data = JSON.parse(jsonString);
|
|
1027
|
+
} catch (e) {
|
|
1028
|
+
logger.warn('Error parsing onTracesExport payload:', e);
|
|
1029
|
+
return;
|
|
1030
|
+
}
|
|
1031
|
+
try {
|
|
1032
|
+
callback(data);
|
|
1033
|
+
} catch (e) {
|
|
1034
|
+
logger.warn('tracesExporter callback threw:', e);
|
|
1035
|
+
}
|
|
1036
|
+
});
|
|
1037
|
+
}
|
|
889
1038
|
await CxSdk.initialize(_extends({}, finalOptions, {
|
|
890
1039
|
frameworkVersion: pkg.version,
|
|
891
1040
|
networkExtraConfig: finalOptions.networkExtraConfig ? serializeNetworkCaptureRules(finalOptions.networkExtraConfig) : undefined,
|
|
892
|
-
hasBeforeSend: !!finalOptions.beforeSend
|
|
1041
|
+
hasBeforeSend: !!finalOptions.beforeSend,
|
|
1042
|
+
hasTracesExporter: !!finalOptions.tracesExporter
|
|
893
1043
|
}));
|
|
894
1044
|
isInited = true;
|
|
895
1045
|
},
|
|
@@ -901,6 +1051,10 @@ const CoralogixRum = {
|
|
|
901
1051
|
if (subscription) {
|
|
902
1052
|
subscription.remove();
|
|
903
1053
|
}
|
|
1054
|
+
if (tracesExporterSubscription) {
|
|
1055
|
+
tracesExporterSubscription.remove();
|
|
1056
|
+
tracesExporterSubscription = undefined;
|
|
1057
|
+
}
|
|
904
1058
|
isInited = false;
|
|
905
1059
|
_deregisterInstrumentations == null || _deregisterInstrumentations();
|
|
906
1060
|
_deregisterInstrumentations = undefined;
|
|
@@ -992,6 +1146,19 @@ const CoralogixRum = {
|
|
|
992
1146
|
reportNetworkRequest: details => {
|
|
993
1147
|
CxSdk.reportNetworkRequest(details);
|
|
994
1148
|
},
|
|
1149
|
+
/**
|
|
1150
|
+
* Returns a tracer for creating manual custom spans.
|
|
1151
|
+
* Pass `ignoredInstruments` to prevent specific auto-instrumented event types from being
|
|
1152
|
+
* linked to spans created by this tracer.
|
|
1153
|
+
*/
|
|
1154
|
+
getCustomTracer(ignoredInstruments = []) {
|
|
1155
|
+
const bridge = {
|
|
1156
|
+
startGlobalSpan: (name, labels, instruments) => CxSdk.startGlobalSpan(name, labels, instruments),
|
|
1157
|
+
startCustomSpan: (parentSpanId, name, labels) => CxSdk.startCustomSpan(parentSpanId, name, labels),
|
|
1158
|
+
endSpan: spanId => CxSdk.endSpan(spanId)
|
|
1159
|
+
};
|
|
1160
|
+
return new CoralogixCustomTracer(ignoredInstruments, bridge);
|
|
1161
|
+
},
|
|
995
1162
|
sendCustomMeasurement: measurement => {
|
|
996
1163
|
if (!isInited) {
|
|
997
1164
|
logger.debug('CoralogixRum must be initiated before sending custom measurements');
|
|
@@ -1221,7 +1388,10 @@ const subscription = eventEmitter.addListener('onBeforeSend', events => {
|
|
|
1221
1388
|
}
|
|
1222
1389
|
});
|
|
1223
1390
|
|
|
1391
|
+
exports.CoralogixCustomSpan = CoralogixCustomSpan;
|
|
1392
|
+
exports.CoralogixCustomTracer = CoralogixCustomTracer;
|
|
1224
1393
|
exports.CoralogixDomain = CoralogixDomain;
|
|
1394
|
+
exports.CoralogixGlobalSpan = CoralogixGlobalSpan;
|
|
1225
1395
|
exports.CoralogixLogSeverity = CoralogixLogSeverity;
|
|
1226
1396
|
exports.CoralogixRum = CoralogixRum;
|
|
1227
1397
|
exports.CxSdk = CxSdk;
|
package/index.esm.js
CHANGED
|
@@ -25,6 +25,14 @@ let CoralogixLogSeverity = /*#__PURE__*/function (CoralogixLogSeverity) {
|
|
|
25
25
|
return CoralogixLogSeverity;
|
|
26
26
|
}({});
|
|
27
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Instrumentation names that can be excluded from a custom tracer's span context.
|
|
30
|
+
* Pass one or more values to `getCustomTracer()` to prevent those event types from
|
|
31
|
+
* being linked to spans created by that tracer.
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
/** OTLP JSON-format trace data delivered to the `tracesExporter` callback. */
|
|
35
|
+
|
|
28
36
|
const ERROR_INSTRUMENTATION_NAME = 'errors';
|
|
29
37
|
const ERROR_INSTRUMENTATION_VERSION = '1';
|
|
30
38
|
|
|
@@ -521,7 +529,7 @@ function stopJsRefreshRateSampler() {
|
|
|
521
529
|
appStateSub = null;
|
|
522
530
|
}
|
|
523
531
|
|
|
524
|
-
var version = "0.
|
|
532
|
+
var version = "0.4.0";
|
|
525
533
|
var pkg = {
|
|
526
534
|
version: version};
|
|
527
535
|
|
|
@@ -559,6 +567,128 @@ class Logger {
|
|
|
559
567
|
}
|
|
560
568
|
const logger = new Logger();
|
|
561
569
|
|
|
570
|
+
let activeGlobalSpanId = null;
|
|
571
|
+
const spanTraceIds = new Map();
|
|
572
|
+
let ignoredInstruments = new Set();
|
|
573
|
+
const CustomSpanRegistry = {
|
|
574
|
+
getActive: () => activeGlobalSpanId,
|
|
575
|
+
setActive: id => {
|
|
576
|
+
activeGlobalSpanId = id;
|
|
577
|
+
},
|
|
578
|
+
clearActive: () => {
|
|
579
|
+
activeGlobalSpanId = null;
|
|
580
|
+
},
|
|
581
|
+
registerSpan: (spanId, traceId) => {
|
|
582
|
+
spanTraceIds.set(spanId, traceId);
|
|
583
|
+
},
|
|
584
|
+
unregisterSpan: spanId => {
|
|
585
|
+
spanTraceIds.delete(spanId);
|
|
586
|
+
},
|
|
587
|
+
getTraceId: spanId => spanTraceIds.get(spanId),
|
|
588
|
+
setIgnoredInstruments: set => {
|
|
589
|
+
ignoredInstruments = set;
|
|
590
|
+
},
|
|
591
|
+
getIgnoredInstruments: () => ignoredInstruments,
|
|
592
|
+
clear: () => {
|
|
593
|
+
activeGlobalSpanId = null;
|
|
594
|
+
spanTraceIds.clear();
|
|
595
|
+
ignoredInstruments.clear();
|
|
596
|
+
}
|
|
597
|
+
};
|
|
598
|
+
|
|
599
|
+
/** A child span nested under a {@link CoralogixGlobalSpan}. */
|
|
600
|
+
class CoralogixCustomSpan {
|
|
601
|
+
constructor(spanId, traceId, bridge) {
|
|
602
|
+
this.spanId = void 0;
|
|
603
|
+
this.traceId = void 0;
|
|
604
|
+
this.bridge = void 0;
|
|
605
|
+
this.spanId = spanId;
|
|
606
|
+
this.traceId = traceId;
|
|
607
|
+
this.bridge = bridge;
|
|
608
|
+
}
|
|
609
|
+
async endSpan() {
|
|
610
|
+
CustomSpanRegistry.unregisterSpan(this.spanId);
|
|
611
|
+
await this.bridge.endSpan(this.spanId);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
/** A root-level custom span. All child spans and `withContext` network calls share its traceId. */
|
|
616
|
+
class CoralogixGlobalSpan {
|
|
617
|
+
constructor(spanId, traceId, bridge) {
|
|
618
|
+
this.spanId = void 0;
|
|
619
|
+
this.traceId = void 0;
|
|
620
|
+
this.bridge = void 0;
|
|
621
|
+
this.spanId = spanId;
|
|
622
|
+
this.traceId = traceId;
|
|
623
|
+
this.bridge = bridge;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
/** Creates a child span nested under this global span. */
|
|
627
|
+
async startCustomSpan(name, labels) {
|
|
628
|
+
const raw = await this.bridge.startCustomSpan(this.spanId, name, labels != null ? labels : null);
|
|
629
|
+
if (!raw) return null;
|
|
630
|
+
CustomSpanRegistry.registerSpan(raw.spanId, raw.traceId);
|
|
631
|
+
return new CoralogixCustomSpan(raw.spanId, raw.traceId, this.bridge);
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
/**
|
|
635
|
+
* Runs fn() with this span set as the active global span for the duration of
|
|
636
|
+
* the returned promise. The active span ID remains set throughout the full
|
|
637
|
+
* async chain — including code after intermediate awaits — because we await
|
|
638
|
+
* fn() before clearing. Only detached callbacks (e.g. setTimeout) that fire
|
|
639
|
+
* after withContext resolves won't be linked.
|
|
640
|
+
*/
|
|
641
|
+
async withContext(fn) {
|
|
642
|
+
const prev = CustomSpanRegistry.getActive();
|
|
643
|
+
CustomSpanRegistry.setActive(this.spanId);
|
|
644
|
+
try {
|
|
645
|
+
return await fn();
|
|
646
|
+
} finally {
|
|
647
|
+
if (prev !== null) {
|
|
648
|
+
CustomSpanRegistry.setActive(prev);
|
|
649
|
+
} else {
|
|
650
|
+
CustomSpanRegistry.clearActive();
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
async endSpan() {
|
|
655
|
+
CustomSpanRegistry.unregisterSpan(this.spanId);
|
|
656
|
+
if (CustomSpanRegistry.getActive() === this.spanId) {
|
|
657
|
+
CustomSpanRegistry.clearActive();
|
|
658
|
+
}
|
|
659
|
+
await this.bridge.endSpan(this.spanId);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
/**
|
|
664
|
+
* Entry point for manual RUM tracing. Obtain an instance via `CoralogixRum.getCustomTracer()`.
|
|
665
|
+
* The `ignoredInstruments` list controls which auto-instrumented events are NOT linked to spans
|
|
666
|
+
* created by this tracer (e.g. passing `['networkRequests']` keeps network spans independent).
|
|
667
|
+
*/
|
|
668
|
+
class CoralogixCustomTracer {
|
|
669
|
+
constructor(ignoredInstruments, bridge) {
|
|
670
|
+
this.ignoredInstruments = void 0;
|
|
671
|
+
this.bridge = void 0;
|
|
672
|
+
this.ignoredInstruments = ignoredInstruments;
|
|
673
|
+
this.bridge = bridge;
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
/**
|
|
677
|
+
* Starts a new global (root) span. Returns `null` if a global span is already active —
|
|
678
|
+
* only one global span may exist at a time across the entire app.
|
|
679
|
+
*/
|
|
680
|
+
async startGlobalSpan(name, labels) {
|
|
681
|
+
const raw = await this.bridge.startGlobalSpan(name, labels != null ? labels : null, this.ignoredInstruments);
|
|
682
|
+
if (!raw) {
|
|
683
|
+
logger.debug('CoralogixCustomTracer: startGlobalSpan returned null — check that the SDK is initialized, traceParentInHeader is enabled, and no other global span is already active');
|
|
684
|
+
return null;
|
|
685
|
+
}
|
|
686
|
+
CustomSpanRegistry.registerSpan(raw.spanId, raw.traceId);
|
|
687
|
+
CustomSpanRegistry.setIgnoredInstruments(new Set(this.ignoredInstruments));
|
|
688
|
+
return new CoralogixGlobalSpan(raw.spanId, raw.traceId, this.bridge);
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
|
|
562
692
|
const CORALOGIX_LOGS_URL_SUFFIX = '/browser/v1beta/logs';
|
|
563
693
|
const CORALOGIX_RECORDING_URL_SUFFIX = '/sessionrecording';
|
|
564
694
|
const OPTIONS_DEFAULTS = {
|
|
@@ -836,6 +966,7 @@ let CoralogixDomain = /*#__PURE__*/function (CoralogixDomain) {
|
|
|
836
966
|
CoralogixDomain["AP1"] = "AP1";
|
|
837
967
|
CoralogixDomain["AP2"] = "AP2";
|
|
838
968
|
CoralogixDomain["AP3"] = "AP3";
|
|
969
|
+
CoralogixDomain["US3"] = "US3";
|
|
839
970
|
CoralogixDomain["STAGING"] = "staging";
|
|
840
971
|
return CoralogixDomain;
|
|
841
972
|
}({});
|
|
@@ -845,6 +976,7 @@ const LINKING_ERROR = `The package 'cx-plugin' doesn't seem to be linked. Make s
|
|
|
845
976
|
default: ''
|
|
846
977
|
}) + '- You rebuilt the app after installing the package\n' + '- You are not using Expo Go\n';
|
|
847
978
|
let beforeSendCallback;
|
|
979
|
+
let tracesExporterSubscription;
|
|
848
980
|
let _deregisterInstrumentations;
|
|
849
981
|
const CxSdk = NativeModules.CxSdk ? NativeModules.CxSdk : createErrorProxy(LINKING_ERROR);
|
|
850
982
|
function createErrorProxy(errorMessage) {
|
|
@@ -884,10 +1016,28 @@ const CoralogixRum = {
|
|
|
884
1016
|
} else {
|
|
885
1017
|
finalOptions = resolvedOptions;
|
|
886
1018
|
}
|
|
1019
|
+
if (finalOptions.tracesExporter) {
|
|
1020
|
+
const callback = finalOptions.tracesExporter;
|
|
1021
|
+
tracesExporterSubscription = eventEmitter.addListener('onTracesExport', jsonString => {
|
|
1022
|
+
let data;
|
|
1023
|
+
try {
|
|
1024
|
+
data = JSON.parse(jsonString);
|
|
1025
|
+
} catch (e) {
|
|
1026
|
+
logger.warn('Error parsing onTracesExport payload:', e);
|
|
1027
|
+
return;
|
|
1028
|
+
}
|
|
1029
|
+
try {
|
|
1030
|
+
callback(data);
|
|
1031
|
+
} catch (e) {
|
|
1032
|
+
logger.warn('tracesExporter callback threw:', e);
|
|
1033
|
+
}
|
|
1034
|
+
});
|
|
1035
|
+
}
|
|
887
1036
|
await CxSdk.initialize(_extends({}, finalOptions, {
|
|
888
1037
|
frameworkVersion: pkg.version,
|
|
889
1038
|
networkExtraConfig: finalOptions.networkExtraConfig ? serializeNetworkCaptureRules(finalOptions.networkExtraConfig) : undefined,
|
|
890
|
-
hasBeforeSend: !!finalOptions.beforeSend
|
|
1039
|
+
hasBeforeSend: !!finalOptions.beforeSend,
|
|
1040
|
+
hasTracesExporter: !!finalOptions.tracesExporter
|
|
891
1041
|
}));
|
|
892
1042
|
isInited = true;
|
|
893
1043
|
},
|
|
@@ -899,6 +1049,10 @@ const CoralogixRum = {
|
|
|
899
1049
|
if (subscription) {
|
|
900
1050
|
subscription.remove();
|
|
901
1051
|
}
|
|
1052
|
+
if (tracesExporterSubscription) {
|
|
1053
|
+
tracesExporterSubscription.remove();
|
|
1054
|
+
tracesExporterSubscription = undefined;
|
|
1055
|
+
}
|
|
902
1056
|
isInited = false;
|
|
903
1057
|
_deregisterInstrumentations == null || _deregisterInstrumentations();
|
|
904
1058
|
_deregisterInstrumentations = undefined;
|
|
@@ -990,6 +1144,19 @@ const CoralogixRum = {
|
|
|
990
1144
|
reportNetworkRequest: details => {
|
|
991
1145
|
CxSdk.reportNetworkRequest(details);
|
|
992
1146
|
},
|
|
1147
|
+
/**
|
|
1148
|
+
* Returns a tracer for creating manual custom spans.
|
|
1149
|
+
* Pass `ignoredInstruments` to prevent specific auto-instrumented event types from being
|
|
1150
|
+
* linked to spans created by this tracer.
|
|
1151
|
+
*/
|
|
1152
|
+
getCustomTracer(ignoredInstruments = []) {
|
|
1153
|
+
const bridge = {
|
|
1154
|
+
startGlobalSpan: (name, labels, instruments) => CxSdk.startGlobalSpan(name, labels, instruments),
|
|
1155
|
+
startCustomSpan: (parentSpanId, name, labels) => CxSdk.startCustomSpan(parentSpanId, name, labels),
|
|
1156
|
+
endSpan: spanId => CxSdk.endSpan(spanId)
|
|
1157
|
+
};
|
|
1158
|
+
return new CoralogixCustomTracer(ignoredInstruments, bridge);
|
|
1159
|
+
},
|
|
993
1160
|
sendCustomMeasurement: measurement => {
|
|
994
1161
|
if (!isInited) {
|
|
995
1162
|
logger.debug('CoralogixRum must be initiated before sending custom measurements');
|
|
@@ -1219,4 +1386,4 @@ const subscription = eventEmitter.addListener('onBeforeSend', events => {
|
|
|
1219
1386
|
}
|
|
1220
1387
|
});
|
|
1221
1388
|
|
|
1222
|
-
export { CoralogixDomain, CoralogixLogSeverity, CoralogixRum, CxSdk, SessionReplay, attachReactNavigationObserver, parseErrorStack };
|
|
1389
|
+
export { CoralogixCustomSpan, CoralogixCustomTracer, CoralogixDomain, CoralogixGlobalSpan, CoralogixLogSeverity, CoralogixRum, CxSdk, SessionReplay, attachReactNavigationObserver, parseErrorStack };
|
package/ios/CxSdk.mm
CHANGED
|
@@ -106,6 +106,22 @@ RCT_EXTERN_METHOD(maskViewByTag:(nonnull NSNumber *)viewTag
|
|
|
106
106
|
withResolver:(RCTPromiseResolveBlock)resolve
|
|
107
107
|
withRejecter:(RCTPromiseRejectBlock)reject)
|
|
108
108
|
|
|
109
|
+
RCT_EXTERN_METHOD(startGlobalSpan:(NSString *)name
|
|
110
|
+
labels:(NSDictionary *)labels
|
|
111
|
+
ignoredInstruments:(NSArray *)ignoredInstruments
|
|
112
|
+
withResolver:(RCTPromiseResolveBlock)resolve
|
|
113
|
+
withRejecter:(RCTPromiseRejectBlock)reject)
|
|
114
|
+
|
|
115
|
+
RCT_EXTERN_METHOD(startCustomSpan:(NSString *)parentSpanId
|
|
116
|
+
name:(NSString *)name
|
|
117
|
+
labels:(NSDictionary *)labels
|
|
118
|
+
withResolver:(RCTPromiseResolveBlock)resolve
|
|
119
|
+
withRejecter:(RCTPromiseRejectBlock)reject)
|
|
120
|
+
|
|
121
|
+
RCT_EXTERN_METHOD(endSpan:(NSString *)spanId
|
|
122
|
+
withResolver:(RCTPromiseResolveBlock)resolve
|
|
123
|
+
withRejecter:(RCTPromiseRejectBlock)reject)
|
|
124
|
+
|
|
109
125
|
+ (BOOL)requiresMainQueueSetup
|
|
110
126
|
{
|
|
111
127
|
return NO;
|
package/ios/CxSdk.swift
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import Foundation
|
|
2
2
|
import Coralogix
|
|
3
|
+
import CoralogixInternal
|
|
3
4
|
import SessionReplay
|
|
4
5
|
import React
|
|
5
6
|
|
|
@@ -11,6 +12,9 @@ enum CxSdkError: Error {
|
|
|
11
12
|
@objc(CxSdk)
|
|
12
13
|
class CxSdk: RCTEventEmitter {
|
|
13
14
|
var coralogixRum: CoralogixRum?
|
|
15
|
+
// Accessed only from the RN methodQueue (serial); no explicit locking required.
|
|
16
|
+
private var globalSpans: [String: CoralogixGlobalSpan] = [:]
|
|
17
|
+
private var customSpans: [String: CoralogixCustomSpan] = [:]
|
|
14
18
|
|
|
15
19
|
override init() {
|
|
16
20
|
super.init()
|
|
@@ -21,7 +25,7 @@ class CxSdk: RCTEventEmitter {
|
|
|
21
25
|
}
|
|
22
26
|
|
|
23
27
|
override func supportedEvents() -> [String]! {
|
|
24
|
-
return ["onBeforeSend"]
|
|
28
|
+
return ["onBeforeSend", "onTracesExport"]
|
|
25
29
|
}
|
|
26
30
|
|
|
27
31
|
@objc(initialize:withResolver:withRejecter:)
|
|
@@ -39,6 +43,15 @@ class CxSdk: RCTEventEmitter {
|
|
|
39
43
|
|
|
40
44
|
var options = try self.toCoralogixOptions(parameter: parameter)
|
|
41
45
|
options.beforeSendCallBack = beforeSendCallBack
|
|
46
|
+
|
|
47
|
+
let hasTracesExporter = parameter["hasTracesExporter"] as? Bool ?? false
|
|
48
|
+
if hasTracesExporter {
|
|
49
|
+
options.tracesExporter = { [weak self] data in
|
|
50
|
+
guard let jsonString = data.jsonString else { return }
|
|
51
|
+
self?.sendEvent(withName: "onTracesExport", body: jsonString)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
42
55
|
let rnPluginVersion = parameter["frameworkVersion"] as? String ?? ""
|
|
43
56
|
|
|
44
57
|
self.coralogixRum = CoralogixRum(options: options, sdkFramework: .reactNative(version: rnPluginVersion))
|
|
@@ -195,6 +208,8 @@ class CxSdk: RCTEventEmitter {
|
|
|
195
208
|
@objc(shutdown:withRejecter:)
|
|
196
209
|
func shutdown(resolve:RCTPromiseResolveBlock,
|
|
197
210
|
reject:RCTPromiseRejectBlock) -> Void {
|
|
211
|
+
globalSpans.removeAll()
|
|
212
|
+
customSpans.removeAll()
|
|
198
213
|
coralogixRum?.shutdown()
|
|
199
214
|
resolve("shutdown success")
|
|
200
215
|
}
|
|
@@ -600,6 +615,78 @@ class CxSdk: RCTEventEmitter {
|
|
|
600
615
|
}
|
|
601
616
|
}
|
|
602
617
|
|
|
618
|
+
// MARK: - Custom Spans
|
|
619
|
+
|
|
620
|
+
@objc(startGlobalSpan:labels:ignoredInstruments:withResolver:withRejecter:)
|
|
621
|
+
func startGlobalSpan(name: String,
|
|
622
|
+
labels: NSDictionary?,
|
|
623
|
+
ignoredInstruments: NSArray?,
|
|
624
|
+
resolve: RCTPromiseResolveBlock,
|
|
625
|
+
reject: RCTPromiseRejectBlock) {
|
|
626
|
+
guard let rum = coralogixRum else { resolve(nil); return }
|
|
627
|
+
let ignored = toIgnoredInstrumentSet(ignoredInstruments)
|
|
628
|
+
guard let tracer = rum.getCustomTracer(ignoredInstruments: ignored) else { resolve(nil); return }
|
|
629
|
+
let labelsDict = toAnyDict(labels)
|
|
630
|
+
guard let globalSpan = tracer.startGlobalSpan(name: name, labels: labelsDict) else { resolve(nil); return }
|
|
631
|
+
let spanId = globalSpan.spanId
|
|
632
|
+
let traceId = globalSpan.traceId
|
|
633
|
+
globalSpans[spanId] = globalSpan
|
|
634
|
+
resolve(["spanId": spanId, "traceId": traceId])
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
@objc(startCustomSpan:name:labels:withResolver:withRejecter:)
|
|
638
|
+
func startCustomSpan(parentSpanId: String,
|
|
639
|
+
name: String,
|
|
640
|
+
labels: NSDictionary?,
|
|
641
|
+
resolve: RCTPromiseResolveBlock,
|
|
642
|
+
reject: RCTPromiseRejectBlock) {
|
|
643
|
+
guard let globalSpan = globalSpans[parentSpanId] else { resolve(nil); return }
|
|
644
|
+
let labelsDict = toAnyDict(labels)
|
|
645
|
+
let customSpan = globalSpan.startCustomSpan(name: name, labels: labelsDict)
|
|
646
|
+
let spanId = customSpan.span.context.spanId.hexString
|
|
647
|
+
let traceId = globalSpan.traceId
|
|
648
|
+
guard !spanId.isEmpty else { resolve(nil); return }
|
|
649
|
+
customSpans[spanId] = customSpan
|
|
650
|
+
resolve(["spanId": spanId, "traceId": traceId])
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
@objc(endSpan:withResolver:withRejecter:)
|
|
654
|
+
func endSpan(spanId: String,
|
|
655
|
+
resolve: RCTPromiseResolveBlock,
|
|
656
|
+
reject: RCTPromiseRejectBlock) {
|
|
657
|
+
if let globalSpan = globalSpans.removeValue(forKey: spanId) {
|
|
658
|
+
globalSpan.endSpan()
|
|
659
|
+
} else if let customSpan = customSpans.removeValue(forKey: spanId) {
|
|
660
|
+
customSpan.endSpan()
|
|
661
|
+
}
|
|
662
|
+
resolve(nil)
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
private func toIgnoredInstrumentSet(_ array: NSArray?) -> Set<CoralogixIgnoredInstrument> {
|
|
666
|
+
guard let array = array else { return [] }
|
|
667
|
+
var set = Set<CoralogixIgnoredInstrument>()
|
|
668
|
+
for item in array {
|
|
669
|
+
switch item as? String {
|
|
670
|
+
case "networkRequests": set.insert(.networkRequests)
|
|
671
|
+
case "userInteractions": set.insert(.userInteractions)
|
|
672
|
+
case "errors": set.insert(.errors)
|
|
673
|
+
default: break
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
return set
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
private func toAnyDict(_ dict: NSDictionary?) -> [String: Any]? {
|
|
680
|
+
guard let dict = dict, dict.count > 0 else { return nil }
|
|
681
|
+
var result = [String: Any]()
|
|
682
|
+
for (key, value) in dict {
|
|
683
|
+
if let k = key as? String {
|
|
684
|
+
result[k] = value
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
return result.isEmpty ? nil : result
|
|
688
|
+
}
|
|
689
|
+
|
|
603
690
|
private func getCoralogixDomain(domain: String) -> CoralogixDomain {
|
|
604
691
|
switch domain.uppercased() {
|
|
605
692
|
case "EU1":
|
|
@@ -616,6 +703,8 @@ class CxSdk: RCTEventEmitter {
|
|
|
616
703
|
return .AP2
|
|
617
704
|
case "AP3":
|
|
618
705
|
return .AP3
|
|
706
|
+
case "US3":
|
|
707
|
+
return .US3
|
|
619
708
|
case "STAGING":
|
|
620
709
|
return .STG
|
|
621
710
|
default:
|
package/package.json
CHANGED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { CustomSpanBridge } from './CustomSpanBridge';
|
|
2
|
+
/** A child span nested under a {@link CoralogixGlobalSpan}. */
|
|
3
|
+
export declare class CoralogixCustomSpan {
|
|
4
|
+
readonly spanId: string;
|
|
5
|
+
readonly traceId: string;
|
|
6
|
+
private readonly bridge;
|
|
7
|
+
constructor(spanId: string, traceId: string, bridge: CustomSpanBridge);
|
|
8
|
+
endSpan(): Promise<void>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { CoralogixIgnoredInstrument } from '../model/Types';
|
|
2
|
+
import { CoralogixGlobalSpan } from './CoralogixGlobalSpan';
|
|
3
|
+
import type { CustomSpanBridge } from './CustomSpanBridge';
|
|
4
|
+
/**
|
|
5
|
+
* Entry point for manual RUM tracing. Obtain an instance via `CoralogixRum.getCustomTracer()`.
|
|
6
|
+
* The `ignoredInstruments` list controls which auto-instrumented events are NOT linked to spans
|
|
7
|
+
* created by this tracer (e.g. passing `['networkRequests']` keeps network spans independent).
|
|
8
|
+
*/
|
|
9
|
+
export declare class CoralogixCustomTracer {
|
|
10
|
+
private readonly ignoredInstruments;
|
|
11
|
+
private readonly bridge;
|
|
12
|
+
constructor(ignoredInstruments: CoralogixIgnoredInstrument[], bridge: CustomSpanBridge);
|
|
13
|
+
/**
|
|
14
|
+
* Starts a new global (root) span. Returns `null` if a global span is already active —
|
|
15
|
+
* only one global span may exist at a time across the entire app.
|
|
16
|
+
*/
|
|
17
|
+
startGlobalSpan(name: string, labels?: Record<string, any>): Promise<CoralogixGlobalSpan | null>;
|
|
18
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { CoralogixCustomSpan } from './CoralogixCustomSpan';
|
|
2
|
+
import type { CustomSpanBridge } from './CustomSpanBridge';
|
|
3
|
+
/** A root-level custom span. All child spans and `withContext` network calls share its traceId. */
|
|
4
|
+
export declare class CoralogixGlobalSpan {
|
|
5
|
+
readonly spanId: string;
|
|
6
|
+
readonly traceId: string;
|
|
7
|
+
private readonly bridge;
|
|
8
|
+
constructor(spanId: string, traceId: string, bridge: CustomSpanBridge);
|
|
9
|
+
/** Creates a child span nested under this global span. */
|
|
10
|
+
startCustomSpan(name: string, labels?: Record<string, any>): Promise<CoralogixCustomSpan | null>;
|
|
11
|
+
/**
|
|
12
|
+
* Runs fn() with this span set as the active global span for the duration of
|
|
13
|
+
* the returned promise. The active span ID remains set throughout the full
|
|
14
|
+
* async chain — including code after intermediate awaits — because we await
|
|
15
|
+
* fn() before clearing. Only detached callbacks (e.g. setTimeout) that fire
|
|
16
|
+
* after withContext resolves won't be linked.
|
|
17
|
+
*/
|
|
18
|
+
withContext<T>(fn: () => Promise<T>): Promise<T>;
|
|
19
|
+
endSpan(): Promise<void>;
|
|
20
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface CustomSpanBridge {
|
|
2
|
+
startGlobalSpan(name: string, labels: Record<string, any> | null, ignoredInstruments: string[]): Promise<{
|
|
3
|
+
spanId: string;
|
|
4
|
+
traceId: string;
|
|
5
|
+
} | null>;
|
|
6
|
+
startCustomSpan(parentSpanId: string, name: string, labels: Record<string, any> | null): Promise<{
|
|
7
|
+
spanId: string;
|
|
8
|
+
traceId: string;
|
|
9
|
+
} | null>;
|
|
10
|
+
endSpan(spanId: string): Promise<void>;
|
|
11
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { CoralogixIgnoredInstrument } from '../model/Types';
|
|
2
|
+
export declare const CustomSpanRegistry: {
|
|
3
|
+
getActive: () => string | null;
|
|
4
|
+
setActive: (id: string) => void;
|
|
5
|
+
clearActive: () => void;
|
|
6
|
+
registerSpan: (spanId: string, traceId: string) => void;
|
|
7
|
+
unregisterSpan: (spanId: string) => void;
|
|
8
|
+
getTraceId: (spanId: string) => string | undefined;
|
|
9
|
+
setIgnoredInstruments: (set: Set<CoralogixIgnoredInstrument>) => void;
|
|
10
|
+
getIgnoredInstruments: () => Set<CoralogixIgnoredInstrument>;
|
|
11
|
+
clear: () => void;
|
|
12
|
+
};
|
package/src/index.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ interface CxSdkClient {
|
|
|
10
10
|
initialize(options: CoralogixBrowserSdkConfig & {
|
|
11
11
|
frameworkVersion?: string;
|
|
12
12
|
hasBeforeSend?: boolean;
|
|
13
|
+
hasTracesExporter?: boolean;
|
|
13
14
|
}): Promise<boolean>;
|
|
14
15
|
setUserContext(userContext: UserContextConfig): void;
|
|
15
16
|
getUserContext(): Promise<UserContextConfig>;
|
|
@@ -38,6 +39,15 @@ interface CxSdkClient {
|
|
|
38
39
|
captureScreenshot(): void;
|
|
39
40
|
maskViewByTag(viewTag: number): void;
|
|
40
41
|
reportUserInteraction(interaction: InteractionContext): void;
|
|
42
|
+
startGlobalSpan(name: string, labels: Record<string, any> | null, ignoredInstruments: string[]): Promise<{
|
|
43
|
+
spanId: string;
|
|
44
|
+
traceId: string;
|
|
45
|
+
} | null>;
|
|
46
|
+
startCustomSpan(parentSpanId: string, name: string, labels: Record<string, any> | null): Promise<{
|
|
47
|
+
spanId: string;
|
|
48
|
+
traceId: string;
|
|
49
|
+
} | null>;
|
|
50
|
+
endSpan(spanId: string): Promise<void>;
|
|
41
51
|
}
|
|
42
52
|
export declare const CxSdk: CxSdkClient;
|
|
43
53
|
export declare const CoralogixRum: CoralogixOtelWebType;
|
|
@@ -47,9 +57,12 @@ export { type ApplicationContextConfig } from './model/ApplicationContextConfig'
|
|
|
47
57
|
export { type ViewContextConfig } from './model/ViewContextConfig';
|
|
48
58
|
export { CoralogixDomain } from './model/CoralogixDomain';
|
|
49
59
|
export { type UserContextConfig } from './model/UserContextConfig';
|
|
50
|
-
export { type CoralogixBrowserSdkConfig, type NetworkCaptureRule, CoralogixLogSeverity, } from './model/Types';
|
|
60
|
+
export { type CoralogixBrowserSdkConfig, type CoralogixIgnoredInstrument, type NetworkCaptureRule, type TraceExporterData, CoralogixLogSeverity, } from './model/Types';
|
|
51
61
|
export { type CoralogixOtelWebOptionsInstrumentations } from './model/CoralogixOtelWebOptionsInstrumentations';
|
|
52
62
|
export { type CustomMeasurement } from './model/CustomMeasurement';
|
|
53
63
|
export { type NetworkRequestDetails } from './model/NetworkRequestDetails';
|
|
54
64
|
export { type CoralogixMobileVitals } from './model/CoralogixMobileVitals';
|
|
55
65
|
export { attachReactNavigationObserver } from './instrumentations/navigation/NavigationInstrumentation';
|
|
66
|
+
export { CoralogixCustomTracer } from './custom-spans/CoralogixCustomTracer';
|
|
67
|
+
export { CoralogixGlobalSpan } from './custom-spans/CoralogixGlobalSpan';
|
|
68
|
+
export { CoralogixCustomSpan } from './custom-spans/CoralogixCustomSpan';
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type { SendLog } from './SendLog';
|
|
2
2
|
import type { CoralogixRumLabels } from './CoralogixRumLabels';
|
|
3
|
-
import { CoralogixBrowserSdkConfig } from './Types';
|
|
3
|
+
import { CoralogixBrowserSdkConfig, CoralogixIgnoredInstrument } from './Types';
|
|
4
4
|
import { UserContextConfig } from './UserContextConfig';
|
|
5
5
|
import { ViewContextConfig } from './ViewContextConfig';
|
|
6
6
|
import { ApplicationContextConfig } from './ApplicationContextConfig';
|
|
7
7
|
import { CustomMeasurement } from './CustomMeasurement';
|
|
8
8
|
import { NetworkRequestDetails } from './NetworkRequestDetails';
|
|
9
|
+
import { CoralogixCustomTracer } from '../custom-spans/CoralogixCustomTracer';
|
|
9
10
|
export interface CoralogixOtelWebType extends SendLog {
|
|
10
11
|
/**
|
|
11
12
|
* Init CoralogixRum.
|
|
@@ -46,5 +47,10 @@ export interface CoralogixOtelWebType extends SendLog {
|
|
|
46
47
|
* @param details
|
|
47
48
|
*/
|
|
48
49
|
reportNetworkRequest: (details: NetworkRequestDetails) => void;
|
|
50
|
+
/**
|
|
51
|
+
* Returns a tracer for creating custom spans. Instruments listed in
|
|
52
|
+
* ignoredInstruments will not be auto-parented to the active global span.
|
|
53
|
+
*/
|
|
54
|
+
getCustomTracer: (ignoredInstruments?: CoralogixIgnoredInstrument[]) => CoralogixCustomTracer;
|
|
49
55
|
readonly isInited: boolean;
|
|
50
56
|
}
|
package/src/model/Types.d.ts
CHANGED
|
@@ -218,12 +218,24 @@ export interface CoralogixBrowserSdkConfig {
|
|
|
218
218
|
sampleIntervalMs?: number;
|
|
219
219
|
};
|
|
220
220
|
mobileVitals?: CoralogixMobileVitals;
|
|
221
|
+
/** Callback invoked with each OTLP trace batch exported by the native SDK. */
|
|
222
|
+
tracesExporter?: (data: TraceExporterData) => void;
|
|
221
223
|
}
|
|
222
224
|
export type HybridMetric = {
|
|
223
225
|
name: string;
|
|
224
226
|
value: number;
|
|
225
227
|
units: string;
|
|
226
228
|
};
|
|
229
|
+
/**
|
|
230
|
+
* Instrumentation names that can be excluded from a custom tracer's span context.
|
|
231
|
+
* Pass one or more values to `getCustomTracer()` to prevent those event types from
|
|
232
|
+
* being linked to spans created by that tracer.
|
|
233
|
+
*/
|
|
234
|
+
export type CoralogixIgnoredInstrument = 'networkRequests' | 'userInteractions' | 'errors';
|
|
235
|
+
/** OTLP JSON-format trace data delivered to the `tracesExporter` callback. */
|
|
236
|
+
export interface TraceExporterData {
|
|
237
|
+
resource_spans: Record<string, unknown>[];
|
|
238
|
+
}
|
|
227
239
|
export interface InteractionContext {
|
|
228
240
|
type: 'click' | 'scroll' | 'swipe';
|
|
229
241
|
/** Required. Element identifier: accessibilityLabel ?? componentName for clicks; 'ScrollView' for scroll/swipe. */
|