@luciq/react-native 19.3.0 → 19.4.0-40394-SNAPSHOT
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 +15 -0
- package/android/native.gradle +1 -1
- package/android/proguard-rules.txt +1 -1
- package/android/src/main/java/ai/luciq/reactlibrary/RNLuciqAPMModule.java +9 -0
- package/android/src/main/java/ai/luciq/reactlibrary/RNLuciqNetworkLoggerModule.java +29 -7
- package/android/src/main/java/ai/luciq/reactlibrary/RNLuciqReactnativeModule.java +74 -9
- package/android/src/main/java/ai/luciq/reactlibrary/RNLuciqReactnativePackage.java +2 -0
- package/android/src/main/java/ai/luciq/reactlibrary/utils/EventEmitterModule.java +7 -0
- package/android/src/main/java/ai/luciq/reactlibrary/utils/ReportUtil.java +0 -7
- package/dist/modules/Luciq.d.ts +15 -0
- package/dist/modules/Luciq.js +23 -1
- package/dist/modules/NetworkLogger.d.ts +0 -5
- package/dist/modules/NetworkLogger.js +9 -1
- package/dist/native/NativeLuciq.d.ts +3 -0
- package/dist/utils/FeatureFlags.d.ts +6 -0
- package/dist/utils/FeatureFlags.js +35 -0
- package/dist/utils/LuciqUtils.js +6 -0
- package/dist/utils/XhrNetworkInterceptor.js +85 -53
- package/ios/RNLuciq/LuciqReactBridge.m +12 -0
- package/ios/native.rb +1 -1
- package/package.json +1 -2
- package/src/modules/Luciq.ts +27 -1
- package/src/modules/NetworkLogger.ts +26 -1
- package/src/native/NativeLuciq.ts +5 -0
- package/src/utils/FeatureFlags.ts +44 -0
- package/src/utils/LuciqUtils.ts +15 -0
- package/src/utils/XhrNetworkInterceptor.ts +128 -55
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [19.4.0](https://github.com/luciqai/luciq-reactnative-sdk/compare/v19.4.0...19.3.0)
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **WebView Monitoring**: Added comprehensive WebView monitoring to capture performance metrics, user interactions, and network requests from WebView components.
|
|
8
|
+
- `Luciq.setWebViewMonitoringEnabled(boolean)` - Enable/disable master WebView monitoring
|
|
9
|
+
- `Luciq.setWebViewUserInteractionsTrackingEnabled(boolean)` - Enable/disable user interaction tracking in WebViews
|
|
10
|
+
- `Luciq.setWebViewNetworkTrackingEnabled(boolean`) - Enable/disable network logging from WebViews
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- Bump Luciq iOS SDK to v19.5.1 ([#42](https://github.com/luciqai/luciq-reactnative-sdk/pull/42)). [See release notes](https://github.com/luciqai/Luciq-iOS-sdk/releases/tag/19.5.1).
|
|
15
|
+
|
|
16
|
+
- Bump Luciq Android SDK to v19.4.0 ([#42](https://github.com/luciqai/luciq-reactnative-sdk/pull/42)). [See release notes](https://github.com/luciqai/Luciq-Android-sdk/releases/tag/v19.4.0).
|
|
17
|
+
|
|
3
18
|
## [19.3.0](https://github.com/luciqai/luciq-reactnative-sdk/compare/v19.3.0...19.2.1)
|
|
4
19
|
|
|
5
20
|
### Added
|
package/android/native.gradle
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
-keep class
|
|
1
|
+
-keep class ai.luciq.** {*;}
|
|
@@ -30,6 +30,8 @@ import ai.luciq.reactlibrary.utils.MainThreadHandler;
|
|
|
30
30
|
|
|
31
31
|
public class RNLuciqAPMModule extends EventEmitterModule {
|
|
32
32
|
|
|
33
|
+
private static final String NET_TAG = "LCQ-RN-NET";
|
|
34
|
+
|
|
33
35
|
public RNLuciqAPMModule(ReactApplicationContext reactApplicationContext) {
|
|
34
36
|
super(reactApplicationContext);
|
|
35
37
|
}
|
|
@@ -328,6 +330,7 @@ public class RNLuciqAPMModule extends EventEmitterModule {
|
|
|
328
330
|
@Nullable final String gqLCQueryName,
|
|
329
331
|
@Nullable final String serverErrorMessage
|
|
330
332
|
) {
|
|
333
|
+
Log.d(NET_TAG, "[networkLogAndroid-APM] Received from JS: " + requestMethod + " " + requestUrl + ", status=" + (int) statusCode + ", duration=" + (long) requestDuration + "ms, startTime=" + (long) requestStartTime + ", error=" + errorDomain + ", gqlQuery=" + gqLCQueryName);
|
|
331
334
|
try {
|
|
332
335
|
APMNetworkLogger networkLogger = new APMNetworkLogger();
|
|
333
336
|
|
|
@@ -349,8 +352,10 @@ public class RNLuciqAPMModule extends EventEmitterModule {
|
|
|
349
352
|
}
|
|
350
353
|
|
|
351
354
|
} catch (Exception e) {
|
|
355
|
+
Log.e(NET_TAG, "[networkLogAndroid-APM] Error parsing W3C attributes for " + requestMethod + " " + requestUrl, e);
|
|
352
356
|
e.printStackTrace();
|
|
353
357
|
}
|
|
358
|
+
Log.d(NET_TAG, "[networkLogAndroid-APM] W3C attrs — isW3cHeaderFound=" + isW3cHeaderFound + ", partialId=" + partialId + ", networkStartTimeInSeconds=" + networkStartTimeInSeconds + ", generatedHeader=" + (w3cAttributes != null && !w3cAttributes.isNull("w3cGeneratedHeader") ? w3cAttributes.getString("w3cGeneratedHeader") : "null") + ", caughtHeader=" + (w3cAttributes != null && !w3cAttributes.isNull("w3cCaughtHeader") ? w3cAttributes.getString("w3cCaughtHeader") : "null"));
|
|
354
359
|
APMCPNetworkLog.W3CExternalTraceAttributes w3cExternalTraceAttributes =
|
|
355
360
|
new APMCPNetworkLog.W3CExternalTraceAttributes(
|
|
356
361
|
isW3cHeaderFound,
|
|
@@ -382,13 +387,17 @@ public class RNLuciqAPMModule extends EventEmitterModule {
|
|
|
382
387
|
serverErrorMessage,
|
|
383
388
|
w3cExternalTraceAttributes
|
|
384
389
|
);
|
|
390
|
+
Log.d(NET_TAG, "[networkLogAndroid-APM] Successfully invoked APMNetworkLogger.log via reflection: " + requestMethod + " " + requestUrl);
|
|
385
391
|
} else {
|
|
392
|
+
Log.e(NET_TAG, "[networkLogAndroid-APM] APMNetworkLogger.log method NOT found by reflection — network log will be lost: " + requestMethod + " " + requestUrl);
|
|
386
393
|
Log.e("IB-CP-Bridge", "APMNetworkLogger.log was not found by reflection");
|
|
387
394
|
}
|
|
388
395
|
} catch (Throwable e) {
|
|
396
|
+
Log.e(NET_TAG, "[networkLogAndroid-APM] Exception invoking APMNetworkLogger.log: " + e.getMessage() + " for " + requestMethod + " " + requestUrl, e);
|
|
389
397
|
e.printStackTrace();
|
|
390
398
|
}
|
|
391
399
|
} catch (Throwable e) {
|
|
400
|
+
Log.e(NET_TAG, "[networkLogAndroid-APM] Top-level exception: " + e.getMessage() + " for " + requestMethod + " " + requestUrl, e);
|
|
392
401
|
e.printStackTrace();
|
|
393
402
|
}
|
|
394
403
|
}
|
|
@@ -32,6 +32,8 @@ import java.util.concurrent.ConcurrentHashMap;
|
|
|
32
32
|
|
|
33
33
|
public class RNLuciqNetworkLoggerModule extends EventEmitterModule {
|
|
34
34
|
|
|
35
|
+
private static final String NET_TAG = "LCQ-RN-NET";
|
|
36
|
+
|
|
35
37
|
public final ConcurrentHashMap<String, OnCompleteCallback<NetworkLogSnapshot>> callbackMap = new ConcurrentHashMap<String, OnCompleteCallback<NetworkLogSnapshot>>();
|
|
36
38
|
|
|
37
39
|
public RNLuciqNetworkLoggerModule(ReactApplicationContext reactContext) {
|
|
@@ -57,7 +59,9 @@ public class RNLuciqNetworkLoggerModule extends EventEmitterModule {
|
|
|
57
59
|
}
|
|
58
60
|
|
|
59
61
|
private boolean getFlagValue(String key) {
|
|
60
|
-
|
|
62
|
+
boolean value = InternalAPM._isFeatureEnabledCP(key, "");
|
|
63
|
+
Log.d(NET_TAG, "[getFlagValue] key=" + key + ", value=" + value);
|
|
64
|
+
return value;
|
|
61
65
|
}
|
|
62
66
|
|
|
63
67
|
private WritableMap convertFromMapToWritableMap(Map<String, Object> map) {
|
|
@@ -86,14 +90,18 @@ public class RNLuciqNetworkLoggerModule extends EventEmitterModule {
|
|
|
86
90
|
*/
|
|
87
91
|
@ReactMethod
|
|
88
92
|
public void isNativeInterceptionEnabled(Promise promise) {
|
|
93
|
+
Log.d(NET_TAG, "[isNativeInterceptionEnabled] Querying CP_NATIVE_INTERCEPTION_ENABLED flag");
|
|
89
94
|
MainThreadHandler.runOnMainThread(new Runnable() {
|
|
90
95
|
@Override
|
|
91
96
|
public void run() {
|
|
92
97
|
try {
|
|
93
|
-
|
|
98
|
+
boolean enabled = getFlagValue(CP_NATIVE_INTERCEPTION_ENABLED);
|
|
99
|
+
Log.d(NET_TAG, "[isNativeInterceptionEnabled] Result=" + enabled);
|
|
100
|
+
promise.resolve(enabled);
|
|
94
101
|
} catch (Exception e) {
|
|
102
|
+
Log.e(NET_TAG, "[isNativeInterceptionEnabled] Error — falling back to false (JS interceptor)", e);
|
|
95
103
|
e.printStackTrace();
|
|
96
|
-
promise.resolve(false);
|
|
104
|
+
promise.resolve(false);
|
|
97
105
|
}
|
|
98
106
|
|
|
99
107
|
}
|
|
@@ -107,14 +115,18 @@ public class RNLuciqNetworkLoggerModule extends EventEmitterModule {
|
|
|
107
115
|
*/
|
|
108
116
|
@ReactMethod
|
|
109
117
|
public void hasAPMNetworkPlugin(Promise promise) {
|
|
118
|
+
Log.d(NET_TAG, "[hasAPMNetworkPlugin] Querying APM_NETWORK_PLUGIN_INSTALLED flag");
|
|
110
119
|
MainThreadHandler.runOnMainThread(new Runnable() {
|
|
111
120
|
@Override
|
|
112
121
|
public void run() {
|
|
113
122
|
try {
|
|
114
|
-
|
|
123
|
+
boolean hasPlugin = getFlagValue(APM_NETWORK_PLUGIN_INSTALLED);
|
|
124
|
+
Log.d(NET_TAG, "[hasAPMNetworkPlugin] Result=" + hasPlugin);
|
|
125
|
+
promise.resolve(hasPlugin);
|
|
115
126
|
} catch (Exception e) {
|
|
127
|
+
Log.e(NET_TAG, "[hasAPMNetworkPlugin] Error — falling back to false", e);
|
|
116
128
|
e.printStackTrace();
|
|
117
|
-
promise.resolve(false);
|
|
129
|
+
promise.resolve(false);
|
|
118
130
|
}
|
|
119
131
|
|
|
120
132
|
}
|
|
@@ -124,12 +136,14 @@ public class RNLuciqNetworkLoggerModule extends EventEmitterModule {
|
|
|
124
136
|
|
|
125
137
|
@ReactMethod
|
|
126
138
|
public void registerNetworkLogsListener() {
|
|
139
|
+
Log.d(NET_TAG, "[registerNetworkLogsListener] Registering network log sanitizer");
|
|
127
140
|
MainThreadHandler.runOnMainThread(new Runnable() {
|
|
128
141
|
@Override
|
|
129
142
|
public void run() {
|
|
130
143
|
InternalAPM._registerNetworkLogSanitizer((networkLogSnapshot, onCompleteCallback) -> {
|
|
131
144
|
final String id = String.valueOf(onCompleteCallback.hashCode());
|
|
132
145
|
callbackMap.put(id, onCompleteCallback);
|
|
146
|
+
Log.d(NET_TAG, "[NetworkLogSanitizer] Received snapshot — id=" + id + ", url=" + networkLogSnapshot.getUrl() + ", responseCode=" + networkLogSnapshot.getResponseCode() + ", callbackMapSize=" + callbackMap.size());
|
|
133
147
|
|
|
134
148
|
WritableMap networkSnapshotParams = Arguments.createMap();
|
|
135
149
|
networkSnapshotParams.putString("id", id);
|
|
@@ -147,6 +161,7 @@ public class RNLuciqNetworkLoggerModule extends EventEmitterModule {
|
|
|
147
161
|
}
|
|
148
162
|
|
|
149
163
|
sendEvent(Constants.LCQ_NETWORK_LOGGER_HANDLER, networkSnapshotParams);
|
|
164
|
+
Log.d(NET_TAG, "[NetworkLogSanitizer] Sent event to JS: " + Constants.LCQ_NETWORK_LOGGER_HANDLER + " for " + networkLogSnapshot.getUrl());
|
|
150
165
|
});
|
|
151
166
|
}
|
|
152
167
|
});
|
|
@@ -154,10 +169,12 @@ public class RNLuciqNetworkLoggerModule extends EventEmitterModule {
|
|
|
154
169
|
|
|
155
170
|
@ReactMethod
|
|
156
171
|
public void resetNetworkLogsListener() {
|
|
172
|
+
Log.d(NET_TAG, "[resetNetworkLogsListener] Clearing network log sanitizer, callbackMapSize=" + callbackMap.size());
|
|
157
173
|
MainThreadHandler.runOnMainThread(new Runnable() {
|
|
158
174
|
@Override
|
|
159
175
|
public void run() {
|
|
160
176
|
InternalAPM._registerNetworkLogSanitizer(null);
|
|
177
|
+
Log.d(NET_TAG, "[resetNetworkLogsListener] Sanitizer cleared");
|
|
161
178
|
}
|
|
162
179
|
});
|
|
163
180
|
}
|
|
@@ -172,23 +189,28 @@ public class RNLuciqNetworkLoggerModule extends EventEmitterModule {
|
|
|
172
189
|
ReadableMap requestHeaders,
|
|
173
190
|
ReadableMap responseHeaders
|
|
174
191
|
) {
|
|
192
|
+
Log.d(NET_TAG, "[updateNetworkLogSnapshot] callbackID=" + callbackID + ", url=" + url + ", responseCode=" + responseCode + ", callbackMapSize=" + callbackMap.size());
|
|
175
193
|
try {
|
|
176
|
-
// Convert ReadableMap to a Java Map for easier handling
|
|
177
194
|
Map<String, Object> requestHeadersMap = convertReadableMapToMap(requestHeaders);
|
|
178
195
|
Map<String, Object> responseHeadersMap = convertReadableMapToMap(responseHeaders);
|
|
179
196
|
|
|
180
197
|
NetworkLogSnapshot modifiedSnapshot = null;
|
|
181
198
|
if (!url.isEmpty()) {
|
|
182
199
|
modifiedSnapshot = new NetworkLogSnapshot(url, requestHeadersMap, requestBody, responseHeadersMap, responseBody, responseCode);
|
|
200
|
+
} else {
|
|
201
|
+
Log.d(NET_TAG, "[updateNetworkLogSnapshot] Empty URL — snapshot will be null (request filtered/removed)");
|
|
183
202
|
}
|
|
184
203
|
|
|
185
204
|
final OnCompleteCallback<NetworkLogSnapshot> callback = callbackMap.get(callbackID);
|
|
186
205
|
if (callback != null) {
|
|
187
206
|
callback.onComplete(modifiedSnapshot);
|
|
188
207
|
callbackMap.remove(callbackID);
|
|
208
|
+
Log.d(NET_TAG, "[updateNetworkLogSnapshot] Callback invoked and removed for " + callbackID + ", remaining=" + callbackMap.size());
|
|
209
|
+
} else {
|
|
210
|
+
Log.e(NET_TAG, "[updateNetworkLogSnapshot] No callback found for callbackID=" + callbackID + " — possible leak or duplicate call, mapKeys=" + callbackMap.keySet());
|
|
189
211
|
}
|
|
190
212
|
} catch (Exception e) {
|
|
191
|
-
|
|
213
|
+
Log.e(NET_TAG, "[updateNetworkLogSnapshot] Exception processing snapshot: " + e.getMessage() + " for callbackID=" + callbackID, e);
|
|
192
214
|
Log.e("IB-CP-Bridge", "LuciqNetworkLogger.updateNetworkLogSnapshot failed to parse the network snapshot object.");
|
|
193
215
|
}
|
|
194
216
|
}
|
|
@@ -86,6 +86,7 @@ import javax.annotation.Nullable;
|
|
|
86
86
|
public class RNLuciqReactnativeModule extends EventEmitterModule {
|
|
87
87
|
|
|
88
88
|
private static final String TAG = "Luciq-RN-Core";
|
|
89
|
+
private static final String NET_TAG = "LCQ-RN-NET";
|
|
89
90
|
|
|
90
91
|
private LuciqCustomTextPlaceHolder placeHolders;
|
|
91
92
|
private static Report currentReport;
|
|
@@ -163,6 +164,7 @@ public class RNLuciqReactnativeModule extends EventEmitterModule {
|
|
|
163
164
|
|
|
164
165
|
|
|
165
166
|
) {
|
|
167
|
+
Log.d(NET_TAG, "[init] Called — logLevel=" + logLevel + ", useNativeNetworkInterception=" + useNativeNetworkInterception + ", codePushVersion=" + codePushVersion + ", appVariant=" + appVariant);
|
|
166
168
|
MainThreadHandler.runOnMainThread(new Runnable() {
|
|
167
169
|
@Override
|
|
168
170
|
public void run() {
|
|
@@ -204,6 +206,7 @@ public class RNLuciqReactnativeModule extends EventEmitterModule {
|
|
|
204
206
|
}
|
|
205
207
|
|
|
206
208
|
builder.build();
|
|
209
|
+
Log.d(NET_TAG, "[init] SDK build complete");
|
|
207
210
|
}
|
|
208
211
|
});
|
|
209
212
|
}
|
|
@@ -969,6 +972,7 @@ public class RNLuciqReactnativeModule extends EventEmitterModule {
|
|
|
969
972
|
final String requestHeaders,
|
|
970
973
|
final String responseHeaders,
|
|
971
974
|
final double duration) {
|
|
975
|
+
Log.d(NET_TAG, "[networkLogAndroid-Core] Received from JS: " + method + " " + url + ", status=" + (int) responseCode + ", duration=" + (long) duration + "ms, reqBodyLen=" + (requestBody != null ? requestBody.length() : 0) + ", resBodyLen=" + (responseBody != null ? responseBody.length() : 0));
|
|
972
976
|
try {
|
|
973
977
|
final String date = String.valueOf(System.currentTimeMillis());
|
|
974
978
|
|
|
@@ -985,11 +989,14 @@ public class RNLuciqReactnativeModule extends EventEmitterModule {
|
|
|
985
989
|
networkLog.setRequestHeaders(requestHeaders);
|
|
986
990
|
networkLog.setResponseHeaders(responseHeaders);
|
|
987
991
|
} catch (OutOfMemoryError | Exception exception) {
|
|
992
|
+
Log.e(NET_TAG, "[networkLogAndroid-Core] OOM/Error setting log contents: " + exception.getMessage() + " for " + method + " " + url);
|
|
988
993
|
Log.d(TAG, "Error: " + exception.getMessage() + "while trying to set network log contents (request body, response body, request headers, and response headers).");
|
|
989
994
|
}
|
|
990
995
|
|
|
991
996
|
networkLog.insert();
|
|
997
|
+
Log.d(NET_TAG, "[networkLogAndroid-Core] Successfully inserted NetworkLog: " + method + " " + url);
|
|
992
998
|
} catch (OutOfMemoryError | Exception exception) {
|
|
999
|
+
Log.e(NET_TAG, "[networkLogAndroid-Core] OOM/Error inserting network log: " + exception.getMessage() + " for " + method + " " + url);
|
|
993
1000
|
Log.d(TAG, "Error: " + exception.getMessage() + "while trying to insert a network log");
|
|
994
1001
|
}
|
|
995
1002
|
}
|
|
@@ -1170,7 +1177,7 @@ public class RNLuciqReactnativeModule extends EventEmitterModule {
|
|
|
1170
1177
|
*/
|
|
1171
1178
|
@ReactMethod
|
|
1172
1179
|
public void registerFeatureFlagsChangeListener() {
|
|
1173
|
-
|
|
1180
|
+
Log.d(NET_TAG, "[registerFeatureFlagsChangeListener] Registering native feature flags listener");
|
|
1174
1181
|
MainThreadHandler.runOnMainThread(new Runnable() {
|
|
1175
1182
|
@Override
|
|
1176
1183
|
public void run() {
|
|
@@ -1178,6 +1185,7 @@ public class RNLuciqReactnativeModule extends EventEmitterModule {
|
|
|
1178
1185
|
InternalCore.INSTANCE._setFeaturesStateListener(new FeaturesStateListener() {
|
|
1179
1186
|
@Override
|
|
1180
1187
|
public void invoke(@NonNull CoreFeaturesState featuresState) {
|
|
1188
|
+
Log.d(NET_TAG, "[FeatureFlagsListener] Received update — W3CTraceID=" + featuresState.isW3CExternalTraceIdEnabled() + ", generatedHeader=" + featuresState.isAttachingGeneratedHeaderEnabled() + ", caughtHeader=" + featuresState.isAttachingCapturedHeaderEnabled() + ", networkBodyLimit=" + featuresState.getNetworkLogCharLimit());
|
|
1181
1189
|
WritableMap params = Arguments.createMap();
|
|
1182
1190
|
params.putBoolean("isW3ExternalTraceIDEnabled", featuresState.isW3CExternalTraceIdEnabled());
|
|
1183
1191
|
params.putBoolean("isW3ExternalGeneratedHeaderEnabled", featuresState.isAttachingGeneratedHeaderEnabled());
|
|
@@ -1185,9 +1193,11 @@ public class RNLuciqReactnativeModule extends EventEmitterModule {
|
|
|
1185
1193
|
params.putInt("networkBodyLimit",featuresState.getNetworkLogCharLimit());
|
|
1186
1194
|
|
|
1187
1195
|
sendEvent(Constants.LCQ_ON_FEATURE_FLAGS_UPDATE_RECEIVED_CALLBACK, params);
|
|
1196
|
+
Log.d(NET_TAG, "[FeatureFlagsListener] Sent event to JS: " + Constants.LCQ_ON_FEATURE_FLAGS_UPDATE_RECEIVED_CALLBACK);
|
|
1188
1197
|
}
|
|
1189
1198
|
});
|
|
1190
1199
|
} catch (Exception e) {
|
|
1200
|
+
Log.e(NET_TAG, "[registerFeatureFlagsChangeListener] Failed to register listener", e);
|
|
1191
1201
|
e.printStackTrace();
|
|
1192
1202
|
}
|
|
1193
1203
|
|
|
@@ -1202,13 +1212,16 @@ public class RNLuciqReactnativeModule extends EventEmitterModule {
|
|
|
1202
1212
|
*/
|
|
1203
1213
|
@ReactMethod
|
|
1204
1214
|
public void isW3ExternalTraceIDEnabled(Promise promise) {
|
|
1205
|
-
|
|
1215
|
+
Log.d(NET_TAG, "[isW3ExternalTraceIDEnabled] Querying native flag");
|
|
1206
1216
|
MainThreadHandler.runOnMainThread(new Runnable() {
|
|
1207
1217
|
@Override
|
|
1208
1218
|
public void run() {
|
|
1209
1219
|
try {
|
|
1210
|
-
|
|
1220
|
+
boolean enabled = InternalCore.INSTANCE._isFeatureEnabled(CoreFeature.W3C_EXTERNAL_TRACE_ID);
|
|
1221
|
+
Log.d(NET_TAG, "[isW3ExternalTraceIDEnabled] Result=" + enabled);
|
|
1222
|
+
promise.resolve(enabled);
|
|
1211
1223
|
} catch (Exception e) {
|
|
1224
|
+
Log.e(NET_TAG, "[isW3ExternalTraceIDEnabled] Error querying flag", e);
|
|
1212
1225
|
e.printStackTrace();
|
|
1213
1226
|
promise.resolve(false);
|
|
1214
1227
|
}
|
|
@@ -1224,13 +1237,16 @@ public class RNLuciqReactnativeModule extends EventEmitterModule {
|
|
|
1224
1237
|
*/
|
|
1225
1238
|
@ReactMethod
|
|
1226
1239
|
public void isW3ExternalGeneratedHeaderEnabled(Promise promise) {
|
|
1227
|
-
|
|
1240
|
+
Log.d(NET_TAG, "[isW3ExternalGeneratedHeaderEnabled] Querying native flag");
|
|
1228
1241
|
MainThreadHandler.runOnMainThread(new Runnable() {
|
|
1229
1242
|
@Override
|
|
1230
1243
|
public void run() {
|
|
1231
1244
|
try {
|
|
1232
|
-
|
|
1245
|
+
boolean enabled = InternalCore.INSTANCE._isFeatureEnabled(CoreFeature.W3C_ATTACHING_GENERATED_HEADER);
|
|
1246
|
+
Log.d(NET_TAG, "[isW3ExternalGeneratedHeaderEnabled] Result=" + enabled);
|
|
1247
|
+
promise.resolve(enabled);
|
|
1233
1248
|
} catch (Exception e) {
|
|
1249
|
+
Log.e(NET_TAG, "[isW3ExternalGeneratedHeaderEnabled] Error querying flag", e);
|
|
1234
1250
|
e.printStackTrace();
|
|
1235
1251
|
promise.resolve(false);
|
|
1236
1252
|
}
|
|
@@ -1245,13 +1261,16 @@ public class RNLuciqReactnativeModule extends EventEmitterModule {
|
|
|
1245
1261
|
*/
|
|
1246
1262
|
@ReactMethod
|
|
1247
1263
|
public void isW3CaughtHeaderEnabled(Promise promise) {
|
|
1248
|
-
|
|
1264
|
+
Log.d(NET_TAG, "[isW3CaughtHeaderEnabled] Querying native flag");
|
|
1249
1265
|
MainThreadHandler.runOnMainThread(new Runnable() {
|
|
1250
1266
|
@Override
|
|
1251
1267
|
public void run() {
|
|
1252
1268
|
try {
|
|
1253
|
-
|
|
1269
|
+
boolean enabled = InternalCore.INSTANCE._isFeatureEnabled(CoreFeature.W3C_ATTACHING_CAPTURED_HEADER);
|
|
1270
|
+
Log.d(NET_TAG, "[isW3CaughtHeaderEnabled] Result=" + enabled);
|
|
1271
|
+
promise.resolve(enabled);
|
|
1254
1272
|
} catch (Exception e) {
|
|
1273
|
+
Log.e(NET_TAG, "[isW3CaughtHeaderEnabled] Error querying flag", e);
|
|
1255
1274
|
e.printStackTrace();
|
|
1256
1275
|
promise.resolve(false);
|
|
1257
1276
|
}
|
|
@@ -1345,13 +1364,16 @@ public class RNLuciqReactnativeModule extends EventEmitterModule {
|
|
|
1345
1364
|
*/
|
|
1346
1365
|
@ReactMethod
|
|
1347
1366
|
public void getNetworkBodyMaxSize(Promise promise) {
|
|
1348
|
-
|
|
1367
|
+
Log.d(NET_TAG, "[getNetworkBodyMaxSize] Querying network body size limit");
|
|
1349
1368
|
MainThreadHandler.runOnMainThread(new Runnable() {
|
|
1350
1369
|
@Override
|
|
1351
1370
|
public void run() {
|
|
1352
1371
|
try {
|
|
1353
|
-
|
|
1372
|
+
Object limit = InternalCore.INSTANCE.get_networkLogCharLimit();
|
|
1373
|
+
Log.d(NET_TAG, "[getNetworkBodyMaxSize] Result=" + limit);
|
|
1374
|
+
promise.resolve(limit);
|
|
1354
1375
|
} catch (Exception e) {
|
|
1376
|
+
Log.e(NET_TAG, "[getNetworkBodyMaxSize] Error querying limit", e);
|
|
1355
1377
|
e.printStackTrace();
|
|
1356
1378
|
promise.resolve(false);
|
|
1357
1379
|
}
|
|
@@ -1373,6 +1395,49 @@ public class RNLuciqReactnativeModule extends EventEmitterModule {
|
|
|
1373
1395
|
e.printStackTrace();
|
|
1374
1396
|
}
|
|
1375
1397
|
}
|
|
1398
|
+
|
|
1399
|
+
/**
|
|
1400
|
+
* Enables or disables WebView monitoring.
|
|
1401
|
+
*
|
|
1402
|
+
* @param isEnabled A boolean to enable/disable WebView monitoring.
|
|
1403
|
+
*/
|
|
1404
|
+
@ReactMethod
|
|
1405
|
+
public void setWebViewMonitoringEnabled(final boolean isEnabled) {
|
|
1406
|
+
try {
|
|
1407
|
+
Luciq.setWebViewMonitoringEnabled(isEnabled);
|
|
1408
|
+
} catch (Exception e) {
|
|
1409
|
+
e.printStackTrace();
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1413
|
+
/**
|
|
1414
|
+
* Enables or disables WebView network tracking.
|
|
1415
|
+
*
|
|
1416
|
+
* @param isEnabled A boolean to enable/disable WebView network tracking.
|
|
1417
|
+
*/
|
|
1418
|
+
@ReactMethod
|
|
1419
|
+
public void setWebViewNetworkTrackingEnabled(final boolean isEnabled) {
|
|
1420
|
+
try {
|
|
1421
|
+
Luciq.setWebViewNetworkTrackingEnabled(isEnabled);
|
|
1422
|
+
} catch (Exception e) {
|
|
1423
|
+
e.printStackTrace();
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
/**
|
|
1428
|
+
* Enables or disables WebView user interactions tracking.
|
|
1429
|
+
*
|
|
1430
|
+
* @param isEnabled A boolean to enable/disable WebView user interactions tracking.
|
|
1431
|
+
*/
|
|
1432
|
+
@ReactMethod
|
|
1433
|
+
public void setWebViewUserInteractionsTrackingEnabled(final boolean isEnabled) {
|
|
1434
|
+
try {
|
|
1435
|
+
Luciq.setWebViewUserInteractionsTrackingEnabled(isEnabled);
|
|
1436
|
+
} catch (Exception e) {
|
|
1437
|
+
e.printStackTrace();
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1376
1441
|
/**
|
|
1377
1442
|
* Sets the theme for Luciq using a configuration object.
|
|
1378
1443
|
*
|
|
@@ -20,6 +20,8 @@ public class RNLuciqReactnativePackage implements ReactPackage {
|
|
|
20
20
|
@NonNull
|
|
21
21
|
@Override
|
|
22
22
|
public List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactContext) {
|
|
23
|
+
RNLuciq.getInstance().setCurrentPlatform();
|
|
24
|
+
|
|
23
25
|
List<NativeModule> modules = new ArrayList<>();
|
|
24
26
|
modules.add(new RNLuciqReactnativeModule(reactContext));
|
|
25
27
|
modules.add(new RNLuciqBugReportingModule(reactContext));
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
package ai.luciq.reactlibrary.utils;
|
|
2
2
|
|
|
3
|
+
import android.util.Log;
|
|
4
|
+
|
|
3
5
|
import androidx.annotation.Nullable;
|
|
4
6
|
import androidx.annotation.VisibleForTesting;
|
|
5
7
|
|
|
@@ -10,6 +12,7 @@ import com.facebook.react.bridge.WritableMap;
|
|
|
10
12
|
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
|
11
13
|
|
|
12
14
|
public abstract class EventEmitterModule extends ReactContextBaseJavaModule {
|
|
15
|
+
private static final String NET_TAG = "LCQ-RN-NET";
|
|
13
16
|
private int listenerCount = 0;
|
|
14
17
|
|
|
15
18
|
public EventEmitterModule(ReactApplicationContext context) {
|
|
@@ -22,14 +25,18 @@ public abstract class EventEmitterModule extends ReactContextBaseJavaModule {
|
|
|
22
25
|
getReactApplicationContext()
|
|
23
26
|
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
|
|
24
27
|
.emit(event, params);
|
|
28
|
+
} else {
|
|
29
|
+
Log.w(NET_TAG, "[EventEmitter] Event DROPPED (no JS listeners): event=" + event + ", module=" + getName() + ", listenerCount=0");
|
|
25
30
|
}
|
|
26
31
|
}
|
|
27
32
|
|
|
28
33
|
protected void addListener(String ignoredEvent) {
|
|
29
34
|
listenerCount++;
|
|
35
|
+
Log.d(NET_TAG, "[EventEmitter] addListener — module=" + getName() + ", event=" + ignoredEvent + ", listenerCount=" + listenerCount);
|
|
30
36
|
}
|
|
31
37
|
|
|
32
38
|
protected void removeListeners(Integer count) {
|
|
33
39
|
listenerCount -= count;
|
|
40
|
+
Log.d(NET_TAG, "[EventEmitter] removeListeners — module=" + getName() + ", removed=" + count + ", listenerCount=" + listenerCount);
|
|
34
41
|
}
|
|
35
42
|
}
|
|
@@ -6,14 +6,7 @@ import com.facebook.react.bridge.ReadableArray;
|
|
|
6
6
|
import com.facebook.react.bridge.ReadableMap;
|
|
7
7
|
import com.facebook.react.bridge.ReadableMapKeySetIterator;
|
|
8
8
|
import com.facebook.react.bridge.ReadableType;
|
|
9
|
-
import com.facebook.react.bridge.WritableArray;
|
|
10
|
-
import com.facebook.react.bridge.WritableNativeArray;
|
|
11
9
|
import ai.luciq.library.model.Report;
|
|
12
|
-
import ai.luciq.library.model.a;
|
|
13
|
-
|
|
14
|
-
import org.json.JSONException;
|
|
15
|
-
|
|
16
|
-
import java.util.ArrayList;
|
|
17
10
|
|
|
18
11
|
|
|
19
12
|
/**
|
package/dist/modules/Luciq.d.ts
CHANGED
|
@@ -26,6 +26,21 @@ export declare const init: (config: LuciqConfig) => void;
|
|
|
26
26
|
* @param appVariant the current App variant name
|
|
27
27
|
*/
|
|
28
28
|
export declare const setAppVariant: (appVariant: string) => void;
|
|
29
|
+
/**
|
|
30
|
+
* Enables or disables WebView monitoring.
|
|
31
|
+
* @param isEnabled A boolean to enable/disable WebView monitoring.
|
|
32
|
+
*/
|
|
33
|
+
export declare const setWebViewMonitoringEnabled: (isEnabled: boolean) => void;
|
|
34
|
+
/**
|
|
35
|
+
* Enables or disables WebView network tracking.
|
|
36
|
+
* @param isEnabled A boolean to enable/disable WebView network tracking.
|
|
37
|
+
*/
|
|
38
|
+
export declare const setWebViewNetworkTrackingEnabled: (isEnabled: boolean) => void;
|
|
39
|
+
/**
|
|
40
|
+
* Enables or disables WebView user interactions tracking.
|
|
41
|
+
* @param isEnabled A boolean to enable/disable WebView user interactions tracking.
|
|
42
|
+
*/
|
|
43
|
+
export declare const setWebViewUserInteractionsTrackingEnabled: (isEnabled: boolean) => void;
|
|
29
44
|
/**
|
|
30
45
|
* Sets the Code Push version to be sent with each report.
|
|
31
46
|
* @param version the Code Push version.
|
package/dist/modules/Luciq.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { AppState, findNodeHandle, Platform } from 'react-native';
|
|
2
2
|
import Report from '../models/Report';
|
|
3
3
|
import { emitter, NativeEvents, NativeLuciq } from '../native/NativeLuciq';
|
|
4
|
-
import { registerFeatureFlagsListener } from '../utils/FeatureFlags';
|
|
4
|
+
import { registerFeatureFlagsListener, initFeatureFlagsCache } from '../utils/FeatureFlags';
|
|
5
5
|
import { LogLevel, NetworkInterceptionMode, ReproStepsMode, StringKey, } from '../utils/Enums';
|
|
6
6
|
import LuciqUtils, { checkNetworkRequestHandlers, resetNativeObfuscationListener, setApmNetworkFlagsIfChanged, stringifyIfNotString, } from '../utils/LuciqUtils';
|
|
7
7
|
import * as NetworkLogger from './NetworkLogger';
|
|
@@ -50,6 +50,7 @@ function reportCurrentViewForAndroid(screenName) {
|
|
|
50
50
|
* @param config SDK configurations. See {@link LuciqConfig} for more info.
|
|
51
51
|
*/
|
|
52
52
|
export const init = (config) => {
|
|
53
|
+
initFeatureFlagsCache();
|
|
53
54
|
if (Platform.OS === 'android') {
|
|
54
55
|
// Add android feature flags listener for android
|
|
55
56
|
registerFeatureFlagsListener();
|
|
@@ -90,6 +91,27 @@ export const init = (config) => {
|
|
|
90
91
|
export const setAppVariant = (appVariant) => {
|
|
91
92
|
NativeLuciq.setAppVariant(appVariant);
|
|
92
93
|
};
|
|
94
|
+
/**
|
|
95
|
+
* Enables or disables WebView monitoring.
|
|
96
|
+
* @param isEnabled A boolean to enable/disable WebView monitoring.
|
|
97
|
+
*/
|
|
98
|
+
export const setWebViewMonitoringEnabled = (isEnabled) => {
|
|
99
|
+
NativeLuciq.setWebViewMonitoringEnabled(isEnabled);
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* Enables or disables WebView network tracking.
|
|
103
|
+
* @param isEnabled A boolean to enable/disable WebView network tracking.
|
|
104
|
+
*/
|
|
105
|
+
export const setWebViewNetworkTrackingEnabled = (isEnabled) => {
|
|
106
|
+
NativeLuciq.setWebViewNetworkTrackingEnabled(isEnabled);
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* Enables or disables WebView user interactions tracking.
|
|
110
|
+
* @param isEnabled A boolean to enable/disable WebView user interactions tracking.
|
|
111
|
+
*/
|
|
112
|
+
export const setWebViewUserInteractionsTrackingEnabled = (isEnabled) => {
|
|
113
|
+
NativeLuciq.setWebViewUserInteractionsTrackingEnabled(isEnabled);
|
|
114
|
+
};
|
|
93
115
|
/**
|
|
94
116
|
* Handles app state changes and updates APM network flags if necessary.
|
|
95
117
|
*/
|
|
@@ -3,11 +3,6 @@ import { NetworkData, ProgressCallback } from '../utils/XhrNetworkInterceptor';
|
|
|
3
3
|
import { NetworkListenerType } from '../native/NativeNetworkLogger';
|
|
4
4
|
export type { NetworkData };
|
|
5
5
|
export type NetworkDataObfuscationHandler = (data: NetworkData) => Promise<NetworkData>;
|
|
6
|
-
/**
|
|
7
|
-
* Sets whether network logs should be sent with bug reports.
|
|
8
|
-
* It is enabled by default.
|
|
9
|
-
* @param isEnabled
|
|
10
|
-
*/
|
|
11
6
|
export declare const setEnabled: (isEnabled: boolean) => void;
|
|
12
7
|
/**
|
|
13
8
|
* @internal
|
|
@@ -20,21 +20,25 @@ function getPortFromUrl(url) {
|
|
|
20
20
|
* It is enabled by default.
|
|
21
21
|
* @param isEnabled
|
|
22
22
|
*/
|
|
23
|
+
const NET_TAG = 'LCQ-RN-NET:';
|
|
23
24
|
export const setEnabled = (isEnabled) => {
|
|
24
25
|
if (isEnabled) {
|
|
25
26
|
xhr.enableInterception();
|
|
26
27
|
xhr.setOnDoneCallback(async (network) => {
|
|
28
|
+
Logger.debug(NET_TAG, `[NetworkLogger] onDoneCallback received: ${network.method} ${network.url}, status=${network.responseCode}`);
|
|
27
29
|
// eslint-disable-next-line no-new-func
|
|
28
30
|
const predicate = Function('network', 'return ' + _requestFilterExpression);
|
|
29
31
|
if (!predicate(network)) {
|
|
30
32
|
const MAX_NETWORK_BODY_SIZE_IN_BYTES = await NativeLuciq.getNetworkBodyMaxSize();
|
|
31
33
|
try {
|
|
32
34
|
if (_networkDataObfuscationHandler) {
|
|
35
|
+
Logger.debug(NET_TAG, `[NetworkLogger] Running obfuscation handler for ${network.url}`);
|
|
33
36
|
network = await _networkDataObfuscationHandler(network);
|
|
34
37
|
}
|
|
35
38
|
if (__DEV__) {
|
|
36
39
|
const urlPort = getPortFromUrl(network.url);
|
|
37
40
|
if (urlPort === LuciqRNConfig.metroDevServerPort) {
|
|
41
|
+
Logger.debug(NET_TAG, `[NetworkLogger] Skipping Metro dev server request: ${network.url}`);
|
|
38
42
|
return;
|
|
39
43
|
}
|
|
40
44
|
}
|
|
@@ -54,12 +58,16 @@ export const setEnabled = (isEnabled) => {
|
|
|
54
58
|
network.responseBody = `Body is omitted because content type ${network.contentType} isn't supported`;
|
|
55
59
|
Logger.warn(`LCQ-RN: The response body for the network request with URL ${network.url} has been omitted because the content type ${network.contentType} isn't supported.`);
|
|
56
60
|
}
|
|
61
|
+
Logger.debug(NET_TAG, `[NetworkLogger] Reporting network log to native: ${network.method} ${network.url}`);
|
|
57
62
|
reportNetworkLog(network);
|
|
58
63
|
}
|
|
59
64
|
catch (e) {
|
|
60
|
-
Logger.error(e);
|
|
65
|
+
Logger.error(NET_TAG, `[NetworkLogger] Error processing network log for ${network.url}:`, e);
|
|
61
66
|
}
|
|
62
67
|
}
|
|
68
|
+
else {
|
|
69
|
+
Logger.debug(NET_TAG, `[NetworkLogger] Request filtered out by predicate: ${network.method} ${network.url}, expression="${_requestFilterExpression}"`);
|
|
70
|
+
}
|
|
63
71
|
});
|
|
64
72
|
}
|
|
65
73
|
else {
|
|
@@ -77,6 +77,9 @@ export interface LuciqNativeModule extends NativeModule {
|
|
|
77
77
|
getNetworkBodyMaxSize(): Promise<number>;
|
|
78
78
|
setTheme(theme: ThemeConfig): void;
|
|
79
79
|
setFullscreen(isEnabled: boolean): void;
|
|
80
|
+
setWebViewMonitoringEnabled(isEnabled: boolean): void;
|
|
81
|
+
setWebViewNetworkTrackingEnabled(isEnabled: boolean): void;
|
|
82
|
+
setWebViewUserInteractionsTrackingEnabled(isEnabled: boolean): void;
|
|
80
83
|
}
|
|
81
84
|
export declare const NativeLuciq: LuciqNativeModule;
|
|
82
85
|
export declare enum NativeEvents {
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
export declare function initFeatureFlagsCache(): Promise<void>;
|
|
2
|
+
export declare function getCachedW3cFlags(): {
|
|
3
|
+
isW3cExternalTraceIDEnabled: boolean;
|
|
4
|
+
isW3cExternalGeneratedHeaderEnabled: boolean;
|
|
5
|
+
isW3cCaughtHeaderEnabled: boolean;
|
|
6
|
+
};
|
|
1
7
|
export declare const FeatureFlags: {
|
|
2
8
|
isW3ExternalTraceID: () => Promise<boolean>;
|
|
3
9
|
isW3ExternalGeneratedHeader: () => Promise<boolean>;
|