@luciq/react-native 19.2.1 → 19.3.0-40271-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.
Files changed (52) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +87 -0
  3. package/RNLuciq.podspec +1 -1
  4. package/android/native.gradle +1 -1
  5. package/android/src/main/java/ai/luciq/reactlibrary/RNLuciqAPMModule.java +211 -117
  6. package/android/src/main/java/ai/luciq/reactlibrary/RNLuciqNetworkLoggerModule.java +29 -7
  7. package/android/src/main/java/ai/luciq/reactlibrary/RNLuciqReactnativeModule.java +51 -9
  8. package/android/src/main/java/ai/luciq/reactlibrary/utils/EventEmitterModule.java +7 -0
  9. package/dist/constants/Strings.d.ts +9 -0
  10. package/dist/constants/Strings.js +12 -0
  11. package/dist/index.d.ts +2 -1
  12. package/dist/index.js +2 -1
  13. package/dist/models/CustomSpan.d.ts +47 -0
  14. package/dist/models/CustomSpan.js +82 -0
  15. package/dist/modules/APM.d.ts +58 -0
  16. package/dist/modules/APM.js +62 -0
  17. package/dist/modules/Luciq.js +2 -1
  18. package/dist/modules/NetworkLogger.d.ts +0 -5
  19. package/dist/modules/NetworkLogger.js +9 -1
  20. package/dist/native/NativeAPM.d.ts +3 -0
  21. package/dist/native/NativeLuciq.d.ts +1 -0
  22. package/dist/utils/CustomSpansManager.d.ts +38 -0
  23. package/dist/utils/CustomSpansManager.js +173 -0
  24. package/dist/utils/FeatureFlags.d.ts +6 -0
  25. package/dist/utils/FeatureFlags.js +35 -0
  26. package/dist/utils/LuciqUtils.js +6 -0
  27. package/dist/utils/XhrNetworkInterceptor.js +85 -53
  28. package/ios/RNLuciq/LuciqAPMBridge.h +13 -0
  29. package/ios/RNLuciq/LuciqAPMBridge.m +55 -0
  30. package/ios/RNLuciq/LuciqReactBridge.m +12 -0
  31. package/ios/RNLuciq/Util/LCQAPM+PrivateAPIs.h +1 -0
  32. package/ios/native.rb +1 -1
  33. package/package.json +1 -2
  34. package/plugin/build/index.js +9 -2
  35. package/plugin/src/withLuciqIOS.ts +9 -2
  36. package/scripts/releases/changelog_to_slack_formatter.sh +9 -0
  37. package/scripts/releases/get_job_approver.sh +60 -0
  38. package/scripts/releases/get_release_notes.sh +22 -0
  39. package/scripts/releases/get_sdk_version.sh +5 -0
  40. package/scripts/releases/get_slack_id_from_username.sh +24 -0
  41. package/src/constants/Strings.ts +24 -0
  42. package/src/index.ts +2 -0
  43. package/src/models/CustomSpan.ts +102 -0
  44. package/src/modules/APM.ts +72 -0
  45. package/src/modules/Luciq.ts +3 -1
  46. package/src/modules/NetworkLogger.ts +26 -1
  47. package/src/native/NativeAPM.ts +7 -0
  48. package/src/native/NativeLuciq.ts +1 -0
  49. package/src/utils/CustomSpansManager.ts +202 -0
  50. package/src/utils/FeatureFlags.ts +44 -0
  51. package/src/utils/LuciqUtils.ts +15 -0
  52. package/src/utils/XhrNetworkInterceptor.ts +128 -55
package/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # Changelog
2
2
 
