@dynatrace/react-native-plugin 2.327.1 → 2.329.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.
- package/README.md +426 -169
- package/android/build.gradle +1 -1
- package/android/src/main/java/com/dynatrace/android/agent/DynatraceConfigurationModule.kt +48 -0
- package/android/src/main/java/com/dynatrace/android/agent/DynatraceRNBridgeImpl.kt +41 -8
- package/android/src/main/java/com/dynatrace/android/agent/DynatraceReactPackage.kt +3 -0
- package/android/src/main/java/com/dynatrace/android/agent/DynatraceRuntimeConfigurationStore.kt +14 -0
- package/android/src/main/java/com/dynatrace/android/agent/DynatraceUtils.kt +103 -47
- package/android/src/new/java/com/dynatrace/android/agent/DynatraceRNBridge.kt +12 -4
- package/android/src/old/java/com/dynatrace/android/agent/DynatraceRNBridge.kt +15 -5
- package/files/default.config.js +7 -0
- package/files/plugin-runtime.gradle +7 -17
- package/files/plugin.gradle +1 -1
- package/instrumentation/DynatraceInstrumentation.js +1 -1
- package/instrumentation/libs/react-native/Touchables.js +9 -0
- package/instrumentation/libs/react-navigation/ReactNavigation.js +53 -18
- package/ios/ConfigurationSubscriber.h +15 -0
- package/ios/DynatraceRNBridge.h +4 -0
- package/ios/DynatraceRNBridge.mm +220 -33
- package/lib/core/Dynatrace.js +8 -11
- package/lib/core/configuration/ConfigurationHandler.js +3 -0
- package/lib/next/Dynatrace.js +14 -32
- package/lib/next/DynatraceEventBus.js +35 -0
- package/lib/next/appstart/AppStartObserver.js +12 -16
- package/lib/next/configuration/INativeRuntimeConfiguration.js +7 -0
- package/lib/next/configuration/RuntimeConfigurationObserver.js +40 -0
- package/lib/next/events/EventBuilderUtil.js +7 -0
- package/lib/next/events/EventData.js +28 -0
- package/lib/next/events/EventPipeline.js +5 -11
- package/lib/next/events/ExceptionEventData.js +26 -0
- package/lib/next/events/{HttpRequestEventBuilder.js → HttpRequestEventData.js} +28 -52
- package/lib/next/events/SessionPropertyEventData.js +22 -0
- package/lib/next/events/interface/IBaseEvent.js +2 -0
- package/lib/next/events/interface/IEventData.js +2 -0
- package/lib/next/events/interface/IExceptionEventData.js +2 -0
- package/lib/next/events/interface/IHttpRequestEventData.js +2 -0
- package/lib/next/events/interface/ISessionPropertyEventData.js +2 -0
- package/lib/next/events/modifier/BaseDataEventModifier.js +1 -3
- package/lib/next/events/modifier/EventModifierUtil.js +34 -41
- package/lib/next/events/modifier/ModifyEventValidation.js +118 -26
- package/lib/next/events/modifier/SendEventValidation.js +53 -22
- package/lib/next/events/modifier/StringLengthEventModifier.js +53 -0
- package/lib/next/events/spec/EventSpecContstants.js +9 -2
- package/package.json +8 -3
- package/public.js +9 -3
- package/react-native-dynatrace.podspec +1 -1
- package/scripts/Config.js +6 -2
- package/scripts/LineOffsetAnalyze.js +1 -4
- package/scripts/core/LineOffsetAnalyzeCall.js +39 -46
- package/src/lib/core/interface/NativeDynatraceBridge.ts +6 -2
- package/types.d.ts +388 -158
- package/lib/next/events/ViewInfoCreator.js +0 -27
- package/lib/next/events/modifier/EventLimitation.js +0 -69
- /package/lib/next/events/{IHttpRequestEventBuilder.js → interface/EventProperty.js} +0 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//
|
|
2
|
+
// ConfigurationSubscriber.h
|
|
3
|
+
// DynatraceUEM
|
|
4
|
+
//
|
|
5
|
+
// Created by Schnalzenberger, Ralph on 07.07.25.
|
|
6
|
+
// Copyright © 2025 Dynatrace LLC. All rights reserved.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
#import <Foundation/Foundation.h>
|
|
10
|
+
|
|
11
|
+
@protocol ConfigurationSubscriber <NSObject>
|
|
12
|
+
|
|
13
|
+
- (void)notifyWithConfiguration:(NSDictionary<NSString*, id>*)configuration;
|
|
14
|
+
|
|
15
|
+
@end
|
package/ios/DynatraceRNBridge.h
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
#import <Dynatrace/Dynatrace.h>
|
|
9
9
|
#import <React/RCTBridgeModule.h>
|
|
10
10
|
#import <React/RCTEventEmitter.h>
|
|
11
|
+
#import "ConfigurationSubscriber.h"
|
|
11
12
|
|
|
12
13
|
@interface DynatraceRNBridge : RCTEventEmitter <RCTBridgeModule>
|
|
13
14
|
- (void) newAction:(NSString *)name key:(NSString *)key parentAction:(DTXAction *)parentAction;
|
|
@@ -18,6 +19,9 @@
|
|
|
18
19
|
@interface HybridBridge : NSObject
|
|
19
20
|
+ (void)forwardEvent:(NSDictionary<NSString*,id>* _Nullable)fields NS_SWIFT_NAME(forwardEvent(fields:));
|
|
20
21
|
+ (void)forwardAppStartEvent:(NSDictionary<NSString*,id>* _Nullable)fields keys:(NSArray<NSString*>* _Nullable)keys NS_SWIFT_NAME(forwardEvent(fields:keys:));
|
|
22
|
+
+ (void)startView:(NSDictionary<NSString*,id>* _Nullable)fields NS_SWIFT_NAME(startView(fields:));
|
|
23
|
+
+ (void)stopView;
|
|
24
|
+
+ (void)addConfigurationSubscriber:(id<ConfigurationSubscriber>)subscriber;
|
|
21
25
|
@end
|
|
22
26
|
|
|
23
27
|
typedef enum : NSUInteger {
|
package/ios/DynatraceRNBridge.mm
CHANGED
|
@@ -13,9 +13,45 @@
|
|
|
13
13
|
#import <CoreLocation/CoreLocation.h>
|
|
14
14
|
#import <React/RCTPerformanceLogger.h>
|
|
15
15
|
#import <React/RCTRootView.h>
|
|
16
|
+
#import <React/RCTBridge+Private.h>
|
|
16
17
|
#import <cxxreact/ReactMarker.h>
|
|
18
|
+
#import <cxxreact/ReactNativeVersion.h>
|
|
17
19
|
|
|
18
20
|
#include <chrono>
|
|
21
|
+
#include <type_traits>
|
|
22
|
+
|
|
23
|
+
@interface DynatraceRNBridge ()
|
|
24
|
+
- (void)handleRuntimeConfiguration:(NSDictionary<NSString*, id>*)configuration;
|
|
25
|
+
- (void)setupRuntimeConfigurationListenerIfNeeded;
|
|
26
|
+
- (void)emitToJS:(NSString*)event body:(id)body;
|
|
27
|
+
@end
|
|
28
|
+
|
|
29
|
+
@interface RNConfigurationSubscriber : NSObject <ConfigurationSubscriber>
|
|
30
|
+
@property (nonatomic, weak) DynatraceRNBridge* bridge;
|
|
31
|
+
- (instancetype)initWithBridge:(DynatraceRNBridge*)bridge;
|
|
32
|
+
@end
|
|
33
|
+
|
|
34
|
+
@implementation RNConfigurationSubscriber
|
|
35
|
+
|
|
36
|
+
- (instancetype)initWithBridge:(DynatraceRNBridge*)bridge
|
|
37
|
+
{
|
|
38
|
+
self = [super init];
|
|
39
|
+
if (self) {
|
|
40
|
+
_bridge = bridge;
|
|
41
|
+
}
|
|
42
|
+
return self;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
- (void)notifyWithConfiguration:(NSDictionary<NSString*, id>*)configuration
|
|
46
|
+
{
|
|
47
|
+
DynatraceRNBridge* bridge = self.bridge;
|
|
48
|
+
if (bridge == nil) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
[bridge handleRuntimeConfiguration:configuration];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
@end
|
|
19
55
|
|
|
20
56
|
@implementation DynatraceRNBridge
|
|
21
57
|
|
|
@@ -35,6 +71,7 @@ NSString *const DataCollectionUserBehavior = @"USER_BEHAVIOR";
|
|
|
35
71
|
* Emitting app start event with this identifier
|
|
36
72
|
*/
|
|
37
73
|
NSString *const EmitAppMeasurementsIdentifier = @"dynatraceAppStartMeasurements";
|
|
74
|
+
NSString *const EmitDynatraceConfiguration = @"dynatraceConfiguration";
|
|
38
75
|
|
|
39
76
|
// All types which are interesting for us
|
|
40
77
|
NSString *const DownloadStart = @"downloadStart";
|
|
@@ -59,6 +96,21 @@ bool didEmit;
|
|
|
59
96
|
*/
|
|
60
97
|
int64_t contentAppeared;
|
|
61
98
|
|
|
99
|
+
/**
|
|
100
|
+
* When the JavaScript bundle started running
|
|
101
|
+
*/
|
|
102
|
+
int64_t runJSBundleStartTime;
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* When the JavaScript bundle stopped running
|
|
106
|
+
*/
|
|
107
|
+
int64_t runJSBundleEndTime;
|
|
108
|
+
|
|
109
|
+
// Runtime configuration (remote config)
|
|
110
|
+
static bool remoteConfigSubscribed;
|
|
111
|
+
static NSDictionary<NSString*, id>* lastRuntimeConfiguration;
|
|
112
|
+
static RNConfigurationSubscriber* configurationSubscriber;
|
|
113
|
+
|
|
62
114
|
RCT_EXPORT_MODULE(DynatraceBridge);
|
|
63
115
|
|
|
64
116
|
- (instancetype) init
|
|
@@ -69,12 +121,58 @@ RCT_EXPORT_MODULE(DynatraceBridge);
|
|
|
69
121
|
hasListeners = NO;
|
|
70
122
|
didEmit = NO;
|
|
71
123
|
contentAppeared = -1;
|
|
124
|
+
runJSBundleStartTime = -1;
|
|
125
|
+
runJSBundleEndTime = -1;
|
|
126
|
+
|
|
127
|
+
remoteConfigSubscribed = NO;
|
|
128
|
+
lastRuntimeConfiguration = nil;
|
|
129
|
+
configurationSubscriber = [[RNConfigurationSubscriber alloc] initWithBridge:self];
|
|
130
|
+
|
|
131
|
+
registerLogTaggedMarkerCallbacks();
|
|
72
132
|
}
|
|
73
133
|
return self;
|
|
74
134
|
}
|
|
75
135
|
|
|
136
|
+
// We have to make sure facebook::react::ReactMarker::StartupLogger::getInstance().getRunJSBundleEndTime() is always available even for the RN < 72s cases.
|
|
137
|
+
// Relying on the if constexpr else does not work since namespaces get resolved before the if branch in the if constexpr gets discarded.
|
|
138
|
+
// SFINAE does not work for top level symbols in namespaces (because it actually is an error).
|
|
139
|
+
// We cannot use preprocessor directives since we don't have the React Native version as preprocessor macro.
|
|
140
|
+
// We cannot use C++ concepts since C++20 is not available.
|
|
141
|
+
// Thus we provide a fallback definition for StartupLogger.
|
|
142
|
+
// Calling the class methods without a definition cannot happen and won't result in a linker error since the if branch in the if constexpr does not get compiled.
|
|
143
|
+
namespace fallback {
|
|
144
|
+
class StartupLogger {
|
|
145
|
+
public:
|
|
146
|
+
static StartupLogger& getInstance();
|
|
147
|
+
double getRunJSBundleStartTime();
|
|
148
|
+
double getRunJSBundleEndTime();
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
namespace facebook::react::ReactMarker {
|
|
153
|
+
using namespace fallback;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
int64_t getRunJSBundleStartTime() {
|
|
157
|
+
if constexpr(facebook::react::ReactNativeVersion.Minor >= 72) {
|
|
158
|
+
auto time = facebook::react::ReactMarker::StartupLogger::getInstance().getRunJSBundleStartTime();
|
|
159
|
+
return std::isnan(time) ? -1 : time;
|
|
160
|
+
} else {
|
|
161
|
+
return runJSBundleStartTime;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
int64_t getRunJSBundleEndTime() {
|
|
166
|
+
if constexpr(facebook::react::ReactNativeVersion.Minor >= 72) {
|
|
167
|
+
auto time = facebook::react::ReactMarker::StartupLogger::getInstance().getRunJSBundleEndTime();
|
|
168
|
+
return std::isnan(time) ? -1 : time;
|
|
169
|
+
} else {
|
|
170
|
+
return runJSBundleEndTime;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
76
174
|
- (NSArray<NSString *> *)supportedEvents {
|
|
77
|
-
return @[EmitAppMeasurementsIdentifier];
|
|
175
|
+
return @[EmitAppMeasurementsIdentifier, EmitDynatraceConfiguration];
|
|
78
176
|
}
|
|
79
177
|
|
|
80
178
|
int64_t GetTimestampUnix()
|
|
@@ -83,21 +181,53 @@ int64_t GetTimestampUnix()
|
|
|
83
181
|
return millisecondsUTC;
|
|
84
182
|
}
|
|
85
183
|
|
|
184
|
+
/*
|
|
185
|
+
In RN < 72, logTaggedMarker and logTaggedMarkerBridgeless are lambdas. In RN >= 72, these symbols are functions.
|
|
186
|
+
Relying on an if constexpr else does not work since types get checked before one branch in an if constexpr else gets discarded.
|
|
187
|
+
We cannot use a fallback declaration since since the symbol is declared as a function in RN >=72.
|
|
188
|
+
We cannot use preprocessor directives since we don't have the React Native version as preprocessor macro.
|
|
189
|
+
We cannot use C++ concepts since C++20 is not available.
|
|
190
|
+
Thus we use SFINAE. This works since types only get checked after template resolution.
|
|
191
|
+
*/
|
|
192
|
+
template<typename T = void> std::enable_if_t<(facebook::react::ReactNativeVersion.Minor < 72), T> registerLogTaggedMarkerCallbacks() {
|
|
193
|
+
using namespace facebook::react::ReactMarker;
|
|
194
|
+
auto logTaggedMarkerCommon = [](const ReactMarkerId markerId, const char* tag, auto previousLogTaggedMarker) {
|
|
195
|
+
if (previousLogTaggedMarker) {
|
|
196
|
+
previousLogTaggedMarker(markerId, tag);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (markerId == RUN_JS_BUNDLE_START) {
|
|
200
|
+
runJSBundleStartTime = GetTimestampUnix();
|
|
201
|
+
} else if (markerId == RUN_JS_BUNDLE_STOP) {
|
|
202
|
+
runJSBundleEndTime = GetTimestampUnix();
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
auto previousLogTaggedMarker = logTaggedMarker;
|
|
207
|
+
logTaggedMarker = [=](const ReactMarkerId markerId, const char* tag) {
|
|
208
|
+
logTaggedMarkerCommon(markerId, tag, previousLogTaggedMarker);
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
auto previousLogTaggedMarkerBridgeless = logTaggedMarkerBridgeless;
|
|
212
|
+
logTaggedMarkerBridgeless = [=](const ReactMarkerId markerId, const char* tag) {
|
|
213
|
+
logTaggedMarkerCommon(markerId, tag, previousLogTaggedMarkerBridgeless);
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
template<typename T = void> std::enable_if_t<(facebook::react::ReactNativeVersion.Minor >= 72), T> registerLogTaggedMarkerCallbacks() {}
|
|
218
|
+
|
|
86
219
|
/**
|
|
87
220
|
* When bridge is starting we will add an observer for content did appear so we can emit our app start measurements
|
|
88
221
|
*/
|
|
89
222
|
- (void)setBridge:(RCTBridge *)bridge
|
|
90
223
|
{
|
|
91
224
|
[super setBridge:bridge];
|
|
92
|
-
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
93
|
-
selector:@selector(contentAppeared)
|
|
94
|
-
name:RCTContentDidAppearNotification
|
|
95
|
-
object:nil];
|
|
225
|
+
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contentAppeared) name:RCTContentDidAppearNotification object:nil];
|
|
96
226
|
}
|
|
97
227
|
|
|
98
228
|
- (BOOL)isReady
|
|
99
229
|
{
|
|
100
|
-
return contentAppeared != -1 &&
|
|
230
|
+
return contentAppeared != -1 && getRunJSBundleEndTime() != -1;
|
|
101
231
|
}
|
|
102
232
|
|
|
103
233
|
- (void) contentAppeared
|
|
@@ -113,13 +243,13 @@ int64_t GetTimestampUnix()
|
|
|
113
243
|
{
|
|
114
244
|
if (!didEmit && hasListeners && [self isReady]) {
|
|
115
245
|
didEmit = YES;
|
|
116
|
-
|
|
246
|
+
|
|
117
247
|
NSMutableDictionary<NSString*, NSNumber*> *appStartMeasurements = [[NSMutableDictionary alloc] init];
|
|
118
|
-
|
|
119
|
-
[appStartMeasurements setObject:[self correctionOfTimestamp:
|
|
120
|
-
[appStartMeasurements setObject:[self correctionOfTimestamp:
|
|
248
|
+
|
|
249
|
+
[appStartMeasurements setObject:[self correctionOfTimestamp:getRunJSBundleStartTime()] forKey:RunJSBundleStart];
|
|
250
|
+
[appStartMeasurements setObject:[self correctionOfTimestamp:getRunJSBundleEndTime()] forKey:RunJSBundleEnd];
|
|
121
251
|
[appStartMeasurements setObject:[NSNumber numberWithLongLong:contentAppeared] forKey:ContentAppeared];
|
|
122
|
-
|
|
252
|
+
|
|
123
253
|
if (hasListeners) {
|
|
124
254
|
[self sendEventWithName:EmitAppMeasurementsIdentifier body:appStartMeasurements];
|
|
125
255
|
}
|
|
@@ -128,7 +258,13 @@ int64_t GetTimestampUnix()
|
|
|
128
258
|
|
|
129
259
|
- (NSNumber* )correctionOfTimestamp:(int64_t) timestamp
|
|
130
260
|
{
|
|
131
|
-
|
|
261
|
+
if constexpr (facebook::react::ReactNativeVersion.Minor < 72) {
|
|
262
|
+
// In RN < 72, timestamps are unix timestamps
|
|
263
|
+
return [NSNumber numberWithLongLong:timestamp];
|
|
264
|
+
} else {
|
|
265
|
+
// IN RN >= 72, timestamps are relative to the system start, which is we we add the unix timestamp of the system start
|
|
266
|
+
return [NSNumber numberWithLongLong:timestamp + GetTimestampUnix() - (CACurrentMediaTime() * 1000)];
|
|
267
|
+
}
|
|
132
268
|
}
|
|
133
269
|
|
|
134
270
|
/**
|
|
@@ -147,6 +283,12 @@ int64_t GetTimestampUnix()
|
|
|
147
283
|
{
|
|
148
284
|
hasListeners = YES;
|
|
149
285
|
[self emitMeasurements];
|
|
286
|
+
|
|
287
|
+
[self setupRuntimeConfigurationListenerIfNeeded];
|
|
288
|
+
|
|
289
|
+
if (lastRuntimeConfiguration != nil) {
|
|
290
|
+
[self emitToJS:EmitDynatraceConfiguration body:lastRuntimeConfiguration];
|
|
291
|
+
}
|
|
150
292
|
}
|
|
151
293
|
|
|
152
294
|
/**
|
|
@@ -157,6 +299,39 @@ int64_t GetTimestampUnix()
|
|
|
157
299
|
hasListeners = NO;
|
|
158
300
|
}
|
|
159
301
|
|
|
302
|
+
- (void)setupRuntimeConfigurationListenerIfNeeded
|
|
303
|
+
{
|
|
304
|
+
if (remoteConfigSubscribed) {
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
remoteConfigSubscribed = YES;
|
|
308
|
+
[HybridBridge addConfigurationSubscriber:(id)configurationSubscriber];
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
- (void)emitToJS:(NSString*)event body:(id)body
|
|
312
|
+
{
|
|
313
|
+
if (self.bridge == nil) {
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
id payload = body == nil ? [NSNull null] : body;
|
|
318
|
+
|
|
319
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
320
|
+
[self.bridge.eventDispatcher sendDeviceEventWithName:event body:payload];
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
- (void)handleRuntimeConfiguration:(NSDictionary<NSString*, id>*)configuration
|
|
325
|
+
{
|
|
326
|
+
lastRuntimeConfiguration = configuration;
|
|
327
|
+
|
|
328
|
+
if (!hasListeners) {
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
[self emitToJS:EmitDynatraceConfiguration body:configuration];
|
|
333
|
+
}
|
|
334
|
+
|
|
160
335
|
/**
|
|
161
336
|
* Constants which are exported to the JS part
|
|
162
337
|
*/
|
|
@@ -174,9 +349,9 @@ RCT_EXPORT_METHOD(start:(NSDictionary *) options)
|
|
|
174
349
|
if (options == nil) {
|
|
175
350
|
return;
|
|
176
351
|
}
|
|
177
|
-
|
|
352
|
+
|
|
178
353
|
NSMutableDictionary<NSString*, id> *properties = [[NSMutableDictionary alloc] init];
|
|
179
|
-
|
|
354
|
+
|
|
180
355
|
if (options[@"applicationId"] != NULL) {
|
|
181
356
|
properties[@"DTXApplicationID"] = options[@"applicationId"];
|
|
182
357
|
}
|
|
@@ -188,11 +363,11 @@ RCT_EXPORT_METHOD(start:(NSDictionary *) options)
|
|
|
188
363
|
if (options[@"userOptIn"] != NULL && [[options valueForKey:@"userOptIn"] isEqual: @(YES)]) {
|
|
189
364
|
properties[@"DTXUserOptIn"] = @YES;
|
|
190
365
|
}
|
|
191
|
-
|
|
366
|
+
|
|
192
367
|
if (options[@"reportCrash"] != NULL && [[options valueForKey:@"reportCrash"] isEqual: @(NO)]) {
|
|
193
368
|
properties[@"DTXCrashReportingEnabled"] = @NO;
|
|
194
369
|
}
|
|
195
|
-
|
|
370
|
+
|
|
196
371
|
if (options[@"logLevel"] != NULL && [((NSNumber *) options[@"logLevel"]) intValue] == 0){
|
|
197
372
|
properties[@"DTXLogLevel"] = @"ALL";
|
|
198
373
|
}
|
|
@@ -218,7 +393,7 @@ RCT_EXPORT_METHOD(enterManualAction:(NSString *)name key:(nonnull NSString *)key
|
|
|
218
393
|
if ([self shouldWorkOnIosWithPlatform: platform])
|
|
219
394
|
{
|
|
220
395
|
DTXAction *action = [DTXAction enterActionWithName:name];
|
|
221
|
-
|
|
396
|
+
|
|
222
397
|
if (action)
|
|
223
398
|
{
|
|
224
399
|
[actionDict setObject:action forKey:key];
|
|
@@ -235,7 +410,7 @@ RCT_EXPORT_METHOD(enterManualActionWithParent:(NSString *)name key:(nonnull NSSt
|
|
|
235
410
|
if (parentAction != nil)
|
|
236
411
|
{
|
|
237
412
|
DTXAction *childAction = [DTXAction enterActionWithName:name parentAction:parentAction];
|
|
238
|
-
|
|
413
|
+
|
|
239
414
|
if (childAction)
|
|
240
415
|
{
|
|
241
416
|
[actionDict setObject:childAction forKey:key];
|
|
@@ -287,11 +462,6 @@ RCT_EXPORT_METHOD(startView: (NSString *) name)
|
|
|
287
462
|
[Dynatrace startViewWithName:name];
|
|
288
463
|
}
|
|
289
464
|
|
|
290
|
-
RCT_EXPORT_METHOD(stopView)
|
|
291
|
-
{
|
|
292
|
-
[Dynatrace stopView];
|
|
293
|
-
}
|
|
294
|
-
|
|
295
465
|
RCT_EXPORT_METHOD(reportErrorWithoutStacktrace:(NSString *)errorName errorCode:(nonnull NSNumber *)errorCode platform: (NSString *) platform)
|
|
296
466
|
{
|
|
297
467
|
if ([self shouldWorkOnIosWithPlatform: platform])
|
|
@@ -315,11 +485,11 @@ RCT_EXPORT_METHOD(reportCrash:(NSString *)errorName errorReason:(NSString *)erro
|
|
|
315
485
|
if ([self shouldWorkOnIosWithPlatform: platform])
|
|
316
486
|
{
|
|
317
487
|
if(isRealError){
|
|
318
|
-
[DTXAction reportExternalCrashForPlatformType:DTXActionPlatformJavaScript crashName:errorName reason:errorReason stacktrace:stacktrace];
|
|
488
|
+
[DTXAction reportExternalCrashForPlatformType:DTXActionPlatformJavaScript crashName:errorName reason:errorReason stacktrace:stacktrace];
|
|
319
489
|
}else{
|
|
320
490
|
[DTXAction reportExternalCrashForPlatformType:DTXActionPlatformCustom crashName:errorName reason:errorReason stacktrace:stacktrace];
|
|
321
491
|
}
|
|
322
|
-
|
|
492
|
+
|
|
323
493
|
// Always end the session as the iOS agent has no troubles with this behavior
|
|
324
494
|
[Dynatrace endVisit];
|
|
325
495
|
}
|
|
@@ -397,7 +567,6 @@ RCT_EXPORT_METHOD(startWebRequestTiming:(NSString*) requestTag url:(NSString*) u
|
|
|
397
567
|
[timing startWebRequestTiming];
|
|
398
568
|
}
|
|
399
569
|
}
|
|
400
|
-
|
|
401
570
|
}
|
|
402
571
|
|
|
403
572
|
- (void)stopWebRequestTimingHelper:(NSString*) requestTag url:(NSString*)url responseCode:(nonnull NSNumber*) responseCode responseMessage:(NSString*)responseMessage bytesSent:(nonnull NSNumber*)bytesSent bytesReceived:(nonnull NSNumber*)bytesReceived
|
|
@@ -499,7 +668,7 @@ RCT_EXPORT_METHOD(getDataCollectionLevel:(NSString *) platform findEventsWithRes
|
|
|
499
668
|
if ([self shouldWorkOnIosWithPlatform: platform])
|
|
500
669
|
{
|
|
501
670
|
int i = [Dynatrace dataCollectionLevel];
|
|
502
|
-
|
|
671
|
+
|
|
503
672
|
if(i == DTX_DataCollectionUserBehavior){
|
|
504
673
|
resolve(DataCollectionUserBehavior);
|
|
505
674
|
}else if(i == DTX_DataCollectionPerformance){
|
|
@@ -542,7 +711,7 @@ RCT_EXPORT_METHOD(getUserPrivacyOptions:(NSString *) platform findEventsWithReso
|
|
|
542
711
|
{
|
|
543
712
|
id<DTXUserPrivacyOptions> privacyConfig = [Dynatrace userPrivacyOptions];
|
|
544
713
|
NSString * level;
|
|
545
|
-
|
|
714
|
+
|
|
546
715
|
if(privacyConfig.dataCollectionLevel == DTX_DataCollectionUserBehavior){
|
|
547
716
|
level = DataCollectionUserBehavior;
|
|
548
717
|
}else if(privacyConfig.dataCollectionLevel == DTX_DataCollectionPerformance){
|
|
@@ -562,7 +731,7 @@ RCT_EXPORT_METHOD(applyUserPrivacyOptions:(NSDictionary *) userPrivacyOptions pl
|
|
|
562
731
|
if ([self shouldWorkOnIosWithPlatform: platform])
|
|
563
732
|
{
|
|
564
733
|
id<DTXUserPrivacyOptions> privacyConfig = [Dynatrace userPrivacyOptions];
|
|
565
|
-
|
|
734
|
+
|
|
566
735
|
if([[userPrivacyOptions valueForKey:@"_dataCollectionLevel"] isEqualToString: DataCollectionPerformance]){
|
|
567
736
|
privacyConfig.dataCollectionLevel = DTX_DataCollectionPerformance;
|
|
568
737
|
}else if([[userPrivacyOptions valueForKey:@"_dataCollectionLevel"] isEqualToString: DataCollectionUserBehavior]){
|
|
@@ -572,7 +741,7 @@ RCT_EXPORT_METHOD(applyUserPrivacyOptions:(NSDictionary *) userPrivacyOptions pl
|
|
|
572
741
|
} else {
|
|
573
742
|
// do nothing and keep current value
|
|
574
743
|
}
|
|
575
|
-
|
|
744
|
+
|
|
576
745
|
if ([[userPrivacyOptions valueForKey:@"_crashReportingOptedIn"] isEqual: @(YES)]) {
|
|
577
746
|
privacyConfig.crashReportingOptedIn = YES;
|
|
578
747
|
} else if ([[userPrivacyOptions valueForKey:@"_crashReportingOptedIn"] isEqual: @(NO)]) {
|
|
@@ -587,10 +756,29 @@ RCT_EXPORT_METHOD(applyUserPrivacyOptions:(NSDictionary *) userPrivacyOptions pl
|
|
|
587
756
|
}
|
|
588
757
|
}
|
|
589
758
|
|
|
759
|
+
RCT_EXPORT_METHOD(getCurrentConfiguration:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
|
|
760
|
+
{
|
|
761
|
+
if (lastRuntimeConfiguration != nil) {
|
|
762
|
+
resolve(lastRuntimeConfiguration);
|
|
763
|
+
} else {
|
|
764
|
+
resolve([NSNull null]);
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
RCT_EXPORT_METHOD(startViewInternal:(NSDictionary<NSString*, id>*) fields)
|
|
769
|
+
{
|
|
770
|
+
[HybridBridge startView:fields];
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
RCT_EXPORT_METHOD(stopViewInternal)
|
|
774
|
+
{
|
|
775
|
+
[HybridBridge stopView];
|
|
776
|
+
}
|
|
777
|
+
|
|
590
778
|
- (void)newAction:(NSString *)name key:(nonnull NSString *)key parentAction:(DTXAction *)parentAction
|
|
591
779
|
{
|
|
592
780
|
DTXAction *action = [DTXAction integrateActionWithName:name];
|
|
593
|
-
|
|
781
|
+
|
|
594
782
|
if (action)
|
|
595
783
|
{
|
|
596
784
|
[actionDict setObject:action forKey:key];
|
|
@@ -602,7 +790,6 @@ RCT_EXPORT_METHOD(applyUserPrivacyOptions:(NSDictionary *) userPrivacyOptions pl
|
|
|
602
790
|
return [actionDict objectForKey:key];
|
|
603
791
|
}
|
|
604
792
|
|
|
605
|
-
|
|
606
793
|
+ (BOOL)requiresMainQueueSetup
|
|
607
794
|
{
|
|
608
795
|
return YES;
|
|
@@ -622,4 +809,4 @@ RCT_EXPORT_METHOD(applyUserPrivacyOptions:(NSDictionary *) userPrivacyOptions pl
|
|
|
622
809
|
}
|
|
623
810
|
#endif
|
|
624
811
|
|
|
625
|
-
@end
|
|
812
|
+
@end
|
package/lib/core/Dynatrace.js
CHANGED
|
@@ -338,22 +338,19 @@ exports.Dynatrace = {
|
|
|
338
338
|
},
|
|
339
339
|
addEventModifier: (eventModifier) => Dynatrace_1.Dynatrace.addEventModifier(eventModifier),
|
|
340
340
|
removeEventModifier: (eventModifier) => Dynatrace_1.Dynatrace.removeEventModifier(eventModifier),
|
|
341
|
-
sendEvent: (properties) => {
|
|
342
|
-
Dynatrace_1.Dynatrace.sendEvent(properties);
|
|
343
|
-
},
|
|
344
341
|
startView: (name) => {
|
|
345
342
|
Dynatrace_1.Dynatrace.startView(name);
|
|
346
343
|
},
|
|
347
|
-
|
|
348
|
-
Dynatrace_1.Dynatrace.
|
|
344
|
+
sendEvent: (customEvent) => {
|
|
345
|
+
Dynatrace_1.Dynatrace.sendEvent(customEvent);
|
|
349
346
|
},
|
|
350
|
-
sendSessionPropertyEvent: (
|
|
351
|
-
Dynatrace_1.Dynatrace.sendSessionPropertyEvent(
|
|
347
|
+
sendSessionPropertyEvent: (sessionPropertyEventData) => {
|
|
348
|
+
Dynatrace_1.Dynatrace.sendSessionPropertyEvent(sessionPropertyEventData);
|
|
352
349
|
},
|
|
353
|
-
sendExceptionEvent: (
|
|
354
|
-
Dynatrace_1.Dynatrace.sendExceptionEvent(
|
|
350
|
+
sendExceptionEvent: (exceptionEvent) => {
|
|
351
|
+
Dynatrace_1.Dynatrace.sendExceptionEvent(exceptionEvent);
|
|
355
352
|
},
|
|
356
|
-
sendHttpRequestEvent(
|
|
357
|
-
Dynatrace_1.Dynatrace.sendHttpRequestEvent(
|
|
353
|
+
sendHttpRequestEvent: (httpRequestEvent) => {
|
|
354
|
+
Dynatrace_1.Dynatrace.sendHttpRequestEvent(httpRequestEvent);
|
|
358
355
|
},
|
|
359
356
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ConfigurationHandler = void 0;
|
|
4
|
+
const RuntimeConfigurationObserver_1 = require("../../next/configuration/RuntimeConfigurationObserver");
|
|
4
5
|
const LogLevel_1 = require("../logging/LogLevel");
|
|
5
6
|
let _configuration;
|
|
6
7
|
exports.ConfigurationHandler = {
|
|
@@ -14,6 +15,8 @@ exports.ConfigurationHandler = {
|
|
|
14
15
|
_configuration.logLevel === LogLevel_1.LogLevel.Debug,
|
|
15
16
|
isLifecycleUpdateEnabled: () => _configuration.lifecycleUpdate,
|
|
16
17
|
isActionNamePrivacyEnabled: () => _configuration.actionNamePrivacy,
|
|
18
|
+
isGrailEnabled: () => RuntimeConfigurationObserver_1.RuntimeConfigurationObserver.getCurrentRuntimeConfiguration()['3rd_gen_enabled'],
|
|
19
|
+
isRuntimeConfigurationInitiated: () => RuntimeConfigurationObserver_1.RuntimeConfigurationObserver.isInitiated(),
|
|
17
20
|
getBundleName: () => _configuration.bundleName,
|
|
18
21
|
getBundleVersion: () => _configuration.bundleVersion,
|
|
19
22
|
};
|
package/lib/next/Dynatrace.js
CHANGED
|
@@ -7,7 +7,6 @@ const EventCreator_1 = require("./events/EventCreator");
|
|
|
7
7
|
const EventPipeline_1 = require("./events/EventPipeline");
|
|
8
8
|
const EventTimestamp_1 = require("./events/EventTimestamp");
|
|
9
9
|
const EventModifierUtil_1 = require("./events/modifier/EventModifierUtil");
|
|
10
|
-
const SendEventValidation_1 = require("./events/modifier/SendEventValidation");
|
|
11
10
|
const TimestampProvider_1 = require("./provider/TimestampProvider");
|
|
12
11
|
class DynatraceImpl {
|
|
13
12
|
constructor(timestampProvider) {
|
|
@@ -24,7 +23,6 @@ class DynatraceImpl {
|
|
|
24
23
|
}
|
|
25
24
|
startView(name) {
|
|
26
25
|
this.logger.debug(`startView(${name})`);
|
|
27
|
-
EventPipeline_1.EventPipeline.generateViewData(name);
|
|
28
26
|
if (name != null && name.length > 0) {
|
|
29
27
|
DynatraceBridge_1.DynatraceNative.startView(name);
|
|
30
28
|
}
|
|
@@ -32,11 +30,6 @@ class DynatraceImpl {
|
|
|
32
30
|
this.logger.debug(`startView(${name}): Name can't be used. Either empty or null!`);
|
|
33
31
|
}
|
|
34
32
|
}
|
|
35
|
-
stopView() {
|
|
36
|
-
this.logger.debug('stopView()');
|
|
37
|
-
EventPipeline_1.EventPipeline.releaseViewData();
|
|
38
|
-
DynatraceBridge_1.DynatraceNative.stopView();
|
|
39
|
-
}
|
|
40
33
|
reportCrash(crash, isApiReported, isFatal = true) {
|
|
41
34
|
this.logger.debug(`reportCrash(${JSON.stringify(crash)}, ${isFatal})`);
|
|
42
35
|
const eventTimestamp = new EventTimestamp_1.EventTimestamp(this.timestampProvider);
|
|
@@ -67,42 +60,31 @@ class DynatraceImpl {
|
|
|
67
60
|
}
|
|
68
61
|
EventPipeline_1.EventPipeline.insertEvent(event);
|
|
69
62
|
}
|
|
70
|
-
sendExceptionEvent(
|
|
71
|
-
this.logger.debug(
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
eventValidated = Object.assign({}, SendEventValidation_1.SendEventValidation.modifyEvent(fields));
|
|
63
|
+
sendExceptionEvent(exceptionEventData) {
|
|
64
|
+
this.logger.debug('sendExceptionEvent(exceptionEventData)');
|
|
65
|
+
const eventValidated = exceptionEventData.toJSON();
|
|
66
|
+
if (eventValidated !== null) {
|
|
67
|
+
EventPipeline_1.EventPipeline.insertEvent(eventValidated);
|
|
76
68
|
}
|
|
77
|
-
eventValidated = Object.assign(Object.assign({}, event), eventValidated);
|
|
78
|
-
(0, EventModifierUtil_1.addIsApiReported)(eventValidated);
|
|
79
|
-
EventPipeline_1.EventPipeline.insertEvent(eventValidated);
|
|
80
69
|
}
|
|
81
|
-
sendEvent(
|
|
82
|
-
this.logger.debug(
|
|
83
|
-
const eventValidated =
|
|
70
|
+
sendEvent(eventData) {
|
|
71
|
+
this.logger.debug('sendEvent(eventData)');
|
|
72
|
+
const eventValidated = eventData.toJSON();
|
|
84
73
|
if (eventValidated !== null) {
|
|
85
|
-
(0, EventModifierUtil_1.flagEventProperties)(eventValidated);
|
|
86
|
-
(0, EventModifierUtil_1.addIsApiReported)(eventValidated);
|
|
87
74
|
EventPipeline_1.EventPipeline.insertEvent(eventValidated);
|
|
88
75
|
}
|
|
89
76
|
}
|
|
90
|
-
sendSessionPropertyEvent(
|
|
91
|
-
this.logger.debug(
|
|
92
|
-
const eventValidated =
|
|
77
|
+
sendSessionPropertyEvent(sessionPropertyEventData) {
|
|
78
|
+
this.logger.debug('sendSessionPropertyEvent(SessionPropertyEventData)');
|
|
79
|
+
const eventValidated = sessionPropertyEventData.toJSON();
|
|
93
80
|
if (eventValidated !== null) {
|
|
94
|
-
if ((0, EventModifierUtil_1.containSessionProperties)(eventValidated)) {
|
|
95
|
-
eventValidated["characteristics.has_session_properties"] = true;
|
|
96
|
-
}
|
|
97
|
-
(0, EventModifierUtil_1.addIsApiReported)(eventValidated);
|
|
98
81
|
EventPipeline_1.EventPipeline.insertEvent(eventValidated);
|
|
99
82
|
}
|
|
100
83
|
}
|
|
101
|
-
sendHttpRequestEvent(
|
|
102
|
-
|
|
103
|
-
|
|
84
|
+
sendHttpRequestEvent(httpRequestEvent) {
|
|
85
|
+
this.logger.debug('sendHttpRequestEvent(HttpRequestEventData)');
|
|
86
|
+
const sanitizedEvent = httpRequestEvent.toJSON();
|
|
104
87
|
if (sanitizedEvent !== null) {
|
|
105
|
-
(0, EventModifierUtil_1.flagEventProperties)(sanitizedEvent);
|
|
106
88
|
EventPipeline_1.EventPipeline.insertEvent(sanitizedEvent);
|
|
107
89
|
}
|
|
108
90
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.addListenerOnce = exports.createEmitterNativeOnly = exports.createEmitterRuntimeConfig = void 0;
|
|
4
|
+
const react_native_1 = require("react-native");
|
|
5
|
+
const DynatraceBridge_1 = require("../core/DynatraceBridge");
|
|
6
|
+
const isEmptyObject = (value) => {
|
|
7
|
+
if (value == null) {
|
|
8
|
+
return true;
|
|
9
|
+
}
|
|
10
|
+
if (typeof value !== 'object') {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
return Object.keys(value).length === 0;
|
|
14
|
+
};
|
|
15
|
+
const createEmitterRuntimeConfig = () => {
|
|
16
|
+
if (react_native_1.Platform.OS === 'ios' && isEmptyObject(DynatraceBridge_1.DynatraceNative || {})) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
const iosModule = react_native_1.NativeModules.DynatraceBridge;
|
|
20
|
+
const nativeEmitterModule = react_native_1.Platform.OS === 'android' ? DynatraceBridge_1.DynatraceNative : iosModule;
|
|
21
|
+
return new react_native_1.NativeEventEmitter(nativeEmitterModule);
|
|
22
|
+
};
|
|
23
|
+
exports.createEmitterRuntimeConfig = createEmitterRuntimeConfig;
|
|
24
|
+
const createEmitterNativeOnly = () => new react_native_1.NativeEventEmitter(DynatraceBridge_1.DynatraceNative);
|
|
25
|
+
exports.createEmitterNativeOnly = createEmitterNativeOnly;
|
|
26
|
+
const addListenerOnce = (emitter, current, eventName, handler) => {
|
|
27
|
+
if (current != null) {
|
|
28
|
+
return current;
|
|
29
|
+
}
|
|
30
|
+
if (emitter == null) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
return emitter.addListener(eventName, handler);
|
|
34
|
+
};
|
|
35
|
+
exports.addListenerOnce = addListenerOnce;
|