@dynatrace/react-native-plugin 2.305.1 → 2.309.1

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 (130) hide show
  1. package/README.md +21 -10
  2. package/android/build.gradle +3 -1
  3. package/android/src/main/java/com/dynatrace/android/agent/DynatraceAppStartModule.kt +128 -0
  4. package/android/src/main/java/com/dynatrace/android/agent/DynatraceInternalModule.kt +22 -0
  5. package/android/src/main/java/com/dynatrace/android/agent/DynatraceRNBridgeImpl.kt +411 -0
  6. package/android/src/main/java/com/dynatrace/android/agent/DynatraceReactPackage.kt +54 -0
  7. package/android/src/main/java/com/dynatrace/android/agent/DynatraceUtils.kt +86 -0
  8. package/android/src/main/java/com/dynatrace/android/agent/model/AppStartMeasurement.kt +15 -0
  9. package/android/src/main/java/com/dynatrace/android/agent/model/AppStartMeasurementType.kt +18 -0
  10. package/android/src/new/java/com/dynatrace/android/agent/DynatraceRNBridge.kt +228 -0
  11. package/android/src/old/java/com/dynatrace/android/agent/DynatraceRNBridge.kt +258 -0
  12. package/files/plugin.gradle +1 -1
  13. package/index.js +10 -10
  14. package/instrumentation/DynatraceInstrumentation.js +1 -0
  15. package/{lib → instrumentation/jsx}/CreateElement.js +6 -5
  16. package/{lib/instrumentor/base → instrumentation/jsx}/ElementHelper.js +14 -12
  17. package/{lib/jsx-dev-runtime.js → instrumentation/jsx/JsxDevRuntime.js} +10 -19
  18. package/instrumentation/jsx/JsxRuntime.js +63 -0
  19. package/instrumentation/jsx/JsxRuntimeUtil.js +31 -0
  20. package/instrumentation/jsx/components/ClassComponent.js +49 -0
  21. package/instrumentation/jsx/components/ComponentUtil.js +33 -0
  22. package/instrumentation/jsx/components/FunctionalComponent.js +20 -0
  23. package/{lib/instrumentor/base → instrumentation/jsx/components}/Picker.js +1 -1
  24. package/{lib/instrumentor/base → instrumentation/jsx/components}/RefreshControl.js +1 -1
  25. package/{lib/instrumentor/base → instrumentation/jsx/components}/Switch.js +1 -1
  26. package/{lib/instrumentor/base → instrumentation/jsx/components}/Touchable.js +5 -5
  27. package/instrumentation/libs/community/Picker.InstrInfo.js +20 -0
  28. package/{lib → instrumentation/libs}/community/Picker.js +1 -1
  29. package/instrumentation/libs/community/gesture-handler/Touchables.InstrInfo.js +23 -0
  30. package/{lib → instrumentation/libs}/community/gesture-handler/Touchables.js +1 -1
  31. package/{lib → instrumentation/libs}/react-native/RefreshControl.InstrInfo.js +2 -2
  32. package/{lib → instrumentation/libs}/react-native/RefreshControl.js +5 -5
  33. package/{lib → instrumentation/libs}/react-native/Switch.InstrInfo.js +2 -2
  34. package/{lib → instrumentation/libs}/react-native/Switch.js +5 -5
  35. package/instrumentation/libs/react-native/Touchables.InstrInfo.js +25 -0
  36. package/{lib → instrumentation/libs}/react-native/Touchables.js +1 -1
  37. package/{lib → instrumentation/libs}/react-navigation/ReactNavigation.js +6 -5
  38. package/{lib/instrumentor → instrumentation}/model/Types.js +1 -14
  39. package/instrumentation/model/TypesUtil.js +17 -0
  40. package/ios/DynatraceRNBridge.h +10 -1
  41. package/ios/DynatraceRNBridge.mm +152 -0
  42. package/jsx-dev-runtime.js +1 -1
  43. package/jsx-runtime.js +1 -1
  44. package/lib/core/Application.js +20 -0
  45. package/lib/{instrumentor/base → core}/Dynatrace.js +57 -48
  46. package/lib/{instrumentor/base → core}/DynatraceAction.js +23 -22
  47. package/lib/core/DynatraceInternal.js +46 -0
  48. package/lib/{instrumentor/base → core}/DynatraceRootAction.js +5 -4
  49. package/lib/{instrumentor/base → core}/DynatraceWebRequestTiming.js +6 -5
  50. package/lib/{instrumentor/base → core}/ErrorHandler.js +6 -5
  51. package/lib/{instrumentor/base → core}/configuration/Configuration.js +1 -1
  52. package/lib/{instrumentor/base → core}/configuration/ConfigurationDefaults.js +1 -2
  53. package/lib/{instrumentor/base → core}/configuration/ConfigurationHandler.js +2 -2
  54. package/lib/{instrumentor/base → core}/configuration/ManualStartupConfiguration.js +1 -1
  55. package/lib/core/logging/ConsoleLogger.js +27 -0
  56. package/lib/core/logging/LogLevel.js +12 -0
  57. package/lib/dynatrace-transformer.js +1 -1
  58. package/lib/next/Dynatrace.js +86 -0
  59. package/lib/next/DynatraceSecondGenForwarder.js +17 -0
  60. package/lib/next/IDynatrace.js +2 -0
  61. package/lib/next/IDynatraceForwarder.js +2 -0
  62. package/lib/next/appstart/AppStartObserver.js +32 -0
  63. package/lib/next/appstart/AppStartType.js +38 -0
  64. package/lib/next/events/EventCreator.js +77 -0
  65. package/lib/next/events/EventPipeline.js +57 -0
  66. package/lib/next/events/EventTimestamp.js +24 -0
  67. package/lib/next/events/ViewInfoCreator.js +27 -0
  68. package/lib/next/events/modifier/BaseDataEventModifier.js +31 -0
  69. package/lib/next/events/modifier/EventLimitation.js +69 -0
  70. package/lib/next/events/modifier/EventModifierUtil.js +88 -0
  71. package/lib/next/events/modifier/IEventModifier.js +2 -0
  72. package/lib/next/events/modifier/ModifyEventValidation.js +187 -0
  73. package/lib/next/events/modifier/NonFiniteNumbersModifier.js +50 -0
  74. package/lib/next/events/modifier/SendEventValidation.js +84 -0
  75. package/lib/next/events/spec/EventFieldKeysEnum.js +2 -0
  76. package/lib/next/events/spec/EventSpecContstants.js +46 -0
  77. package/lib/next/events/spec/IAppStartEvent.js +2 -0
  78. package/lib/next/events/spec/ICrashEvent.js +2 -0
  79. package/lib/next/events/spec/IErrorCodeEvent.js +2 -0
  80. package/lib/next/events/spec/IErrorExceptionEvent.js +2 -0
  81. package/lib/next/events/spec/IReactNativeEvent.js +2 -0
  82. package/lib/next/events/spec/IRumEvent.js +2 -0
  83. package/lib/next/provider/ITimestampProvider.js +2 -0
  84. package/lib/next/provider/TimestampProvider.js +10 -0
  85. package/package.json +51 -40
  86. package/react-native-dynatrace.podspec +1 -1
  87. package/src/lib/{instrumentor/base → core}/interface/NativeDynatraceBridge.ts +10 -0
  88. package/typings/react-native-dynatrace.d.ts +0 -1
  89. package/android/src/main/java/com/dynatrace/android/agent/DynatraceRNBridgeImpl.java +0 -362
  90. package/android/src/main/java/com/dynatrace/android/agent/DynatraceReactPackage.java +0 -67
  91. package/android/src/main/java/com/dynatrace/android/agent/DynatraceUtils.java +0 -76
  92. package/android/src/main/java/com/dynatrace/android/agent/PrivateDTBridge.java +0 -28
  93. package/android/src/new/java/com/dynatrace/android/agent/DynatraceRNBridge.java +0 -187
  94. package/android/src/old/java/com/dynatrace/android/agent/DynatraceRNBridge.java +0 -189
  95. package/lib/community/Picker.InstrInfo.js +0 -20
  96. package/lib/community/gesture-handler/Touchables.InstrInfo.js +0 -56
  97. package/lib/instrumentor/DynatraceInstrumentation.js +0 -1
  98. package/lib/instrumentor/base/Application.js +0 -16
  99. package/lib/instrumentor/base/DynatraceInternal.js +0 -34
  100. package/lib/instrumentor/base/Logger.js +0 -16
  101. package/lib/instrumentor/base/model/LogLevel.js +0 -17
  102. package/lib/jsx-runtime.js +0 -69
  103. package/lib/react/Component.js +0 -90
  104. package/lib/react-native/Touchables.InstrInfo.js +0 -60
  105. /package/{lib/instrumentor/base/interface → instrumentation/jsx}/IDynatraceProperties.js +0 -0
  106. /package/{lib → instrumentation/libs}/community/gesture-handler/index.js +0 -0
  107. /package/{lib → instrumentation/libs}/gesture-handler.js +0 -0
  108. /package/{lib → instrumentation/libs}/react-native/index.js +0 -0
  109. /package/{lib → instrumentation/libs}/react-native.js +0 -0
  110. /package/{lib/instrumentor → instrumentation}/model/Reference.js +0 -0
  111. /package/{lib/instrumentor → instrumentation}/parser/Babel.js +0 -0
  112. /package/lib/{instrumentor/base → core}/DynatraceBridge.js +0 -0
  113. /package/lib/{instrumentor/base → core}/NullAction.js +0 -0
  114. /package/lib/{instrumentor/base → core}/NullRootAction.js +0 -0
  115. /package/lib/{instrumentor/base → core}/NullWebRequestTiming.js +0 -0
  116. /package/lib/{instrumentor/base → core}/UserPrivacyOptions.js +0 -0
  117. /package/lib/{instrumentor/base → core}/configuration/ConfigurationBuilder.js +0 -0
  118. /package/lib/{instrumentor/base → core}/configuration/ConfigurationPreset.js +0 -0
  119. /package/lib/{instrumentor/base → core}/configuration/IConfiguration.js +0 -0
  120. /package/lib/{instrumentor/base → core}/interface/IDynatrace.js +0 -0
  121. /package/lib/{instrumentor/base → core}/interface/IDynatraceAction.js +0 -0
  122. /package/lib/{instrumentor/base → core}/interface/IDynatraceInternal.js +0 -0
  123. /package/lib/{instrumentor/base → core}/interface/IDynatraceRootAction.js +0 -0
  124. /package/lib/{instrumentor/base → core}/interface/IWebRequestTiming.js +0 -0
  125. /package/lib/{instrumentor/base → core}/interface/NativeDynatraceBridge.js +0 -0
  126. /package/lib/{instrumentor/base/interface → core/logging}/ILogger.js +0 -0
  127. /package/lib/{instrumentor/base → core}/model/DataCollectionLevel.js +0 -0
  128. /package/lib/{instrumentor/base → core}/model/Json.js +0 -0
  129. /package/lib/{instrumentor/base → core}/model/Platform.js +0 -0
  130. /package/lib/{instrumentor/base → core}/util/StringUtils.js +0 -0