3
+ ## [19.3.0](https://github.com/luciqai/luciq-reactnative-sdk/compare/v19.3.0...19.2.1)
4
+
5
+ ### Added
6
+
7
+ - **Custom Spans**: New feature to manually instrument code paths for performance tracking
8
+ - `APM.startCustomSpan(name)` - Start a custom span and return a span object
9
+ - `CustomSpan.end()` - End the span and report to SDK
10
+ - `APM.addCompletedCustomSpan(name, startDate, endDate)` - Record a pre-completed span
11
+ - Support for up to 100 concurrent spans
12
+ - Comprehensive validation (name length, empty checks, timestamp validation)
13
+ - Feature flag support to enable/disable custom spans
14
+
15
+ ### Changed
16
+
17
+ - Bump Luciq iOS SDK to v19.5.0 ([#37](https://github.com/luciqai/luciq-reactnative-sdk/pull/37)). [See release notes](https://github.com/luciqai/Luciq-iOS-sdk/releases/tag/19.5.0).
18
+
19
+ - Bump Luciq Android SDK to v19.3.0 ([#37](https://github.com/luciqai/luciq-reactnative-sdk/pull/37)). [See release notes](https://github.com/luciqai/Luciq-Android-sdk/releases/tag/v19.4.0).
20
+
21
+ ## [19.2.2](https://github.com/luciqai/luciq-reactnative-sdk/compare/v19.2.2...19.2.1)
22
+
23
+ ### Changed
24
+
25
+ - Bump Luciq iOS SDK to v19.4.1 ([#34](https://github.com/luciqai/luciq-reactnative-sdk/pull/34)). [See release notes](https://github.com/luciqai/Luciq-iOS-sdk/releases/tag/19.4.1).
26
+
27
+ - Bump Luciq Android SDK to v19.2.2 ([#34](https://github.com/luciqai/luciq-reactnative-sdk/pull/34)). [See release notes](https://github.com/luciqai/Luciq-Android-sdk/releases/tag/v19.2.2).
28
+
3
29
  ## [19.2.1](https://github.com/luciqai/luciq-reactnative-sdk/compare/v19.2.1...19.1.0)
4
30
 
5
31
  ### Added
@@ -14,6 +40,10 @@
14
40
 
15
41
  - Bump Luciq Android SDK to v19.2.1 ([#29](https://github.com/luciqai/luciq-reactnative-sdk/pull/29)). [See release notes](https://github.com/luciqai/Luciq-Android-sdk/releases/tag/v19.2.1).
16
42
 
43
+ ### Fixed
44
+
45
+ - Running Expo Plugin on ios [#31](https://github.com/luciqai/luciq-reactnative-sdk/pull/31))
46
+
17
47
  ## [19.1.0](https://github.com/luciqai/luciq-reactnative-sdk/compare/v19.1.0...19.0.0)
18
48
 
19
49
  ### Added
package/README.md CHANGED
@@ -141,6 +141,93 @@ You can disable Repro Steps using the following API:
141
141
  Luciq.setReproStepsConfig({ all: ReproStepsMode.disabled });
142
142
  ```
143
143
 
144
+ ## Custom Spans
145
+
146
+ Custom spans allow you to manually instrument arbitrary code paths for performance tracking. This feature enables tracking of operations not covered by automatic instrumentation.
147
+
148
+ ### Starting and Ending a Span
149
+
150
+ ```javascript
151
+ import { APM } from '@luciq/react-native';
152
+
153
+ // Start a custom span
154
+ const span = await APM.startCustomSpan('Load User Profile');
155
+
156
+ if (span) {
157
+ try {
158
+ // Perform your operation
159
+ await loadUserProfile();
160
+ } finally {
161
+ // Always end the span, even if operation fails
162
+ await span.end();
163
+ }
164
+ }
165
+ ```
166
+
167
+ ### Recording a Completed Span
168
+
169
+ ```javascript
170
+ const start = new Date();
171
+ // ... operation already completed ...
172
+ const end = new Date();
173
+
174
+ await APM.addCompletedCustomSpan('Cache Lookup', start, end);
175
+ ```
176
+
177
+ ### Important Notes
178
+
179
+ - **Span Limit**: Maximum of 100 concurrent spans at any time
180
+ - **Name Length**: Span names are truncated to 150 characters
181
+ - **Validation**: Empty names or invalid timestamps will be rejected
182
+ - **Idempotent**: Calling `span.end()` multiple times is safe
183
+ - **Feature Flags**: Spans are only created when SDK is initialized, APM is enabled, and custom spans feature is enabled
184
+
185
+ ### API Reference
186
+
187
+ #### `APM.startCustomSpan(name: string): Promise<CustomSpan | null>`
188
+
189
+ Starts a custom span for performance tracking.
190
+
191
+ **Parameters:**
192
+
193
+ - `name` (string): The name of the span. Cannot be empty. Max 150 characters.
194
+
195
+ **Returns:**
196
+
197
+ - `Promise<CustomSpan | null>`: The span object to end later, or `null` if the span could not be created.
198
+
199
+ **Example:**
200
+
201
+ ```javascript
202
+ const span = await APM.startCustomSpan('Database Query');
203
+ if (span) {
204
+ // ... perform operation ...
205
+ await span.end();
206
+ }
207
+ ```
208
+
209
+ #### `CustomSpan.end(): Promise<void>`
210
+
211
+ Ends the custom span and reports it to the SDK. This method is idempotent.
212
+
213
+ #### `APM.addCompletedCustomSpan(name: string, startDate: Date, endDate: Date): Promise<void>`
214
+
215
+ Records a completed custom span with pre-recorded timestamps.
216
+
217
+ **Parameters:**
218
+
219
+ - `name` (string): The name of the span. Cannot be empty. Max 150 characters.
220
+ - `startDate` (Date): The start time of the operation.
221
+ - `endDate` (Date): The end time of the operation (must be after startDate).
222
+
223
+ **Example:**
224
+
225
+ ```javascript
226
+ const start = new Date(Date.now() - 1500);
227
+ const end = new Date();
228
+ await APM.addCompletedCustomSpan('Background Task', start, end);
229
+ ```
230
+
144
231
  ## Documentation
145
232
 
146
233
  For more details about the supported APIs and how to use them, check our [**Documentation**](https://docs.luciq.ai/docs/react-native-overview).
package/RNLuciq.podspec CHANGED
@@ -12,7 +12,7 @@ Pod::Spec.new do |s|
12
12
  s.homepage = package["homepage"]
13
13
  s.source = { :git => "https://github.com/Instabug/Instabug-React-Native.git", :tag => 'v' + package["version"] }
14
14
 
15
- s.platform = :ios, "13.0"
15
+ s.platform = :ios, "15.0"
16
16
  s.source_files = "ios/**/*.{h,m,mm}"
17
17
 
18
18
  s.dependency 'React-Core'
@@ -1,5 +1,5 @@
1
1
  project.ext.luciq = [
2
- version: '19.2.1'
2
+ version: '19.3.0'
3
3
  ]
4
4
 
5
5
  dependencies {
@@ -13,21 +13,25 @@ import com.facebook.react.bridge.Promise;
13
13
  import com.facebook.react.bridge.ReactApplicationContext;
14
14
  import com.facebook.react.bridge.ReactMethod;
15
15
  import com.facebook.react.bridge.ReadableMap;
16
- import ai.luciq.apm.APM;
17
- import ai.luciq.apm.networking.APMNetworkLogger;
18
- import ai.luciq.apm.networkinterception.cp.APMCPNetworkLog;
19
- import ai.luciq.reactlibrary.utils.EventEmitterModule;
20
- import ai.luciq.reactlibrary.utils.MainThreadHandler;
21
16
 
22
17
  import java.lang.reflect.Method;
23
- import java.util.HashMap;
18
+ import java.util.Date;
24
19
 
25
20
  import javax.annotation.Nonnull;
26
21
 
27
- import static ai.luciq.reactlibrary.utils.LuciqUtil.getMethod;
22
+ import ai.luciq.apm.APM;
23
+ import ai.luciq.apm.InternalAPM;
24
+ import ai.luciq.apm.configuration.cp.APMFeature;
25
+ import ai.luciq.apm.configuration.cp.FeatureAvailabilityCallback;
26
+ import ai.luciq.apm.networking.APMNetworkLogger;
27
+ import ai.luciq.apm.networkinterception.cp.APMCPNetworkLog;
28
+ import ai.luciq.reactlibrary.utils.EventEmitterModule;
29
+ import ai.luciq.reactlibrary.utils.MainThreadHandler;
28
30
 
29
31
  public class RNLuciqAPMModule extends EventEmitterModule {
30
32
 
33
+ private static final String NET_TAG = "LCQ-RN-NET";
34
+
31
35
  public RNLuciqAPMModule(ReactApplicationContext reactApplicationContext) {
32
36
  super(reactApplicationContext);
33
37
  }
@@ -240,73 +244,73 @@ public class RNLuciqAPMModule extends EventEmitterModule {
240
244
  });
241
245
  }
242
246
 
243
- /**
244
- * The `networkLogAndroid` function logs network-related information using APMNetworkLogger in a React
245
- * Native module.
246
- *
247
- * @param requestStartTime The `requestStartTime` parameter in the `networkLogAndroid` method
248
- * represents the timestamp when the network request started. It is of type `double` and is passed as
249
- * a parameter to log network-related information.
250
- * @param requestDuration The `requestDuration` parameter in the `networkLogAndroid` method represents
251
- * the duration of the network request in milliseconds. It indicates the time taken for the request to
252
- * complete from the moment it was initiated until the response was received. This parameter helps in
253
- * measuring the performance of network requests and identifying any potential
254
- * @param requestHeaders requestHeaders is a string parameter that contains the headers of the network
255
- * request. It typically includes information such as the content type, authorization token, and any
256
- * other headers that were sent with the request.
257
- * @param requestBody The `requestBody` parameter in the `networkLogAndroid` method represents the
258
- * body of the HTTP request being logged. It contains the data that is sent as part of the request to
259
- * the server. This could include form data, JSON payload, XML data, or any other content that is
260
- * being transmitted
261
- * @param requestBodySize The `requestBodySize` parameter in the `networkLogAndroid` method represents
262
- * the size of the request body in bytes. It is a double value that indicates the size of the request
263
- * body being sent in the network request. This parameter is used to log information related to the
264
- * network request, including details
265
- * @param requestMethod The `requestMethod` parameter in the `networkLogAndroid` method represents the
266
- * HTTP method used in the network request, such as GET, POST, PUT, DELETE, etc. It indicates the type
267
- * of operation that the client is requesting from the server.
268
- * @param requestUrl The `requestUrl` parameter in the `networkLogAndroid` method represents the URL
269
- * of the network request being logged. It typically contains the address of the server to which the
270
- * request is being made, along with any additional path or query parameters required for the request.
271
- * This URL is essential for identifying the
272
- * @param requestContentType The `requestContentType` parameter in the `networkLogAndroid` method
273
- * represents the content type of the request being made. This could be values like
274
- * "application/json", "application/xml", "text/plain", etc., indicating the format of the data being
275
- * sent in the request body. It helps in specifying
276
- * @param responseHeaders The `responseHeaders` parameter in the `networkLogAndroid` method represents
277
- * the headers of the response received from a network request. These headers typically include
278
- * information such as content type, content length, server information, and any other metadata
279
- * related to the response. The `responseHeaders` parameter is expected to
280
- * @param responseBody The `responseBody` parameter in the `networkLogAndroid` method represents the
281
- * body of the response received from a network request. It contains the data or content sent back by
282
- * the server in response to the request made by the client. This could be in various formats such as
283
- * JSON, XML, HTML
284
- * @param responseBodySize The `responseBodySize` parameter in the `networkLogAndroid` method
285
- * represents the size of the response body in bytes. It is a double value that indicates the size of
286
- * the response body received from the network request. This parameter is used to log information
287
- * related to the network request and response, including
288
- * @param statusCode The `statusCode` parameter in the `networkLogAndroid` method represents the HTTP
289
- * status code of the network request/response. It indicates the status of the HTTP response, such as
290
- * success (200), redirection (3xx), client errors (4xx), or server errors (5xx). This parameter is
291
- * @param responseContentType The `responseContentType` parameter in the `networkLogAndroid` method
292
- * represents the content type of the response received from the network request. It indicates the
293
- * format of the data in the response, such as JSON, XML, HTML, etc. This information is useful for
294
- * understanding how to parse and handle the
295
- * @param errorDomain The `errorDomain` parameter in the `networkLogAndroid` method is used to specify
296
- * the domain of an error, if any occurred during the network request. If there was no error, this
297
- * parameter will be `null`.
298
- * @param w3cAttributes The `w3cAttributes` parameter in the `networkLogAndroid` method is a
299
- * ReadableMap object that contains additional attributes related to W3C external trace. It may
300
- * include the following key-value pairs:
301
- * @param gqLCQueryName The `gqLCQueryName` parameter in the `networkLogAndroid` method represents the
302
- * name of the GraphQL query being executed. It is a nullable parameter, meaning it can be null if no
303
- * GraphQL query name is provided. This parameter is used to log information related to GraphQL
304
- * queries in the network logging
305
- * @param serverErrorMessage The `serverErrorMessage` parameter in the `networkLogAndroid` method is
306
- * used to pass any error message received from the server during network communication. This message
307
- * can provide additional details about any errors that occurred on the server side, helping in
308
- * debugging and troubleshooting network-related issues.
309
- */
247
+ /**
248
+ * The `networkLogAndroid` function logs network-related information using APMNetworkLogger in a React
249
+ * Native module.
250
+ *
251
+ * @param requestStartTime The `requestStartTime` parameter in the `networkLogAndroid` method
252
+ * represents the timestamp when the network request started. It is of type `double` and is passed as
253
+ * a parameter to log network-related information.
254
+ * @param requestDuration The `requestDuration` parameter in the `networkLogAndroid` method represents
255
+ * the duration of the network request in milliseconds. It indicates the time taken for the request to
256
+ * complete from the moment it was initiated until the response was received. This parameter helps in
257
+ * measuring the performance of network requests and identifying any potential
258
+ * @param requestHeaders requestHeaders is a string parameter that contains the headers of the network
259
+ * request. It typically includes information such as the content type, authorization token, and any
260
+ * other headers that were sent with the request.
261
+ * @param requestBody The `requestBody` parameter in the `networkLogAndroid` method represents the
262
+ * body of the HTTP request being logged. It contains the data that is sent as part of the request to
263
+ * the server. This could include form data, JSON payload, XML data, or any other content that is
264
+ * being transmitted
265
+ * @param requestBodySize The `requestBodySize` parameter in the `networkLogAndroid` method represents
266
+ * the size of the request body in bytes. It is a double value that indicates the size of the request
267
+ * body being sent in the network request. This parameter is used to log information related to the
268
+ * network request, including details
269
+ * @param requestMethod The `requestMethod` parameter in the `networkLogAndroid` method represents the
270
+ * HTTP method used in the network request, such as GET, POST, PUT, DELETE, etc. It indicates the type
271
+ * of operation that the client is requesting from the server.
272
+ * @param requestUrl The `requestUrl` parameter in the `networkLogAndroid` method represents the URL
273
+ * of the network request being logged. It typically contains the address of the server to which the
274
+ * request is being made, along with any additional path or query parameters required for the request.
275
+ * This URL is essential for identifying the
276
+ * @param requestContentType The `requestContentType` parameter in the `networkLogAndroid` method
277
+ * represents the content type of the request being made. This could be values like
278
+ * "application/json", "application/xml", "text/plain", etc., indicating the format of the data being
279
+ * sent in the request body. It helps in specifying
280
+ * @param responseHeaders The `responseHeaders` parameter in the `networkLogAndroid` method represents
281
+ * the headers of the response received from a network request. These headers typically include
282
+ * information such as content type, content length, server information, and any other metadata
283
+ * related to the response. The `responseHeaders` parameter is expected to
284
+ * @param responseBody The `responseBody` parameter in the `networkLogAndroid` method represents the
285
+ * body of the response received from a network request. It contains the data or content sent back by
286
+ * the server in response to the request made by the client. This could be in various formats such as
287
+ * JSON, XML, HTML
288
+ * @param responseBodySize The `responseBodySize` parameter in the `networkLogAndroid` method
289
+ * represents the size of the response body in bytes. It is a double value that indicates the size of
290
+ * the response body received from the network request. This parameter is used to log information
291
+ * related to the network request and response, including
292
+ * @param statusCode The `statusCode` parameter in the `networkLogAndroid` method represents the HTTP
293
+ * status code of the network request/response. It indicates the status of the HTTP response, such as
294
+ * success (200), redirection (3xx), client errors (4xx), or server errors (5xx). This parameter is
295
+ * @param responseContentType The `responseContentType` parameter in the `networkLogAndroid` method
296
+ * represents the content type of the response received from the network request. It indicates the
297
+ * format of the data in the response, such as JSON, XML, HTML, etc. This information is useful for
298
+ * understanding how to parse and handle the
299
+ * @param errorDomain The `errorDomain` parameter in the `networkLogAndroid` method is used to specify
300
+ * the domain of an error, if any occurred during the network request. If there was no error, this
301
+ * parameter will be `null`.
302
+ * @param w3cAttributes The `w3cAttributes` parameter in the `networkLogAndroid` method is a
303
+ * ReadableMap object that contains additional attributes related to W3C external trace. It may
304
+ * include the following key-value pairs:
305
+ * @param gqLCQueryName The `gqLCQueryName` parameter in the `networkLogAndroid` method represents the
306
+ * name of the GraphQL query being executed. It is a nullable parameter, meaning it can be null if no
307
+ * GraphQL query name is provided. This parameter is used to log information related to GraphQL
308
+ * queries in the network logging
309
+ * @param serverErrorMessage The `serverErrorMessage` parameter in the `networkLogAndroid` method is
310
+ * used to pass any error message received from the server during network communication. This message
311
+ * can provide additional details about any errors that occurred on the server side, helping in
312
+ * debugging and troubleshooting network-related issues.
313
+ */
310
314
  @ReactMethod
311
315
  private void networkLogAndroid(final double requestStartTime,
312
316
  final double requestDuration,
@@ -325,15 +329,16 @@ public class RNLuciqAPMModule extends EventEmitterModule {
325
329
  @Nullable final ReadableMap w3cAttributes,
326
330
  @Nullable final String gqLCQueryName,
327
331
  @Nullable final String serverErrorMessage
328
- ) {
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);
329
334
  try {
330
335
  APMNetworkLogger networkLogger = new APMNetworkLogger();
331
336
 
332
337
  final boolean hasError = errorDomain != null && !errorDomain.isEmpty();
333
338
  final String errorMessage = hasError ? errorDomain : null;
334
- Boolean isW3cHeaderFound=false;
335
- Long partialId=null;
336
- Long networkStartTimeInSeconds=null;
339
+ Boolean isW3cHeaderFound = false;
340
+ Long partialId = null;
341
+ Long networkStartTimeInSeconds = null;
337
342
 
338
343
 
339
344
  try {
@@ -342,13 +347,15 @@ public class RNLuciqAPMModule extends EventEmitterModule {
342
347
  }
343
348
 
344
349
  if (!w3cAttributes.isNull("partialId")) {
345
- partialId =(long) w3cAttributes.getDouble("partialId");
350
+ partialId = (long) w3cAttributes.getDouble("partialId");
346
351
  networkStartTimeInSeconds = (long) w3cAttributes.getDouble("networkStartTimeInSeconds");
347
352
  }
348
353
 
349
354
  } catch (Exception e) {
355
+ Log.e(NET_TAG, "[networkLogAndroid-APM] Error parsing W3C attributes for " + requestMethod + " " + requestUrl, e);
350
356
  e.printStackTrace();
351
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"));
352
359
  APMCPNetworkLog.W3CExternalTraceAttributes w3cExternalTraceAttributes =
353
360
  new APMCPNetworkLog.W3CExternalTraceAttributes(
354
361
  isW3cHeaderFound,
@@ -360,52 +367,139 @@ public class RNLuciqAPMModule extends EventEmitterModule {
360
367
  try {
361
368
  Method method = getMethod(Class.forName("ai.luciq.apm.networking.APMNetworkLogger"), "log", long.class, long.class, String.class, String.class, long.class, String.class, String.class, String.class, String.class, String.class, long.class, int.class, String.class, String.class, String.class, String.class, APMCPNetworkLog.W3CExternalTraceAttributes.class);
362
369
  if (method != null) {
363
- method.invoke(
364
- networkLogger,
365
- (long) requestStartTime * 1000,
366
- (long) requestDuration,
367
- requestHeaders,
368
- requestBody,
369
- (long) requestBodySize,
370
- requestMethod,
371
- requestUrl,
372
- requestContentType,
373
- responseHeaders,
374
- responseBody,
375
- (long)responseBodySize,
376
- (int) statusCode,
377
- responseContentType,
378
- errorMessage,
379
- gqLCQueryName,
380
- serverErrorMessage,
381
- w3cExternalTraceAttributes
382
- );
370
+ method.invoke(
371
+ networkLogger,
372
+ (long) requestStartTime * 1000,
373
+ (long) requestDuration,
374
+ requestHeaders,
375
+ requestBody,
376
+ (long) requestBodySize,
377
+ requestMethod,
378
+ requestUrl,
379
+ requestContentType,
380
+ responseHeaders,
381
+ responseBody,
382
+ (long) responseBodySize,
383
+ (int) statusCode,
384
+ responseContentType,
385
+ errorMessage,
386
+ gqLCQueryName,
387
+ serverErrorMessage,
388
+ w3cExternalTraceAttributes
389
+ );
390
+ Log.d(NET_TAG, "[networkLogAndroid-APM] Successfully invoked APMNetworkLogger.log via reflection: " + requestMethod + " " + requestUrl);
383
391
  } else {
392
+ Log.e(NET_TAG, "[networkLogAndroid-APM] APMNetworkLogger.log method NOT found by reflection — network log will be lost: " + requestMethod + " " + requestUrl);
384
393
  Log.e("IB-CP-Bridge", "APMNetworkLogger.log was not found by reflection");
385
394
  }
386
395
  } catch (Throwable e) {
396
+ Log.e(NET_TAG, "[networkLogAndroid-APM] Exception invoking APMNetworkLogger.log: " + e.getMessage() + " for " + requestMethod + " " + requestUrl, e);
387
397
  e.printStackTrace();
388
398
  }
389
- } catch(Throwable e) {
399
+ } catch (Throwable e) {
400
+ Log.e(NET_TAG, "[networkLogAndroid-APM] Top-level exception: " + e.getMessage() + " for " + requestMethod + " " + requestUrl, e);
390
401
  e.printStackTrace();
391
402
  }
392
403
  }
393
- /**
394
- * Enables or disables screen rendering
395
- *
396
- * @param isEnabled boolean indicating enabled or disabled.
397
- */
398
- @ReactMethod
399
- public void setScreenRenderingEnabled(boolean isEnabled) {
400
- MainThreadHandler.runOnMainThread(new Runnable() {
401
- @Override
402
- public void run() {
403
- try {
404
- APM.setScreenRenderingEnabled(isEnabled);
405
- } catch (Exception e) {
406
- e.printStackTrace();
407
- }
404
+
405
+ /**
406
+ * Enables or disables screen rendering
407
+ *
408
+ * @param isEnabled boolean indicating enabled or disabled.
409
+ */
410
+ @ReactMethod
411
+ public void setScreenRenderingEnabled(boolean isEnabled) {
412
+ MainThreadHandler.runOnMainThread(new Runnable() {
413
+ @Override
414
+ public void run() {
415
+ try {
416
+ APM.setScreenRenderingEnabled(isEnabled);
417
+ } catch (Exception e) {
418
+ e.printStackTrace();
408
419
  }
409
- });
410
- }
420
+ }
421
+ });
422
+ }
423
+
424
+ /**
425
+ * Syncs a custom span to the native SDK (currently logs only).
426
+ *
427
+ * @param name Name of the custom span
428
+ * @param startTimestamp Start time in microseconds since epoch
429
+ * @param endTimestamp End time in microseconds since epoch
430
+ * @param promise Promise to resolve when complete
431
+ */
432
+ @ReactMethod
433
+ public void syncCustomSpan(final String name,
434
+ final double startTimestamp,
435
+ final double endTimestamp,
436
+ final Promise promise) {
437
+ MainThreadHandler.runOnMainThread(new Runnable() {
438
+ @Override
439
+ public void run() {
440
+ try {
441
+ // Convert microseconds to milliseconds for Date objects
442
+ Date startDate = new Date((long) (startTimestamp / 1000));
443
+ Date endDate = new Date((long) (endTimestamp / 1000));
444
+
445
+ APM.addCompletedCustomSpan(name, startDate, endDate);
446
+
447
+ promise.resolve(true);
448
+ } catch (Exception e) {
449
+ Log.e("IB-CP-Bridge", "Error syncing span", e);
450
+ promise.resolve(false);
451
+ }
452
+ }
453
+ });
454
+ }
455
+
456
+ /**
457
+ * Checks if custom spans feature is enabled.
458
+ *
459
+ * @param promise Promise that resolves with boolean indicating if enabled
460
+ */
461
+ @ReactMethod
462
+ public void isCustomSpanEnabled(final Promise promise) {
463
+ MainThreadHandler.runOnMainThread(new Runnable() {
464
+ @Override
465
+ public void run() {
466
+ try {
467
+ InternalAPM._isFeatureEnabledCP(APMFeature.CUSTOM_SPANS, "LuciqCustomSpan", new FeatureAvailabilityCallback() {
468
+ @Override
469
+ public void invoke(boolean isEnabled) {
470
+ promise.resolve(isEnabled);
471
+ }
472
+ });
473
+ } catch (Exception e) {
474
+ Log.e("IB-CP-Bridge", "Error checking feature flag", e);
475
+ promise.resolve(false);
476
+ }
477
+ }
478
+ });
479
+ }
480
+
481
+ /**
482
+ * Checks if APM is enabled.
483
+ *
484
+ * @param promise Promise that resolves with boolean indicating if enabled
485
+ */
486
+ @ReactMethod
487
+ public void isAPMEnabled(final Promise promise) {
488
+ MainThreadHandler.runOnMainThread(new Runnable() {
489
+ @Override
490
+ public void run() {
491
+ try {
492
+ InternalAPM._isFeatureEnabledCP(APMFeature.APM, "APM", new FeatureAvailabilityCallback() {
493
+ @Override
494
+ public void invoke(boolean isEnabled) {
495
+ promise.resolve(isEnabled);
496
+ }
497
+ });
498
+ } catch (Exception e) {
499
+ Log.e("IB-CP-Bridge", "Error checking APM enabled", e);
500
+ promise.resolve(false);
501
+ }
502
+ }
503
+ });
504
+ }
411
505
  }