dd-trace 3.8.0 → 3.9.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/LICENSE-3rdparty.csv +2 -0
- package/index.d.ts +11 -0
- package/package.json +4 -2
- package/packages/datadog-instrumentations/src/body-parser.js +26 -0
- package/packages/datadog-instrumentations/src/child-process.js +30 -0
- package/packages/datadog-instrumentations/src/cucumber.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/hooks.js +5 -0
- package/packages/datadog-instrumentations/src/jest.js +102 -42
- package/packages/datadog-instrumentations/src/mocha.js +87 -6
- package/packages/datadog-instrumentations/src/pg.js +1 -2
- package/packages/datadog-instrumentations/src/qs.js +24 -0
- package/packages/datadog-plugin-cucumber/src/index.js +13 -32
- package/packages/datadog-plugin-cypress/src/plugin.js +2 -1
- package/packages/datadog-plugin-google-cloud-pubsub/src/client.js +0 -1
- package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +0 -1
- package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +0 -1
- package/packages/datadog-plugin-http/src/client.js +5 -3
- package/packages/datadog-plugin-http/src/server.js +3 -0
- package/packages/datadog-plugin-http2/src/client.js +2 -0
- package/packages/datadog-plugin-http2/src/server.js +3 -0
- package/packages/datadog-plugin-jest/src/index.js +11 -131
- package/packages/datadog-plugin-mocha/src/index.js +33 -46
- package/packages/datadog-plugin-net/src/index.js +4 -0
- package/packages/datadog-plugin-next/src/index.js +3 -0
- package/packages/datadog-plugin-pg/src/index.js +5 -2
- package/packages/datadog-plugin-router/src/index.js +2 -0
- package/packages/dd-trace/src/appsec/callbacks/ddwaf.js +3 -5
- package/packages/dd-trace/src/appsec/gateway/engine/index.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +3 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/command-injection-analyzer.js +11 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/injection-analyzer.js +19 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +13 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/index.js +6 -0
- package/packages/dd-trace/src/appsec/iast/path-line.js +8 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/filter.js +16 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/index.js +18 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +125 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/origin-types.js +4 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +38 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +66 -0
- package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +52 -6
- package/packages/dd-trace/src/appsec/index.js +8 -0
- package/packages/dd-trace/src/appsec/remote_config/capabilities.js +7 -0
- package/packages/dd-trace/src/appsec/remote_config/index.js +34 -0
- package/packages/dd-trace/src/appsec/remote_config/manager.js +264 -0
- package/packages/dd-trace/src/{exporters → appsec/remote_config}/scheduler.js +9 -9
- package/packages/dd-trace/src/appsec/rule_manager.js +3 -0
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +5 -7
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-itr-configuration.js +1 -3
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +1 -3
- package/packages/dd-trace/src/config.js +25 -9
- package/packages/dd-trace/src/constants.js +6 -1
- package/packages/dd-trace/src/exporters/common/request.js +7 -1
- package/packages/dd-trace/src/format.js +12 -10
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +1 -5
- package/packages/dd-trace/src/opentracing/span_context.js +9 -0
- package/packages/dd-trace/src/plugin_manager.js +4 -1
- package/packages/dd-trace/src/plugins/ci_plugin.js +132 -0
- package/packages/dd-trace/src/plugins/database.js +46 -0
- package/packages/dd-trace/src/plugins/tracing.js +2 -0
- package/packages/dd-trace/src/plugins/util/test.js +61 -8
- package/packages/dd-trace/src/plugins/util/web.js +9 -8
- package/packages/dd-trace/src/proxy.js +5 -1
- package/packages/dd-trace/src/tracer.js +4 -3
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const uuid = require('crypto-randomuuid')
|
|
4
|
+
const { EventEmitter } = require('events')
|
|
5
|
+
const Scheduler = require('./scheduler')
|
|
6
|
+
const tracerVersion = require('../../../../../package.json').version
|
|
7
|
+
const request = require('../../exporters/common/request')
|
|
8
|
+
const log = require('../../log')
|
|
9
|
+
|
|
10
|
+
const clientId = uuid()
|
|
11
|
+
|
|
12
|
+
const POLL_INTERVAL = 5e3
|
|
13
|
+
const DEFAULT_CAPABILITY = Buffer.alloc(1).toString('base64') // 0x00
|
|
14
|
+
|
|
15
|
+
// There MUST NOT exist separate instances of RC clients in a tracer making separate ClientGetConfigsRequest
|
|
16
|
+
// with their own separated Client.ClientState.
|
|
17
|
+
class RemoteConfigManager extends EventEmitter {
|
|
18
|
+
constructor (config) {
|
|
19
|
+
super()
|
|
20
|
+
|
|
21
|
+
this.scheduler = new Scheduler((cb) => this.poll(cb), POLL_INTERVAL)
|
|
22
|
+
|
|
23
|
+
this.requestOptions = {
|
|
24
|
+
url: config.url,
|
|
25
|
+
hostname: config.hostname,
|
|
26
|
+
port: config.port,
|
|
27
|
+
method: 'POST',
|
|
28
|
+
path: '/v0.7/config'
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
this.state = {
|
|
32
|
+
client: {
|
|
33
|
+
state: { // updated by `parseConfig()`
|
|
34
|
+
root_version: 1,
|
|
35
|
+
targets_version: 0,
|
|
36
|
+
config_states: [],
|
|
37
|
+
has_error: false,
|
|
38
|
+
error: '',
|
|
39
|
+
backend_client_state: ''
|
|
40
|
+
},
|
|
41
|
+
id: clientId,
|
|
42
|
+
products: [], // updated by `updateProducts()`
|
|
43
|
+
is_tracer: true,
|
|
44
|
+
client_tracer: {
|
|
45
|
+
runtime_id: config.tags['runtime-id'],
|
|
46
|
+
language: 'node',
|
|
47
|
+
tracer_version: tracerVersion,
|
|
48
|
+
service: config.service,
|
|
49
|
+
env: config.env,
|
|
50
|
+
app_version: config.version
|
|
51
|
+
},
|
|
52
|
+
capabilities: DEFAULT_CAPABILITY // updated by `updateCapabilities()`
|
|
53
|
+
},
|
|
54
|
+
cached_target_files: [] // updated by `parseConfig()`
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
this.appliedConfigs = new Map()
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
updateCapabilities (mask, value) {
|
|
61
|
+
const hex = Buffer.from(this.state.client.capabilities, 'base64').toString('hex')
|
|
62
|
+
|
|
63
|
+
let num = BigInt(`0x${hex}`)
|
|
64
|
+
|
|
65
|
+
if (value) {
|
|
66
|
+
num |= mask
|
|
67
|
+
} else {
|
|
68
|
+
num &= ~mask
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
let str = num.toString(16)
|
|
72
|
+
|
|
73
|
+
if (str.length % 2) str = `0${str}`
|
|
74
|
+
|
|
75
|
+
this.state.client.capabilities = Buffer.from(str, 'hex').toString('base64')
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
on (event, listener) {
|
|
79
|
+
super.on(event, listener)
|
|
80
|
+
|
|
81
|
+
this.state.client.products = this.eventNames()
|
|
82
|
+
|
|
83
|
+
this.scheduler.start()
|
|
84
|
+
|
|
85
|
+
return this
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
off (event, listener) {
|
|
89
|
+
super.off(event, listener)
|
|
90
|
+
|
|
91
|
+
this.state.client.products = this.eventNames()
|
|
92
|
+
|
|
93
|
+
if (!this.state.client.products.length) {
|
|
94
|
+
this.scheduler.stop()
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return this
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
poll (cb) {
|
|
101
|
+
request(JSON.stringify(this.state), this.requestOptions, (err, data, statusCode) => {
|
|
102
|
+
// 404 means RC is disabled, ignore it
|
|
103
|
+
if (statusCode === 404) return cb()
|
|
104
|
+
|
|
105
|
+
if (err) {
|
|
106
|
+
log.error(err)
|
|
107
|
+
return cb()
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// if error was just sent, reset the state
|
|
111
|
+
if (this.state.client.state.has_error) {
|
|
112
|
+
this.state.client.state.has_error = false
|
|
113
|
+
this.state.client.state.error = ''
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (data && data !== '{}') { // '{}' means the tracer is up to date
|
|
117
|
+
try {
|
|
118
|
+
this.parseConfig(JSON.parse(data))
|
|
119
|
+
} catch (err) {
|
|
120
|
+
log.error(`Could not parse remote config response: ${err}`)
|
|
121
|
+
|
|
122
|
+
this.state.client.state.has_error = true
|
|
123
|
+
this.state.client.state.error = err.toString()
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
cb()
|
|
128
|
+
})
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// `client_configs` is the list of config paths to have applied
|
|
132
|
+
// `targets` is the signed index with metadata for config files
|
|
133
|
+
// `target_files` is the list of config files containing the actual config data
|
|
134
|
+
parseConfig ({
|
|
135
|
+
client_configs: clientConfigs = [],
|
|
136
|
+
targets,
|
|
137
|
+
target_files: targetFiles = []
|
|
138
|
+
}) {
|
|
139
|
+
const toUnapply = []
|
|
140
|
+
const toApply = []
|
|
141
|
+
const toModify = []
|
|
142
|
+
|
|
143
|
+
for (const appliedConfig of this.appliedConfigs.values()) {
|
|
144
|
+
if (!clientConfigs.includes(appliedConfig.path)) {
|
|
145
|
+
toUnapply.push(appliedConfig)
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
targets = fromBase64JSON(targets)
|
|
150
|
+
|
|
151
|
+
if (targets) {
|
|
152
|
+
for (const path of clientConfigs) {
|
|
153
|
+
const meta = targets.signed.targets[path]
|
|
154
|
+
if (!meta) throw new Error(`Unable to find target for path ${path}`)
|
|
155
|
+
|
|
156
|
+
const current = this.appliedConfigs.get(path)
|
|
157
|
+
|
|
158
|
+
const newConf = {}
|
|
159
|
+
|
|
160
|
+
if (current) {
|
|
161
|
+
if (current.hashes.sha256 === meta.hashes.sha256) continue
|
|
162
|
+
|
|
163
|
+
toModify.push(newConf)
|
|
164
|
+
} else {
|
|
165
|
+
toApply.push(newConf)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const file = targetFiles.find(file => file.path === path)
|
|
169
|
+
if (!file) throw new Error(`Unable to find file for path ${path}`)
|
|
170
|
+
|
|
171
|
+
// TODO: verify signatures
|
|
172
|
+
// verify length
|
|
173
|
+
// verify hash
|
|
174
|
+
// verify _type
|
|
175
|
+
// TODO: new Date(meta.signed.expires) ignore the Targets data if it has expired ?
|
|
176
|
+
|
|
177
|
+
const { product, id } = parseConfigPath(path)
|
|
178
|
+
|
|
179
|
+
Object.assign(newConf, {
|
|
180
|
+
path,
|
|
181
|
+
product,
|
|
182
|
+
id,
|
|
183
|
+
version: meta.custom.v,
|
|
184
|
+
apply_state: 1,
|
|
185
|
+
apply_error: '',
|
|
186
|
+
length: meta.length,
|
|
187
|
+
hashes: meta.hashes,
|
|
188
|
+
file: fromBase64JSON(file.raw)
|
|
189
|
+
})
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
this.state.client.state.targets_version = targets.signed.version
|
|
193
|
+
this.state.client.state.backend_client_state = targets.signed.custom.opaque_backend_state
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (toUnapply.length || toApply.length || toModify.length) {
|
|
197
|
+
this.dispatch(toUnapply, 'unapply')
|
|
198
|
+
this.dispatch(toApply, 'apply')
|
|
199
|
+
this.dispatch(toModify, 'modify')
|
|
200
|
+
|
|
201
|
+
this.state.client.state.config_states = []
|
|
202
|
+
this.state.cached_target_files = []
|
|
203
|
+
|
|
204
|
+
for (const conf of this.appliedConfigs.values()) {
|
|
205
|
+
this.state.client.state.config_states.push({
|
|
206
|
+
id: conf.id,
|
|
207
|
+
version: conf.version,
|
|
208
|
+
product: conf.product,
|
|
209
|
+
apply_state: conf.apply_state,
|
|
210
|
+
apply_error: conf.apply_error
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
this.state.cached_target_files.push({
|
|
214
|
+
path: conf.path,
|
|
215
|
+
length: conf.length,
|
|
216
|
+
hashes: Object.entries(conf.hashes).map((entry) => ({ algorithm: entry[0], hash: entry[1] }))
|
|
217
|
+
})
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
dispatch (list, action) {
|
|
223
|
+
for (const item of list) {
|
|
224
|
+
try {
|
|
225
|
+
// TODO: do we want to pass old and new config ?
|
|
226
|
+
this.emit(item.product, action, item.file)
|
|
227
|
+
|
|
228
|
+
item.apply_state = 2
|
|
229
|
+
} catch (err) {
|
|
230
|
+
item.apply_state = 3
|
|
231
|
+
item.apply_error = err.toString()
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (action === 'unapply') {
|
|
235
|
+
this.appliedConfigs.delete(item.path)
|
|
236
|
+
} else {
|
|
237
|
+
this.appliedConfigs.set(item.path, item)
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function fromBase64JSON (str) {
|
|
244
|
+
if (!str) return null
|
|
245
|
+
|
|
246
|
+
return JSON.parse(Buffer.from(str, 'base64').toString())
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const configPathRegex = /^(?:datadog\/\d+|employee)\/([^/]+)\/([^/]+)\/[^/]+$/
|
|
250
|
+
|
|
251
|
+
function parseConfigPath (configPath) {
|
|
252
|
+
const match = configPathRegex.exec(configPath)
|
|
253
|
+
|
|
254
|
+
if (!match || !match[1] || !match[2]) {
|
|
255
|
+
throw new Error(`Unable to parse path ${configPath}`)
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return {
|
|
259
|
+
product: match[1],
|
|
260
|
+
id: match[2]
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
module.exports = RemoteConfigManager
|
|
@@ -8,21 +8,21 @@ class Scheduler {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
start () {
|
|
11
|
-
|
|
12
|
-
this._timer.unref && this._timer.unref()
|
|
11
|
+
if (this._timer) return
|
|
13
12
|
|
|
14
|
-
|
|
13
|
+
this.runAfterDelay(0)
|
|
15
14
|
}
|
|
16
15
|
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
runAfterDelay (interval = this._interval) {
|
|
17
|
+
this._timer = setTimeout(this._callback, interval, () => this.runAfterDelay())
|
|
19
18
|
|
|
20
|
-
|
|
19
|
+
this._timer.unref && this._timer.unref()
|
|
21
20
|
}
|
|
22
21
|
|
|
23
|
-
|
|
24
|
-
this.
|
|
25
|
-
|
|
22
|
+
stop () {
|
|
23
|
+
clearTimeout(this._timer)
|
|
24
|
+
|
|
25
|
+
this._timer = null
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const callbacks = require('./callbacks')
|
|
4
|
+
const Gateway = require('./gateway/engine')
|
|
4
5
|
|
|
5
6
|
const appliedCallbacks = new Map()
|
|
6
7
|
|
|
@@ -14,6 +15,8 @@ function applyRules (rules, config) {
|
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
function clearAllRules () {
|
|
18
|
+
Gateway.manager.clear()
|
|
19
|
+
|
|
17
20
|
for (const [key, callback] of appliedCallbacks) {
|
|
18
21
|
callback.clear()
|
|
19
22
|
|
|
@@ -35,9 +35,7 @@ function getCommonRequestOptions (url) {
|
|
|
35
35
|
'dd-api-key': process.env.DATADOG_API_KEY || process.env.DD_API_KEY
|
|
36
36
|
},
|
|
37
37
|
timeout: 15000,
|
|
38
|
-
|
|
39
|
-
hostname: url.hostname,
|
|
40
|
-
port: url.port
|
|
38
|
+
url
|
|
41
39
|
}
|
|
42
40
|
}
|
|
43
41
|
|
|
@@ -71,16 +69,16 @@ function getCommitsToExclude ({ url, repositoryUrl }, callback) {
|
|
|
71
69
|
}))
|
|
72
70
|
})
|
|
73
71
|
|
|
74
|
-
request(localCommitData, options, (err, response
|
|
72
|
+
request(localCommitData, options, (err, response) => {
|
|
75
73
|
if (err) {
|
|
76
|
-
const error = new Error(`
|
|
74
|
+
const error = new Error(`Error fetching commits to exclude: ${err.message}`)
|
|
77
75
|
return callback(error)
|
|
78
76
|
}
|
|
79
77
|
let commitsToExclude
|
|
80
78
|
try {
|
|
81
79
|
commitsToExclude = sanitizeCommits(JSON.parse(response).data)
|
|
82
80
|
} catch (e) {
|
|
83
|
-
return callback(new Error(`Can't parse
|
|
81
|
+
return callback(new Error(`Can't parse commits to exclude response: ${e.message}`))
|
|
84
82
|
}
|
|
85
83
|
callback(null, commitsToExclude, headCommit)
|
|
86
84
|
})
|
|
@@ -129,7 +127,7 @@ function uploadPackFile ({ url, packFileToUpload, repositoryUrl, headCommit }, c
|
|
|
129
127
|
}
|
|
130
128
|
request(form, options, (err, _, statusCode) => {
|
|
131
129
|
if (err) {
|
|
132
|
-
const error = new Error(`Could not upload packfiles: status code ${statusCode}`)
|
|
130
|
+
const error = new Error(`Could not upload packfiles: status code ${statusCode}: ${err.message}`)
|
|
133
131
|
return callback(error)
|
|
134
132
|
}
|
|
135
133
|
callback(null)
|
package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-itr-configuration.js
CHANGED
|
@@ -36,9 +36,7 @@ function getItrConfiguration ({
|
|
|
36
36
|
'dd-application-key': appKey,
|
|
37
37
|
'Content-Type': 'application/json'
|
|
38
38
|
},
|
|
39
|
-
|
|
40
|
-
hostname: intakeUrl.hostname,
|
|
41
|
-
port: intakeUrl.port
|
|
39
|
+
url: intakeUrl
|
|
42
40
|
}
|
|
43
41
|
|
|
44
42
|
const data = JSON.stringify({
|
|
@@ -95,6 +95,11 @@ class Config {
|
|
|
95
95
|
process.env.DD_RUNTIME_METRICS_ENABLED,
|
|
96
96
|
false
|
|
97
97
|
)
|
|
98
|
+
const DD_DBM_PROPAGATION_MODE = coalesce(
|
|
99
|
+
options.dbmPropagationMode,
|
|
100
|
+
process.env.DD_DBM_PROPAGATION_MODE,
|
|
101
|
+
'disabled'
|
|
102
|
+
)
|
|
98
103
|
const DD_AGENT_HOST = coalesce(
|
|
99
104
|
options.hostname,
|
|
100
105
|
process.env.DD_AGENT_HOST,
|
|
@@ -113,6 +118,7 @@ class Config {
|
|
|
113
118
|
null
|
|
114
119
|
)
|
|
115
120
|
const DD_CIVISIBILITY_AGENTLESS_URL = process.env.DD_CIVISIBILITY_AGENTLESS_URL
|
|
121
|
+
const DD_CIVISIBILITY_AGENTLESS_ENABLED = process.env.DD_CIVISIBILITY_AGENTLESS_ENABLED
|
|
116
122
|
|
|
117
123
|
const DD_CIVISIBILITY_ITR_ENABLED = coalesce(
|
|
118
124
|
process.env.DD_CIVISIBILITY_ITR_ENABLED,
|
|
@@ -201,16 +207,21 @@ class Config {
|
|
|
201
207
|
false
|
|
202
208
|
)
|
|
203
209
|
|
|
204
|
-
let appsec = options.appsec
|
|
210
|
+
let appsec = options.appsec != null ? options.appsec : options.experimental && options.experimental.appsec
|
|
211
|
+
|
|
212
|
+
if (typeof appsec === 'boolean') {
|
|
213
|
+
appsec = {
|
|
214
|
+
enabled: appsec
|
|
215
|
+
}
|
|
216
|
+
} else if (appsec == null) {
|
|
217
|
+
appsec = {}
|
|
218
|
+
}
|
|
205
219
|
|
|
206
220
|
const DD_APPSEC_ENABLED = coalesce(
|
|
207
|
-
appsec
|
|
208
|
-
process.env.DD_APPSEC_ENABLED
|
|
209
|
-
false
|
|
221
|
+
appsec.enabled,
|
|
222
|
+
process.env.DD_APPSEC_ENABLED && isTrue(process.env.DD_APPSEC_ENABLED)
|
|
210
223
|
)
|
|
211
224
|
|
|
212
|
-
appsec = appsec || {}
|
|
213
|
-
|
|
214
225
|
const DD_APPSEC_RULES = coalesce(
|
|
215
226
|
appsec.rules,
|
|
216
227
|
process.env.DD_APPSEC_RULES,
|
|
@@ -310,6 +321,7 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
|
|
|
310
321
|
const defaultFlushInterval = inAWSLambda ? 0 : 2000
|
|
311
322
|
|
|
312
323
|
this.tracing = !isFalse(DD_TRACING_ENABLED)
|
|
324
|
+
this.dbmPropagationMode = DD_DBM_PROPAGATION_MODE
|
|
313
325
|
this.logInjection = isTrue(DD_LOGS_INJECTION)
|
|
314
326
|
this.env = DD_ENV
|
|
315
327
|
this.url = DD_CIVISIBILITY_AGENTLESS_URL ? new URL(DD_CIVISIBILITY_AGENTLESS_URL)
|
|
@@ -356,7 +368,7 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
|
|
|
356
368
|
this.protocolVersion = DD_TRACE_AGENT_PROTOCOL_VERSION
|
|
357
369
|
this.tagsHeaderMaxLength = parseInt(DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH)
|
|
358
370
|
this.appsec = {
|
|
359
|
-
enabled:
|
|
371
|
+
enabled: DD_APPSEC_ENABLED,
|
|
360
372
|
rules: DD_APPSEC_RULES,
|
|
361
373
|
rateLimit: DD_APPSEC_TRACE_RATE_LIMIT,
|
|
362
374
|
wafTimeout: DD_APPSEC_WAF_TIMEOUT,
|
|
@@ -369,8 +381,12 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
|
|
|
369
381
|
maxConcurrentRequests: DD_IAST_MAX_CONCURRENT_REQUESTS,
|
|
370
382
|
maxContextOperations: DD_IAST_MAX_CONTEXT_OPERATIONS
|
|
371
383
|
}
|
|
372
|
-
|
|
373
|
-
|
|
384
|
+
|
|
385
|
+
const isCiVisibilityAgentlessEnabled = isTrue(DD_CIVISIBILITY_AGENTLESS_ENABLED)
|
|
386
|
+
this.isIntelligentTestRunnerEnabled = isCiVisibilityAgentlessEnabled && isTrue(DD_CIVISIBILITY_ITR_ENABLED)
|
|
387
|
+
this.isGitUploadEnabled = this.isIntelligentTestRunnerEnabled ||
|
|
388
|
+
(isCiVisibilityAgentlessEnabled && isTrue(DD_CIVISIBILITY_GIT_UPLOAD_ENABLED))
|
|
389
|
+
|
|
374
390
|
this.stats = {
|
|
375
391
|
enabled: isTrue(DD_TRACE_STATS_COMPUTATION_ENABLED)
|
|
376
392
|
}
|
|
@@ -19,5 +19,10 @@ module.exports = {
|
|
|
19
19
|
SPAN_SAMPLING_RULE_RATE: '_dd.span_sampling.rule_rate',
|
|
20
20
|
SPAN_SAMPLING_MAX_PER_SECOND: '_dd.span_sampling.max_per_second',
|
|
21
21
|
DATADOG_LAMBDA_EXTENSION_PATH: '/opt/extensions/datadog-agent',
|
|
22
|
-
DECISION_MAKER_KEY: '_dd.p.dm'
|
|
22
|
+
DECISION_MAKER_KEY: '_dd.p.dm',
|
|
23
|
+
PROCESS_ID: 'process_id',
|
|
24
|
+
ERROR_TYPE: 'error.type',
|
|
25
|
+
ERROR_MESSAGE: 'error.message',
|
|
26
|
+
ERROR_STACK: 'error.stack',
|
|
27
|
+
COMPONENT: 'component'
|
|
23
28
|
}
|
|
@@ -66,7 +66,13 @@ function request (data, options, callback) {
|
|
|
66
66
|
if (res.statusCode >= 200 && res.statusCode <= 299) {
|
|
67
67
|
callback(null, responseData, res.statusCode)
|
|
68
68
|
} else {
|
|
69
|
-
const
|
|
69
|
+
const fullUrl = `${options.url || options.hostname || `localhost:${options.port}`}${options.path}`
|
|
70
|
+
// eslint-disable-next-line
|
|
71
|
+
let errorMessage = `Error from ${fullUrl}: ${res.statusCode} ${http.STATUS_CODES[res.statusCode]}.`
|
|
72
|
+
if (responseData) {
|
|
73
|
+
errorMessage += ` Response from the endpoint: "${responseData}"`
|
|
74
|
+
}
|
|
75
|
+
const error = new Error(errorMessage)
|
|
70
76
|
error.status = res.statusCode
|
|
71
77
|
|
|
72
78
|
callback(error, null, res.statusCode)
|
|
@@ -17,6 +17,10 @@ const MEASURED = tags.MEASURED
|
|
|
17
17
|
const ORIGIN_KEY = constants.ORIGIN_KEY
|
|
18
18
|
const HOSTNAME_KEY = constants.HOSTNAME_KEY
|
|
19
19
|
const TOP_LEVEL_KEY = constants.TOP_LEVEL_KEY
|
|
20
|
+
const PROCESS_ID = constants.PROCESS_ID
|
|
21
|
+
const ERROR_MESSAGE = constants.ERROR_MESSAGE
|
|
22
|
+
const ERROR_STACK = constants.ERROR_STACK
|
|
23
|
+
const ERROR_TYPE = constants.ERROR_TYPE
|
|
20
24
|
|
|
21
25
|
const map = {
|
|
22
26
|
'service.name': 'service',
|
|
@@ -89,9 +93,9 @@ function extractTags (trace, span) {
|
|
|
89
93
|
extractError(trace, tags[tag])
|
|
90
94
|
}
|
|
91
95
|
break
|
|
92
|
-
case
|
|
93
|
-
case
|
|
94
|
-
case
|
|
96
|
+
case ERROR_TYPE:
|
|
97
|
+
case ERROR_MESSAGE:
|
|
98
|
+
case ERROR_STACK:
|
|
95
99
|
// HACK: remove when implemented in the backend
|
|
96
100
|
if (context._name !== 'fs.operation') {
|
|
97
101
|
trace.error = 1
|
|
@@ -103,12 +107,10 @@ function extractTags (trace, span) {
|
|
|
103
107
|
}
|
|
104
108
|
}
|
|
105
109
|
|
|
106
|
-
if (span.tracer()._service === tags['service.name']) {
|
|
107
|
-
addTag(trace.meta, trace.metrics, 'language', 'javascript')
|
|
108
|
-
}
|
|
109
|
-
|
|
110
110
|
setSingleSpanIngestionTags(trace, context._sampling.spanSampling)
|
|
111
111
|
|
|
112
|
+
addTag(trace.meta, trace.metrics, 'language', 'javascript')
|
|
113
|
+
addTag(trace.meta, trace.metrics, PROCESS_ID, process.pid)
|
|
112
114
|
addTag(trace.meta, trace.metrics, SAMPLING_PRIORITY_KEY, priority)
|
|
113
115
|
addTag(trace.meta, trace.metrics, ORIGIN_KEY, origin)
|
|
114
116
|
addTag(trace.meta, trace.metrics, HOSTNAME_KEY, hostname)
|
|
@@ -144,9 +146,9 @@ function extractError (trace, error) {
|
|
|
144
146
|
trace.error = 1
|
|
145
147
|
|
|
146
148
|
if (isError(error)) {
|
|
147
|
-
addTag(trace.meta, trace.metrics,
|
|
148
|
-
addTag(trace.meta, trace.metrics,
|
|
149
|
-
addTag(trace.meta, trace.metrics,
|
|
149
|
+
addTag(trace.meta, trace.metrics, ERROR_MESSAGE, error.message)
|
|
150
|
+
addTag(trace.meta, trace.metrics, ERROR_TYPE, error.name)
|
|
151
|
+
addTag(trace.meta, trace.metrics, ERROR_STACK, error.stack)
|
|
150
152
|
}
|
|
151
153
|
}
|
|
152
154
|
|
|
@@ -130,11 +130,7 @@ class TextMapPropagator {
|
|
|
130
130
|
|
|
131
131
|
_injectTraceparent (spanContext, carrier) {
|
|
132
132
|
if (!this._config.experimental.traceparent) return
|
|
133
|
-
|
|
134
|
-
const sampling = spanContext._sampling.priority >= AUTO_KEEP ? '01' : '00'
|
|
135
|
-
const traceId = spanContext._traceId.toString(16).padStart(32, '0')
|
|
136
|
-
const spanId = spanContext._spanId.toString(16).padStart(16, '0')
|
|
137
|
-
carrier[traceparentKey] = `01-${traceId}-${spanId}-${sampling}`
|
|
133
|
+
carrier[traceparentKey] = spanContext.toTraceparent()
|
|
138
134
|
}
|
|
139
135
|
|
|
140
136
|
_extractSpanContext (carrier) {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const { AUTO_KEEP } = require('../../../../ext/priority')
|
|
4
|
+
|
|
3
5
|
class DatadogSpanContext {
|
|
4
6
|
constructor (props) {
|
|
5
7
|
props = props || {}
|
|
@@ -27,6 +29,13 @@ class DatadogSpanContext {
|
|
|
27
29
|
toSpanId () {
|
|
28
30
|
return this._spanId.toString(10)
|
|
29
31
|
}
|
|
32
|
+
|
|
33
|
+
toTraceparent () {
|
|
34
|
+
const sampling = this._sampling.priority >= AUTO_KEEP ? '01' : '00'
|
|
35
|
+
const traceId = this._traceId.toString(16).padStart(32, '0')
|
|
36
|
+
const spanId = this._spanId.toString(16).padStart(16, '0')
|
|
37
|
+
return `01-${traceId}-${spanId}-${sampling}`
|
|
38
|
+
}
|
|
30
39
|
}
|
|
31
40
|
|
|
32
41
|
module.exports = DatadogSpanContext
|
|
@@ -125,7 +125,8 @@ module.exports = class PluginManager {
|
|
|
125
125
|
isIntelligentTestRunnerEnabled,
|
|
126
126
|
site,
|
|
127
127
|
experimental,
|
|
128
|
-
url
|
|
128
|
+
url,
|
|
129
|
+
dbmPropagationMode
|
|
129
130
|
} = this._tracerConfig
|
|
130
131
|
|
|
131
132
|
const sharedConfig = {}
|
|
@@ -152,6 +153,8 @@ module.exports = class PluginManager {
|
|
|
152
153
|
|
|
153
154
|
sharedConfig.isIntelligentTestRunnerEnabled = isIntelligentTestRunnerEnabled
|
|
154
155
|
|
|
156
|
+
sharedConfig.dbmPropagationMode = dbmPropagationMode
|
|
157
|
+
|
|
155
158
|
if (serviceMapping && serviceMapping[name]) {
|
|
156
159
|
sharedConfig.service = serviceMapping[name]
|
|
157
160
|
}
|