dd-trace 4.5.0 → 4.7.0
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/package.json +3 -3
- package/packages/datadog-instrumentations/src/cucumber.js +5 -2
- package/packages/datadog-instrumentations/src/grpc/client.js +44 -42
- package/packages/datadog-instrumentations/src/grpc/server.js +69 -60
- package/packages/datadog-instrumentations/src/http2/client.js +25 -26
- package/packages/datadog-instrumentations/src/jest.js +3 -1
- package/packages/datadog-instrumentations/src/kafkajs.js +11 -2
- package/packages/datadog-instrumentations/src/mocha.js +5 -3
- package/packages/datadog-instrumentations/src/redis.js +48 -5
- package/packages/datadog-plugin-cypress/src/plugin.js +4 -2
- package/packages/datadog-plugin-grpc/src/client.js +29 -11
- package/packages/datadog-plugin-grpc/src/server.js +22 -6
- package/packages/datadog-plugin-http2/src/client.js +46 -29
- package/packages/datadog-plugin-kafkajs/src/producer.js +6 -1
- package/packages/datadog-plugin-openai/src/services.js +14 -10
- package/packages/datadog-plugin-router/src/index.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/command-injection-analyzer.js +3 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/cookie-analyzer.js +7 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/ldap-injection-analyzer.js +3 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/path-traversal-analyzer.js +19 -15
- package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +5 -2
- package/packages/dd-trace/src/appsec/iast/analyzers/ssrf-analyzer.js +2 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/unvalidated-redirect-analyzer.js +3 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +18 -19
- package/packages/dd-trace/src/appsec/iast/analyzers/weak-cipher-analyzer.js +3 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/weak-hash-analyzer.js +3 -0
- package/packages/dd-trace/src/appsec/iast/iast-log.js +1 -1
- package/packages/dd-trace/src/appsec/iast/iast-plugin.js +205 -0
- package/packages/dd-trace/src/appsec/iast/index.js +6 -5
- package/packages/dd-trace/src/appsec/iast/tags.js +2 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/csi-methods.js +6 -6
- package/packages/dd-trace/src/appsec/iast/taint-tracking/index.js +3 -3
- package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +23 -4
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +32 -16
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter-telemetry.js +33 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +23 -16
- package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +76 -37
- package/packages/dd-trace/src/appsec/iast/telemetry/iast-metric.js +101 -0
- package/packages/dd-trace/src/appsec/iast/telemetry/index.js +45 -0
- package/packages/dd-trace/src/appsec/iast/telemetry/{logs.js → log/index.js} +5 -5
- package/packages/dd-trace/src/appsec/iast/telemetry/{log_collector.js → log/log-collector.js} +1 -1
- package/packages/dd-trace/src/appsec/iast/telemetry/namespaces.js +76 -0
- package/packages/dd-trace/src/appsec/iast/telemetry/span-tags.js +53 -0
- package/packages/dd-trace/src/appsec/iast/telemetry/verbosity.js +42 -0
- package/packages/dd-trace/src/config.js +21 -2
- package/packages/dd-trace/src/constants.js +1 -0
- package/packages/dd-trace/src/dogstatsd.js +14 -1
- package/packages/dd-trace/src/metrics.js +2 -2
- package/packages/dd-trace/src/opentracing/tracer.js +1 -0
- package/packages/dd-trace/src/plugins/ci_plugin.js +6 -1
- package/packages/dd-trace/src/plugins/outbound.js +29 -12
- package/packages/dd-trace/src/plugins/plugin.js +28 -0
- package/packages/dd-trace/src/plugins/tracing.js +33 -16
- package/packages/dd-trace/src/plugins/util/ci.js +1 -1
- package/packages/dd-trace/src/plugins/util/test.js +55 -11
- package/packages/dd-trace/src/plugins/util/user-provided-git.js +1 -22
- package/packages/dd-trace/src/profiling/config.js +0 -3
- package/packages/dd-trace/src/profiling/index.js +0 -2
- package/packages/dd-trace/src/profiling/profilers/wall.js +23 -11
- package/packages/diagnostics_channel/src/index.js +64 -0
- package/packages/dd-trace/src/profiling/profilers/cpu.js +0 -126
- /package/packages/dd-trace/src/appsec/iast/taint-tracking/{origin-types.js → source-types.js} +0 -0
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
const {
|
|
4
4
|
CLIENT_PORT_KEY,
|
|
5
5
|
PEER_SERVICE_KEY,
|
|
6
|
-
PEER_SERVICE_SOURCE_KEY
|
|
6
|
+
PEER_SERVICE_SOURCE_KEY,
|
|
7
|
+
PEER_SERVICE_REMAP_KEY
|
|
7
8
|
} = require('../constants')
|
|
8
9
|
const TracingPlugin = require('./tracing')
|
|
9
10
|
|
|
@@ -34,9 +35,11 @@ class OutboundPlugin extends TracingPlugin {
|
|
|
34
35
|
* - If `peer.service` was defined _before_ we compute it (for example in custom instrumentation),
|
|
35
36
|
* `_dd.peer.service.source`'s value is `peer.service`
|
|
36
37
|
*/
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
if (tags[PEER_SERVICE_KEY] !== undefined) {
|
|
39
|
+
return {
|
|
40
|
+
[PEER_SERVICE_KEY]: tags[PEER_SERVICE_KEY],
|
|
41
|
+
[PEER_SERVICE_SOURCE_KEY]: PEER_SERVICE_KEY
|
|
42
|
+
}
|
|
40
43
|
}
|
|
41
44
|
|
|
42
45
|
const sourceTags = [
|
|
@@ -52,23 +55,37 @@ class OutboundPlugin extends TracingPlugin {
|
|
|
52
55
|
}
|
|
53
56
|
}
|
|
54
57
|
}
|
|
55
|
-
return
|
|
58
|
+
return undefined
|
|
56
59
|
}
|
|
57
60
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
+
getPeerServiceRemap (peerData) {
|
|
62
|
+
/**
|
|
63
|
+
* If DD_TRACE_PEER_SERVICE_MAPPING is matched, we need to override the existing
|
|
64
|
+
* peer service and add the value we overrode.
|
|
65
|
+
*/
|
|
66
|
+
const peerService = peerData[PEER_SERVICE_KEY]
|
|
67
|
+
if (peerService && this.tracer._peerServiceMapping[peerService]) {
|
|
68
|
+
return {
|
|
69
|
+
...peerData,
|
|
70
|
+
[PEER_SERVICE_KEY]: this.tracer._peerServiceMapping[peerService],
|
|
71
|
+
[PEER_SERVICE_REMAP_KEY]: peerService
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return peerData
|
|
61
75
|
}
|
|
62
76
|
|
|
63
77
|
finish () {
|
|
64
|
-
|
|
78
|
+
this.tagPeerService(this.activeSpan)
|
|
79
|
+
super.finish(...arguments)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
tagPeerService (span) {
|
|
65
83
|
if (this.tracer._computePeerService) {
|
|
66
84
|
const peerData = this.getPeerService(span.context()._tags)
|
|
67
|
-
if (peerData) {
|
|
68
|
-
span.addTags(peerData)
|
|
85
|
+
if (peerData !== undefined) {
|
|
86
|
+
span.addTags(this.getPeerServiceRemap(peerData))
|
|
69
87
|
}
|
|
70
88
|
}
|
|
71
|
-
super.finish(...arguments)
|
|
72
89
|
}
|
|
73
90
|
|
|
74
91
|
connect (url) {
|
|
@@ -25,9 +25,31 @@ class Subscription {
|
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
class StoreBinding {
|
|
29
|
+
constructor (event, transform) {
|
|
30
|
+
this._channel = dc.channel(event)
|
|
31
|
+
this._transform = data => {
|
|
32
|
+
const store = storage.getStore()
|
|
33
|
+
|
|
34
|
+
return !store || !store.noop
|
|
35
|
+
? transform(data)
|
|
36
|
+
: store
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
enable () {
|
|
41
|
+
this._channel.bindStore(storage, this._transform)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
disable () {
|
|
45
|
+
this._channel.unbindStore(storage, this._transform)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
28
49
|
module.exports = class Plugin {
|
|
29
50
|
constructor (tracer, tracerConfig) {
|
|
30
51
|
this._subscriptions = []
|
|
52
|
+
this._bindings = []
|
|
31
53
|
this._enabled = false
|
|
32
54
|
this._tracer = tracer
|
|
33
55
|
this.config = {} // plugin-specific configuration, unset until .configure() is called
|
|
@@ -53,6 +75,10 @@ module.exports = class Plugin {
|
|
|
53
75
|
this._subscriptions.push(new Subscription(channelName, handler))
|
|
54
76
|
}
|
|
55
77
|
|
|
78
|
+
addBind (channelName, transform) {
|
|
79
|
+
this._bindings.push(new StoreBinding(channelName, transform))
|
|
80
|
+
}
|
|
81
|
+
|
|
56
82
|
addError (error) {
|
|
57
83
|
const store = storage.getStore()
|
|
58
84
|
|
|
@@ -71,9 +97,11 @@ module.exports = class Plugin {
|
|
|
71
97
|
if (config.enabled && !this._enabled) {
|
|
72
98
|
this._enabled = true
|
|
73
99
|
this._subscriptions.forEach(sub => sub.enable())
|
|
100
|
+
this._bindings.forEach(sub => sub.enable())
|
|
74
101
|
} else if (!config.enabled && this._enabled) {
|
|
75
102
|
this._enabled = false
|
|
76
103
|
this._subscriptions.forEach(sub => sub.disable())
|
|
104
|
+
this._bindings.forEach(sub => sub.disable())
|
|
77
105
|
}
|
|
78
106
|
}
|
|
79
107
|
}
|
|
@@ -13,17 +13,7 @@ class TracingPlugin extends Plugin {
|
|
|
13
13
|
this.component = this.constructor.component || this.constructor.id
|
|
14
14
|
this.operation = this.constructor.operation
|
|
15
15
|
|
|
16
|
-
this.
|
|
17
|
-
this.start(message)
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
this.addTraceSub('error', err => {
|
|
21
|
-
this.error(err)
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
this.addTraceSub('finish', message => {
|
|
25
|
-
this.finish(message)
|
|
26
|
-
})
|
|
16
|
+
this.addTraceSubs()
|
|
27
17
|
}
|
|
28
18
|
|
|
29
19
|
get activeSpan () {
|
|
@@ -65,19 +55,43 @@ class TracingPlugin extends Plugin {
|
|
|
65
55
|
this.addError(error)
|
|
66
56
|
}
|
|
67
57
|
|
|
58
|
+
addTraceSubs () {
|
|
59
|
+
const events = ['start', 'end', 'asyncStart', 'asyncEnd', 'error', 'finish']
|
|
60
|
+
|
|
61
|
+
for (const event of events) {
|
|
62
|
+
const bindName = `bind${event.charAt(0).toUpperCase()}${event.slice(1)}`
|
|
63
|
+
|
|
64
|
+
if (this[event]) {
|
|
65
|
+
this.addTraceSub(event, message => {
|
|
66
|
+
this[event](message)
|
|
67
|
+
})
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (this[bindName]) {
|
|
71
|
+
this.addTraceBind(event, message => this[bindName](message))
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
68
76
|
addTraceSub (eventName, handler) {
|
|
69
|
-
this.
|
|
77
|
+
const prefix = this.constructor.prefix || `apm:${this.component}:${this.operation}`
|
|
78
|
+
this.addSub(`${prefix}:${eventName}`, handler)
|
|
70
79
|
}
|
|
71
80
|
|
|
72
|
-
|
|
73
|
-
const
|
|
81
|
+
addTraceBind (eventName, transform) {
|
|
82
|
+
const prefix = this.constructor.prefix || `apm:${this.component}:${this.operation}`
|
|
83
|
+
this.addBind(`${prefix}:${eventName}`, transform)
|
|
84
|
+
}
|
|
74
85
|
|
|
86
|
+
addError (error, span = this.activeSpan) {
|
|
75
87
|
if (!span._spanContext._tags['error']) {
|
|
88
|
+
// Errors may be wrapped in a context.
|
|
89
|
+
error = (error && error.error) || error
|
|
76
90
|
span.setTag('error', error || 1)
|
|
77
91
|
}
|
|
78
92
|
}
|
|
79
93
|
|
|
80
|
-
startSpan (name, { childOf, kind, meta, metrics, service, resource, type } = {}) {
|
|
94
|
+
startSpan (name, { childOf, kind, meta, metrics, service, resource, type } = {}, enter = true) {
|
|
81
95
|
const store = storage.getStore()
|
|
82
96
|
|
|
83
97
|
if (store && childOf === undefined) {
|
|
@@ -100,7 +114,10 @@ class TracingPlugin extends Plugin {
|
|
|
100
114
|
|
|
101
115
|
analyticsSampler.sample(span, this.config.measured)
|
|
102
116
|
|
|
103
|
-
|
|
117
|
+
// TODO: Remove this after migration to TracingChannel is done.
|
|
118
|
+
if (enter) {
|
|
119
|
+
storage.enterWith({ ...store, span })
|
|
120
|
+
}
|
|
104
121
|
|
|
105
122
|
return span
|
|
106
123
|
}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
const path = require('path')
|
|
2
2
|
const fs = require('fs')
|
|
3
|
+
const { URL } = require('url')
|
|
4
|
+
const log = require('../../log')
|
|
3
5
|
|
|
4
6
|
const istanbul = require('istanbul-lib-coverage')
|
|
5
7
|
const ignore = require('ignore')
|
|
6
8
|
|
|
7
9
|
const { getGitMetadata } = require('./git')
|
|
8
|
-
const { getUserProviderGitMetadata } = require('./user-provided-git')
|
|
10
|
+
const { getUserProviderGitMetadata, validateGitRepositoryUrl, validateGitCommitSha } = require('./user-provided-git')
|
|
9
11
|
const { getCIMetadata } = require('./ci')
|
|
10
12
|
const { getRuntimeAndOSMetadata } = require('./env')
|
|
11
13
|
const {
|
|
@@ -16,7 +18,8 @@ const {
|
|
|
16
18
|
GIT_COMMIT_AUTHOR_EMAIL,
|
|
17
19
|
GIT_COMMIT_AUTHOR_NAME,
|
|
18
20
|
GIT_COMMIT_MESSAGE,
|
|
19
|
-
CI_WORKSPACE_PATH
|
|
21
|
+
CI_WORKSPACE_PATH,
|
|
22
|
+
CI_PIPELINE_URL
|
|
20
23
|
} = require('./tags')
|
|
21
24
|
const id = require('../../id')
|
|
22
25
|
|
|
@@ -104,7 +107,8 @@ module.exports = {
|
|
|
104
107
|
mergeCoverage,
|
|
105
108
|
fromCoverageMapToCoverage,
|
|
106
109
|
getTestLineStart,
|
|
107
|
-
getCallSites
|
|
110
|
+
getCallSites,
|
|
111
|
+
removeInvalidMetadata
|
|
108
112
|
}
|
|
109
113
|
|
|
110
114
|
// Returns pkg manager and its version, separated by '-', e.g. npm-8.15.0 or yarn-1.22.19
|
|
@@ -116,6 +120,39 @@ function getPkgManager () {
|
|
|
116
120
|
}
|
|
117
121
|
}
|
|
118
122
|
|
|
123
|
+
function validateUrl (url) {
|
|
124
|
+
try {
|
|
125
|
+
const urlObject = new URL(url)
|
|
126
|
+
return (urlObject.protocol === 'https:' || urlObject.protocol === 'http:')
|
|
127
|
+
} catch (e) {
|
|
128
|
+
return false
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function removeInvalidMetadata (metadata) {
|
|
133
|
+
return Object.keys(metadata).reduce((filteredTags, tag) => {
|
|
134
|
+
if (tag === GIT_REPOSITORY_URL) {
|
|
135
|
+
if (!validateGitRepositoryUrl(metadata[GIT_REPOSITORY_URL])) {
|
|
136
|
+
log.error('DD_GIT_REPOSITORY_URL must be a valid URL')
|
|
137
|
+
return filteredTags
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (tag === GIT_COMMIT_SHA) {
|
|
141
|
+
if (!validateGitCommitSha(metadata[GIT_COMMIT_SHA])) {
|
|
142
|
+
log.error('DD_GIT_COMMIT_SHA must be a full-length git SHA')
|
|
143
|
+
return filteredTags
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (tag === CI_PIPELINE_URL) {
|
|
147
|
+
if (!validateUrl(metadata[CI_PIPELINE_URL])) {
|
|
148
|
+
return filteredTags
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
filteredTags[tag] = metadata[tag]
|
|
152
|
+
return filteredTags
|
|
153
|
+
}, {})
|
|
154
|
+
}
|
|
155
|
+
|
|
119
156
|
function getTestEnvironmentMetadata (testFramework, config) {
|
|
120
157
|
// TODO: eventually these will come from the tracer (generally available)
|
|
121
158
|
const ciMetadata = getCIMetadata()
|
|
@@ -155,7 +192,7 @@ function getTestEnvironmentMetadata (testFramework, config) {
|
|
|
155
192
|
if (config && config.service) {
|
|
156
193
|
metadata['service.name'] = config.service
|
|
157
194
|
}
|
|
158
|
-
return metadata
|
|
195
|
+
return removeInvalidMetadata(metadata)
|
|
159
196
|
}
|
|
160
197
|
|
|
161
198
|
function getTestParametersString (parametersByTestName, testName) {
|
|
@@ -173,6 +210,13 @@ function getTestParametersString (parametersByTestName, testName) {
|
|
|
173
210
|
}
|
|
174
211
|
}
|
|
175
212
|
|
|
213
|
+
function getTestTypeFromFramework (testFramework) {
|
|
214
|
+
if (testFramework === 'playwright' || testFramework === 'cypress') {
|
|
215
|
+
return 'browser'
|
|
216
|
+
}
|
|
217
|
+
return 'test'
|
|
218
|
+
}
|
|
219
|
+
|
|
176
220
|
function finishAllTraceSpans (span) {
|
|
177
221
|
span.context()._trace.started.forEach(traceSpan => {
|
|
178
222
|
if (traceSpan !== span) {
|
|
@@ -188,10 +232,10 @@ function getTestParentSpan (tracer) {
|
|
|
188
232
|
})
|
|
189
233
|
}
|
|
190
234
|
|
|
191
|
-
function getTestCommonTags (name, suite, version) {
|
|
235
|
+
function getTestCommonTags (name, suite, version, testFramework) {
|
|
192
236
|
return {
|
|
193
237
|
[SPAN_TYPE]: 'test',
|
|
194
|
-
[TEST_TYPE]:
|
|
238
|
+
[TEST_TYPE]: getTestTypeFromFramework(testFramework),
|
|
195
239
|
[SAMPLING_RULE_DECISION]: 1,
|
|
196
240
|
[SAMPLING_PRIORITY]: AUTO_KEEP,
|
|
197
241
|
[TEST_NAME]: name,
|
|
@@ -269,12 +313,12 @@ function getCodeOwnersForFilename (filename, entries) {
|
|
|
269
313
|
return null
|
|
270
314
|
}
|
|
271
315
|
|
|
272
|
-
function getTestLevelCommonTags (command, testFrameworkVersion) {
|
|
316
|
+
function getTestLevelCommonTags (command, testFrameworkVersion, testFramework) {
|
|
273
317
|
return {
|
|
274
318
|
[TEST_FRAMEWORK_VERSION]: testFrameworkVersion,
|
|
275
319
|
[LIBRARY_VERSION]: ddTraceVersion,
|
|
276
320
|
[TEST_COMMAND]: command,
|
|
277
|
-
[TEST_TYPE]:
|
|
321
|
+
[TEST_TYPE]: getTestTypeFromFramework(testFramework)
|
|
278
322
|
}
|
|
279
323
|
}
|
|
280
324
|
|
|
@@ -284,7 +328,7 @@ function getTestSessionCommonTags (command, testFrameworkVersion, testFramework)
|
|
|
284
328
|
[RESOURCE_NAME]: `test_session.${command}`,
|
|
285
329
|
[TEST_MODULE]: testFramework,
|
|
286
330
|
[TEST_TOOLCHAIN]: getPkgManager(),
|
|
287
|
-
...getTestLevelCommonTags(command, testFrameworkVersion)
|
|
331
|
+
...getTestLevelCommonTags(command, testFrameworkVersion, testFramework)
|
|
288
332
|
}
|
|
289
333
|
}
|
|
290
334
|
|
|
@@ -293,7 +337,7 @@ function getTestModuleCommonTags (command, testFrameworkVersion, testFramework)
|
|
|
293
337
|
[SPAN_TYPE]: 'test_module_end',
|
|
294
338
|
[RESOURCE_NAME]: `test_module.${command}`,
|
|
295
339
|
[TEST_MODULE]: testFramework,
|
|
296
|
-
...getTestLevelCommonTags(command, testFrameworkVersion)
|
|
340
|
+
...getTestLevelCommonTags(command, testFrameworkVersion, testFramework)
|
|
297
341
|
}
|
|
298
342
|
}
|
|
299
343
|
|
|
@@ -303,7 +347,7 @@ function getTestSuiteCommonTags (command, testFrameworkVersion, testSuite, testF
|
|
|
303
347
|
[RESOURCE_NAME]: `test_suite.${testSuite}`,
|
|
304
348
|
[TEST_MODULE]: testFramework,
|
|
305
349
|
[TEST_SUITE]: testSuite,
|
|
306
|
-
...getTestLevelCommonTags(command, testFrameworkVersion)
|
|
350
|
+
...getTestLevelCommonTags(command, testFrameworkVersion, testFramework)
|
|
307
351
|
}
|
|
308
352
|
}
|
|
309
353
|
|
|
@@ -13,7 +13,6 @@ const {
|
|
|
13
13
|
} = require('./tags')
|
|
14
14
|
|
|
15
15
|
const { normalizeRef } = require('./ci')
|
|
16
|
-
const log = require('../../log')
|
|
17
16
|
const { URL } = require('url')
|
|
18
17
|
|
|
19
18
|
function removeEmptyValues (tags) {
|
|
@@ -53,25 +52,6 @@ function validateGitCommitSha (gitCommitSha) {
|
|
|
53
52
|
return isValidSha1 || isValidSha256
|
|
54
53
|
}
|
|
55
54
|
|
|
56
|
-
function removeInvalidGitMetadata (metadata) {
|
|
57
|
-
return Object.keys(metadata).reduce((filteredTags, tag) => {
|
|
58
|
-
if (tag === GIT_REPOSITORY_URL) {
|
|
59
|
-
if (!validateGitRepositoryUrl(metadata[GIT_REPOSITORY_URL])) {
|
|
60
|
-
log.error('DD_GIT_REPOSITORY_URL must be a valid URL')
|
|
61
|
-
return filteredTags
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
if (tag === GIT_COMMIT_SHA) {
|
|
65
|
-
if (!validateGitCommitSha(metadata[GIT_COMMIT_SHA])) {
|
|
66
|
-
log.error('DD_GIT_COMMIT_SHA must be a full-length git SHA')
|
|
67
|
-
return filteredTags
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
filteredTags[tag] = metadata[tag]
|
|
71
|
-
return filteredTags
|
|
72
|
-
}, {})
|
|
73
|
-
}
|
|
74
|
-
|
|
75
55
|
function getUserProviderGitMetadata () {
|
|
76
56
|
const {
|
|
77
57
|
DD_GIT_COMMIT_SHA,
|
|
@@ -95,7 +75,7 @@ function getUserProviderGitMetadata () {
|
|
|
95
75
|
tag = normalizeRef(DD_GIT_BRANCH)
|
|
96
76
|
}
|
|
97
77
|
|
|
98
|
-
|
|
78
|
+
return removeEmptyValues({
|
|
99
79
|
[GIT_COMMIT_SHA]: DD_GIT_COMMIT_SHA,
|
|
100
80
|
[GIT_BRANCH]: branch,
|
|
101
81
|
[GIT_REPOSITORY_URL]: filterSensitiveInfoFromRepository(DD_GIT_REPOSITORY_URL),
|
|
@@ -108,7 +88,6 @@ function getUserProviderGitMetadata () {
|
|
|
108
88
|
[GIT_COMMIT_AUTHOR_EMAIL]: DD_GIT_COMMIT_AUTHOR_EMAIL,
|
|
109
89
|
[GIT_COMMIT_AUTHOR_DATE]: DD_GIT_COMMIT_AUTHOR_DATE
|
|
110
90
|
})
|
|
111
|
-
return removeInvalidGitMetadata(metadata)
|
|
112
91
|
}
|
|
113
92
|
|
|
114
93
|
module.exports = { getUserProviderGitMetadata, validateGitRepositoryUrl, validateGitCommitSha }
|
|
@@ -7,7 +7,6 @@ const { URL, format, pathToFileURL } = require('url')
|
|
|
7
7
|
const { AgentExporter } = require('./exporters/agent')
|
|
8
8
|
const { FileExporter } = require('./exporters/file')
|
|
9
9
|
const { ConsoleLogger } = require('./loggers/console')
|
|
10
|
-
const CpuProfiler = require('./profilers/cpu')
|
|
11
10
|
const WallProfiler = require('./profilers/wall')
|
|
12
11
|
const SpaceProfiler = require('./profilers/space')
|
|
13
12
|
const { oomExportStrategies, snapshotKinds } = require('./constants')
|
|
@@ -202,8 +201,6 @@ function getProfiler (name, options) {
|
|
|
202
201
|
return new WallProfiler(options)
|
|
203
202
|
case 'space':
|
|
204
203
|
return new SpaceProfiler(options)
|
|
205
|
-
case 'cpu-experimental':
|
|
206
|
-
return new CpuProfiler(options)
|
|
207
204
|
default:
|
|
208
205
|
options.logger.error(`Unknown profiler "${name}"`)
|
|
209
206
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { Profiler, ServerlessProfiler } = require('./profiler')
|
|
4
|
-
const CpuProfiler = require('./profilers/cpu')
|
|
5
4
|
const WallProfiler = require('./profilers/wall')
|
|
6
5
|
const SpaceProfiler = require('./profilers/space')
|
|
7
6
|
const { AgentExporter } = require('./exporters/agent')
|
|
@@ -14,7 +13,6 @@ module.exports = {
|
|
|
14
13
|
profiler,
|
|
15
14
|
AgentExporter,
|
|
16
15
|
FileExporter,
|
|
17
|
-
CpuProfiler,
|
|
18
16
|
WallProfiler,
|
|
19
17
|
SpaceProfiler,
|
|
20
18
|
ConsoleLogger
|
|
@@ -3,12 +3,19 @@
|
|
|
3
3
|
class NativeWallProfiler {
|
|
4
4
|
constructor (options = {}) {
|
|
5
5
|
this.type = 'wall'
|
|
6
|
-
this.
|
|
6
|
+
this._samplingIntervalMicros = options.samplingInterval || 1e6 / 99 // 99hz
|
|
7
|
+
this._flushIntervalMillis = options.flushInterval || 60 * 1e3 // 60 seconds
|
|
8
|
+
this._codeHotspotsEnabled = !!options.codeHotspotsEnabled
|
|
7
9
|
this._mapper = undefined
|
|
8
10
|
this._pprof = undefined
|
|
11
|
+
|
|
12
|
+
this._logger = options.logger
|
|
13
|
+
this._started = false
|
|
9
14
|
}
|
|
10
15
|
|
|
11
16
|
start ({ mapper } = {}) {
|
|
17
|
+
if (this._started) return
|
|
18
|
+
|
|
12
19
|
this._mapper = mapper
|
|
13
20
|
this._pprof = require('@datadog/pprof')
|
|
14
21
|
|
|
@@ -20,12 +27,20 @@ class NativeWallProfiler {
|
|
|
20
27
|
process._stopProfilerIdleNotifier = () => {}
|
|
21
28
|
}
|
|
22
29
|
|
|
23
|
-
this.
|
|
30
|
+
this._pprof.time.start({
|
|
31
|
+
intervalMicros: this._samplingIntervalMicros,
|
|
32
|
+
durationMillis: this._flushIntervalMillis,
|
|
33
|
+
sourceMapper: this._mapper,
|
|
34
|
+
customLabels: this._codeHotspotsEnabled,
|
|
35
|
+
lineNumbers: false
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
this._started = true
|
|
24
39
|
}
|
|
25
40
|
|
|
26
41
|
profile () {
|
|
27
|
-
if (!this.
|
|
28
|
-
return this.
|
|
42
|
+
if (!this._started) return
|
|
43
|
+
return this._pprof.time.stop(true)
|
|
29
44
|
}
|
|
30
45
|
|
|
31
46
|
encode (profile) {
|
|
@@ -33,14 +48,11 @@ class NativeWallProfiler {
|
|
|
33
48
|
}
|
|
34
49
|
|
|
35
50
|
stop () {
|
|
36
|
-
if (!this.
|
|
37
|
-
this._stop()
|
|
38
|
-
this._stop = undefined
|
|
39
|
-
}
|
|
51
|
+
if (!this._started) return
|
|
40
52
|
|
|
41
|
-
|
|
42
|
-
this.
|
|
43
|
-
|
|
53
|
+
const profile = this._pprof.time.stop()
|
|
54
|
+
this._started = false
|
|
55
|
+
return profile
|
|
44
56
|
}
|
|
45
57
|
}
|
|
46
58
|
|
|
@@ -54,4 +54,68 @@ if (major === '19' && minor === '9') {
|
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
if (!Channel.prototype.runStores) {
|
|
58
|
+
const ActiveChannelPrototype = getActiveChannelPrototype()
|
|
59
|
+
|
|
60
|
+
Channel.prototype.bindStore = ActiveChannelPrototype.bindStore = function (store, transform) {
|
|
61
|
+
if (!this._stores) {
|
|
62
|
+
this._stores = new Map()
|
|
63
|
+
}
|
|
64
|
+
this._stores.set(store, transform)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
Channel.prototype.unbindStore = ActiveChannelPrototype.runStores = function (store) {
|
|
68
|
+
if (!this._stores) return
|
|
69
|
+
this._stores.delete(store)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
Channel.prototype.runStores = ActiveChannelPrototype.runStores = function (data, fn, thisArg, ...args) {
|
|
73
|
+
if (!this._stores) return Reflect.apply(fn, thisArg, args)
|
|
74
|
+
|
|
75
|
+
let run = () => {
|
|
76
|
+
this.publish(data)
|
|
77
|
+
return Reflect.apply(fn, thisArg, args)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
for (const entry of this._stores.entries()) {
|
|
81
|
+
const store = entry[0]
|
|
82
|
+
const transform = entry[1]
|
|
83
|
+
run = wrapStoreRun(store, data, run, transform)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return run()
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function defaultTransform (data) {
|
|
91
|
+
return data
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function wrapStoreRun (store, data, next, transform = defaultTransform) {
|
|
95
|
+
return () => {
|
|
96
|
+
let context
|
|
97
|
+
try {
|
|
98
|
+
context = transform(data)
|
|
99
|
+
} catch (err) {
|
|
100
|
+
process.nextTick(() => {
|
|
101
|
+
throw err
|
|
102
|
+
})
|
|
103
|
+
return next()
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return store.run(context, next)
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function getActiveChannelPrototype () {
|
|
111
|
+
const dummyChannel = channel('foo')
|
|
112
|
+
const listener = () => {}
|
|
113
|
+
|
|
114
|
+
dummyChannel.subscribe(listener)
|
|
115
|
+
const ActiveChannelPrototype = Object.getPrototypeOf(dummyChannel)
|
|
116
|
+
dummyChannel.unsubscribe(listener)
|
|
117
|
+
|
|
118
|
+
return ActiveChannelPrototype
|
|
119
|
+
}
|
|
120
|
+
|
|
57
121
|
module.exports = dc
|