@coralogix/react-native-plugin 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/CxSdk.podspec +45 -0
- package/LICENSE +201 -0
- package/README.md +187 -0
- package/android/build.gradle +87 -0
- package/android/gradle.properties +5 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/com/cxsdk/CxSdkModule.kt +457 -0
- package/android/src/main/java/com/cxsdk/CxSdkPackage.kt +16 -0
- package/android/src/main/java/com/cxsdk/ICxSdkModule.kt +24 -0
- package/index.cjs.js +682 -0
- package/index.d.ts +1 -0
- package/index.esm.js +678 -0
- package/ios/CxSdk-Bridging-Header.h +2 -0
- package/ios/CxSdk.mm +81 -0
- package/ios/CxSdk.swift +371 -0
- package/package.json +34 -0
- package/src/CoralogixPropgator.d.ts +2 -0
- package/src/consts.d.ts +23 -0
- package/src/index.d.ts +10 -0
- package/src/instrumentations/error/ErrorInstrumentation.d.ts +18 -0
- package/src/instrumentations/error/error.consts.d.ts +7 -0
- package/src/instrumentations/error/error.enums.d.ts +4 -0
- package/src/instrumentations/mobile-vitals/JsRefreshRateSamplerInstrumentation.d.ts +8 -0
- package/src/instrumentations/mobile-vitals/loopDetectorInstrumentation.d.ts +16 -0
- package/src/instrumentations/network/FetchInstrumentation.d.ts +5 -0
- package/src/instrumentations/network/network.enums.d.ts +10 -0
- package/src/logger.d.ts +16 -0
- package/src/model/ApplicationContextConfig.d.ts +4 -0
- package/src/model/CoralogixDomain.d.ts +10 -0
- package/src/model/CoralogixOtelWebOptionsInstrumentations.d.ts +9 -0
- package/src/model/CoralogixOtelWebType.d.ts +49 -0
- package/src/model/CoralogixRumLabels.d.ts +1 -0
- package/src/model/CustomMeasurement.d.ts +4 -0
- package/src/model/NetworkRequestDetails.d.ts +14 -0
- package/src/model/SendLog.d.ts +10 -0
- package/src/model/Types.d.ts +209 -0
- package/src/model/UserContextConfig.d.ts +8 -0
- package/src/model/ViewContextConfig.d.ts +3 -0
- package/src/utils.d.ts +5 -0
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
package com.cxsdk
|
|
2
|
+
|
|
3
|
+
import android.app.Application
|
|
4
|
+
import android.os.Handler
|
|
5
|
+
import android.os.Looper
|
|
6
|
+
import android.util.Log
|
|
7
|
+
import com.coralogix.android.sdk.CoralogixRum
|
|
8
|
+
import com.coralogix.android.sdk.internal.features.instrumentations.error.CoralogixErrorDecorator
|
|
9
|
+
import com.coralogix.android.sdk.internal.features.instrumentations.network.NetworkRequestDetails
|
|
10
|
+
import com.coralogix.android.sdk.internal.infrastructure.threaddump.CoralogixJsStackFrame
|
|
11
|
+
import com.coralogix.android.sdk.internal.infrastructure.threaddump.CoralogixStackTrace
|
|
12
|
+
import com.coralogix.android.sdk.model.CoralogixDomain
|
|
13
|
+
import com.coralogix.android.sdk.model.CoralogixLogSeverity
|
|
14
|
+
import com.coralogix.android.sdk.model.CoralogixOptions
|
|
15
|
+
import com.coralogix.android.sdk.model.Framework
|
|
16
|
+
import com.coralogix.android.sdk.model.HybridMetric
|
|
17
|
+
import com.coralogix.android.sdk.model.Instrumentation
|
|
18
|
+
import com.coralogix.android.sdk.model.UserContext
|
|
19
|
+
import com.coralogix.android.sdk.model.ViewContext
|
|
20
|
+
import com.facebook.react.bridge.Arguments
|
|
21
|
+
import com.facebook.react.bridge.Promise
|
|
22
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
23
|
+
import com.facebook.react.bridge.ReactContextBaseJavaModule
|
|
24
|
+
import com.facebook.react.bridge.ReactMethod
|
|
25
|
+
import com.facebook.react.bridge.ReadableArray
|
|
26
|
+
import com.facebook.react.bridge.ReadableMap
|
|
27
|
+
import com.facebook.react.bridge.ReadableType
|
|
28
|
+
import com.facebook.react.bridge.WritableArray
|
|
29
|
+
import com.facebook.react.bridge.WritableMap
|
|
30
|
+
import com.facebook.react.modules.core.DeviceEventManagerModule
|
|
31
|
+
import java.lang.Long.getLong
|
|
32
|
+
|
|
33
|
+
class CxSdkModule(reactContext: ReactApplicationContext) :
|
|
34
|
+
ReactContextBaseJavaModule(reactContext), ICxSdkModule {
|
|
35
|
+
|
|
36
|
+
override fun getName(): String {
|
|
37
|
+
return NAME
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
@ReactMethod
|
|
41
|
+
override fun initialize(config: ReadableMap) {
|
|
42
|
+
val application = reactApplicationContext.applicationContext as Application
|
|
43
|
+
val options = config.toCoralogixOptions()
|
|
44
|
+
|
|
45
|
+
val rnPluginVersion = if (config.hasKey("frameworkVersion") && !config.isNull("frameworkVersion"))
|
|
46
|
+
config.getString("frameworkVersion") ?: ""
|
|
47
|
+
else ""
|
|
48
|
+
|
|
49
|
+
Handler(Looper.getMainLooper()).post {
|
|
50
|
+
CoralogixRum.initialize(
|
|
51
|
+
application = application,
|
|
52
|
+
options = options,
|
|
53
|
+
framework = Framework.HybridFramework.ReactNative(rnPluginVersion))
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
@ReactMethod
|
|
58
|
+
override fun setUserContext(userContextMap: ReadableMap) {
|
|
59
|
+
val userContext = userContextMap.toUserContext()
|
|
60
|
+
CoralogixRum.setUserContext(userContext)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
@ReactMethod
|
|
64
|
+
override fun getUserContext(promise: Promise) {
|
|
65
|
+
promise.resolve(CoralogixRum.getUserContext().toWritableMap())
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
@ReactMethod
|
|
69
|
+
override fun setApplicationContext(appContextMap: ReadableMap) {
|
|
70
|
+
val appName = appContextMap.getString("application")
|
|
71
|
+
?: throw IllegalArgumentException("Missing required parameter: application")
|
|
72
|
+
val appVersion = appContextMap.getString("version")
|
|
73
|
+
?: throw IllegalArgumentException("Missing required parameter: version")
|
|
74
|
+
|
|
75
|
+
CoralogixRum.setApplicationContext(appName, appVersion)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
@ReactMethod
|
|
79
|
+
override fun getSessionId(promise: Promise) {
|
|
80
|
+
promise.resolve(CoralogixRum.getSessionId())
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
@ReactMethod
|
|
84
|
+
override fun setLabels(labelsMap: ReadableMap) {
|
|
85
|
+
val labels = labelsMap.toStringMap()
|
|
86
|
+
CoralogixRum.setLabels(labels)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
@ReactMethod
|
|
90
|
+
override fun getLabels(promise: Promise) {
|
|
91
|
+
promise.resolve(CoralogixRum.getLabels().toWritableMap())
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
@ReactMethod
|
|
95
|
+
override fun setViewContext(viewContext: String) {
|
|
96
|
+
CoralogixRum.setViewContext(viewContext)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
@ReactMethod
|
|
100
|
+
override fun log(severity: Int, message: String, data: ReadableMap) {
|
|
101
|
+
CoralogixRum.log(severity.toCoralogixLogSeverity(), message, data.toStringMap())
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
@ReactMethod
|
|
105
|
+
override fun reportNetworkRequest(requestDetails: ReadableMap) {
|
|
106
|
+
val details = requestDetails.toNetworkRequestDetails()
|
|
107
|
+
CoralogixRum.reportNetworkRequest(details)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
@ReactMethod
|
|
111
|
+
override fun sendCustomMeasurement(measurement: ReadableMap) {
|
|
112
|
+
val name = measurement.getString("name")
|
|
113
|
+
?: throw IllegalArgumentException("Missing required parameter: name")
|
|
114
|
+
|
|
115
|
+
val value = if (measurement.hasKey("value"))
|
|
116
|
+
measurement.getDouble("value").toLong()
|
|
117
|
+
else throw IllegalArgumentException("Missing required parameter: value")
|
|
118
|
+
|
|
119
|
+
CoralogixRum.sendCustomMeasurement(name, value)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
@ReactMethod
|
|
123
|
+
override fun reportError(details: ReadableMap) {
|
|
124
|
+
val errorType = details.getString("error_type").orEmpty()
|
|
125
|
+
val message = details.getString("error_message").orEmpty()
|
|
126
|
+
val isCrash = details.getBoolean("is_crash").takeIf {
|
|
127
|
+
details.hasKey("is_crash")
|
|
128
|
+
} ?: false
|
|
129
|
+
|
|
130
|
+
val parsedStackFrames = details.getArray("stack_trace")
|
|
131
|
+
?.let { stackArray ->
|
|
132
|
+
(0 until stackArray.size())
|
|
133
|
+
.mapNotNull { index -> stackArray.getMap(index) }
|
|
134
|
+
.map { frame ->
|
|
135
|
+
CoralogixJsStackFrame(
|
|
136
|
+
functionName = frame.getString("functionName").orEmpty(),
|
|
137
|
+
fileName = frame.getString("fileName").orEmpty(),
|
|
138
|
+
lineNumber = if (frame.hasKey("lineNumber")) frame.getInt("lineNumber") else -1,
|
|
139
|
+
columnNumber = if (frame.hasKey("columnNumber")) frame.getInt("columnNumber") else -1,
|
|
140
|
+
)
|
|
141
|
+
}
|
|
142
|
+
}.orEmpty()
|
|
143
|
+
|
|
144
|
+
CoralogixRum.reportError(
|
|
145
|
+
CoralogixErrorDecorator(
|
|
146
|
+
errorType = errorType,
|
|
147
|
+
errorMessage = message,
|
|
148
|
+
errorStack = CoralogixStackTrace(parsedStackFrames),
|
|
149
|
+
isCrash = isCrash
|
|
150
|
+
)
|
|
151
|
+
)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
@ReactMethod
|
|
155
|
+
override fun sendCxSpanData(results: ReadableArray) {
|
|
156
|
+
val data = convertStrictReadableArrayToListOfMaps(results)
|
|
157
|
+
CoralogixRum.sendCxSpanData(data)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
@ReactMethod
|
|
161
|
+
override fun reportMobileVitalsMeasurement(type: String, value: Double, units: String) {
|
|
162
|
+
CoralogixRum.reportMobileVitalsMeasurement(type, value, units)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
@ReactMethod
|
|
166
|
+
override fun reportMobileVitalsMeasurementSet(type: String, metrics: ReadableArray) {
|
|
167
|
+
val list = metrics.toHybridMetricList()
|
|
168
|
+
CoralogixRum.reportMobileVitalsMeasurement(type, list)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
@ReactMethod
|
|
172
|
+
override fun shutdown() {
|
|
173
|
+
Handler(Looper.getMainLooper()).post {
|
|
174
|
+
CoralogixRum.shutdown()
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
@ReactMethod
|
|
179
|
+
fun addListener(eventName: String) {
|
|
180
|
+
Log.d("CxSdkModule", "addListener called with eventName: $eventName")
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
@ReactMethod
|
|
184
|
+
fun removeListeners(count: Int) {
|
|
185
|
+
Log.d("CxSdkModule", "removeListeners: $count")
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
private fun ReadableMap.toCoralogixOptions(): CoralogixOptions {
|
|
189
|
+
val applicationName = getString("application")
|
|
190
|
+
?: throw IllegalArgumentException("Missing required parameter: application")
|
|
191
|
+
val publicKey = getString("public_key")
|
|
192
|
+
?: throw IllegalArgumentException("Missing required parameter: publicKey")
|
|
193
|
+
val coralogixDomain = getString("coralogixDomain")?.toCoralogixDomain()
|
|
194
|
+
?: throw IllegalArgumentException("Missing required parameter: coralogixDomain")
|
|
195
|
+
|
|
196
|
+
val traceParentInHeaderMap = getMap("traceParentInHeader")
|
|
197
|
+
val isTraceParentInHeaderEnabled = traceParentInHeaderMap?.let {
|
|
198
|
+
it.hasKey("enable") && it.getBoolean("enable")
|
|
199
|
+
} ?: false
|
|
200
|
+
val collectIpData = if (hasKey("collectIPData")) getBoolean("collectIPData") else true
|
|
201
|
+
|
|
202
|
+
return CoralogixOptions(
|
|
203
|
+
applicationName = applicationName,
|
|
204
|
+
coralogixDomain = coralogixDomain,
|
|
205
|
+
publicKey = publicKey,
|
|
206
|
+
labels = getMap("labels")?.toStringMap() ?: mapOf(),
|
|
207
|
+
environment = getString("environment") ?: "",
|
|
208
|
+
version = getString("version") ?: "",
|
|
209
|
+
userContext = getMap("user_context")?.toUserContext() ?: UserContext(),
|
|
210
|
+
viewContext = ViewContext(getMap("view_context")?.getString("view") ?: ""),
|
|
211
|
+
instrumentations = getMap("instrumentations")?.toInstrumentationMap() ?: mapOf(),
|
|
212
|
+
ignoreUrls = getArray("ignoreUrls")?.handleStringOrRegexList() ?: listOf(),
|
|
213
|
+
ignoreErrors = getArray("ignoreErrors")?.handleStringOrRegexList() ?: listOf(),
|
|
214
|
+
sessionSampleRate = 100,
|
|
215
|
+
traceParentInHeader = isTraceParentInHeaderEnabled,
|
|
216
|
+
fpsSamplingSeconds = if (hasKey("fpsSamplingSeconds")) getLong("fpsSamplingSeconds") else 300,
|
|
217
|
+
debug = if (hasKey("debug")) getBoolean("debug") else false,
|
|
218
|
+
proxyUrl = getString("proxyUrl"),
|
|
219
|
+
beforeSendCallback = ::beforeSendCallback,
|
|
220
|
+
collectIPData = collectIpData
|
|
221
|
+
)
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
private fun beforeSendCallback(data: List<Map<String, Any?>>) {
|
|
225
|
+
val args = convertAnyListToWritableArray(data)
|
|
226
|
+
reactApplicationContext
|
|
227
|
+
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
|
|
228
|
+
.emit("onBeforeSend", args)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
private fun convertAnyListToWritableArray(list: List<Any?>): WritableArray {
|
|
232
|
+
val array = Arguments.createArray()
|
|
233
|
+
list.forEach { value ->
|
|
234
|
+
when (value) {
|
|
235
|
+
null -> array.pushNull()
|
|
236
|
+
is Boolean -> array.pushBoolean(value)
|
|
237
|
+
is Int -> array.pushInt(value)
|
|
238
|
+
is Double -> array.pushDouble(value)
|
|
239
|
+
is Float -> array.pushDouble(value.toDouble())
|
|
240
|
+
is String -> array.pushString(value)
|
|
241
|
+
is Map<*, *> -> {
|
|
242
|
+
@Suppress("UNCHECKED_CAST")
|
|
243
|
+
array.pushMap(convertMapToWritableMap(value as Map<String, Any?>))
|
|
244
|
+
}
|
|
245
|
+
is List<*> -> {
|
|
246
|
+
array.pushArray(convertAnyListToWritableArray(value as List<Any?>))
|
|
247
|
+
}
|
|
248
|
+
else -> array.pushString(value.toString()) // fallback
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
return array
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
private fun convertMapToWritableMap(map: Map<String, Any?>): WritableMap {
|
|
255
|
+
val writableMap = Arguments.createMap()
|
|
256
|
+
map.forEach { (key, value) ->
|
|
257
|
+
when (value) {
|
|
258
|
+
null -> writableMap.putNull(key)
|
|
259
|
+
is Boolean -> writableMap.putBoolean(key, value)
|
|
260
|
+
is Int -> writableMap.putInt(key, value)
|
|
261
|
+
is Double -> writableMap.putDouble(key, value)
|
|
262
|
+
is Float -> writableMap.putDouble(key, value.toDouble())
|
|
263
|
+
is String -> writableMap.putString(key, value)
|
|
264
|
+
is Map<*, *> -> {
|
|
265
|
+
@Suppress("UNCHECKED_CAST")
|
|
266
|
+
writableMap.putMap(key, convertMapToWritableMap(value as Map<String, Any?>))
|
|
267
|
+
}
|
|
268
|
+
is List<*> -> {
|
|
269
|
+
writableMap.putArray(key, convertAnyListToWritableArray(value))
|
|
270
|
+
}
|
|
271
|
+
else -> writableMap.putString(key, value.toString()) // fallback
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
return writableMap
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
private fun convertStrictReadableArrayToListOfMaps(readableArray: ReadableArray): List<Map<String, Any?>> {
|
|
278
|
+
val list = mutableListOf<Map<String, Any?>>()
|
|
279
|
+
for (i in 0 until readableArray.size()) {
|
|
280
|
+
if (readableArray.getType(i) != ReadableType.Map) {
|
|
281
|
+
throw IllegalArgumentException("Expected array of maps, but found ${readableArray.getType(i)} at index $i")
|
|
282
|
+
}
|
|
283
|
+
val map = readableArray.getMap(i)
|
|
284
|
+
list.add(convertReadableMapToMap(map))
|
|
285
|
+
}
|
|
286
|
+
return list
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
private fun convertReadableArrayToAnyList(readableArray: ReadableArray): List<Any?> {
|
|
290
|
+
val list = mutableListOf<Any?>()
|
|
291
|
+
for (i in 0 until readableArray.size()) {
|
|
292
|
+
when (readableArray.getType(i)) {
|
|
293
|
+
ReadableType.Null -> list.add(null)
|
|
294
|
+
ReadableType.Boolean -> list.add(readableArray.getBoolean(i))
|
|
295
|
+
ReadableType.Number -> {
|
|
296
|
+
val value = readableArray.getDouble(i)
|
|
297
|
+
list.add(if (value % 1 == 0.0) value.toInt() else value)
|
|
298
|
+
}
|
|
299
|
+
ReadableType.String -> list.add(readableArray.getString(i))
|
|
300
|
+
ReadableType.Map -> list.add(convertReadableMapToMap(readableArray.getMap(i)))
|
|
301
|
+
ReadableType.Array -> list.add(convertReadableArrayToAnyList(readableArray.getArray(i)))
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
return list
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
private fun convertReadableMapToMap(readableMap: ReadableMap): Map<String, Any?> {
|
|
308
|
+
val map = mutableMapOf<String, Any?>()
|
|
309
|
+
val iterator = readableMap.keySetIterator()
|
|
310
|
+
while (iterator.hasNextKey()) {
|
|
311
|
+
val key = iterator.nextKey()
|
|
312
|
+
when (readableMap.getType(key)) {
|
|
313
|
+
ReadableType.Null -> map[key] = null
|
|
314
|
+
ReadableType.Boolean -> map[key] = readableMap.getBoolean(key)
|
|
315
|
+
ReadableType.Number -> {
|
|
316
|
+
val value = readableMap.getDouble(key)
|
|
317
|
+
// Try to preserve integer-ness when possible
|
|
318
|
+
map[key] = if (value % 1 == 0.0) value.toInt() else value
|
|
319
|
+
}
|
|
320
|
+
ReadableType.String -> map[key] = readableMap.getString(key)
|
|
321
|
+
ReadableType.Map -> map[key] = convertReadableMapToMap(readableMap.getMap(key)!!)
|
|
322
|
+
ReadableType.Array -> map[key] = convertReadableArrayToAnyList(readableMap.getArray(key)!!)
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
return map
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
private fun String.toCoralogixDomain(): CoralogixDomain {
|
|
329
|
+
return when (this.uppercase()) {
|
|
330
|
+
"EU1" -> CoralogixDomain.EU1
|
|
331
|
+
"EU2" -> CoralogixDomain.EU2
|
|
332
|
+
"US1" -> CoralogixDomain.US1
|
|
333
|
+
"US2" -> CoralogixDomain.US2
|
|
334
|
+
"AP1" -> CoralogixDomain.AP1
|
|
335
|
+
"AP2" -> CoralogixDomain.AP2
|
|
336
|
+
"AP3" -> CoralogixDomain.AP3
|
|
337
|
+
"STAGING" -> CoralogixDomain.STAGING
|
|
338
|
+
else -> throw IllegalArgumentException("Invalid coralogixDomain: $this. Must be one of [EU1, EU2, US1, US2, AP1, AP2, AP3, STAGING]")
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
private fun ReadableArray.handleStringOrRegexList(): List<String> {
|
|
343
|
+
val result = mutableListOf<String>()
|
|
344
|
+
|
|
345
|
+
for (i in 0 until size()) {
|
|
346
|
+
when (getType(i)) {
|
|
347
|
+
ReadableType.String -> {
|
|
348
|
+
result.add(getString(i))
|
|
349
|
+
}
|
|
350
|
+
ReadableType.Map -> {
|
|
351
|
+
val map = getMap(i)
|
|
352
|
+
val pattern = map.getString("source") // Extract regex pattern
|
|
353
|
+
pattern?.let { result.add(it) }
|
|
354
|
+
}
|
|
355
|
+
else -> {
|
|
356
|
+
// Skip other types (Numbers, Booleans, etc.)
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
return result
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
private fun ReadableMap.toUserContext() = UserContext(
|
|
364
|
+
userId = getString("user_id") ?: "",
|
|
365
|
+
username = getString("user_name") ?: "",
|
|
366
|
+
email = getString("user_email") ?: "",
|
|
367
|
+
metadata = getMap("user_metadata")?.toStringMap() ?: mapOf()
|
|
368
|
+
)
|
|
369
|
+
|
|
370
|
+
private fun ReadableMap.toInstrumentationMap(): Map<Instrumentation, Boolean> {
|
|
371
|
+
return mapOf(
|
|
372
|
+
Instrumentation.Error to if (hasKey("error")) getBoolean("error") else true,
|
|
373
|
+
Instrumentation.Network to if (hasKey("fetch")) getBoolean("fetch") else true,
|
|
374
|
+
Instrumentation.Custom to if (hasKey("custom")) getBoolean("custom") else true,
|
|
375
|
+
Instrumentation.MobileVitals to if (hasKey("mobile_vitals")) getBoolean("mobile_vitals") else true,
|
|
376
|
+
Instrumentation.Anr to if (hasKey("anr")) getBoolean("anr") else true,
|
|
377
|
+
Instrumentation.Lifecycle to if (hasKey("lifecycle")) getBoolean("lifecycle") else true,
|
|
378
|
+
Instrumentation.UserInteraction to if (hasKey("user_interaction")) getBoolean("user_interaction") else true,
|
|
379
|
+
)
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
private fun ReadableMap.toStringMap(): Map<String, String> {
|
|
383
|
+
val map = mutableMapOf<String, String>()
|
|
384
|
+
val iterator = keySetIterator()
|
|
385
|
+
while (iterator.hasNextKey()) {
|
|
386
|
+
val key = iterator.nextKey()
|
|
387
|
+
getString(key)?.let { map[key] = it }
|
|
388
|
+
}
|
|
389
|
+
return map
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
private fun Map<String, String>.toWritableMap(): WritableMap {
|
|
393
|
+
val map = Arguments.createMap()
|
|
394
|
+
for ((key, value) in this) {
|
|
395
|
+
map.putString(key, value)
|
|
396
|
+
}
|
|
397
|
+
return map
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
private fun UserContext.toWritableMap(): WritableMap {
|
|
401
|
+
val map = Arguments.createMap()
|
|
402
|
+
map.putString("user_id", userId)
|
|
403
|
+
map.putString("user_name", username)
|
|
404
|
+
map.putString("user_email", email)
|
|
405
|
+
map.putMap("user_metadata", metadata.toWritableMap())
|
|
406
|
+
|
|
407
|
+
return map
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
private fun Int.toCoralogixLogSeverity(): CoralogixLogSeverity {
|
|
411
|
+
return when (this) {
|
|
412
|
+
1 -> CoralogixLogSeverity.Debug
|
|
413
|
+
2 -> CoralogixLogSeverity.Verbose
|
|
414
|
+
3 -> CoralogixLogSeverity.Info
|
|
415
|
+
4 -> CoralogixLogSeverity.Warn
|
|
416
|
+
5 -> CoralogixLogSeverity.Error
|
|
417
|
+
6 -> CoralogixLogSeverity.Critical
|
|
418
|
+
else -> throw IllegalArgumentException("Invalid severity: $this. Must be one of [1, 2, 3, 4, 5, 6]")
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
private fun ReadableMap.toNetworkRequestDetails() = NetworkRequestDetails(
|
|
423
|
+
method = getString("method") ?: "",
|
|
424
|
+
statusCode = if (hasKey("statusCode")) getInt("statusCode") else 0,
|
|
425
|
+
url = getString("url") ?: "",
|
|
426
|
+
fragments = getString("fragments") ?: "",
|
|
427
|
+
host = getString("host") ?: "",
|
|
428
|
+
schema = getString("schema") ?: "",
|
|
429
|
+
statusText = getString("statusText") ?: "",
|
|
430
|
+
duration = if (hasKey("duration")) getDouble("duration").toLong() else 0,
|
|
431
|
+
responseContentLength = if (hasKey("responseContentLength"))
|
|
432
|
+
getDouble("responseContentLength").toLong() else 0,
|
|
433
|
+
errorMessage = getString("errorMessage"),
|
|
434
|
+
traceId = getString("customTraceId"),
|
|
435
|
+
spanId = getString("customSpanId")
|
|
436
|
+
).also { Log.d("CxSdkModule", "toNetworkRequestDetails: $it") }
|
|
437
|
+
|
|
438
|
+
private fun ReadableArray.toHybridMetricList(): List<HybridMetric> {
|
|
439
|
+
val out = ArrayList<HybridMetric>(size())
|
|
440
|
+
for (i in 0 until size()) {
|
|
441
|
+
val m = getMap(i)
|
|
442
|
+
val name = m.getString("name") ?: throw IllegalArgumentException("metrics[$i].name is required")
|
|
443
|
+
// RN numbers are Double; accept both Int and Double transparently:
|
|
444
|
+
val value = when {
|
|
445
|
+
m.hasKey("value") && !m.isNull("value") -> m.getDouble("value")
|
|
446
|
+
else -> throw IllegalArgumentException("metrics[$i].value is required")
|
|
447
|
+
}
|
|
448
|
+
val units = m.getString("units") ?: throw IllegalArgumentException("metrics[$i].units is required")
|
|
449
|
+
out += HybridMetric(name = name, value = value, units = units)
|
|
450
|
+
}
|
|
451
|
+
return out
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
companion object {
|
|
455
|
+
const val NAME = "CxSdk"
|
|
456
|
+
}
|
|
457
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
package com.cxsdk
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.ReactPackage
|
|
4
|
+
import com.facebook.react.bridge.NativeModule
|
|
5
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
6
|
+
import com.facebook.react.uimanager.ViewManager
|
|
7
|
+
|
|
8
|
+
class CxSdkPackage : ReactPackage {
|
|
9
|
+
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
|
|
10
|
+
return listOf(CxSdkModule(reactContext))
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
|
|
14
|
+
return emptyList()
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
package com.cxsdk
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.Promise
|
|
4
|
+
import com.facebook.react.bridge.ReadableArray
|
|
5
|
+
import com.facebook.react.bridge.ReadableMap
|
|
6
|
+
|
|
7
|
+
interface ICxSdkModule {
|
|
8
|
+
fun initialize(config: ReadableMap)
|
|
9
|
+
fun setUserContext(userContextMap: ReadableMap)
|
|
10
|
+
fun getUserContext(promise: Promise)
|
|
11
|
+
fun setApplicationContext(appContextMap: ReadableMap)
|
|
12
|
+
fun getSessionId(promise: Promise)
|
|
13
|
+
fun setLabels(labelsMap: ReadableMap)
|
|
14
|
+
fun getLabels(promise: Promise)
|
|
15
|
+
fun setViewContext(viewContext: String)
|
|
16
|
+
fun log(severity: Int, message: String, data: ReadableMap)
|
|
17
|
+
fun reportNetworkRequest(requestDetails: ReadableMap)
|
|
18
|
+
fun sendCustomMeasurement(measurement: ReadableMap)
|
|
19
|
+
fun reportError(details: ReadableMap)
|
|
20
|
+
fun sendCxSpanData(results: ReadableArray)
|
|
21
|
+
fun reportMobileVitalsMeasurement(type: String, value: Double, units: String)
|
|
22
|
+
fun reportMobileVitalsMeasurementSet(type: String, metrics: ReadableArray)
|
|
23
|
+
fun shutdown()
|
|
24
|
+
}
|