@dynatrace/react-native-plugin 2.321.2 → 2.323.2
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 +54 -17
- package/android/build.gradle +3 -3
- package/files/plugin-runtime.gradle +8 -1
- package/files/plugin.gradle +1 -1
- package/index.js +1 -0
- package/instrumentation/DynatraceInstrumentation.js +1 -1
- package/instrumentation/jsx/CreateElement.js +1 -1
- package/instrumentation/jsx/ElementHelper.js +2 -21
- package/instrumentation/jsx/IDynatraceProperties.js +0 -7
- package/instrumentation/jsx/JsxDevRuntime.js +2 -7
- package/instrumentation/jsx/JsxRuntime.js +2 -7
- package/instrumentation/jsx/components/ComponentUtil.js +12 -1
- package/instrumentation/jsx/components/Picker.js +3 -3
- package/instrumentation/jsx/components/RefreshControl.js +3 -3
- package/instrumentation/libs/community/gesture-handler/Touchables.js +7 -37
- package/instrumentation/libs/react-native/Switch.js +55 -12
- package/instrumentation/libs/react-native/Touchables.js +8 -47
- package/instrumentation/libs/withOnPressMonitoring.js +121 -0
- package/instrumentation/model/Types.js +3 -15
- package/instrumentation/model/TypesUtil.js +5 -34
- package/lib/core/Dynatrace.js +4 -1
- package/lib/core/ErrorHandler.js +18 -34
- package/lib/next/Dynatrace.js +16 -10
- package/lib/next/events/EventCreator.js +2 -1
- package/lib/next/events/HttpRequestEventBuilder.js +196 -0
- package/lib/next/events/ViewInfoCreator.js +1 -1
- package/lib/next/events/modifier/EventModifierUtil.js +14 -1
- package/lib/next/events/modifier/SendEventValidation.js +23 -10
- package/lib/next/events/spec/EventSpecContstants.js +1 -1
- package/package.json +6 -4
- package/react-native-dynatrace.podspec +1 -1
- package/scripts/Ios.js +1 -1
- package/scripts/Logger.js +20 -1
- package/scripts/core/InstrumentCall.js +62 -34
- package/scripts/util/SourceMapUtil.js +4 -4
- package/src/instrumentation/jsx/IDynatraceProperties.ts +15 -0
- package/typings/react-native-dynatrace.d.ts +130 -1
- package/instrumentation/jsx/components/Switch.js +0 -57
- package/instrumentation/jsx/components/Touchable.js +0 -151
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.containEventPropertiesInArray = exports.containEventProperties = exports.containSessionProperties = exports.trimStringValuesInObject = exports.trimString = exports.isObject = exports.flattenAdditionalData = void 0;
|
|
3
|
+
exports.containEventPropertiesInArray = exports.addIsApiReported = exports.flagEventProperties = exports.containEventProperties = exports.containSessionProperties = exports.trimStringValuesInObject = exports.trimString = exports.isObject = exports.flattenAdditionalData = void 0;
|
|
4
4
|
const MAX_STRING_LENGTH_FOR_VALUES = 5000;
|
|
5
5
|
const flattenAdditionalData = (obj, parent, res = {}) => {
|
|
6
6
|
for (const key in obj) {
|
|
@@ -60,6 +60,19 @@ const containEventProperties = (jsonData) => {
|
|
|
60
60
|
return false;
|
|
61
61
|
};
|
|
62
62
|
exports.containEventProperties = containEventProperties;
|
|
63
|
+
const flagEventProperties = (event) => {
|
|
64
|
+
if (event !== null && (0, exports.containEventProperties)(event)) {
|
|
65
|
+
event["characteristics.has_event_properties"] =
|
|
66
|
+
true;
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
exports.flagEventProperties = flagEventProperties;
|
|
70
|
+
const addIsApiReported = (event) => {
|
|
71
|
+
if (event !== null) {
|
|
72
|
+
event["characteristics.is_api_reported"] = true;
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
exports.addIsApiReported = addIsApiReported;
|
|
63
76
|
const containEventPropertiesInArray = (eventEntries) => {
|
|
64
77
|
for (const [key, value] of eventEntries) {
|
|
65
78
|
if (key.startsWith(`${"event_properties"}.`)) {
|
|
@@ -23,18 +23,17 @@ class SendEventValidationImpl {
|
|
|
23
23
|
}
|
|
24
24
|
const timeNow = this.timestampProvider.getCurrentTimestamp();
|
|
25
25
|
const eventCopy = Object.entries(event).slice();
|
|
26
|
-
const filteredEvent = eventCopy
|
|
27
|
-
.filter(this.isKeyNameAllowed, this)
|
|
28
|
-
.filter(this.isFieldTypeAllowed, this);
|
|
26
|
+
const filteredEvent = eventCopy.filter(this.isKeyNameAllowed, this);
|
|
29
27
|
const limitedEntries = new EventLimitation_1.EventLimitation().limitEventEntries(filteredEvent);
|
|
30
28
|
const sizedEntries = new EventLimitation_1.EventLimitation().limitEventProperties(limitedEntries);
|
|
31
|
-
this.applyOverriddenKeys(sizedEntries);
|
|
32
29
|
if (sizedEntries.length < eventCopy.length) {
|
|
33
30
|
sizedEntries.push([
|
|
34
31
|
"dt.support.api.has_dropped_custom_properties",
|
|
35
32
|
true,
|
|
36
33
|
]);
|
|
37
34
|
}
|
|
35
|
+
this.sanitizeDuration(sizedEntries);
|
|
36
|
+
this.applyOverriddenKeys(sizedEntries);
|
|
38
37
|
const jsonObject = Object.fromEntries(sizedEntries);
|
|
39
38
|
if (jsonObject["duration"] !== undefined) {
|
|
40
39
|
jsonObject["start_time"] =
|
|
@@ -60,13 +59,27 @@ class SendEventValidationImpl {
|
|
|
60
59
|
]);
|
|
61
60
|
}
|
|
62
61
|
}
|
|
63
|
-
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
key === "
|
|
67
|
-
|
|
62
|
+
sanitizeDuration(event) {
|
|
63
|
+
for (const entry of event) {
|
|
64
|
+
const [key, value] = entry;
|
|
65
|
+
if (key === "duration") {
|
|
66
|
+
if (typeof value !== 'number' ||
|
|
67
|
+
!isFinite(value) ||
|
|
68
|
+
value < 0) {
|
|
69
|
+
entry[1] = 0;
|
|
70
|
+
event.push([
|
|
71
|
+
"dt.support.api.has_dropped_custom_properties",
|
|
72
|
+
true,
|
|
73
|
+
]);
|
|
74
|
+
}
|
|
75
|
+
if (typeof value === 'number' && !isFinite(value)) {
|
|
76
|
+
event.push([
|
|
77
|
+
"dt.support.has_nfn_values",
|
|
78
|
+
true,
|
|
79
|
+
]);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
68
82
|
}
|
|
69
|
-
return true;
|
|
70
83
|
}
|
|
71
84
|
isKeyNameAllowed(entry) {
|
|
72
85
|
const [key] = entry;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ALL_APP_START_KEYS = exports.MODIFY_EVENT_WHITELIST_NAMESPACE = exports.MODIFY_EVENT_WHITELIST_FIELDS = exports.SEND_SESSION_PROPERTY_EVENT_WHITELIST_FIELDS = exports.SEND_EVENT_WHITELIST_FIELDS = exports.SEND_SESSION_PROPERTY_EVENT_WHITELIST_NAMESPACES = exports.SEND_EVENT_WHITELIST_NAMESPACES = exports.AllCharacteristicsKeys = exports.KEY_NAME_REGEX = exports.MAX_CUSTOM_EVENT_VALUE_LENGTH = exports.MAX_CUSTOM_EVENT_KEY_LENGTH = exports.MAX_CUSTOM_EVENT_FIELDS = void 0;
|
|
4
|
-
const SPECIFICATION_VERSION = '0.
|
|
4
|
+
const SPECIFICATION_VERSION = '0.22';
|
|
5
5
|
exports.MAX_CUSTOM_EVENT_FIELDS = 50;
|
|
6
6
|
exports.MAX_CUSTOM_EVENT_KEY_LENGTH = 100;
|
|
7
7
|
exports.MAX_CUSTOM_EVENT_VALUE_LENGTH = 5000;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dynatrace/react-native-plugin",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.323.2",
|
|
4
4
|
"description": "This plugin gives you the ability to use the Dynatrace Mobile agent in your react native application.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "typings/react-native-dynatrace.d.ts",
|
|
@@ -101,6 +101,7 @@
|
|
|
101
101
|
"jest-mock": "^30.0.2",
|
|
102
102
|
"npm-check-updates": "^18.0.1",
|
|
103
103
|
"prettier": "^2.6.1",
|
|
104
|
+
"react-native-gesture-handler": "^2.28.0",
|
|
104
105
|
"shelljs": "^0.10.0",
|
|
105
106
|
"ts-jest": "^29.4.0",
|
|
106
107
|
"typescript": "^4.7.4",
|
|
@@ -154,7 +155,8 @@
|
|
|
154
155
|
"lib/next/events/modifier/*.js",
|
|
155
156
|
"lib/next/events/spec/*.js",
|
|
156
157
|
"lib/next/provider/*.js",
|
|
157
|
-
"src/lib/core/interface/NativeDynatraceBridge.ts"
|
|
158
|
+
"src/lib/core/interface/NativeDynatraceBridge.ts",
|
|
159
|
+
"src/instrumentation/jsx/IDynatraceProperties.ts"
|
|
158
160
|
],
|
|
159
161
|
"codegenConfig": {
|
|
160
162
|
"name": "DynatraceBridgeSpec",
|
|
@@ -165,6 +167,6 @@
|
|
|
165
167
|
}
|
|
166
168
|
},
|
|
167
169
|
"engines": {
|
|
168
|
-
"node": ">=
|
|
170
|
+
"node": ">=16"
|
|
169
171
|
}
|
|
170
|
-
}
|
|
172
|
+
}
|
|
@@ -111,7 +111,7 @@ Pod::Spec.new do |s|
|
|
|
111
111
|
#
|
|
112
112
|
|
|
113
113
|
s.dependency "React"
|
|
114
|
-
s.dependency 'Dynatrace', '~> 8.
|
|
114
|
+
s.dependency 'Dynatrace', '~> 8.323.1.1009'
|
|
115
115
|
|
|
116
116
|
# Allows for better compatibility for older and newer versions
|
|
117
117
|
if defined?(install_modules_dependencies)
|
package/scripts/Ios.js
CHANGED
|
@@ -186,7 +186,7 @@ const createNewPListIfRequired = (parsedPList, configProps, pathToPList) => {
|
|
|
186
186
|
const configIncludingFlavor = configProps + getAdditionalInternalPluginKeys() + updatedExcludedStr(configProps);
|
|
187
187
|
if (isPropertyCountEqual(parsedPList, configIncludingFlavor) && comparePListAndConfig(parsedPList, configIncludingFlavor)) {
|
|
188
188
|
Logger_1.default.logMessageSync('Not generating a new plist as the current plist and ' +
|
|
189
|
-
'
|
|
189
|
+
'dynatrace.config.js iOS properties are identical!', Logger_1.default.INFO);
|
|
190
190
|
}
|
|
191
191
|
else {
|
|
192
192
|
Logger_1.default.logMessageSync('Generating a new plist as the current plist ' +
|
package/scripts/Logger.js
CHANGED
|
@@ -41,19 +41,23 @@ const logMessageSync = (_message, _logLevel, _onlyConsole = false) => {
|
|
|
41
41
|
catch (e) {
|
|
42
42
|
}
|
|
43
43
|
let logString;
|
|
44
|
+
let prefix = '';
|
|
44
45
|
if (_logLevel === INFO) {
|
|
45
46
|
logString = '#INFO ';
|
|
47
|
+
prefix = _prefix.info;
|
|
46
48
|
}
|
|
47
49
|
else if (_logLevel === WARNING) {
|
|
48
50
|
logString = '#WARN ';
|
|
51
|
+
prefix = _prefix.warning;
|
|
49
52
|
}
|
|
50
53
|
else if (_logLevel === ERROR) {
|
|
51
54
|
logString = '#ERROR ';
|
|
55
|
+
prefix = _prefix.error;
|
|
52
56
|
}
|
|
53
57
|
else {
|
|
54
58
|
logString = '#NONE ';
|
|
55
59
|
}
|
|
56
|
-
const outputString = logString + '[' + currentDate() + ']: ' + _message;
|
|
60
|
+
const outputString = logString + '[' + currentDate() + ']: ' + prefix + _message;
|
|
57
61
|
console.log(outputString);
|
|
58
62
|
if (!_onlyConsole) {
|
|
59
63
|
fs.appendFileSync(PathsConstants_1.default.getCurrentLogPath(), outputString + '\r\n');
|
|
@@ -67,10 +71,25 @@ const currentDate = () => {
|
|
|
67
71
|
const localISOTime = (new Date(Date.now() - tzoffset)).toISOString().slice(0, -5);
|
|
68
72
|
return localISOTime.replace('T', ' ');
|
|
69
73
|
};
|
|
74
|
+
const noPrefix = {
|
|
75
|
+
info: '',
|
|
76
|
+
warning: '',
|
|
77
|
+
error: '',
|
|
78
|
+
};
|
|
79
|
+
let _prefix = noPrefix;
|
|
70
80
|
exports.default = {
|
|
71
81
|
ERROR,
|
|
72
82
|
INFO,
|
|
73
83
|
WARNING,
|
|
84
|
+
withPrefix(prefix, callback) {
|
|
85
|
+
try {
|
|
86
|
+
_prefix = Object.assign(Object.assign({}, _prefix), prefix);
|
|
87
|
+
return callback();
|
|
88
|
+
}
|
|
89
|
+
finally {
|
|
90
|
+
_prefix = noPrefix;
|
|
91
|
+
}
|
|
92
|
+
},
|
|
74
93
|
closeLogFile,
|
|
75
94
|
logMessageSync,
|
|
76
95
|
logErrorSync,
|
|
@@ -6,14 +6,42 @@ const Logger_1 = require("../Logger");
|
|
|
6
6
|
const Config_1 = require("../Config");
|
|
7
7
|
const android = require("../Android");
|
|
8
8
|
const PathsConstants_1 = require("../PathsConstants");
|
|
9
|
+
const nodePath = require("path");
|
|
9
10
|
const Ios_1 = require("../Ios");
|
|
10
11
|
const InstrumentUtil_1 = require("../util/InstrumentUtil");
|
|
11
12
|
const CustomArgumentUtil_1 = require("../util/CustomArgumentUtil");
|
|
12
13
|
const Platform_1 = require("../api/model/Platform");
|
|
13
14
|
const SourceMapUtil_1 = require("../util/SourceMapUtil");
|
|
14
15
|
const instrumentCommand = () => {
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
if (process.argv.includes('--help')) {
|
|
17
|
+
Logger_1.default.logMessageSync(`
|
|
18
|
+
Usage: npx instrumentDynatrace [options]
|
|
19
|
+
|
|
20
|
+
Options:
|
|
21
|
+
--help Show this help message and exit.
|
|
22
|
+
config="/custom/path/to/dynatrace.config.js"
|
|
23
|
+
Specify a custom path to the Dynatrace configuration file.
|
|
24
|
+
Default: ${PathsConstants_1.default.getConfigFilePath()}
|
|
25
|
+
gradle="/custom/path/to/build.gradle(.kts)"
|
|
26
|
+
Specify a custom path to the top level build.gradle file of your android project.
|
|
27
|
+
Default: ${PathsConstants_1.default.getAndroidGradleFile(PathsConstants_1.default.getAndroidFolder())}
|
|
28
|
+
plist="/custom/path/to/Info.plist"
|
|
29
|
+
Specify a custom path to the Info.plist file of your ios project.
|
|
30
|
+
Default: Extracts <appName> from app.json and then tries
|
|
31
|
+
${nodePath.join(PathsConstants_1.default.getIOSFolder(), "<appName>", 'Info.plist')}
|
|
32
|
+
and ${nodePath.join(PathsConstants_1.default.getIOSFolder(), "<appName>", "Supporting", "Info.plist")}
|
|
33
|
+
in that order
|
|
34
|
+
|
|
35
|
+
Examples:
|
|
36
|
+
npx instrumentDynatrace
|
|
37
|
+
npx instrumentDynatrace config="/custom/path/to/dynatrace.config.js"
|
|
38
|
+
npx instrumentDynatrace gradle="/custom/path/to/build.gradle"
|
|
39
|
+
npx instrumentDynatrace plist="/custom/path/to/Info.plist"
|
|
40
|
+
`, Logger_1.default.INFO);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
Logger_1.default.logMessageSync('⏳ Starting instrumentation of React Native application ..', Logger_1.default.INFO);
|
|
44
|
+
Logger_1.default.withPrefix({ info: ' ℹ️ ', warning: ' ⚠️ ' }, () => (0, InstrumentUtil_1.showVersionOfPlugin)());
|
|
17
45
|
let pathToConfig = PathsConstants_1.default.getConfigFilePath();
|
|
18
46
|
let pathToGradle = PathsConstants_1.default.getAndroidGradleFile(PathsConstants_1.default.getAndroidFolder());
|
|
19
47
|
const pathToAppGradle = PathsConstants_1.default.getAndroidAppGradleFile(PathsConstants_1.default.getAndroidFolder());
|
|
@@ -30,69 +58,69 @@ const instrumentCommand = () => {
|
|
|
30
58
|
if (argv.isCustomConfigurationPathSet()) {
|
|
31
59
|
pathToConfig = argv.getCustomConfigurationPath();
|
|
32
60
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
61
|
+
Logger_1.default.withPrefix({ info: ' ℹ️ ', warning: ' ⚠️ ', error: ' ❌ ' }, () => {
|
|
62
|
+
if (argv.isCustomGradlePathSet()) {
|
|
63
|
+
pathToGradle = argv.getCustomGradlePath();
|
|
64
|
+
androidAvailable = (0, InstrumentUtil_1.isPlatformAvailable)(pathToGradle, Platform_1.Platform.Android);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
androidAvailable = (0, InstrumentUtil_1.isPlatformAvailable)(PathsConstants_1.default.getAndroidFolder(), Platform_1.Platform.Android);
|
|
68
|
+
}
|
|
69
|
+
if (argv.isCustomPlistPathSet()) {
|
|
70
|
+
pathToPList = (0, path_1.resolve)(argv.getCustomPlistPath());
|
|
71
|
+
iosAvailable = (0, InstrumentUtil_1.isPlatformAvailable)(pathToPList, Platform_1.Platform.IOS);
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
iosAvailable = (0, InstrumentUtil_1.isPlatformAvailable)(PathsConstants_1.default.getIOSFolder(), Platform_1.Platform.IOS);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
47
77
|
pathToConfig = (0, path_1.resolve)(pathToConfig);
|
|
48
78
|
pathToGradle = (0, path_1.resolve)(pathToGradle);
|
|
49
79
|
if (iosAvailable || androidAvailable) {
|
|
50
80
|
try {
|
|
51
|
-
Logger_1.default.logMessageSync('Trying to read configuration file: ' + pathToConfig, Logger_1.default.INFO);
|
|
81
|
+
Logger_1.default.logMessageSync('⏳ Trying to read configuration file: ' + pathToConfig, Logger_1.default.INFO);
|
|
52
82
|
const configAgent = (0, Config_1.readConfig)(pathToConfig);
|
|
53
83
|
if (androidAvailable) {
|
|
54
84
|
try {
|
|
55
|
-
Logger_1.default.logMessageSync('Starting Android Instrumentation with Dynatrace!', Logger_1.default.INFO);
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
85
|
+
Logger_1.default.logMessageSync('⏳ Starting Android Instrumentation with Dynatrace!', Logger_1.default.INFO);
|
|
86
|
+
Logger_1.default.withPrefix({ info: ' ℹ️ ', warning: ' ⚠️ ', error: ' ❌ ' }, () => {
|
|
87
|
+
android.instrumentAndroidPlatform(pathToGradle, false);
|
|
88
|
+
android.writeGradleConfig(configAgent.android);
|
|
89
|
+
android.ensureRuntimeScriptApplied(pathToAppGradle);
|
|
90
|
+
});
|
|
59
91
|
android.copyGradleConfigFile(pathToGradle);
|
|
92
|
+
Logger_1.default.logMessageSync(' ✅ Finished Android Instrumentation with Dynatrace!', Logger_1.default.INFO);
|
|
60
93
|
}
|
|
61
94
|
catch (e) {
|
|
62
95
|
if (e instanceof Error) {
|
|
63
|
-
Logger_1.default.logMessageSync(e.message, Logger_1.default.ERROR);
|
|
96
|
+
Logger_1.default.logMessageSync(' ❌ Android Instrumentation failed: ' + e.message, Logger_1.default.ERROR);
|
|
64
97
|
}
|
|
65
98
|
}
|
|
66
|
-
finally {
|
|
67
|
-
Logger_1.default.logMessageSync('Finished Android Instrumentation with Dynatrace!', Logger_1.default.INFO);
|
|
68
|
-
}
|
|
69
99
|
}
|
|
70
100
|
if (iosAvailable) {
|
|
71
101
|
try {
|
|
72
|
-
Logger_1.default.logMessageSync('Starting iOS Instrumentation with Dynatrace!', Logger_1.default.INFO);
|
|
73
|
-
Ios_1.default.modifyPListFile(pathToPList, configAgent.ios, false);
|
|
102
|
+
Logger_1.default.logMessageSync('⏳ Starting iOS Instrumentation with Dynatrace!', Logger_1.default.INFO);
|
|
103
|
+
Logger_1.default.withPrefix({ info: ' ℹ️ ', warning: ' ⚠️ ', error: ' ❌ ' }, () => Ios_1.default.modifyPListFile(pathToPList, configAgent.ios, false));
|
|
104
|
+
Logger_1.default.logMessageSync(' ✅ Finished iOS Instrumentation with Dynatrace!', Logger_1.default.INFO);
|
|
74
105
|
}
|
|
75
106
|
catch (e) {
|
|
76
107
|
if (e instanceof Error) {
|
|
77
|
-
Logger_1.default.logMessageSync(e.message, Logger_1.default.ERROR);
|
|
108
|
+
Logger_1.default.logMessageSync(' ❌ iOS Instrumentation failed: ' + e.message, Logger_1.default.ERROR);
|
|
78
109
|
}
|
|
79
110
|
}
|
|
80
|
-
finally {
|
|
81
|
-
Logger_1.default.logMessageSync('Finished iOS Instrumentation with Dynatrace!', Logger_1.default.INFO);
|
|
82
|
-
}
|
|
83
111
|
}
|
|
84
112
|
(0, SourceMapUtil_1.patchMetroSourceMap)();
|
|
113
|
+
Logger_1.default.logMessageSync('🎉 Finished instrumentation of React Native application ..', Logger_1.default.INFO);
|
|
85
114
|
}
|
|
86
115
|
catch (e) {
|
|
87
116
|
if (e instanceof Error) {
|
|
88
|
-
Logger_1.default.logMessageSync(e.message, Logger_1.default.ERROR);
|
|
117
|
+
Logger_1.default.logMessageSync('❌ Instrumentation failed: ' + e.message, Logger_1.default.ERROR);
|
|
89
118
|
}
|
|
90
119
|
}
|
|
91
120
|
}
|
|
92
121
|
else {
|
|
93
|
-
Logger_1.default.logMessageSync('Both Android and iOS Folder are not available - Skip instrumentation.', Logger_1.default.WARNING);
|
|
122
|
+
Logger_1.default.logMessageSync('⚠️ Both Android and iOS Folder are not available - Skip instrumentation.', Logger_1.default.WARNING);
|
|
94
123
|
}
|
|
95
|
-
Logger_1.default.logMessageSync('Finished instrumentation of React Native application ..', Logger_1.default.INFO);
|
|
96
124
|
Logger_1.default.closeLogFile();
|
|
97
125
|
};
|
|
98
126
|
exports.instrumentCommand = instrumentCommand;
|
|
@@ -8,11 +8,11 @@ const FileOperationHelper_1 = require("../FileOperationHelper");
|
|
|
8
8
|
exports.SOURCE_MAP_BACKUP_FILE = 'getSourceMapInfoOrig.js';
|
|
9
9
|
exports.SOURCE_MAP_FILE = 'getSourceMapInfo.js';
|
|
10
10
|
const patchMetroSourceMap = () => {
|
|
11
|
-
Logger_1.default.logMessageSync('Patching SourceMap generation of Metro .. ', Logger_1.default.INFO);
|
|
11
|
+
Logger_1.default.logMessageSync('⏳ Patching SourceMap generation of Metro .. ', Logger_1.default.INFO);
|
|
12
12
|
const origSourceMapPath = (0, path_1.join)(PathsConstants_1.default.getMetroSouceMapPath(), exports.SOURCE_MAP_BACKUP_FILE);
|
|
13
13
|
try {
|
|
14
14
|
FileOperationHelper_1.default.checkIfFileExistsSync(origSourceMapPath);
|
|
15
|
-
Logger_1.default.logMessageSync('Patching of SourceMap already happened!', Logger_1.default.INFO);
|
|
15
|
+
Logger_1.default.logMessageSync(' ℹ️ Patching of SourceMap already happened!', Logger_1.default.INFO);
|
|
16
16
|
}
|
|
17
17
|
catch (e) {
|
|
18
18
|
try {
|
|
@@ -20,10 +20,10 @@ const patchMetroSourceMap = () => {
|
|
|
20
20
|
FileOperationHelper_1.default.checkIfFileExistsSync(currentSourceMapPath);
|
|
21
21
|
FileOperationHelper_1.default.renameFileSync(currentSourceMapPath, origSourceMapPath);
|
|
22
22
|
FileOperationHelper_1.default.copyFileSync(PathsConstants_1.default.getOurSourceMapFile(), currentSourceMapPath);
|
|
23
|
-
Logger_1.default.logMessageSync('Patching of SourceMap successful!', Logger_1.default.INFO);
|
|
23
|
+
Logger_1.default.logMessageSync(' ✅ Patching of SourceMap successful!', Logger_1.default.INFO);
|
|
24
24
|
}
|
|
25
25
|
catch (e) {
|
|
26
|
-
Logger_1.default.logMessageSync('Patching of SourceMap generation failed!', Logger_1.default.ERROR);
|
|
26
|
+
Logger_1.default.logMessageSync(' ❌ Patching of SourceMap generation failed!', Logger_1.default.ERROR);
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interface which is containing the additional properties available for instrumentation.
|
|
3
|
+
*/
|
|
4
|
+
export interface IDynatraceProperties {
|
|
5
|
+
/**
|
|
6
|
+
* This string is changing the name of the action. So it is possible to override the action naming.
|
|
7
|
+
*/
|
|
8
|
+
dtActionName?: string;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* If true is passed the auto instrumentation will skip the action creation. We allow both string
|
|
12
|
+
* and boolean.
|
|
13
|
+
*/
|
|
14
|
+
dtActionIgnore?: boolean | 'true' | 'false';
|
|
15
|
+
}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import 'react'
|
|
2
|
+
import { IDynatraceProperties } from '../src/instrumentation/jsx/IDynatraceProperties';
|
|
3
|
+
|
|
1
4
|
/**
|
|
2
5
|
* react-native-dynatrace.d.ts
|
|
3
6
|
*
|
|
@@ -526,7 +529,7 @@ export declare const Dynatrace: {
|
|
|
526
529
|
*
|
|
527
530
|
* @see https://www.npmjs.com/package/@dynatrace/react-native-plugin#manually-report-a-crash
|
|
528
531
|
*/
|
|
529
|
-
reportCrashWithException(crashName: string, crash: Error, platform?: Platform);
|
|
532
|
+
reportCrashWithException(crashName: string, crash: Error, platform?: Platform): void;
|
|
530
533
|
|
|
531
534
|
/**
|
|
532
535
|
* Puts a set of http headers on every agent http request (eg. the Authorization header). It also triggers the agent to
|
|
@@ -637,6 +640,35 @@ export declare const Dynatrace: {
|
|
|
637
640
|
* @param properties any attributes that should be reported for every event in the session.
|
|
638
641
|
*/
|
|
639
642
|
sendSessionPropertyEvent(properties: JSONObject): void;
|
|
643
|
+
|
|
644
|
+
/**
|
|
645
|
+
*
|
|
646
|
+
* Send an HttpRequestEvent by passing in an instance of HttpRequestEventBuilder.
|
|
647
|
+
* The Builder allows you to configure common properties of an HttpRequest like url, requestMethod and duration.
|
|
648
|
+
* Additionally, it allows you to set custom event properties.
|
|
649
|
+
*
|
|
650
|
+
* @param httpRequestEventBuilder Mandatory Builder which allows you to configure common properties of an HttpRequest
|
|
651
|
+
*
|
|
652
|
+
* Usage:
|
|
653
|
+
*
|
|
654
|
+
* ```ts
|
|
655
|
+
* import { Dynatrace, HttpRequestEventBuilder } from '@dynatrace/react-native-plugin';
|
|
656
|
+
*
|
|
657
|
+
* Dynatrace.sendHttpRequestEvent(
|
|
658
|
+
* new HttpRequestEventBuilder("http://www.dynatrace.com", "POST")
|
|
659
|
+
* .withDuration(100)
|
|
660
|
+
* .withStatusCode(404)
|
|
661
|
+
* .withReasonPhrase("HTTP/1.1 404 Not Found")
|
|
662
|
+
* .withError(new Error())
|
|
663
|
+
* .withBytesSent(100)
|
|
664
|
+
* .withBytesReceived(100)
|
|
665
|
+
* .withTraceparentHeader("traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01")
|
|
666
|
+
* .addEventProperty("event_properties.userid", 12345)
|
|
667
|
+
* .addEventProperty("event_properties.response", "example body")
|
|
668
|
+
* );
|
|
669
|
+
* ```
|
|
670
|
+
*/
|
|
671
|
+
sendHttpRequestEvent(httpRequestEventBuilder: HttpRequestEventBuilder): void
|
|
640
672
|
}
|
|
641
673
|
|
|
642
674
|
/**
|
|
@@ -1717,4 +1749,101 @@ export declare class ConfigurationBuilder {
|
|
|
1717
1749
|
* @see https://www.npmjs.com/package/@dynatrace/react-native-plugin#plugin-startup
|
|
1718
1750
|
*/
|
|
1719
1751
|
public buildConfiguration(): IConfiguration;
|
|
1752
|
+
}
|
|
1753
|
+
|
|
1754
|
+
type EventProperty = string | number | boolean;
|
|
1755
|
+
type TraceparentHeader = `00-${string}-${string}-0${'0' | '1'}`;
|
|
1756
|
+
type AllowedRequestMethods =
|
|
1757
|
+
| 'GET'
|
|
1758
|
+
| 'HEAD'
|
|
1759
|
+
| 'POST'
|
|
1760
|
+
| 'PUT'
|
|
1761
|
+
| 'DELETE'
|
|
1762
|
+
| 'CONNECT'
|
|
1763
|
+
| 'OPTIONS'
|
|
1764
|
+
| 'TRACE'
|
|
1765
|
+
| 'PATCH'
|
|
1766
|
+
| 'get'
|
|
1767
|
+
| 'head'
|
|
1768
|
+
| 'post'
|
|
1769
|
+
| 'put'
|
|
1770
|
+
| 'delete'
|
|
1771
|
+
| 'connect'
|
|
1772
|
+
| 'options'
|
|
1773
|
+
| 'trace'
|
|
1774
|
+
| 'patch';
|
|
1775
|
+
|
|
1776
|
+
export declare class HttpRequestEventBuilder {
|
|
1777
|
+
/**
|
|
1778
|
+
*
|
|
1779
|
+
* @param url Accepts only URLs that are valid according to the WHATWG URL Standard. Mandatory.
|
|
1780
|
+
* @param requestMethod Accepts GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE and PATCH. Mandatory
|
|
1781
|
+
*/
|
|
1782
|
+
constructor(
|
|
1783
|
+
url: `http://${string}` | `https://${string}`,
|
|
1784
|
+
requestMethod: AllowedRequestMethods
|
|
1785
|
+
);
|
|
1786
|
+
|
|
1787
|
+
/**
|
|
1788
|
+
*
|
|
1789
|
+
* @param duration Only positive numbers are valid.
|
|
1790
|
+
* @returns the HttpRequestEventBuilder
|
|
1791
|
+
*/
|
|
1792
|
+
withDuration(duration: number): this;
|
|
1793
|
+
|
|
1794
|
+
/**
|
|
1795
|
+
*
|
|
1796
|
+
* @param statusCode Only positive numbers are valid.
|
|
1797
|
+
* @returns the HttpRequestEventBuilder
|
|
1798
|
+
*/
|
|
1799
|
+
withStatusCode(statusCode: number): this;
|
|
1800
|
+
|
|
1801
|
+
/**
|
|
1802
|
+
*
|
|
1803
|
+
* @param reasonPhrase Max. 5000 characters.
|
|
1804
|
+
* @returns the HttpRequestEventBuilder
|
|
1805
|
+
*/
|
|
1806
|
+
withReasonPhrase(reasonPhrase: string): this;
|
|
1807
|
+
|
|
1808
|
+
/**
|
|
1809
|
+
*
|
|
1810
|
+
* @param error A standard Javascript Error Object.
|
|
1811
|
+
* @returns the HttpRequestEventBuilder
|
|
1812
|
+
*/
|
|
1813
|
+
withError(error: Error): this;
|
|
1814
|
+
|
|
1815
|
+
/**
|
|
1816
|
+
*
|
|
1817
|
+
* @param bytesSent Only positive numbers are valid.
|
|
1818
|
+
* @returns the HttpRequestEventBuilder
|
|
1819
|
+
*/
|
|
1820
|
+
withBytesSent(bytesSent: number): this;
|
|
1821
|
+
|
|
1822
|
+
/**
|
|
1823
|
+
*
|
|
1824
|
+
* @param bytesReceived Only positive numbers are valid.
|
|
1825
|
+
* @returns the HttpRequestEventBuilder
|
|
1826
|
+
*/
|
|
1827
|
+
withBytesReceived(bytesReceived: number): this;
|
|
1828
|
+
|
|
1829
|
+
/**
|
|
1830
|
+
*
|
|
1831
|
+
* @param traceparentHeader Accepts Traceparent Headers that are valid according to the W3C Trace Context Specification.
|
|
1832
|
+
* @returns the HttpRequestEventBuilder
|
|
1833
|
+
*/
|
|
1834
|
+
withTraceparentHeader(traceparentHeader: TraceparentHeader): this;
|
|
1835
|
+
|
|
1836
|
+
/**
|
|
1837
|
+
*
|
|
1838
|
+
* @param key Accepts any string that starts with 'event_properties.'.
|
|
1839
|
+
* @param value Accepts any string (max. 5000 characters), number or boolean.
|
|
1840
|
+
* @returns the HttpRequestEventBuilder
|
|
1841
|
+
*/
|
|
1842
|
+
addEventProperty(key: `event_properties.${string}`, value: EventProperty): this;
|
|
1843
|
+
}
|
|
1844
|
+
|
|
1845
|
+
declare module 'react' {
|
|
1846
|
+
namespace JSX {
|
|
1847
|
+
interface IntrinsicAttributes extends IDynatraceProperties {}
|
|
1848
|
+
}
|
|
1720
1849
|
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SwitchHelper = void 0;
|
|
4
|
-
const IDynatraceProperties_1 = require("../IDynatraceProperties");
|
|
5
|
-
const ConfigurationHandler_1 = require("../../../lib/core/configuration/ConfigurationHandler");
|
|
6
|
-
const SwitchHelper = (Dynatrace) => ({
|
|
7
|
-
attachOnValueChange: (switchProps) => {
|
|
8
|
-
if ((0, IDynatraceProperties_1.isDynatraceIgnored)(switchProps)) {
|
|
9
|
-
return;
|
|
10
|
-
}
|
|
11
|
-
const origOnValueChange = switchProps.onValueChange;
|
|
12
|
-
const nameOfAction = _findActionName(switchProps);
|
|
13
|
-
if (origOnValueChange != null) {
|
|
14
|
-
switchProps.onValueChange = (value) => {
|
|
15
|
-
const useGenericName = nameOfAction == null ||
|
|
16
|
-
(!(0, IDynatraceProperties_1.isDynatraceNaming)(switchProps) &&
|
|
17
|
-
ConfigurationHandler_1.ConfigurationHandler.isActionNamePrivacyEnabled());
|
|
18
|
-
const finalNameOfAction = useGenericName
|
|
19
|
-
? `Touch on Switch to ${value}`
|
|
20
|
-
: `Touch on ${nameOfAction} to ${value}`;
|
|
21
|
-
const action = Dynatrace.enterAutoAction(finalNameOfAction);
|
|
22
|
-
let isSyncError = true;
|
|
23
|
-
try {
|
|
24
|
-
const returnValue = origOnValueChange(value);
|
|
25
|
-
if (_isPromise(returnValue)) {
|
|
26
|
-
isSyncError = false;
|
|
27
|
-
return returnValue.finally(() => {
|
|
28
|
-
action.leaveAction();
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
else {
|
|
32
|
-
action.leaveAction();
|
|
33
|
-
}
|
|
34
|
-
isSyncError = false;
|
|
35
|
-
}
|
|
36
|
-
finally {
|
|
37
|
-
if (isSyncError) {
|
|
38
|
-
action.leaveAction();
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
},
|
|
44
|
-
});
|
|
45
|
-
exports.SwitchHelper = SwitchHelper;
|
|
46
|
-
const _findActionName = (switchProps) => {
|
|
47
|
-
if ((0, IDynatraceProperties_1.isDynatraceNaming)(switchProps)) {
|
|
48
|
-
return switchProps.dtActionName;
|
|
49
|
-
}
|
|
50
|
-
else if (switchProps.accessibilityLabel != null) {
|
|
51
|
-
return switchProps.accessibilityLabel;
|
|
52
|
-
}
|
|
53
|
-
return null;
|
|
54
|
-
};
|
|
55
|
-
const _isPromise = (object) => object != null &&
|
|
56
|
-
typeof object.then === 'function' &&
|
|
57
|
-
typeof object.catch === 'function';
|