dd-trace 3.26.0 → 3.28.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
|
@@ -4,30 +4,45 @@ const TaintedUtils = require('@datadog/native-iast-taint-tracking')
|
|
|
4
4
|
const { storage } = require('../../../../../datadog-core')
|
|
5
5
|
const iastContextFunctions = require('../iast-context')
|
|
6
6
|
const iastLog = require('../iast-log')
|
|
7
|
+
const { EXECUTED_PROPAGATION } = require('../telemetry/iast-metric')
|
|
8
|
+
const { isDebugAllowed } = require('../telemetry/verbosity')
|
|
7
9
|
|
|
8
10
|
function noop (res) { return res }
|
|
9
|
-
|
|
11
|
+
// NOTE: methods of this object must be synchronized with csi-methods.js file definitions!
|
|
12
|
+
// Otherwise you may end up rewriting a method and not providing its rewritten implementation
|
|
13
|
+
const TaintTrackingNoop = {
|
|
10
14
|
plusOperator: noop,
|
|
11
|
-
trim: noop,
|
|
12
|
-
trimEnd: noop,
|
|
13
15
|
concat: noop,
|
|
14
|
-
|
|
15
|
-
substr: noop,
|
|
16
|
+
replace: noop,
|
|
16
17
|
slice: noop,
|
|
17
|
-
|
|
18
|
+
substr: noop,
|
|
19
|
+
substring: noop,
|
|
20
|
+
trim: noop,
|
|
21
|
+
trimEnd: noop
|
|
18
22
|
}
|
|
19
23
|
|
|
20
|
-
function getTransactionId () {
|
|
21
|
-
const store = storage.getStore()
|
|
22
|
-
const iastContext = iastContextFunctions.getIastContext(store)
|
|
24
|
+
function getTransactionId (iastContext) {
|
|
23
25
|
return iastContext && iastContext[iastContextFunctions.IAST_TRANSACTION_ID]
|
|
24
26
|
}
|
|
25
27
|
|
|
26
|
-
function
|
|
28
|
+
function getContextDefault () {
|
|
29
|
+
const store = storage.getStore()
|
|
30
|
+
return iastContextFunctions.getIastContext(store)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function getContextDebug () {
|
|
34
|
+
const iastContext = getContextDefault()
|
|
35
|
+
EXECUTED_PROPAGATION.inc(null, iastContext)
|
|
36
|
+
return iastContext
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function getFilteredCsiFn (cb, filter, getContext) {
|
|
27
40
|
return function csiCall (res, fn, target, ...rest) {
|
|
28
41
|
try {
|
|
29
42
|
if (filter(res, fn, target)) { return res }
|
|
30
|
-
|
|
43
|
+
|
|
44
|
+
const context = getContext()
|
|
45
|
+
const transactionId = getTransactionId(context)
|
|
31
46
|
if (transactionId) {
|
|
32
47
|
return cb(transactionId, res, target, ...rest)
|
|
33
48
|
}
|
|
@@ -47,7 +62,7 @@ function isValidCsiMethod (fn, protos) {
|
|
|
47
62
|
return protos.some(proto => fn === proto)
|
|
48
63
|
}
|
|
49
64
|
|
|
50
|
-
function getCsiFn (cb, ...protos) {
|
|
65
|
+
function getCsiFn (cb, getContext, ...protos) {
|
|
51
66
|
let filter
|
|
52
67
|
if (!protos || protos.length === 0) {
|
|
53
68
|
filter = (res, fn, target) => notString(res, target)
|
|
@@ -57,49 +72,73 @@ function getCsiFn (cb, ...protos) {
|
|
|
57
72
|
} else {
|
|
58
73
|
filter = (res, fn, target) => notString(res, target) || !isValidCsiMethod(fn, protos)
|
|
59
74
|
}
|
|
60
|
-
return getFilteredCsiFn(cb, filter)
|
|
75
|
+
return getFilteredCsiFn(cb, filter, getContext)
|
|
61
76
|
}
|
|
62
77
|
|
|
63
|
-
function csiMethodsDefaults (names, excluded) {
|
|
78
|
+
function csiMethodsDefaults (names, excluded, getContext) {
|
|
64
79
|
const impl = {}
|
|
65
80
|
names.forEach(name => {
|
|
66
81
|
if (excluded.indexOf(name) !== -1) return
|
|
67
82
|
impl[name] = getCsiFn(
|
|
68
83
|
(transactionId, res, target, ...rest) => TaintedUtils[name](transactionId, res, target, ...rest),
|
|
84
|
+
getContext,
|
|
69
85
|
String.prototype[name]
|
|
70
86
|
)
|
|
71
87
|
})
|
|
72
88
|
return impl
|
|
73
89
|
}
|
|
74
90
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
91
|
+
function csiMethodsOverrides (getContext) {
|
|
92
|
+
return {
|
|
93
|
+
plusOperator: function (res, op1, op2) {
|
|
94
|
+
try {
|
|
95
|
+
if (notString(res) || (notString(op1) && notString(op2))) { return res }
|
|
96
|
+
const iastContext = getContext()
|
|
97
|
+
const transactionId = getTransactionId(iastContext)
|
|
98
|
+
if (transactionId) {
|
|
99
|
+
return TaintedUtils.concat(transactionId, res, op1, op2)
|
|
100
|
+
}
|
|
101
|
+
} catch (e) {
|
|
102
|
+
iastLog.error(`Error invoking CSI plusOperator`)
|
|
103
|
+
.errorAndPublish(e)
|
|
82
104
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
105
|
+
return res
|
|
106
|
+
},
|
|
107
|
+
|
|
108
|
+
trim: getCsiFn(
|
|
109
|
+
(transactionId, res, target) => TaintedUtils.trim(transactionId, res, target),
|
|
110
|
+
getContext,
|
|
111
|
+
String.prototype.trim,
|
|
112
|
+
String.prototype.trimStart
|
|
113
|
+
)
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function createImplWith (getContext) {
|
|
118
|
+
const methodNames = Object.keys(TaintTrackingNoop)
|
|
119
|
+
const overrides = csiMethodsOverrides(getContext)
|
|
120
|
+
|
|
121
|
+
// impls could be cached but at the moment there is only one invocation to getTaintTrackingImpl
|
|
122
|
+
return {
|
|
123
|
+
...csiMethodsDefaults(methodNames, Object.keys(overrides), getContext),
|
|
124
|
+
...overrides
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function getTaintTrackingImpl (telemetryVerbosity, dummy = false) {
|
|
129
|
+
if (dummy) return TaintTrackingNoop
|
|
89
130
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
)
|
|
131
|
+
// with Verbosity.DEBUG every invocation of a TaintedUtils method increases the EXECUTED_PROPAGATION metric
|
|
132
|
+
return isDebugAllowed(telemetryVerbosity)
|
|
133
|
+
? createImplWith(getContextDebug)
|
|
134
|
+
: createImplWith(getContextDefault)
|
|
95
135
|
}
|
|
96
136
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
...csiMethodsOverrides
|
|
137
|
+
function getTaintTrackingNoop () {
|
|
138
|
+
return getTaintTrackingImpl(null, true)
|
|
100
139
|
}
|
|
101
140
|
|
|
102
141
|
module.exports = {
|
|
103
|
-
|
|
104
|
-
|
|
142
|
+
getTaintTrackingImpl,
|
|
143
|
+
getTaintTrackingNoop
|
|
105
144
|
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { getNamespaceFromContext, globalNamespace } = require('./namespaces')
|
|
4
|
+
|
|
5
|
+
const Scope = {
|
|
6
|
+
GLOBAL: 'GLOBAL',
|
|
7
|
+
REQUEST: 'REQUEST'
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const PropagationType = {
|
|
11
|
+
STRING: 'STRING',
|
|
12
|
+
JSON: 'JSON',
|
|
13
|
+
URL: 'URL'
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const TagKey = {
|
|
17
|
+
VULNERABILITY_TYPE: 'vulnerability_type',
|
|
18
|
+
SOURCE_TYPE: 'source_type',
|
|
19
|
+
PROPAGATION_TYPE: 'propagation_type'
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
class IastMetric {
|
|
23
|
+
constructor (name, scope, tagKey) {
|
|
24
|
+
this.name = name
|
|
25
|
+
this.scope = scope
|
|
26
|
+
this.tagKey = tagKey
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
getNamespace (context) {
|
|
30
|
+
return getNamespaceFromContext(context) || globalNamespace
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
getTag (tagValue) {
|
|
34
|
+
return tagValue ? { [this.tagKey]: tagValue } : undefined
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
addValue (value, tagValue, context) {
|
|
38
|
+
this.getNamespace(context)
|
|
39
|
+
.count(this.name, this.getTag(tagValue))
|
|
40
|
+
.inc(value)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
add (value, tagValue, context) {
|
|
44
|
+
if (Array.isArray(tagValue)) {
|
|
45
|
+
tagValue.forEach(tag => this.addValue(value, tag, context))
|
|
46
|
+
} else {
|
|
47
|
+
this.addValue(value, tagValue, context)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
inc (tagValue, context) {
|
|
52
|
+
this.add(1, tagValue, context)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function getExecutedMetric (tagKey) {
|
|
57
|
+
return tagKey === TagKey.VULNERABILITY_TYPE ? EXECUTED_SINK : EXECUTED_SOURCE
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function getInstrumentedMetric (tagKey) {
|
|
61
|
+
return tagKey === TagKey.VULNERABILITY_TYPE ? INSTRUMENTED_SINK : INSTRUMENTED_SOURCE
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const INSTRUMENTED_PROPAGATION = new IastMetric('instrumented.propagation', Scope.GLOBAL)
|
|
65
|
+
const INSTRUMENTED_SOURCE = new IastMetric('instrumented.source', Scope.GLOBAL, TagKey.SOURCE_TYPE)
|
|
66
|
+
const INSTRUMENTED_SINK = new IastMetric('instrumented.sink', Scope.GLOBAL, TagKey.VULNERABILITY_TYPE)
|
|
67
|
+
|
|
68
|
+
const EXECUTED_SOURCE = new IastMetric('executed.source', Scope.REQUEST, TagKey.SOURCE_TYPE)
|
|
69
|
+
const EXECUTED_SINK = new IastMetric('executed.sink', Scope.REQUEST, TagKey.VULNERABILITY_TYPE)
|
|
70
|
+
|
|
71
|
+
const REQUEST_TAINTED = new IastMetric('request.tainted', Scope.REQUEST)
|
|
72
|
+
|
|
73
|
+
// DEBUG using metrics
|
|
74
|
+
const EXECUTED_PROPAGATION = new IastMetric('executed.propagation', Scope.REQUEST)
|
|
75
|
+
const EXECUTED_TAINTED = new IastMetric('executed.tainted', Scope.REQUEST)
|
|
76
|
+
|
|
77
|
+
// DEBUG using distribution endpoint
|
|
78
|
+
const INSTRUMENTATION_TIME = new IastMetric('instrumentation.time', Scope.GLOBAL)
|
|
79
|
+
|
|
80
|
+
module.exports = {
|
|
81
|
+
INSTRUMENTED_PROPAGATION,
|
|
82
|
+
INSTRUMENTED_SOURCE,
|
|
83
|
+
INSTRUMENTED_SINK,
|
|
84
|
+
|
|
85
|
+
EXECUTED_PROPAGATION,
|
|
86
|
+
EXECUTED_SOURCE,
|
|
87
|
+
EXECUTED_SINK,
|
|
88
|
+
EXECUTED_TAINTED,
|
|
89
|
+
|
|
90
|
+
REQUEST_TAINTED,
|
|
91
|
+
|
|
92
|
+
INSTRUMENTATION_TIME,
|
|
93
|
+
|
|
94
|
+
PropagationType,
|
|
95
|
+
TagKey,
|
|
96
|
+
|
|
97
|
+
IastMetric,
|
|
98
|
+
|
|
99
|
+
getExecutedMetric,
|
|
100
|
+
getInstrumentedMetric
|
|
101
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const telemetryMetrics = require('../../../telemetry/metrics')
|
|
4
|
+
const telemetryLogs = require('./log')
|
|
5
|
+
const { Verbosity, getVerbosity } = require('./verbosity')
|
|
6
|
+
const { initRequestNamespace, finalizeRequestNamespace, globalNamespace } = require('./namespaces')
|
|
7
|
+
|
|
8
|
+
class Telemetry {
|
|
9
|
+
configure (config, verbosity) {
|
|
10
|
+
// in order to telemetry be enabled, tracer telemetry and metrics collection have to be enabled
|
|
11
|
+
this.enabled = config && config.telemetry && config.telemetry.enabled && config.telemetry.metrics
|
|
12
|
+
this.verbosity = this.enabled ? getVerbosity(verbosity) : Verbosity.OFF
|
|
13
|
+
|
|
14
|
+
if (this.enabled) {
|
|
15
|
+
telemetryMetrics.manager.set('iast', globalNamespace)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
telemetryLogs.start()
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
stop () {
|
|
22
|
+
this.enabled = false
|
|
23
|
+
telemetryMetrics.manager.delete('iast')
|
|
24
|
+
|
|
25
|
+
telemetryLogs.stop()
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
isEnabled () {
|
|
29
|
+
return this.enabled
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
onRequestStart (context) {
|
|
33
|
+
if (this.isEnabled() && this.verbosity !== Verbosity.OFF) {
|
|
34
|
+
initRequestNamespace(context)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
onRequestEnd (context, rootSpan) {
|
|
39
|
+
if (this.isEnabled() && this.verbosity !== Verbosity.OFF) {
|
|
40
|
+
finalizeRequestNamespace(context, rootSpan)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
module.exports = new Telemetry()
|
|
@@ -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
|
+
}
|
|
@@ -247,6 +247,10 @@ class Config {
|
|
|
247
247
|
process.env.DD_TELEMETRY_DEBUG,
|
|
248
248
|
false
|
|
249
249
|
)
|
|
250
|
+
const DD_TELEMETRY_METRICS_ENABLED = coalesce(
|
|
251
|
+
process.env.DD_TELEMETRY_METRICS_ENABLED,
|
|
252
|
+
false
|
|
253
|
+
)
|
|
250
254
|
const DD_TRACE_AGENT_PROTOCOL_VERSION = coalesce(
|
|
251
255
|
options.protocolVersion,
|
|
252
256
|
process.env.DD_TRACE_AGENT_PROTOCOL_VERSION,
|
|
@@ -319,6 +323,12 @@ class Config {
|
|
|
319
323
|
const DD_TRACE_SPAN_ATTRIBUTE_SCHEMA = validateNamingVersion(
|
|
320
324
|
process.env.DD_TRACE_SPAN_ATTRIBUTE_SCHEMA
|
|
321
325
|
)
|
|
326
|
+
const DD_TRACE_PEER_SERVICE_MAPPING = coalesce(
|
|
327
|
+
options.peerServiceMapping,
|
|
328
|
+
process.env.DD_TRACE_PEER_SERVICE_MAPPING ? fromEntries(
|
|
329
|
+
process.env.DD_TRACE_PEER_SERVICE_MAPPING.split(',').map(x => x.trim().split(':'))
|
|
330
|
+
) : {}
|
|
331
|
+
)
|
|
322
332
|
const DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED = process.env.DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED
|
|
323
333
|
|
|
324
334
|
const DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED = coalesce(
|
|
@@ -461,6 +471,12 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
|
|
|
461
471
|
true
|
|
462
472
|
)
|
|
463
473
|
|
|
474
|
+
const DD_IAST_TELEMETRY_VERBOSITY = coalesce(
|
|
475
|
+
iastOptions && iastOptions.telemetryVerbosity,
|
|
476
|
+
process.env.DD_IAST_TELEMETRY_VERBOSITY,
|
|
477
|
+
'INFORMATION'
|
|
478
|
+
)
|
|
479
|
+
|
|
464
480
|
const DD_CIVISIBILITY_GIT_UPLOAD_ENABLED = coalesce(
|
|
465
481
|
process.env.DD_CIVISIBILITY_GIT_UPLOAD_ENABLED,
|
|
466
482
|
true
|
|
@@ -554,6 +570,7 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
|
|
|
554
570
|
: true
|
|
555
571
|
)
|
|
556
572
|
this.traceRemoveIntegrationServiceNamesEnabled = DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED
|
|
573
|
+
this.peerServiceMapping = DD_TRACE_PEER_SERVICE_MAPPING
|
|
557
574
|
this.lookup = options.lookup
|
|
558
575
|
this.startupLogs = isTrue(DD_TRACE_STARTUP_LOGS)
|
|
559
576
|
// Disabled for CI Visibility's agentless
|
|
@@ -561,7 +578,8 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
|
|
|
561
578
|
enabled: DD_TRACE_EXPORTER !== 'datadog' && isTrue(DD_TRACE_TELEMETRY_ENABLED),
|
|
562
579
|
heartbeatInterval: DD_TELEMETRY_HEARTBEAT_INTERVAL,
|
|
563
580
|
logCollection: isTrue(DD_TELEMETRY_LOG_COLLECTION_ENABLED),
|
|
564
|
-
debug: isTrue(DD_TELEMETRY_DEBUG)
|
|
581
|
+
debug: isTrue(DD_TELEMETRY_DEBUG),
|
|
582
|
+
metrics: isTrue(DD_TELEMETRY_METRICS_ENABLED)
|
|
565
583
|
}
|
|
566
584
|
this.protocolVersion = DD_TRACE_AGENT_PROTOCOL_VERSION
|
|
567
585
|
this.tagsHeaderMaxLength = parseInt(DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH)
|
|
@@ -590,7 +608,8 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
|
|
|
590
608
|
maxConcurrentRequests: DD_IAST_MAX_CONCURRENT_REQUESTS,
|
|
591
609
|
maxContextOperations: DD_IAST_MAX_CONTEXT_OPERATIONS,
|
|
592
610
|
deduplicationEnabled: DD_IAST_DEDUPLICATION_ENABLED,
|
|
593
|
-
redactionEnabled: DD_IAST_REDACTION_ENABLED
|
|
611
|
+
redactionEnabled: DD_IAST_REDACTION_ENABLED,
|
|
612
|
+
telemetryVerbosity: DD_IAST_TELEMETRY_VERBOSITY
|
|
594
613
|
}
|
|
595
614
|
|
|
596
615
|
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
|
}
|
|
@@ -143,4 +143,17 @@ class DogStatsDClient {
|
|
|
143
143
|
}
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
-
|
|
146
|
+
class NoopDogStatsDClient {
|
|
147
|
+
gauge () { }
|
|
148
|
+
|
|
149
|
+
increment () { }
|
|
150
|
+
|
|
151
|
+
distribution () { }
|
|
152
|
+
|
|
153
|
+
flush () { }
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
module.exports = {
|
|
157
|
+
DogStatsDClient,
|
|
158
|
+
NoopDogStatsDClient
|
|
159
|
+
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
const { URL, format } = require('url')
|
|
6
6
|
const v8 = require('v8')
|
|
7
7
|
const os = require('os')
|
|
8
|
-
const
|
|
8
|
+
const { DogStatsDClient } = require('./dogstatsd')
|
|
9
9
|
const log = require('./log')
|
|
10
10
|
const Histogram = require('./histogram')
|
|
11
11
|
const { performance } = require('perf_hooks')
|
|
@@ -67,7 +67,7 @@ module.exports = {
|
|
|
67
67
|
}))
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
client = new
|
|
70
|
+
client = new DogStatsDClient(clientConfig)
|
|
71
71
|
|
|
72
72
|
time = process.hrtime()
|
|
73
73
|
|
|
@@ -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
|
}
|