package/README.md CHANGED
@@ -27,17 +27,18 @@ If you want to start using this plugin and are not a Dynatrace customer yet, hea
27
27
  * Android Gradle plugin version 7.0+
28
28
  * Java 11
29
29
  * For iOS users: Minimum iOS 12
30
+ * NodeJS 18+
30
31
 
31
32
  ## Agent Versions
32
33
  This agent versions are configured in this plugin:
33
34
 
34
- * Android Agent: 8.305.1.1005
35
- * iOS Agent: 8.305.3.1016
35
+ * Android Agent: 8.309.2.1011
36
+ * iOS Agent: 8.309.1.1009
36
37
 
37
38
  ## Quick Setup
38
39
 
39
40
  1. [Install plugin](#1-install-the-plugin)
40
- 2. [Register Dynatrace transformer](#2-register-the-dynatrace-transformer)
41
+ 2. [Register Dynatrace transformer and reporter](#2-register-the-dynatrace-transformer-and-reporter)
41
42
  3. [Setup configuration](#3-setup-dynatraceconfigjs)
42
43
  4. [Update Babel Configuration](#4-update-babel-configuration)
43
44
  5. [Build and run your app](#4-build-and-run-your-app)
@@ -106,7 +107,9 @@ This agent versions are configured in this plugin:
106
107
  - Standalone Project: If you are using React Native standalone and embed it in your native project have a look [here](#configuration-of-standalone-react-native-project).
107
108
  - If for some reason (e.g. seperate native projects) `react-native link` doesn't work as expected, [manually add the iOS agent to your project](#manually-adding-ios-oneagent-to-a-project).
108
109
 
109
- ## 2. Register the Dynatrace transformer
110
+ ## 2. Register the Dynatrace transformer and reporter
111
+
112
+ The transformer will add modifications to your code during build. The reporter will notify us if you clear the cache of the metro bundler.
110
113
 
111
114
  Depending on your React Native version, you will need to use a different way to register the transformer. If you don't know the version, enter `react-native --version` in your terminal.
112
115
 
@@ -193,7 +196,7 @@ The required changes for the versions above can be found [here](#react-automatic
193
196
 
194
197
  1. Only for Expo: If using expo make sure that your project is containing a "android" and/or "ios" folder. This can be done by using `npx expo prebuild`.
195
198
 
196
- 2. Execute [`npx instrumentDynatrace`](#npx-instrumentdynatrace) or `react-native instrument-dynatrace` in the root of your React Native project. This will configure both Android and iOS projects with the settings from `dynatrace.config.js`. You can use the same [custom arguments](#customizing-paths-for-configuration) as mentioned above.
199
+ 2. Execute [`npx instrumentDynatrace`](#npx-instrumentdynatrace) or `react-native instrument-dynatrace` in the root of your React Native project. This will configure both Android and iOS projects with the settings from `dynatrace.config.js`. You can use the same [custom arguments](#customizing-paths-for-configuration) as mentioned above. Be aware this configuration step will modify your application's *.plist and build.gradle file. This modification enables auto instrumentation on Android and is writing the configuration for both platforms needed for the OneAgent.
197
200
 
198
201
  1. Use `react-native run-android` or `react-native run-ios` to rebuild and run your app. Specify custom paths via [custom arguments.](#customizing-paths-for-configuration).
199
202
 
@@ -318,13 +321,13 @@ Dynatrace.withMonitoring(MyFunctionalComponent, "MyFunctionalComponent");
318
321
 
319
322
  The String "MyFunctionalComponent" is optional as the name of the component can be retrieved through [different properties](#how-does-dynatrace-determine-the-user-action-name).
320
323
 
321
- Combining manual and auto instrumentation is not creating a problem as both are executing the same thing. Manual instrumentation would only override the content of auto instrumentation happening through the transformer.
324
+ Combining manual and auto instrumentation should not be a problem. As they're running the same execution, the manual instrumentation will only override the content of auto instrumentation happening through the transformer.
322
325
 
323
326
  ### Create custom actions
324
327
 
325
328
  There are two options to create an action. Either using `enterAutoAction` (the previous `enterAction`) or `enterManualAction`:
326
329
 
327
- * `enterAutoAction` - Creates an Action which will be automatically handled by the plugin (This is the type of action which is internally used by the plugin when monitoring components and touchables). This means that the plugin decides about the hierachy of this action. If there is no open action, the following action will be a root action. All other actions created by this method, while a root action is open, will be automatically inserted as a child action. Furthermore the plugin will automatically link webrequest (if they are not tagged manually) to the open root action.
330
+ * `enterAutoAction` - Creates an Action which will be automatically handled by the plugin (This is the type of action which is internally used by the plugin when monitoring components and touchables). This means that the plugin decides about the hierachy of this action. If there is no open action, the following action will be a root action. All other actions created by this method, while a root action is open, will be automatically inserted as a child action. Furthermore the plugin will automatically link webrequest (if they are not tagged manually) to the open root action. Be aware that the timeout/wait time for sub actions or web requests cannot be modified on the Android side for React Native Auto actions. The timeout is fixed to a 1000ms.
328
331
 
329
332
  ```ts
330
333
  import { Dynatrace } from '@dynatrace/react-native-plugin';
@@ -399,7 +402,7 @@ let url = 'https://www.dynatrace.com';
399
402
  // You can also use enterAutoAction if desired
400
403
  let action = Dynatrace.enterManualAction("Manual Web Request");
401
404
  let tag = await action.getRequestTag(url);
402
- let timing = new DynatraceWebRequestTiming(url, tag);
405
+ let timing = new DynatraceWebRequestTiming(tag, url);
403
406
 
404
407
  try {
405
408
  timing.startWebRequestTiming();
@@ -1236,7 +1239,7 @@ module.exports = {
1236
1239
 
1237
1240
  If you want to register the Dynatrace transformer in your configuration and you already have a transformer in place, change the upstreaming transformer for the Dynatrace transformer.
1238
1241
 
1239
- This can be done via a configuration value in the `dynatrace.config.js`. The following example shows how the configuration might look like for the popular `react-native-svg-transformer`. Be aware that the following example is targeting *React Native v0.72.1* or newer.
1242
+ This can be done via a configuration value in the `dynatrace.config.js`. The following example shows how the configuration might look like for the popular `react-native-svg-transformer`. Be aware that the following example is targeting *React Native v0.72.1* or newer. Be aware if you are using a different second transformer, you need to change `react-native-svg-transformer/react-native` accordingly.
1240
1243
 
1241
1244
  #### dynatrace.config.js
1242
1245
 
@@ -1244,7 +1247,7 @@ This can be done via a configuration value in the `dynatrace.config.js`. The fol
1244
1247
  // The `...` only indicates that there are other values as well, but we've omitted them in this example.
1245
1248
  module.exports = {
1246
1249
  react : {
1247
- upstreamTransformer: require.resolve('customTransformerLib/myTransformer'),
1250
+ upstreamTransformer: require.resolve('react-native-svg-transformer/react-native'),
1248
1251
  ...
1249
1252
  },
1250
1253
  ...
@@ -1460,6 +1463,14 @@ If you are struggling with a problem, submit a support ticket to Dynatrace (supp
1460
1463
  <br/><br/>
1461
1464
  ## Changelog
1462
1465
 
1466
+ 2.309.1
1467
+ * Updated Android (8.309.2.1011) & iOS Agent (8.309.1.1009)
1468
+ * Fixed issue with metro when internal require was not resolved correctly
1469
+
1470
+ 2.307.1
1471
+ * Updated Android (8.307.1.1005) & iOS Agent (8.307.1.1014)
1472
+ * Now require the use of NodeJS 18+
1473
+
1463
1474
  2.305.1
1464
1475
  * Updated Android (8.305.1.1005) & iOS Agent (8.305.3.1016)
1465
1476
 
@@ -16,10 +16,12 @@ buildscript {
16
16
 
17
17
  dependencies {
18
18
  classpath 'com.android.tools.build:gradle:7.3.1'
19
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.10"
19
20
  }
20
21
  }
21
22
 
22
23
  apply plugin: 'com.android.library'
24
+ apply plugin: 'org.jetbrains.kotlin.android'
23
25
 
24
26
  if (isNewArchitectureEnabled()) {
25
27
  apply plugin: 'com.facebook.react'
@@ -70,7 +72,7 @@ repositories {
70
72
  }
71
73
 
72
74
  dependencies {
73
- implementation 'com.dynatrace.agent:agent-android:8.305.1.1005'
75
+ implementation 'com.dynatrace.agent:agent-android:8.309.2.1011'
74
76
  implementation "com.facebook.react:react-native:${safeExtGet('reactNative', '+')}"
75
77
  }
76
78
 
@@ -0,0 +1,128 @@
1
+ package com.dynatrace.android.agent
2
+
3
+ import android.os.SystemClock
4
+ import com.dynatrace.android.agent.model.AppStartMeasurement
5
+ import com.dynatrace.android.agent.model.AppStartMeasurementType
6
+ import com.facebook.react.bridge.Arguments
7
+ import com.facebook.react.bridge.ReactApplicationContext
8
+ import com.facebook.react.bridge.ReactContextBaseJavaModule
9
+ import com.facebook.react.bridge.ReactMarker
10
+ import com.facebook.react.bridge.ReactMarkerConstants
11
+ import com.facebook.react.modules.core.DeviceEventManagerModule
12
+ import java.util.Queue
13
+ import java.util.concurrent.ConcurrentLinkedQueue
14
+
15
+ /**
16
+ * Name of the module
17
+ */
18
+ private const val APP_START_MODULE = "DynatraceAppStartModule"
19
+
20
+ /**
21
+ * Emitting app start event with this identifier
22
+ */
23
+ private const val EMIT_APP_START = "dynatraceAppStartMeasurements"
24
+
25
+ /**
26
+ * Queue which contains all our measured app start timestamps
27
+ */
28
+ private val buffer: Queue<AppStartMeasurement> = ConcurrentLinkedQueue()
29
+
30
+ /**
31
+ * Setup to register all time points which we want to use to report correct app startup time.
32
+ */
33
+ fun setupAppStartListener() {
34
+ ReactMarker.addListener { name: ReactMarkerConstants?, _: String?, _: Int ->
35
+ when (name) {
36
+ ReactMarkerConstants.RELOAD -> {
37
+ buffer.clear()
38
+ buffer.add(
39
+ AppStartMeasurement(
40
+ AppStartMeasurementType.RELOAD.value,
41
+ SystemClock.uptimeMillis()
42
+ )
43
+ )
44
+ }
45
+
46
+ ReactMarkerConstants.CONTENT_APPEARED -> buffer.add(
47
+ AppStartMeasurement(
48
+ AppStartMeasurementType.CONTENT_APPEARED.value,
49
+ SystemClock.uptimeMillis()
50
+ )
51
+ )
52
+
53
+ ReactMarkerConstants.DOWNLOAD_END -> buffer.add(
54
+ AppStartMeasurement(
55
+ AppStartMeasurementType.DOWNLOAD_END.value,
56
+ SystemClock.uptimeMillis()
57
+ )
58
+ )
59
+
60
+ ReactMarkerConstants.DOWNLOAD_START -> buffer.add(
61
+ AppStartMeasurement(
62
+ AppStartMeasurementType.DOWNLOAD_START.value,
63
+ SystemClock.uptimeMillis()
64
+ )
65
+ )
66
+
67
+ ReactMarkerConstants.RUN_JS_BUNDLE_END -> buffer.add(
68
+ AppStartMeasurement(
69
+ AppStartMeasurementType.RUN_JS_BUNDLE_END.value,
70
+ SystemClock.uptimeMillis()
71
+ )
72
+ )
73
+
74
+ ReactMarkerConstants.RUN_JS_BUNDLE_START -> buffer.add(
75
+ AppStartMeasurement(
76
+ AppStartMeasurementType.RUN_JS_BUNDLE_START.value,
77
+ SystemClock.uptimeMillis()
78
+ )
79
+ )
80
+
81
+ else -> {
82
+ // Not important
83
+ }
84
+ }
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Module which is handling the app start measurements
90
+ */
91
+ internal class DynatraceAppStartModule(reactContext: ReactApplicationContext?) :
92
+ ReactContextBaseJavaModule(reactContext) {
93
+ init {
94
+ setupInternalListener()
95
+ }
96
+
97
+ /**
98
+ * We setup the listener internally as we
99
+ */
100
+ private fun setupInternalListener() {
101
+ ReactMarker.addListener { name: ReactMarkerConstants, _: String?, _: Int ->
102
+ if (name == ReactMarkerConstants.CONTENT_APPEARED) {
103
+ // When content appeared we will emit the event with all the information
104
+ flushMeasurements()
105
+ }
106
+ }
107
+ }
108
+
109
+ /**
110
+ * We flush all events when content appeared is triggered, as it marks the last event
111
+ */
112
+ private fun flushMeasurements() {
113
+ val params = Arguments.createMap()
114
+ val iterator: Iterator<AppStartMeasurement> = buffer.iterator()
115
+ while (iterator.hasNext()) {
116
+ val entry = iterator.next()
117
+ params.putDouble(entry.name, entry.timestamp.toDouble())
118
+ }
119
+
120
+ reactApplicationContext
121
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
122
+ .emit(EMIT_APP_START, params)
123
+ }
124
+
125
+ override fun getName(): String {
126
+ return APP_START_MODULE
127
+ }
128
+ }
@@ -0,0 +1,22 @@
1
+ package com.dynatrace.android.agent
2
+
3
+ import com.facebook.react.bridge.ReactApplicationContext
4
+ import com.facebook.react.bridge.ReactContextBaseJavaModule
5
+ import com.facebook.react.bridge.ReactMethod
6
+
7
+ class DynatraceInternalModule(reactContext: ReactApplicationContext?) :
8
+ ReactContextBaseJavaModule(reactContext) {
9
+ override fun getName(): String {
10
+ return "DynatraceInternalModule"
11
+ }
12
+
13
+ /**
14
+ * Helper method which should not be called.
15
+ * @param name Action name
16
+ * @return Action
17
+ */
18
+ @ReactMethod
19
+ fun enterAction(name: String?): DTXAction {
20
+ return Dynatrace.integrateNewAction(name)
21
+ }
22
+ }
@@ -0,0 +1,411 @@
1
+ package com.dynatrace.android.agent
2
+
3
+ import android.location.Location
4
+ import com.dynatrace.android.agent.conf.DataCollectionLevel
5
+ import com.dynatrace.android.agent.conf.DynatraceConfigurationBuilder
6
+ import com.dynatrace.android.agent.conf.UserPrivacyOptions
7
+ import com.dynatrace.android.agent.crash.PlatformType
8
+ import com.facebook.react.bridge.Arguments
9
+ import com.facebook.react.bridge.Promise
10
+ import com.facebook.react.bridge.ReactApplicationContext
11
+ import com.facebook.react.bridge.ReadableMap
12
+ import org.json.JSONObject
13
+ import java.net.URI
14
+ import java.net.URISyntaxException
15
+
16
+ private const val PLATFORM_ANDROID = "android"
17
+ private const val PLATFORM_IOS = "ios"
18
+ private const val DATA_COLLECTION_OFF = "OFF"
19
+ private const val DATA_COLLECTION_PERFORMANCE = "PERFORMANCE"
20
+ private const val DATA_COLLECTION_USERBEHAVIOR = "USER_BEHAVIOR"
21
+ const val BRIDGE_NAME = "DynatraceBridge"
22
+
23
+ class DynatraceRNBridgeImpl(
24
+ private val reactApplicationContext: ReactApplicationContext,
25
+ private val _internal: DynatraceInternalModule
26
+ ) {
27
+ private val webTimings: HashMap<String, WebRequestTiming> = HashMap()
28
+ private val actions: HashMap<String, DTXAction?> = HashMap()
29
+
30
+ private val constants = mapOf(
31
+ "PLATFORM_ANDROID" to PLATFORM_ANDROID,
32
+ "PLATFORM_IOS" to PLATFORM_IOS,
33
+ "DATA_COLLECTION_OFF" to DATA_COLLECTION_OFF,
34
+ "DATA_COLLECTION_PERFORMANCE" to DATA_COLLECTION_PERFORMANCE,
35
+ "DATA_COLLECTION_USERBEHAVIOR" to DATA_COLLECTION_USERBEHAVIOR
36
+ )
37
+
38
+ fun getConstants(): Map<String, Any> {
39
+ return constants;
40
+ }
41
+
42
+ fun start(configuration: ReadableMap?, promise: Promise) {
43
+ if (configuration == null) {
44
+ promise.resolve(false)
45
+ return
46
+ } else {
47
+ if (configuration.getString("applicationId") == null || configuration.getString("beaconUrl") == null) {
48
+ promise.resolve(false)
49
+ return
50
+ }
51
+
52
+ val builder = DynatraceConfigurationBuilder(
53
+ configuration.getString("applicationId"),
54
+ configuration.getString("beaconUrl")
55
+ )
56
+
57
+ builder.apply {
58
+ withUserOptIn(configuration.getBoolean("userOptIn"))
59
+ withCrashReporting(configuration.getBoolean("reportCrash"))
60
+ // 0 == Debug / 1 == Info
61
+ withDebugLogging(configuration.getInt("logLevel") == 0)
62
+ }
63
+
64
+ Dynatrace.startup(reactApplicationContext, builder.buildConfiguration())
65
+ promise.resolve(true)
66
+ }
67
+ }
68
+
69
+ //
70
+ // Expects a key which is generated in JS. This is to circumvent the async callback system.
71
+ //
72
+ fun enterAction(name: String, key: String, platform: String?) {
73
+ if (shouldWorkOnAndroid(platform)) {
74
+ newAction(name, key)
75
+ }
76
+ }
77
+
78
+ fun enterManualAction(name: String, key: String, platform: String?) {
79
+ if (shouldWorkOnAndroid(platform)) {
80
+ actions[key] = Dynatrace.enterAction(name)
81
+ }
82
+ }
83
+
84
+ fun enterManualActionWithParent(
85
+ name: String,
86
+ key: String,
87
+ parentKey: String,
88
+ platform: String?
89
+ ) {
90
+ if (shouldWorkOnAndroid(platform)) {
91
+ val parent = actions[parentKey]
92
+ if (parent != null) {
93
+ actions[key] = Dynatrace.enterAction(name, parent)
94
+ } else {
95
+ enterManualAction(name, key, platform)
96
+ }
97
+ }
98
+ }
99
+
100
+ fun leaveAction(key: String, @Suppress("UNUSED_PARAMETER") leave: Boolean, platform: String?) {
101
+ if (shouldWorkOnAndroid(platform)) {
102
+ val action = getAction(key) ?: return
103
+ if (action is DTXAutoAction) {
104
+ action.startTimer()
105
+ } else {
106
+ action.leaveAction()
107
+ }
108
+ actions.remove(key)
109
+ }
110
+ }
111
+
112
+ fun cancelAction(key: String, platform: String?) {
113
+ if (shouldWorkOnAndroid(platform)) {
114
+ val action = getAction(key) ?: return
115
+ action.cancel()
116
+ actions.remove(key)
117
+ }
118
+ }
119
+
120
+ fun endVisit(platform: String?) {
121
+ if (shouldWorkOnAndroid(platform)) {
122
+ Dynatrace.endVisit()
123
+ }
124
+ }
125
+
126
+ fun reportErrorWithoutStacktrace(errorName: String, errorCode: Int, platform: String?) {
127
+ if (shouldWorkOnAndroid(platform)) {
128
+ Dynatrace.internalReportError(errorName, errorCode)
129
+ }
130
+ }
131
+
132
+ /**
133
+ * Reports a stacktrace
134
+ * @param errorName Name of the Error - SyntaxError
135
+ * @param errorValue Value of the Error
136
+ * @param reason Reason for the Error
137
+ * @param stacktrace Whole Stacktrace
138
+ * @param platform Platform wise or both
139
+ */
140
+ fun reportError(
141
+ errorName: String,
142
+ errorValue: String,
143
+ reason: String,
144
+ stacktrace: String,
145
+ platform: String?
146
+ ) {
147
+ if (shouldWorkOnAndroid(platform)) {
148
+ Dynatrace.reportError(PlatformType.CUSTOM, errorName, errorValue, reason, stacktrace)
149
+ }
150
+ }
151
+
152
+ fun reportCrash(
153
+ errorName: String,
154
+ reason: String,
155
+ stacktrace: String,
156
+ isRealError: Boolean,
157
+ platform: String?
158
+ ) {
159
+ if (shouldWorkOnAndroid(platform)) {
160
+ Dynatrace.reportCrash(
161
+ if (isRealError) PlatformType.JAVA_SCRIPT else PlatformType.CUSTOM,
162
+ errorName,
163
+ reason,
164
+ stacktrace
165
+ )
166
+ // Generate new session like iOS to make sure the behavior is the same
167
+ Dynatrace.createNewSession()
168
+ }
169
+ }
170
+
171
+ fun reportErrorInAction(key: String, errorName: String, errorCode: Int, platform: String?) {
172
+ if (shouldWorkOnAndroid(platform)) {
173
+ val action = getAction(key) ?: return
174
+ action.reportError(errorName, errorCode)
175
+ }
176
+ }
177
+
178
+ fun reportValue(key: String, valueName: String, value: String, platform: String?) {
179
+ if (shouldWorkOnAndroid(platform)) {
180
+ val action = getAction(key) ?: return
181
+ action.reportValue(valueName, value)
182
+ }
183
+ }
184
+
185
+ fun getRequestTag(key: String, @Suppress("UNUSED_PARAMETER") url: String, promise: Promise) {
186
+ val action = getAction(key)
187
+ if (action == null) {
188
+ promise.resolve(Dynatrace.getRequestTag())
189
+ return
190
+ }
191
+ promise.resolve(action.requestTag)
192
+ }
193
+
194
+ fun startWebRequestTiming(requestTag: String?, @Suppress("UNUSED_PARAMETER") url: String) {
195
+ if (requestTag != null) {
196
+ val timing = Dynatrace.getWebRequestTiming(requestTag)
197
+ if (timing != null) {
198
+ webTimings[requestTag] = timing
199
+ timing.startWebRequestTiming()
200
+ }
201
+ }
202
+ }
203
+
204
+ fun stopWebRequestTiming(
205
+ requestTag: String?,
206
+ url: String,
207
+ responseCode: Int,
208
+ responseMessage: String
209
+ ) {
210
+ stopWebRequestTimingWithSize(requestTag, url, responseCode, responseMessage, -1, -1)
211
+ }
212
+
213
+ fun stopWebRequestTimingWithSize(
214
+ requestTag: String?,
215
+ url: String,
216
+ responseCode: Int,
217
+ responseMessage: String,
218
+ requestSize: Long,
219
+ responseSize: Long
220
+ ) {
221
+ if (requestTag != null) {
222
+ val timing = webTimings[requestTag]
223
+ if (timing != null) {
224
+ try {
225
+ timing.stopWebRequestTiming(
226
+ URI(url),
227
+ responseCode,
228
+ responseMessage,
229
+ requestSize,
230
+ responseSize
231
+ )
232
+ webTimings.remove(requestTag)
233
+ } catch (ex: URISyntaxException) {
234
+ // do nothing
235
+ }
236
+ }
237
+ }
238
+ }
239
+
240
+ fun identifyUser(user: String, platform: String?) {
241
+ if (shouldWorkOnAndroid(platform)) {
242
+ Dynatrace.identifyUser(user)
243
+ }
244
+ }
245
+
246
+ fun reportEventInAction(actionKey: String, name: String, platform: String?) {
247
+ if (shouldWorkOnAndroid(platform)) {
248
+ val action = getAction(actionKey) ?: return
249
+ action.reportEvent(name)
250
+ }
251
+ }
252
+
253
+ fun reportStringValueInAction(
254
+ actionKey: String,
255
+ name: String,
256
+ value: String,
257
+ platform: String?
258
+ ) {
259
+ if (shouldWorkOnAndroid(platform)) {
260
+ val action = getAction(actionKey) ?: return
261
+ action.reportValue(name, value)
262
+ }
263
+ }
264
+
265
+ fun reportIntValueInAction(actionKey: String, name: String, value: Int, platform: String?) {
266
+ if (shouldWorkOnAndroid(platform)) {
267
+ val action = getAction(actionKey) ?: return
268
+ action.reportValue(name, value)
269
+ }
270
+ }
271
+
272
+ fun reportDoubleValueInAction(
273
+ actionKey: String,
274
+ name: String,
275
+ value: Double,
276
+ platform: String?
277
+ ) {
278
+ if (shouldWorkOnAndroid(platform)) {
279
+ val action = getAction(actionKey) ?: return
280
+ action.reportValue(name, value)
281
+ }
282
+ }
283
+
284
+ fun sendBizEvent(type: String, attributes: ReadableMap, platform: String?) {
285
+ if (shouldWorkOnAndroid(platform)) {
286
+ Dynatrace.sendBizEvent(type, JSONObject(DynatraceUtils.toHashMap(attributes)))
287
+ }
288
+ }
289
+
290
+ fun forwardEvent(attributes: ReadableMap) {
291
+ HybridBridge.forwardEvent(JSONObject(DynatraceUtils.toHashMap(attributes)))
292
+ }
293
+
294
+ fun startView(name: String) {
295
+ Dynatrace.startView(name)
296
+ }
297
+
298
+ fun stopView() {
299
+ Dynatrace.stopView()
300
+ }
301
+
302
+ fun setGPSLocation(lat: Double, lng: Double, platform: String?) {
303
+ if (shouldWorkOnAndroid(platform)) {
304
+ val location = Location("")
305
+
306
+ location.apply {
307
+ latitude = lat
308
+ longitude = lng
309
+ }
310
+
311
+ Dynatrace.setGpsLocation(location)
312
+ }
313
+ }
314
+
315
+ fun flushEvents(platform: String?) {
316
+ if (shouldWorkOnAndroid(platform)) {
317
+ Dynatrace.flushEvents()
318
+ }
319
+ }
320
+
321
+ fun isCrashReportingOptedIn(platform: String?, promise: Promise) {
322
+ if (shouldWorkOnAndroid(platform)) {
323
+ promise.resolve(Dynatrace.isCrashReportingOptedIn())
324
+ }
325
+ }
326
+
327
+ fun setCrashReportingOptedIn(crashReporting: Boolean, platform: String?) {
328
+ if (shouldWorkOnAndroid(platform)) {
329
+ Dynatrace.setCrashReportingOptedIn(crashReporting)
330
+ }
331
+ }
332
+
333
+ fun setDataCollectionLevel(collectionLevel: String, platform: String?) {
334
+ if (shouldWorkOnAndroid(platform)) {
335
+ Dynatrace.setDataCollectionLevel(DataCollectionLevel.valueOf(collectionLevel))
336
+ }
337
+ }
338
+
339
+ fun getDataCollectionLevel(platform: String?, promise: Promise) {
340
+ if (shouldWorkOnAndroid(platform)) {
341
+ val level = Dynatrace.getDataCollectionLevel()
342
+ promise.resolve(level.name)
343
+ }
344
+ }
345
+
346
+ fun setBeaconHeaders(headers: ReadableMap?, platform: String?) {
347
+ if (shouldWorkOnAndroid(platform)) {
348
+ if (headers == null) {
349
+ Dynatrace.setBeaconHeaders(null)
350
+ } else {
351
+ val beaconHeaders = mutableMapOf<String, String?>()
352
+ val iterator = headers.keySetIterator()
353
+ while (iterator.hasNextKey()) {
354
+ val currentKey = iterator.nextKey()
355
+ beaconHeaders[currentKey] = headers.getString(currentKey)
356
+ }
357
+ Dynatrace.setBeaconHeaders(beaconHeaders)
358
+ }
359
+ }
360
+ }
361
+
362
+ fun applyUserPrivacyOptions(userPrivacyOptions: ReadableMap, platform: String?) {
363
+ if (shouldWorkOnAndroid(platform)) {
364
+ val optionsBuilder = UserPrivacyOptions.builder()
365
+ optionsBuilder.withCrashReportingOptedIn(userPrivacyOptions.getBoolean("_crashReportingOptedIn"))
366
+ optionsBuilder.withDataCollectionLevel(
367
+ DataCollectionLevel.valueOf(
368
+ userPrivacyOptions.getString(
369
+ "_dataCollectionLevel"
370
+ )!!
371
+ )
372
+ )
373
+ Dynatrace.applyUserPrivacyOptions(
374
+ optionsBuilder
375
+ .build()
376
+ )
377
+ }
378
+ }
379
+
380
+ fun getUserPrivacyOptions(platform: String?, promise: Promise) {
381
+ if (shouldWorkOnAndroid(platform)) {
382
+ val options = Dynatrace.getUserPrivacyOptions()
383
+ val privacyMap = Arguments.createMap()
384
+ privacyMap.putString("dataCollectionLevel", options.dataCollectionLevel.name)
385
+ privacyMap.putBoolean("crashReportingOptedIn", options.isCrashReportingOptedIn)
386
+ promise.resolve(privacyMap)
387
+ }
388
+ }
389
+
390
+ @Suppress("UNUSED_PARAMETER")
391
+ fun addListener(eventName: String) {
392
+ // Here because of event emitter
393
+ }
394
+
395
+ @Suppress("UNUSED_PARAMETER")
396
+ fun removeListeners(count: Double) {
397
+ // Here because of event emitter
398
+ }
399
+
400
+ private fun newAction(name: String, key: String) {
401
+ actions[key] = _internal.enterAction(name)
402
+ }
403
+
404
+ private fun getAction(key: String): DTXAction? {
405
+ return actions[key]
406
+ }
407
+
408
+ private fun shouldWorkOnAndroid(platform: String?): Boolean {
409
+ return platform == null || platform == PLATFORM_ANDROID || platform == ""
410
+ }
411
+ }