@dynatrace/react-native-plugin 2.333.1 → 2.337.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 +181 -232
- package/android/build.gradle +1 -1
- package/files/plugin-runtime.gradle +27 -13
- package/files/plugin.gradle +1 -1
- package/instrumentation/BabelPluginDynatrace.js +1 -0
- package/instrumentation/DynatraceInstrumentation.js +1 -1
- package/instrumentation/jsx/JsxRuntime.js +4 -4
- package/instrumentation/libs/UserInteraction.js +114 -0
- package/instrumentation/libs/community/Picker.js +1 -1
- package/instrumentation/libs/community/gesture-handler/Touchables.InstrInfo.js +2 -0
- package/instrumentation/libs/community/gesture-handler/Touchables.js +3 -1
- package/instrumentation/libs/community/gesture-handler/index.js +3 -1
- package/instrumentation/libs/react-navigation/ReactNavigation.js +9 -0
- package/instrumentation/libs/withOnPressMonitoring.js +65 -14
- package/lib/core/Dynatrace.js +3 -0
- package/lib/core/DynatraceBridge.js +5 -7
- package/lib/core/configuration/ActionNameOptions.js +2 -0
- package/lib/core/configuration/Configuration.js +5 -1
- package/lib/core/configuration/ConfigurationBuilder.js +11 -1
- package/lib/core/configuration/ConfigurationDefaults.js +3 -1
- package/lib/core/configuration/ConfigurationHandler.js +64 -0
- package/lib/core/configuration/ConfigurationPreset.js +6 -0
- package/lib/core/configuration/ManualStartupConfiguration.js +9 -1
- package/lib/dynatrace-reporter.js +0 -14
- package/lib/dynatrace-transformer.js +10 -13
- package/lib/features/ui-interaction/Config.js +8 -2
- package/lib/features/ui-interaction/Plugin.Fragment.Test.js +170 -0
- package/lib/features/ui-interaction/Plugin.js +226 -882
- package/lib/features/ui-interaction/Run.js +11 -7
- package/lib/features/ui-interaction/Runtime.js +258 -913
- package/lib/features/ui-interaction/TouchMetaResolver.js +492 -0
- package/lib/features/ui-interaction/Types.js +1 -62
- package/lib/next/Dynatrace.js +44 -0
- package/lib/next/configuration/INativeRuntimeConfiguration.js +9 -0
- package/lib/next/configuration/RuntimeConfigurationObserver.js +50 -6
- package/lib/next/events/EventPipeline.js +14 -6
- package/lib/next/events/HttpRequestEventData.js +26 -30
- package/lib/next/provider/TimestampProvider.js +20 -7
- package/lib/next/util/TraceContextUtils.js +108 -0
- package/package.json +8 -10
- package/react-native-dynatrace.podspec +1 -1
- package/scripts/Android.js +96 -66
- package/scripts/Config.js +11 -1
- package/scripts/Ios.js +288 -71
- package/scripts/PathsConstants.js +34 -20
- package/scripts/core/InstrumentCall.js +8 -3
- package/scripts/core/LineOffsetAnalyzeCall.js +9 -15
- package/scripts/util/SourceMapUtil.js +49 -11
- package/types.d.ts +178 -39
- package/scripts/util/ReactOptions.js +0 -21
|
@@ -31,10 +31,55 @@ class RuntimeConfigurationObserverImpl {
|
|
|
31
31
|
const touchInteractionEnabled = typeof payload.touch_interaction_enabled === 'boolean'
|
|
32
32
|
? payload.touch_interaction_enabled
|
|
33
33
|
: undefined;
|
|
34
|
-
const
|
|
34
|
+
const traceContextEnabled = typeof payload.trace_context_enabled === 'boolean'
|
|
35
|
+
? payload.trace_context_enabled
|
|
36
|
+
: undefined;
|
|
37
|
+
const dataCollectionLevel = payload.data_collection_level === 0 ||
|
|
38
|
+
payload.data_collection_level === 1 ||
|
|
39
|
+
payload.data_collection_level === 2
|
|
40
|
+
? payload.data_collection_level
|
|
41
|
+
: undefined;
|
|
42
|
+
const agentStatus = typeof payload.agent_status === 'boolean'
|
|
43
|
+
? payload.agent_status
|
|
44
|
+
: undefined;
|
|
45
|
+
const trafficControl = typeof payload.traffic_control === 'boolean'
|
|
46
|
+
? payload.traffic_control
|
|
47
|
+
: undefined;
|
|
48
|
+
const crashReporting = typeof payload.crash_reporting === 'boolean'
|
|
49
|
+
? payload.crash_reporting
|
|
50
|
+
: undefined;
|
|
51
|
+
const instanceId = typeof payload.instance_id === 'string'
|
|
52
|
+
? payload.instance_id
|
|
53
|
+
: undefined;
|
|
54
|
+
const sessionId = typeof payload.session_id === 'string'
|
|
55
|
+
? payload.session_id
|
|
56
|
+
: undefined;
|
|
57
|
+
const applicationId = typeof payload.application_id === 'string'
|
|
58
|
+
? payload.application_id
|
|
59
|
+
: undefined;
|
|
60
|
+
const tracestateKeyPrefix = typeof payload.tracestate_key_prefix === 'string'
|
|
61
|
+
? payload.tracestate_key_prefix
|
|
62
|
+
: undefined;
|
|
63
|
+
const normalized = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, (typeof thirdGenEnabled === 'boolean'
|
|
35
64
|
? { '3rd_gen_enabled': thirdGenEnabled }
|
|
36
65
|
: {})), (typeof touchInteractionEnabled === 'boolean'
|
|
37
66
|
? { touch_interaction_enabled: touchInteractionEnabled }
|
|
67
|
+
: {})), (typeof traceContextEnabled === 'boolean'
|
|
68
|
+
? { trace_context_enabled: traceContextEnabled }
|
|
69
|
+
: {})), (typeof dataCollectionLevel === 'number'
|
|
70
|
+
? { data_collection_level: dataCollectionLevel }
|
|
71
|
+
: {})), (typeof agentStatus === 'boolean'
|
|
72
|
+
? { agent_status: agentStatus }
|
|
73
|
+
: {})), (typeof trafficControl === 'boolean'
|
|
74
|
+
? { traffic_control: trafficControl }
|
|
75
|
+
: {})), (typeof crashReporting === 'boolean'
|
|
76
|
+
? { crash_reporting: crashReporting }
|
|
77
|
+
: {})), (typeof instanceId === 'string'
|
|
78
|
+
? { instance_id: instanceId }
|
|
79
|
+
: {})), (typeof sessionId === 'string' ? { session_id: sessionId } : {})), (typeof applicationId === 'string'
|
|
80
|
+
? { application_id: applicationId }
|
|
81
|
+
: {})), (typeof tracestateKeyPrefix === 'string'
|
|
82
|
+
? { tracestate_key_prefix: tracestateKeyPrefix }
|
|
38
83
|
: {}));
|
|
39
84
|
this.runtimeConfiguration = Object.assign(Object.assign({}, (0, INativeRuntimeConfiguration_1.generateDefaultConfiguration)()), normalized);
|
|
40
85
|
this.observerIsInitiated = true;
|
|
@@ -50,6 +95,7 @@ class RuntimeConfigurationObserverImpl {
|
|
|
50
95
|
return react_native_1.NativeModules.DynatraceBridge;
|
|
51
96
|
}
|
|
52
97
|
setupNativeEventEmitter() {
|
|
98
|
+
var _a;
|
|
53
99
|
const bridgeModule = this.resolveBridgeModule();
|
|
54
100
|
if (!bridgeModule) {
|
|
55
101
|
return;
|
|
@@ -57,11 +103,9 @@ class RuntimeConfigurationObserverImpl {
|
|
|
57
103
|
const iosModule = react_native_1.NativeModules.DynatraceBridge;
|
|
58
104
|
const nativeEmitterModule = react_native_1.Platform.OS === 'ios' ? iosModule || bridgeModule : bridgeModule;
|
|
59
105
|
const emitter = new react_native_1.NativeEventEmitter(nativeEmitterModule);
|
|
60
|
-
|
|
61
|
-
this.
|
|
62
|
-
|
|
63
|
-
});
|
|
64
|
-
}
|
|
106
|
+
(_a = this.subscription) !== null && _a !== void 0 ? _a : (this.subscription = emitter.addListener(this.EMIT_CONFIGURATION, (data) => {
|
|
107
|
+
this.updateRuntimeConfiguration(data);
|
|
108
|
+
}));
|
|
65
109
|
if (typeof bridgeModule.getCurrentConfiguration === 'function') {
|
|
66
110
|
Promise.resolve(bridgeModule.getCurrentConfiguration())
|
|
67
111
|
.then((data) => {
|
|
@@ -9,6 +9,14 @@ const ValueRestrictionModifier_1 = require("./modifier/ValueRestrictionModifier"
|
|
|
9
9
|
const ModifyEventValidation_1 = require("./modifier/ModifyEventValidation");
|
|
10
10
|
const EventSpecContstants_1 = require("./spec/EventSpecContstants");
|
|
11
11
|
const StringLengthEventModifier_1 = require("./modifier/StringLengthEventModifier");
|
|
12
|
+
const DECISION_REASON_TEXT = {
|
|
13
|
+
third_gen_disabled: '3rd generation RUM is disabled',
|
|
14
|
+
runtime_config_unavailable: 'Runtime configuration is not yet available',
|
|
15
|
+
data_collection_off: 'Data collection is disabled',
|
|
16
|
+
agent_inactive: 'Agent is inactive',
|
|
17
|
+
traffic_control_active: 'Traffic control is limiting data transmission',
|
|
18
|
+
crash_reporting_disabled: 'Crash reporting is disabled',
|
|
19
|
+
};
|
|
12
20
|
class EventPipelineImpl {
|
|
13
21
|
constructor() {
|
|
14
22
|
this.customEventModifierChain = new ModifyEventValidation_1.ModifyEventValidation();
|
|
@@ -25,12 +33,12 @@ class EventPipelineImpl {
|
|
|
25
33
|
];
|
|
26
34
|
}
|
|
27
35
|
insertEvent(event) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
this.logger.debug(
|
|
36
|
+
const decision = ConfigurationHandler_1.ConfigurationHandler.getThirdGenDataReportingDecision();
|
|
37
|
+
if (!decision.allowed) {
|
|
38
|
+
const reasonText = decision.reason
|
|
39
|
+
? DECISION_REASON_TEXT[decision.reason]
|
|
40
|
+
: 'Unknown reason';
|
|
41
|
+
this.logger.debug(`3rd gen event suppressed: ${reasonText}`);
|
|
34
42
|
return;
|
|
35
43
|
}
|
|
36
44
|
this.logger.debug(`insertEvent(${JSON.stringify(event)})`);
|
|
@@ -5,6 +5,8 @@ const TimestampProvider_1 = require("../provider/TimestampProvider");
|
|
|
5
5
|
const SendEventValidation_1 = require("./modifier/SendEventValidation");
|
|
6
6
|
const EventModifierUtil_1 = require("./modifier/EventModifierUtil");
|
|
7
7
|
const EventBuilderUtil_1 = require("./EventBuilderUtil");
|
|
8
|
+
const TraceContextUtils_1 = require("../util/TraceContextUtils");
|
|
9
|
+
const ConfigurationHandler_1 = require("../../core/configuration/ConfigurationHandler");
|
|
8
10
|
const logger = new ConsoleLogger_1.ConsoleLogger('HttpRequestEventData');
|
|
9
11
|
class HttpRequestEventData {
|
|
10
12
|
constructor(url, requestMethod) {
|
|
@@ -43,7 +45,9 @@ class HttpRequestEventData {
|
|
|
43
45
|
return this;
|
|
44
46
|
}
|
|
45
47
|
withTraceparentHeader(traceparentHeader) {
|
|
46
|
-
|
|
48
|
+
if (traceparentHeader !== undefined) {
|
|
49
|
+
this.traceparentHeader = traceparentHeader;
|
|
50
|
+
}
|
|
47
51
|
return this;
|
|
48
52
|
}
|
|
49
53
|
addEventProperty(key, value) {
|
|
@@ -59,13 +63,8 @@ class HttpRequestEventData {
|
|
|
59
63
|
const sanitizedStatusCode = this.sanitizeStatusCode();
|
|
60
64
|
const sanitizedBytesReceived = this.sanitizeBytesReceived();
|
|
61
65
|
const sanitizedBytesSent = this.sanitizeBytesSent();
|
|
62
|
-
const parsedTraceparentHeader = this.traceparentHeader &&
|
|
63
|
-
|
|
64
|
-
const traceContextHint = !this.traceparentHeader
|
|
65
|
-
? "api_unused"
|
|
66
|
-
: parsedTraceparentHeader
|
|
67
|
-
? "api_set"
|
|
68
|
-
: "invalid";
|
|
66
|
+
const parsedTraceparentHeader = this.traceparentHeader && (0, TraceContextUtils_1.parseTraceparent)(this.traceparentHeader);
|
|
67
|
+
const traceContextHint = this.getTraceContextHint(parsedTraceparentHeader);
|
|
69
68
|
const hasFailedRequest = this.isStatusCodeError() || !!this.error;
|
|
70
69
|
const sanitizedEventProperties = SendEventValidation_1.SendEventValidation.modifyEvent(this.rawEventProperties);
|
|
71
70
|
(0, EventModifierUtil_1.flagEventProperties)(sanitizedEventProperties);
|
|
@@ -76,9 +75,27 @@ class HttpRequestEventData {
|
|
|
76
75
|
],
|
|
77
76
|
})), (0, EventBuilderUtil_1.includeIfDefined)("http.response.status_code", sanitizedStatusCode)), (0, EventBuilderUtil_1.includeIfDefined)("http.response.reason_phrase", this.reasonPhrase)), (0, EventBuilderUtil_1.includeIfDefined)("request.bytes_sent", sanitizedBytesSent)), (0, EventBuilderUtil_1.includeIfDefined)("request.bytes_received", sanitizedBytesReceived)), { ["characteristics.has_request"]: true, ["characteristics.is_api_reported"]: true }), (0, EventBuilderUtil_1.includeIfTrue)("characteristics.has_failed_request", hasFailedRequest)), (0, EventBuilderUtil_1.includeIfTrue)("characteristics.has_error", hasFailedRequest)), (this.error !== undefined && Object.assign({ ["characteristics.has_exception"]: true, ["exception.type"]: this.error.name, ["exception.message"]: this.error.message }, (0, EventBuilderUtil_1.includeIfDefined)("exception.stack_trace", this.error.stack)))), (parsedTraceparentHeader && {
|
|
78
77
|
["trace.id"]: parsedTraceparentHeader.traceId,
|
|
79
|
-
["span.id"]: parsedTraceparentHeader.
|
|
78
|
+
["span.id"]: parsedTraceparentHeader.parentId,
|
|
80
79
|
})), (0, EventBuilderUtil_1.includeIfTrue)("dt.support.api.has_dropped_properties", this.hasDroppedProperties));
|
|
81
80
|
}
|
|
81
|
+
getTraceContextHint(parsedTraceparentHeader) {
|
|
82
|
+
if (!ConfigurationHandler_1.ConfigurationHandler.isConfigurationAvailable() ||
|
|
83
|
+
!ConfigurationHandler_1.ConfigurationHandler.getTracestateKeyPrefix()) {
|
|
84
|
+
return "not_initialized";
|
|
85
|
+
}
|
|
86
|
+
if (!ConfigurationHandler_1.ConfigurationHandler.getTraceContextEnabled()) {
|
|
87
|
+
return "disabled";
|
|
88
|
+
}
|
|
89
|
+
if (!this.traceparentHeader) {
|
|
90
|
+
return "api_unused";
|
|
91
|
+
}
|
|
92
|
+
if (parsedTraceparentHeader) {
|
|
93
|
+
return "api_set";
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
return "invalid";
|
|
97
|
+
}
|
|
98
|
+
}
|
|
82
99
|
hasValidMandatoryAttributes() {
|
|
83
100
|
let isValid = true;
|
|
84
101
|
if (this.isInvalidUrl(this.url)) {
|
|
@@ -138,27 +155,6 @@ class HttpRequestEventData {
|
|
|
138
155
|
isStatusCodeError() {
|
|
139
156
|
return (this.statusCode && 400 <= this.statusCode && this.statusCode <= 599);
|
|
140
157
|
}
|
|
141
|
-
parseTraceparent(header) {
|
|
142
|
-
const traceparentRegex = /^00-([0-9a-f]{32})-([0-9a-f]{16})-0[01]$/;
|
|
143
|
-
const match = header.match(traceparentRegex);
|
|
144
|
-
if (!match) {
|
|
145
|
-
logger.debug("The provided traceparent header does not match the format: '00-<trace-id-32-HEXDIG>-<parent-id-16-HEXDIG>-<trace-flags-2-HEXDIG>'");
|
|
146
|
-
return null;
|
|
147
|
-
}
|
|
148
|
-
const [, traceId, spanId] = match;
|
|
149
|
-
if (this.allZeros(traceId)) {
|
|
150
|
-
logger.debug('Trace ID in traceparent header must not be all zeros');
|
|
151
|
-
return null;
|
|
152
|
-
}
|
|
153
|
-
if (this.allZeros(spanId)) {
|
|
154
|
-
logger.debug('Parent ID in traceparent header must not be all zeros');
|
|
155
|
-
return null;
|
|
156
|
-
}
|
|
157
|
-
return { traceId, spanId };
|
|
158
|
-
}
|
|
159
|
-
allZeros(str) {
|
|
160
|
-
return /^0*$/.test(str);
|
|
161
|
-
}
|
|
162
158
|
}
|
|
163
159
|
exports.default = HttpRequestEventData;
|
|
164
160
|
HttpRequestEventData.allowedRequestMethods = [
|
|
@@ -1,10 +1,23 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.defaultTimestampProvider =
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
exports.defaultTimestampProvider = void 0;
|
|
4
|
+
let baseRealtimeMs = null;
|
|
5
|
+
let baseMonotonicMs = null;
|
|
6
|
+
const getMonotonicNow = () => {
|
|
7
|
+
var _a;
|
|
8
|
+
if (typeof ((_a = globalThis.performance) === null || _a === void 0 ? void 0 : _a.now) === 'function') {
|
|
9
|
+
return globalThis.performance.now();
|
|
7
10
|
}
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
exports.defaultTimestampProvider =
|
|
11
|
+
return Date.now();
|
|
12
|
+
};
|
|
13
|
+
exports.defaultTimestampProvider = {
|
|
14
|
+
getCurrentTimestamp: () => {
|
|
15
|
+
const currentMonotonicMs = getMonotonicNow();
|
|
16
|
+
if (baseRealtimeMs == null || baseMonotonicMs == null) {
|
|
17
|
+
baseRealtimeMs = Date.now();
|
|
18
|
+
baseMonotonicMs = currentMonotonicMs;
|
|
19
|
+
return baseRealtimeMs;
|
|
20
|
+
}
|
|
21
|
+
return baseRealtimeMs + (currentMonotonicMs - baseMonotonicMs);
|
|
22
|
+
},
|
|
23
|
+
};
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.trimTraceState = exports.generateTracestate = exports.generateTraceparentHeader = exports.parseTraceparent = void 0;
|
|
4
|
+
const ConsoleLogger_1 = require("../../core/logging/ConsoleLogger");
|
|
5
|
+
const ConfigurationHandler_1 = require("../../core/configuration/ConfigurationHandler");
|
|
6
|
+
const logger = new ConsoleLogger_1.ConsoleLogger('TraceContextUtils');
|
|
7
|
+
const parseTraceparent = (traceparent) => {
|
|
8
|
+
const traceparentRegex = /^[0-9a-f]{2}-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})$/i;
|
|
9
|
+
const match = traceparentRegex.exec(traceparent);
|
|
10
|
+
if (!match) {
|
|
11
|
+
logger.debug("The traceparent header doesn't match the format: '<version-2-hex>-<trace-id-32-hex>-<parent-id-16-hex>-<flags-2-hex>'");
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
const [, traceId, parentId] = match;
|
|
15
|
+
if (allZeros(traceId)) {
|
|
16
|
+
logger.debug('Trace ID in traceparent header must not be all zeros');
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
if (allZeros(parentId)) {
|
|
20
|
+
logger.debug('Parent ID in traceparent header must not be all zeros');
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
return { traceId, parentId };
|
|
24
|
+
};
|
|
25
|
+
exports.parseTraceparent = parseTraceparent;
|
|
26
|
+
const allZeros = (str) => /^0*$/.test(str);
|
|
27
|
+
const generateTraceparentHeader = () => {
|
|
28
|
+
let traceId = randomHex(32);
|
|
29
|
+
if (/^0+$/.test(traceId)) {
|
|
30
|
+
traceId = '1' + traceId.slice(1);
|
|
31
|
+
}
|
|
32
|
+
let spanId = randomHex(16);
|
|
33
|
+
if (/^0+$/.test(spanId)) {
|
|
34
|
+
spanId = '1' + spanId.slice(1);
|
|
35
|
+
}
|
|
36
|
+
return `00-${traceId}-${spanId}-01`;
|
|
37
|
+
};
|
|
38
|
+
exports.generateTraceparentHeader = generateTraceparentHeader;
|
|
39
|
+
const randomHex = (length) => {
|
|
40
|
+
let hex = '';
|
|
41
|
+
while (hex.length < length) {
|
|
42
|
+
hex += Math.floor(Math.random() * 0xffffffff)
|
|
43
|
+
.toString(16)
|
|
44
|
+
.padStart(8, '0');
|
|
45
|
+
}
|
|
46
|
+
return hex.slice(0, length);
|
|
47
|
+
};
|
|
48
|
+
const generateTracestate = (parentId, existingTracestate) => {
|
|
49
|
+
const instanceId = ConfigurationHandler_1.ConfigurationHandler.getInstanceId();
|
|
50
|
+
const sessionId = ConfigurationHandler_1.ConfigurationHandler.getSessionId();
|
|
51
|
+
const applicationId = ConfigurationHandler_1.ConfigurationHandler.getApplicationId();
|
|
52
|
+
const tracestateKeyPrefix = ConfigurationHandler_1.ConfigurationHandler.getTracestateKeyPrefix();
|
|
53
|
+
if (!ConfigurationHandler_1.ConfigurationHandler.getTraceContextEnabled() ||
|
|
54
|
+
!(instanceId && sessionId && applicationId && tracestateKeyPrefix)) {
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
const version = 1;
|
|
58
|
+
const originMarker = 'dtr';
|
|
59
|
+
const capture = 0;
|
|
60
|
+
let tracestate = `${tracestateKeyPrefix}@${originMarker}=${version};${parentId};${capture};${formatApplicationId(applicationId)};${instanceId};${sessionId}`;
|
|
61
|
+
if (typeof existingTracestate === 'string' && existingTracestate.trim()) {
|
|
62
|
+
tracestate += `,${existingTracestate}`;
|
|
63
|
+
}
|
|
64
|
+
return (0, exports.trimTraceState)(tracestate);
|
|
65
|
+
};
|
|
66
|
+
exports.generateTracestate = generateTracestate;
|
|
67
|
+
const formatApplicationId = (applicationId) => applicationId.split('-').slice(0, 3).join('');
|
|
68
|
+
const findLastLongSegmentIndex = (segments, longSegmentLength) => {
|
|
69
|
+
for (let i = segments.length - 1; i > 0; i--) {
|
|
70
|
+
if (segments[i].length > longSegmentLength) {
|
|
71
|
+
return i;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return -1;
|
|
75
|
+
};
|
|
76
|
+
const trimTraceState = (tracestate, maxLength = 512, longSegmentLength = 128, maxSegments = 32) => {
|
|
77
|
+
let segments = tracestate.split(',');
|
|
78
|
+
let length = tracestate.length;
|
|
79
|
+
if (length <= maxLength && segments.length <= maxSegments) {
|
|
80
|
+
return tracestate;
|
|
81
|
+
}
|
|
82
|
+
if (segments.length > maxSegments) {
|
|
83
|
+
segments = segments.slice(0, maxSegments);
|
|
84
|
+
length =
|
|
85
|
+
segments.reduce((sum, s) => sum + s.length, 0) +
|
|
86
|
+
(segments.length - 1);
|
|
87
|
+
}
|
|
88
|
+
let hasLongSegments = true;
|
|
89
|
+
while (length > maxLength && segments.length > 1) {
|
|
90
|
+
let removed = '';
|
|
91
|
+
if (hasLongSegments) {
|
|
92
|
+
const idx = findLastLongSegmentIndex(segments, longSegmentLength);
|
|
93
|
+
if (idx > 0) {
|
|
94
|
+
removed = segments.splice(idx, 1)[0];
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
hasLongSegments = false;
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
removed = segments.pop();
|
|
103
|
+
}
|
|
104
|
+
length -= removed.length + 1;
|
|
105
|
+
}
|
|
106
|
+
return segments.join(',');
|
|
107
|
+
};
|
|
108
|
+
exports.trimTraceState = trimTraceState;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dynatrace/react-native-plugin",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.337.1",
|
|
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": "types.d.ts",
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
"scripts": {
|
|
25
25
|
"uninstall": "node ./scripts/Uninstall.js",
|
|
26
26
|
"test": "jest --runInBand",
|
|
27
|
+
"test:coverage": "jest --runInBand --coverage",
|
|
27
28
|
"test:debug": "node --inspect-brk ./node_modules/jest/bin/jest.js --runInBand",
|
|
28
29
|
"test:local": "npm run lint && node runner.js test",
|
|
29
30
|
"test:examples": "node tests/jsdoc_examples/RunJestTest.js",
|
|
@@ -48,7 +49,7 @@
|
|
|
48
49
|
"author": "Dynatrace",
|
|
49
50
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
50
51
|
"dependencies": {
|
|
51
|
-
"@babel/runtime": "^7.
|
|
52
|
+
"@babel/runtime": "^7.29.2",
|
|
52
53
|
"jscodeshift": "^17.3.0",
|
|
53
54
|
"plist": "^3.1.0",
|
|
54
55
|
"proxy-polyfill": "^0.3.2",
|
|
@@ -56,8 +57,7 @@
|
|
|
56
57
|
},
|
|
57
58
|
"homepage": "https://www.dynatrace.com/",
|
|
58
59
|
"peerDependencies": {
|
|
59
|
-
"@babel/
|
|
60
|
-
"@react-native-picker/picker": ">=1.0.0",
|
|
60
|
+
"@babel/core": ">=7.4.4",
|
|
61
61
|
"diff": "^8.0.2",
|
|
62
62
|
"react": ">=16.11.0",
|
|
63
63
|
"react-native": ">=0.62.0"
|
|
@@ -67,12 +67,7 @@
|
|
|
67
67
|
"ast-types": "npm:ast-types-x"
|
|
68
68
|
},
|
|
69
69
|
"ast-types": "npm:ast-types-x",
|
|
70
|
-
"flow-parser": "0.160"
|
|
71
|
-
"fast-xml-parser@>=4.3.6 <=5.3.5": "5.3.6",
|
|
72
|
-
"@isaacs/brace-expansion": ">=5.0.1",
|
|
73
|
-
"minimatch@>=9.0.0 <9.0.6": ">=9.0.6",
|
|
74
|
-
"minimatch@>=10.0.0 <10.2.2": ">=10.2.2",
|
|
75
|
-
"minimatch@>=3.0.0 <3.1.3": ">=3.1.3"
|
|
70
|
+
"flow-parser": "0.160"
|
|
76
71
|
},
|
|
77
72
|
"devDependencies": {
|
|
78
73
|
"@babel/plugin-transform-class-properties": "^7.27.1",
|
|
@@ -81,6 +76,7 @@
|
|
|
81
76
|
"@babel/plugin-transform-optional-chaining": "^7.27.1",
|
|
82
77
|
"@babel/preset-env": "^7.27.2",
|
|
83
78
|
"@babel/preset-react": "^7.27.1",
|
|
79
|
+
"@react-native-picker/picker": "^2.11.4",
|
|
84
80
|
"@react-native/babel-preset": "^0.80.1",
|
|
85
81
|
"@react-navigation/core": "^7.13.0",
|
|
86
82
|
"@react-navigation/drawer": "^7.7.2",
|
|
@@ -158,6 +154,7 @@
|
|
|
158
154
|
"instrumentation/model/*.js",
|
|
159
155
|
"instrumentation/parser/*.js",
|
|
160
156
|
"instrumentation/DynatraceInstrumentation.js",
|
|
157
|
+
"instrumentation/BabelPluginDynatrace.js",
|
|
161
158
|
"lib/*.js",
|
|
162
159
|
"lib/core/*.js",
|
|
163
160
|
"lib/core/configuration/*.js",
|
|
@@ -174,6 +171,7 @@
|
|
|
174
171
|
"lib/next/events/interface/*.js",
|
|
175
172
|
"lib/next/events/modifier/*.js",
|
|
176
173
|
"lib/next/events/spec/*.js",
|
|
174
|
+
"lib/next/util/*.js",
|
|
177
175
|
"lib/next/provider/*.js",
|
|
178
176
|
"lib/features/ui-interaction/*.js",
|
|
179
177
|
"src/lib/core/interface/NativeDynatraceBridge.ts",
|
|
@@ -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.337.1.1003'
|
|
115
115
|
|
|
116
116
|
# Allows for better compatibility for older and newer versions
|
|
117
117
|
if defined?(install_modules_dependencies)
|
package/scripts/Android.js
CHANGED
|
@@ -1,21 +1,37 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.ensureRuntimeScriptApplied = exports.
|
|
4
|
+
exports.ensureRuntimeScriptApplied = exports.writeGradleConfig = exports.instrumentAndroidPlatform = exports.GRADLE_APPLY_RUNTIME_SCRIPT_KTS = exports.GRADLE_APPLY_RUNTIME_SCRIPT = exports.GRADLE_APPLY_BUILDSCRIPT_KTS = exports.GRADLE_APPLY_BUILDSCRIPT = exports.GRADLE_DYNATRACE_FILE_KTS = exports.GRADLE_DYNATRACE_FILE = void 0;
|
|
5
5
|
const path_1 = require("path");
|
|
6
6
|
const Logger_1 = require("./Logger");
|
|
7
7
|
const FileOperationHelper_1 = require("./FileOperationHelper");
|
|
8
8
|
const PathsConstants_1 = require("./PathsConstants");
|
|
9
9
|
const GRADLE_CONFIG_IDENTIFIER = '// AUTO - INSERTED';
|
|
10
10
|
exports.GRADLE_DYNATRACE_FILE = `apply from: "./${PathsConstants_1.DYNATRACE_CONFIG_GRADLE_FILE}"`;
|
|
11
|
+
exports.GRADLE_DYNATRACE_FILE_KTS = `apply(from = "./${PathsConstants_1.DYNATRACE_CONFIG_GRADLE_FILE}")`;
|
|
12
|
+
const LEGACY_GRADLE_DYNATRACE_NODE_MODULES = 'node_modules/@dynatrace/react-native-plugin/files/dynatrace.gradle';
|
|
11
13
|
const GRADLE_BUILDSCRIPT_IDENTIFIER = 'buildscript';
|
|
12
14
|
exports.GRADLE_APPLY_BUILDSCRIPT = 'apply from: "../node_modules/@dynatrace/react-native-plugin/files/plugin.gradle", to: buildscript';
|
|
15
|
+
exports.GRADLE_APPLY_BUILDSCRIPT_KTS = 'apply(from = "../node_modules/@dynatrace/react-native-plugin/files/plugin.gradle", to = buildscript)';
|
|
13
16
|
const GRADLE_REACT_NATIVE_PLUGIN = 'apply plugin: "com.facebook.react.rootproject"';
|
|
14
17
|
exports.GRADLE_APPLY_RUNTIME_SCRIPT = 'apply from: "../../node_modules/@dynatrace/react-native-plugin/files/plugin-runtime.gradle"';
|
|
18
|
+
exports.GRADLE_APPLY_RUNTIME_SCRIPT_KTS = 'apply(from = "../../node_modules/@dynatrace/react-native-plugin/files/plugin-runtime.gradle")';
|
|
19
|
+
const isKotlinDslGradleFile = (pathToGradle) => pathToGradle.endsWith('.gradle.kts');
|
|
20
|
+
const getGradleStatements = (pathToGradle) => isKotlinDslGradleFile(pathToGradle)
|
|
21
|
+
? {
|
|
22
|
+
applyBuildscript: exports.GRADLE_APPLY_BUILDSCRIPT_KTS,
|
|
23
|
+
dynatraceFile: exports.GRADLE_DYNATRACE_FILE_KTS,
|
|
24
|
+
runtimeScript: exports.GRADLE_APPLY_RUNTIME_SCRIPT_KTS,
|
|
25
|
+
}
|
|
26
|
+
: {
|
|
27
|
+
applyBuildscript: exports.GRADLE_APPLY_BUILDSCRIPT,
|
|
28
|
+
dynatraceFile: exports.GRADLE_DYNATRACE_FILE,
|
|
29
|
+
runtimeScript: exports.GRADLE_APPLY_RUNTIME_SCRIPT,
|
|
30
|
+
};
|
|
15
31
|
const instrumentAndroidPlatform = (pathToGradle, remove) => {
|
|
16
32
|
const path = FileOperationHelper_1.default.checkIfFileExistsSync(pathToGradle);
|
|
17
|
-
if (!path.endsWith('.gradle')) {
|
|
18
|
-
throw new Error("Can't find .gradle file. gradle path must
|
|
33
|
+
if (!path.endsWith('.gradle') && !path.endsWith('.gradle.kts')) {
|
|
34
|
+
throw new Error("Can't find .gradle(.kts) file. gradle path must include build.gradle or build.gradle.kts!");
|
|
19
35
|
}
|
|
20
36
|
changeReactNativeBuildGradleFile(path, remove);
|
|
21
37
|
};
|
|
@@ -31,78 +47,92 @@ const removeOldDynatraceClasspath = (gradleFileContent) => {
|
|
|
31
47
|
}
|
|
32
48
|
return gradleFileContentLines.join('\n');
|
|
33
49
|
};
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
for (let i = 0; i < gradleFileContentLines.length && (gradleDynatraceFileIndex === -1 || gradlePluginFileIndex === -1); i++) {
|
|
41
|
-
if (gradleFileContentLines[i].indexOf('plugin.gradle') > -1) {
|
|
42
|
-
gradlePluginFileIndex = i;
|
|
50
|
+
const findGradleLineIndices = (lines) => {
|
|
51
|
+
let pluginFileIndex = -1;
|
|
52
|
+
let dynatraceFileIndex = -1;
|
|
53
|
+
for (let i = 0; i < lines.length && (dynatraceFileIndex === -1 || pluginFileIndex === -1); i++) {
|
|
54
|
+
if (lines[i].indexOf('plugin.gradle') > -1) {
|
|
55
|
+
pluginFileIndex = i;
|
|
43
56
|
}
|
|
44
|
-
else if (
|
|
45
|
-
|
|
57
|
+
else if (lines[i].indexOf(PathsConstants_1.DYNATRACE_CONFIG_GRADLE_FILE) > -1) {
|
|
58
|
+
dynatraceFileIndex = i;
|
|
46
59
|
}
|
|
47
60
|
}
|
|
61
|
+
return { pluginFileIndex, dynatraceFileIndex };
|
|
62
|
+
};
|
|
63
|
+
const removeDynatraceFromGradle = (lines, indices, pathToGradle) => {
|
|
48
64
|
let modified = false;
|
|
49
|
-
if (
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
65
|
+
if (indices.pluginFileIndex !== -1) {
|
|
66
|
+
lines.splice(indices.pluginFileIndex, 1);
|
|
67
|
+
modified = true;
|
|
68
|
+
}
|
|
69
|
+
if (indices.dynatraceFileIndex !== -1) {
|
|
70
|
+
lines.splice(indices.dynatraceFileIndex - (modified ? 1 : 0), 1);
|
|
71
|
+
modified = true;
|
|
72
|
+
}
|
|
73
|
+
if (modified) {
|
|
74
|
+
Logger_1.default.logMessageSync('Removed Dynatrace modifications from build.gradle: ' + pathToGradle, Logger_1.default.INFO);
|
|
75
|
+
}
|
|
76
|
+
return modified;
|
|
77
|
+
};
|
|
78
|
+
const addDynatraceToGradle = (lines, indices, pathToGradle, statements) => {
|
|
79
|
+
let modified = false;
|
|
80
|
+
if (indices.dynatraceFileIndex !== -1 &&
|
|
81
|
+
lines[indices.dynatraceFileIndex].includes(LEGACY_GRADLE_DYNATRACE_NODE_MODULES)) {
|
|
82
|
+
lines[indices.dynatraceFileIndex] = statements.dynatraceFile;
|
|
83
|
+
Logger_1.default.logMessageSync('Migrated old node_modules dynatrace.gradle path to local path in build.gradle', Logger_1.default.INFO);
|
|
84
|
+
modified = true;
|
|
85
|
+
}
|
|
86
|
+
if (indices.pluginFileIndex === -1) {
|
|
87
|
+
const buildscriptIndex = lines.findIndex((line) => line.startsWith(GRADLE_BUILDSCRIPT_IDENTIFIER));
|
|
88
|
+
if (buildscriptIndex === -1) {
|
|
89
|
+
throw new Error('Could not find Buildscript block in build.gradle.');
|
|
60
90
|
}
|
|
91
|
+
lines.splice(buildscriptIndex + 1, 0, statements.applyBuildscript);
|
|
92
|
+
modified = true;
|
|
93
|
+
}
|
|
94
|
+
if (indices.dynatraceFileIndex === -1) {
|
|
95
|
+
const pluginLineIndex = lines.findIndex((line) => line.includes(GRADLE_REACT_NATIVE_PLUGIN));
|
|
96
|
+
lines.splice(pluginLineIndex !== -1 ? pluginLineIndex : lines.length, 0, statements.dynatraceFile);
|
|
97
|
+
modified = true;
|
|
98
|
+
}
|
|
99
|
+
if (modified) {
|
|
100
|
+
Logger_1.default.logMessageSync('Added Dynatrace plugin.gradle to the build.gradle: ' + pathToGradle, Logger_1.default.INFO);
|
|
61
101
|
}
|
|
62
102
|
else {
|
|
63
|
-
|
|
64
|
-
let gradleFileReactIndex = -1;
|
|
65
|
-
for (let i = 0; i < gradleFileContentLines.length; i++) {
|
|
66
|
-
if (gradleFileContentLines[i].startsWith(GRADLE_BUILDSCRIPT_IDENTIFIER)) {
|
|
67
|
-
gradleFileReactIndex = i;
|
|
68
|
-
break;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
if (gradleFileReactIndex === -1) {
|
|
72
|
-
throw new Error('Could not find Buildscript block in build.gradle.');
|
|
73
|
-
}
|
|
74
|
-
gradleFileContentLines.splice(gradleFileReactIndex + 1, 0, exports.GRADLE_APPLY_BUILDSCRIPT);
|
|
75
|
-
modified = true;
|
|
76
|
-
}
|
|
77
|
-
if (gradleDynatraceFileIndex === -1) {
|
|
78
|
-
let pluginLineIndex = -1;
|
|
79
|
-
for (let i = 0; i < gradleFileContentLines.length; i++) {
|
|
80
|
-
if (gradleFileContentLines[i].includes(GRADLE_REACT_NATIVE_PLUGIN)) {
|
|
81
|
-
pluginLineIndex = i;
|
|
82
|
-
break;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
gradleFileContentLines.splice(pluginLineIndex !== -1 ? pluginLineIndex : gradleFileContentLines.length, 0, exports.GRADLE_DYNATRACE_FILE);
|
|
86
|
-
modified = true;
|
|
87
|
-
}
|
|
88
|
-
if (modified) {
|
|
89
|
-
Logger_1.default.logMessageSync('Added Dynatrace plugin.gradle to the build.gradle: ' + pathToGradle, Logger_1.default.INFO);
|
|
90
|
-
}
|
|
91
|
-
else {
|
|
92
|
-
Logger_1.default.logMessageSync('Dynatrace plugin & agent already added to build.gradle', Logger_1.default.INFO);
|
|
93
|
-
}
|
|
103
|
+
Logger_1.default.logMessageSync('Dynatrace plugin & agent already added to build.gradle', Logger_1.default.INFO);
|
|
94
104
|
}
|
|
105
|
+
return modified;
|
|
106
|
+
};
|
|
107
|
+
const changeReactNativeBuildGradleFile = (pathToGradle, remove) => {
|
|
108
|
+
const gradleFileContent = FileOperationHelper_1.default.readTextFromFileSync(pathToGradle);
|
|
109
|
+
const modifiedFileContent = removeOldDynatraceClasspath(gradleFileContent);
|
|
110
|
+
const gradleFileContentLines = modifiedFileContent.split('\n');
|
|
111
|
+
const statements = getGradleStatements(pathToGradle);
|
|
112
|
+
const indices = findGradleLineIndices(gradleFileContentLines);
|
|
113
|
+
const modified = remove
|
|
114
|
+
? removeDynatraceFromGradle(gradleFileContentLines, indices, pathToGradle)
|
|
115
|
+
: addDynatraceToGradle(gradleFileContentLines, indices, pathToGradle, statements);
|
|
95
116
|
if (modified) {
|
|
96
117
|
const fullGradleFile = gradleFileContentLines.join('\n');
|
|
97
118
|
FileOperationHelper_1.default.writeTextToFileSync(pathToGradle, fullGradleFile);
|
|
98
119
|
}
|
|
99
120
|
};
|
|
100
|
-
const writeGradleConfig = (androidConfig) => {
|
|
121
|
+
const writeGradleConfig = (androidConfig, pathToGradle) => {
|
|
101
122
|
if (androidConfig === undefined || androidConfig.config === undefined) {
|
|
102
123
|
Logger_1.default.logMessageSync("Can't write configuration of Android agent because it is missing!", Logger_1.default.WARNING);
|
|
103
124
|
return;
|
|
104
125
|
}
|
|
105
|
-
const
|
|
126
|
+
const gradleDirectory = (0, path_1.dirname)(pathToGradle);
|
|
127
|
+
const targetPath = (0, path_1.join)(gradleDirectory, PathsConstants_1.DYNATRACE_CONFIG_GRADLE_FILE);
|
|
128
|
+
let gradleFileContent;
|
|
129
|
+
try {
|
|
130
|
+
FileOperationHelper_1.default.checkIfFileExistsSync(targetPath);
|
|
131
|
+
gradleFileContent = FileOperationHelper_1.default.readTextFromFileSync(targetPath);
|
|
132
|
+
}
|
|
133
|
+
catch (_a) {
|
|
134
|
+
gradleFileContent = FileOperationHelper_1.default.readTextFromFileSync(PathsConstants_1.default.getDynatraceGradleFile());
|
|
135
|
+
}
|
|
106
136
|
const gradleFileContentLines = removeOldGradleConfig(gradleFileContent);
|
|
107
137
|
let gradleFileIndex = -1;
|
|
108
138
|
for (let i = 0; i < gradleFileContentLines.length; i++) {
|
|
@@ -113,15 +143,14 @@ const writeGradleConfig = (androidConfig) => {
|
|
|
113
143
|
}
|
|
114
144
|
gradleFileContentLines.splice(gradleFileIndex + 1, 0, androidConfig.config);
|
|
115
145
|
const fullGradleFile = gradleFileContentLines.join('\n');
|
|
116
|
-
|
|
146
|
+
if (fullGradleFile === gradleFileContent) {
|
|
147
|
+
Logger_1.default.logMessageSync(`Configuration in ${PathsConstants_1.DYNATRACE_CONFIG_GRADLE_FILE} is already up to date`, Logger_1.default.INFO);
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
FileOperationHelper_1.default.writeTextToFileSync(targetPath, fullGradleFile);
|
|
117
151
|
Logger_1.default.logMessageSync(`Replaced old configuration with current configuration in ${PathsConstants_1.DYNATRACE_CONFIG_GRADLE_FILE}`, Logger_1.default.INFO);
|
|
118
152
|
};
|
|
119
153
|
exports.writeGradleConfig = writeGradleConfig;
|
|
120
|
-
const copyGradleConfigFile = (pathToGradle) => {
|
|
121
|
-
const gradleDirectory = (0, path_1.dirname)(pathToGradle);
|
|
122
|
-
FileOperationHelper_1.default.copyFileSync(PathsConstants_1.default.getDynatraceGradleFile(), (0, path_1.join)(gradleDirectory, PathsConstants_1.DYNATRACE_CONFIG_GRADLE_FILE));
|
|
123
|
-
};
|
|
124
|
-
exports.copyGradleConfigFile = copyGradleConfigFile;
|
|
125
154
|
const removeOldGradleConfig = (gradleFileContent) => {
|
|
126
155
|
const gradleFileContentLines = gradleFileContent.split('\n');
|
|
127
156
|
const gradleConfigIndex = [];
|
|
@@ -139,9 +168,10 @@ const removeOldGradleConfig = (gradleFileContent) => {
|
|
|
139
168
|
const ensureRuntimeScriptApplied = (pathToGradle) => {
|
|
140
169
|
const gradleContent = FileOperationHelper_1.default.readTextFromFileSync(pathToGradle);
|
|
141
170
|
const gradleLines = gradleContent.split('\n');
|
|
142
|
-
const
|
|
171
|
+
const { runtimeScript } = getGradleStatements(pathToGradle);
|
|
172
|
+
const alreadyApplied = gradleLines.some((line) => line.includes('plugin-runtime.gradle'));
|
|
143
173
|
if (!alreadyApplied) {
|
|
144
|
-
gradleLines.push(
|
|
174
|
+
gradleLines.push(runtimeScript);
|
|
145
175
|
FileOperationHelper_1.default.writeTextToFileSync(pathToGradle, gradleLines.join('\n'));
|
|
146
176
|
Logger_1.default.logMessageSync(`Added runtime script to ${pathToGradle}`, Logger_1.default.INFO);
|
|
147
177
|
}
|