dd-trace 2.40.0 → 2.41.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/mocha.js +5 -3
- 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-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/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
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const dc = require('
|
|
4
|
-
const logCollector = require('./
|
|
5
|
-
const { sendData } = require('
|
|
6
|
-
const log = require('
|
|
3
|
+
const dc = require('../../../../../../diagnostics_channel')
|
|
4
|
+
const logCollector = require('./log-collector')
|
|
5
|
+
const { sendData } = require('../../../../telemetry/send-data')
|
|
6
|
+
const log = require('../../../../log')
|
|
7
7
|
|
|
8
8
|
const telemetryStartChannel = dc.channel('datadog:telemetry:start')
|
|
9
9
|
const telemetryStopChannel = dc.channel('datadog:telemetry:stop')
|
|
@@ -37,7 +37,7 @@ function isLogCollectionEnabled (config) {
|
|
|
37
37
|
|
|
38
38
|
function onTelemetryStart (msg) {
|
|
39
39
|
if (!msg || !isLogCollectionEnabled(msg.config)) {
|
|
40
|
-
log.info('IAST telemetry logs start received but log collection is not enabled or configuration is incorrect')
|
|
40
|
+
log.info('IAST telemetry logs start event received but log collection is not enabled or configuration is incorrect')
|
|
41
41
|
return false
|
|
42
42
|
}
|
|
43
43
|
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const log = require('../../../log')
|
|
4
|
+
const { Namespace } = require('../../../telemetry/metrics')
|
|
5
|
+
const { addMetricsToSpan, filterTags } = require('./span-tags')
|
|
6
|
+
const { IAST_TRACE_METRIC_PREFIX } = require('../tags')
|
|
7
|
+
|
|
8
|
+
const DD_IAST_METRICS_NAMESPACE = Symbol('_dd.iast.request.metrics.namespace')
|
|
9
|
+
|
|
10
|
+
function initRequestNamespace (context) {
|
|
11
|
+
if (!context) return
|
|
12
|
+
|
|
13
|
+
const namespace = new Namespace('iast')
|
|
14
|
+
context[DD_IAST_METRICS_NAMESPACE] = namespace
|
|
15
|
+
return namespace
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function getNamespaceFromContext (context) {
|
|
19
|
+
return context && context[DD_IAST_METRICS_NAMESPACE]
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function finalizeRequestNamespace (context, rootSpan) {
|
|
23
|
+
try {
|
|
24
|
+
const namespace = getNamespaceFromContext(context)
|
|
25
|
+
if (!namespace) return
|
|
26
|
+
|
|
27
|
+
const metrics = [...namespace.metrics.values()]
|
|
28
|
+
namespace.metrics.clear()
|
|
29
|
+
|
|
30
|
+
addMetricsToSpan(rootSpan, metrics, IAST_TRACE_METRIC_PREFIX)
|
|
31
|
+
|
|
32
|
+
merge(metrics)
|
|
33
|
+
} catch (e) {
|
|
34
|
+
log.error(e)
|
|
35
|
+
} finally {
|
|
36
|
+
if (context) {
|
|
37
|
+
delete context[DD_IAST_METRICS_NAMESPACE]
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function merge (metrics) {
|
|
43
|
+
metrics.forEach(metric => metric.points.forEach(point => {
|
|
44
|
+
globalNamespace
|
|
45
|
+
.count(metric.metric, getTagsObject(metric.tags))
|
|
46
|
+
.inc(point[1])
|
|
47
|
+
}))
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function getTagsObject (tags) {
|
|
51
|
+
if (tags && tags.length > 0) {
|
|
52
|
+
return filterTags(tags)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
class IastNamespace extends Namespace {
|
|
57
|
+
constructor () {
|
|
58
|
+
super('iast')
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
reset () {
|
|
62
|
+
this.metrics.clear()
|
|
63
|
+
this.distributions.clear()
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const globalNamespace = new IastNamespace()
|
|
68
|
+
|
|
69
|
+
module.exports = {
|
|
70
|
+
initRequestNamespace,
|
|
71
|
+
getNamespaceFromContext,
|
|
72
|
+
finalizeRequestNamespace,
|
|
73
|
+
globalNamespace,
|
|
74
|
+
|
|
75
|
+
DD_IAST_METRICS_NAMESPACE
|
|
76
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
function addMetricsToSpan (rootSpan, metrics, tagPrefix) {
|
|
4
|
+
if (!rootSpan || !rootSpan.addTags || !metrics) return
|
|
5
|
+
|
|
6
|
+
const flattenMap = new Map()
|
|
7
|
+
metrics
|
|
8
|
+
.filter(data => data && data.metric)
|
|
9
|
+
.forEach(data => {
|
|
10
|
+
const name = taggedMetricName(data)
|
|
11
|
+
let total = flattenMap.get(name)
|
|
12
|
+
const value = flatten(data)
|
|
13
|
+
if (!total) {
|
|
14
|
+
total = value
|
|
15
|
+
} else {
|
|
16
|
+
total += value
|
|
17
|
+
}
|
|
18
|
+
flattenMap.set(name, total)
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
for (const [key, value] of flattenMap) {
|
|
22
|
+
const tagName = `${tagPrefix}.${key}`
|
|
23
|
+
rootSpan.addTags({
|
|
24
|
+
[tagName]: value
|
|
25
|
+
})
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function flatten (metricData) {
|
|
30
|
+
return metricData.points && metricData.points.map(point => point[1]).reduce((total, value) => total + value, 0)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function taggedMetricName (data) {
|
|
34
|
+
const metric = data.metric
|
|
35
|
+
const tags = data.tags && filterTags(data.tags)
|
|
36
|
+
return !tags || !tags.length
|
|
37
|
+
? metric
|
|
38
|
+
: `${metric}.${processTagValue(tags)}`
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function filterTags (tags) {
|
|
42
|
+
return tags.filter(tag => !tag.startsWith('lib_language') && !tag.startsWith('version'))
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function processTagValue (tags) {
|
|
46
|
+
return tags.map(tag => tag.includes(':') ? tag.split(':')[1] : tag)
|
|
47
|
+
.join('_').replace(/\./g, '_')
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
module.exports = {
|
|
51
|
+
addMetricsToSpan,
|
|
52
|
+
filterTags
|
|
53
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const Verbosity = {
|
|
4
|
+
OFF: 0,
|
|
5
|
+
MANDATORY: 1,
|
|
6
|
+
INFORMATION: 2,
|
|
7
|
+
DEBUG: 3
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function isDebugAllowed (value) {
|
|
11
|
+
return value >= Verbosity.DEBUG
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function isInfoAllowed (value) {
|
|
15
|
+
return value >= Verbosity.INFORMATION
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function getVerbosity (verbosity) {
|
|
19
|
+
if (verbosity) {
|
|
20
|
+
verbosity = verbosity.toUpperCase()
|
|
21
|
+
return Verbosity[verbosity] !== undefined ? Verbosity[verbosity] : Verbosity.INFORMATION
|
|
22
|
+
} else {
|
|
23
|
+
return Verbosity.INFORMATION
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function getName (verbosityValue) {
|
|
28
|
+
for (const name in Verbosity) {
|
|
29
|
+
if (Verbosity[name] === verbosityValue) {
|
|
30
|
+
return name
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return 'OFF'
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
module.exports = {
|
|
37
|
+
Verbosity,
|
|
38
|
+
isDebugAllowed,
|
|
39
|
+
isInfoAllowed,
|
|
40
|
+
getVerbosity,
|
|
41
|
+
getName
|
|
42
|
+
}
|
|
@@ -244,6 +244,10 @@ class Config {
|
|
|
244
244
|
process.env.DD_TELEMETRY_DEBUG,
|
|
245
245
|
false
|
|
246
246
|
)
|
|
247
|
+
const DD_TELEMETRY_METRICS_ENABLED = coalesce(
|
|
248
|
+
process.env.DD_TELEMETRY_METRICS_ENABLED,
|
|
249
|
+
false
|
|
250
|
+
)
|
|
247
251
|
const DD_TRACE_AGENT_PROTOCOL_VERSION = coalesce(
|
|
248
252
|
options.protocolVersion,
|
|
249
253
|
process.env.DD_TRACE_AGENT_PROTOCOL_VERSION,
|
|
@@ -316,6 +320,12 @@ class Config {
|
|
|
316
320
|
const DD_TRACE_SPAN_ATTRIBUTE_SCHEMA = validateNamingVersion(
|
|
317
321
|
process.env.DD_TRACE_SPAN_ATTRIBUTE_SCHEMA
|
|
318
322
|
)
|
|
323
|
+
const DD_TRACE_PEER_SERVICE_MAPPING = coalesce(
|
|
324
|
+
options.peerServiceMapping,
|
|
325
|
+
process.env.DD_TRACE_PEER_SERVICE_MAPPING ? fromEntries(
|
|
326
|
+
process.env.DD_TRACE_PEER_SERVICE_MAPPING.split(',').map(x => x.trim().split(':'))
|
|
327
|
+
) : {}
|
|
328
|
+
)
|
|
319
329
|
const DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED = process.env.DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED
|
|
320
330
|
|
|
321
331
|
const DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED = coalesce(
|
|
@@ -458,6 +468,12 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
|
|
|
458
468
|
true
|
|
459
469
|
)
|
|
460
470
|
|
|
471
|
+
const DD_IAST_TELEMETRY_VERBOSITY = coalesce(
|
|
472
|
+
iastOptions && iastOptions.telemetryVerbosity,
|
|
473
|
+
process.env.DD_IAST_TELEMETRY_VERBOSITY,
|
|
474
|
+
'INFORMATION'
|
|
475
|
+
)
|
|
476
|
+
|
|
461
477
|
const DD_CIVISIBILITY_GIT_UPLOAD_ENABLED = coalesce(
|
|
462
478
|
process.env.DD_CIVISIBILITY_GIT_UPLOAD_ENABLED,
|
|
463
479
|
true
|
|
@@ -551,6 +567,7 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
|
|
|
551
567
|
: true
|
|
552
568
|
)
|
|
553
569
|
this.traceRemoveIntegrationServiceNamesEnabled = DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED
|
|
570
|
+
this.peerServiceMapping = DD_TRACE_PEER_SERVICE_MAPPING
|
|
554
571
|
this.lookup = options.lookup
|
|
555
572
|
this.startupLogs = isTrue(DD_TRACE_STARTUP_LOGS)
|
|
556
573
|
// Disabled for CI Visibility's agentless
|
|
@@ -558,7 +575,8 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
|
|
|
558
575
|
enabled: DD_TRACE_EXPORTER !== 'datadog' && isTrue(DD_TRACE_TELEMETRY_ENABLED),
|
|
559
576
|
heartbeatInterval: DD_TELEMETRY_HEARTBEAT_INTERVAL,
|
|
560
577
|
logCollection: isTrue(DD_TELEMETRY_LOG_COLLECTION_ENABLED),
|
|
561
|
-
debug: isTrue(DD_TELEMETRY_DEBUG)
|
|
578
|
+
debug: isTrue(DD_TELEMETRY_DEBUG),
|
|
579
|
+
metrics: isTrue(DD_TELEMETRY_METRICS_ENABLED)
|
|
562
580
|
}
|
|
563
581
|
this.protocolVersion = DD_TRACE_AGENT_PROTOCOL_VERSION
|
|
564
582
|
this.tagsHeaderMaxLength = parseInt(DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH)
|
|
@@ -587,7 +605,8 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
|
|
|
587
605
|
maxConcurrentRequests: DD_IAST_MAX_CONCURRENT_REQUESTS,
|
|
588
606
|
maxContextOperations: DD_IAST_MAX_CONTEXT_OPERATIONS,
|
|
589
607
|
deduplicationEnabled: DD_IAST_DEDUPLICATION_ENABLED,
|
|
590
|
-
redactionEnabled: DD_IAST_REDACTION_ENABLED
|
|
608
|
+
redactionEnabled: DD_IAST_REDACTION_ENABLED,
|
|
609
|
+
telemetryVerbosity: DD_IAST_TELEMETRY_VERBOSITY
|
|
591
610
|
}
|
|
592
611
|
|
|
593
612
|
this.isCiVisibility = isTrue(DD_IS_CIVISIBILITY)
|
|
@@ -28,6 +28,7 @@ module.exports = {
|
|
|
28
28
|
CLIENT_PORT_KEY: 'network.destination.port',
|
|
29
29
|
PEER_SERVICE_KEY: 'peer.service',
|
|
30
30
|
PEER_SERVICE_SOURCE_KEY: '_dd.peer.service.source',
|
|
31
|
+
PEER_SERVICE_REMAP_KEY: '_dd.peer.service.remapped_from',
|
|
31
32
|
SCI_REPOSITORY_URL: '_dd.git.repository_url',
|
|
32
33
|
SCI_COMMIT_SHA: '_dd.git.commit.sha'
|
|
33
34
|
}
|
|
@@ -27,6 +27,7 @@ class DatadogTracer {
|
|
|
27
27
|
this._env = config.env
|
|
28
28
|
this._tags = config.tags
|
|
29
29
|
this._computePeerService = config.spanComputePeerService
|
|
30
|
+
this._peerServiceMapping = config.peerServiceMapping
|
|
30
31
|
this._logInjection = config.logInjection
|
|
31
32
|
this._debug = config.debug
|
|
32
33
|
this._prioritySampler = new PrioritySampler(config.env, config.sampler)
|
|
@@ -111,7 +111,12 @@ module.exports = class CiPlugin extends Plugin {
|
|
|
111
111
|
const childOf = getTestParentSpan(this.tracer)
|
|
112
112
|
|
|
113
113
|
let testTags = {
|
|
114
|
-
...getTestCommonTags(
|
|
114
|
+
...getTestCommonTags(
|
|
115
|
+
testName,
|
|
116
|
+
testSuite,
|
|
117
|
+
this.frameworkVersion,
|
|
118
|
+
this.constructor.id
|
|
119
|
+
),
|
|
115
120
|
[COMPONENT]: this.constructor.id,
|
|
116
121
|
...extraTags
|
|
117
122
|
}
|
|
@@ -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
|
|