dd-trace 2.20.1 → 2.22.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.
Files changed (69) hide show
  1. package/LICENSE-3rdparty.csv +2 -0
  2. package/index.d.ts +11 -0
  3. package/package.json +4 -2
  4. package/packages/datadog-instrumentations/src/body-parser.js +26 -0
  5. package/packages/datadog-instrumentations/src/child-process.js +30 -0
  6. package/packages/datadog-instrumentations/src/cucumber.js +1 -1
  7. package/packages/datadog-instrumentations/src/hapi.js +3 -3
  8. package/packages/datadog-instrumentations/src/helpers/hooks.js +5 -0
  9. package/packages/datadog-instrumentations/src/jest.js +110 -40
  10. package/packages/datadog-instrumentations/src/mocha.js +87 -6
  11. package/packages/datadog-instrumentations/src/pg.js +1 -2
  12. package/packages/datadog-instrumentations/src/qs.js +24 -0
  13. package/packages/datadog-instrumentations/src/restify.js +1 -1
  14. package/packages/datadog-plugin-cucumber/src/index.js +13 -32
  15. package/packages/datadog-plugin-cypress/src/plugin.js +2 -1
  16. package/packages/datadog-plugin-google-cloud-pubsub/src/client.js +0 -1
  17. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +0 -1
  18. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +0 -1
  19. package/packages/datadog-plugin-http/src/client.js +14 -4
  20. package/packages/datadog-plugin-http/src/server.js +3 -0
  21. package/packages/datadog-plugin-http2/src/client.js +20 -1
  22. package/packages/datadog-plugin-http2/src/server.js +3 -0
  23. package/packages/datadog-plugin-jest/src/index.js +11 -129
  24. package/packages/datadog-plugin-mocha/src/index.js +33 -46
  25. package/packages/datadog-plugin-net/src/index.js +4 -0
  26. package/packages/datadog-plugin-next/src/index.js +3 -0
  27. package/packages/datadog-plugin-oracledb/src/index.js +0 -1
  28. package/packages/datadog-plugin-pg/src/index.js +5 -2
  29. package/packages/datadog-plugin-router/src/index.js +2 -0
  30. package/packages/dd-trace/src/appsec/callbacks/ddwaf.js +3 -5
  31. package/packages/dd-trace/src/appsec/gateway/engine/index.js +1 -1
  32. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +3 -1
  33. package/packages/dd-trace/src/appsec/iast/analyzers/command-injection-analyzer.js +11 -0
  34. package/packages/dd-trace/src/appsec/iast/analyzers/injection-analyzer.js +19 -0
  35. package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +13 -0
  36. package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +1 -1
  37. package/packages/dd-trace/src/appsec/iast/index.js +6 -0
  38. package/packages/dd-trace/src/appsec/iast/path-line.js +8 -1
  39. package/packages/dd-trace/src/appsec/iast/taint-tracking/filter.js +16 -0
  40. package/packages/dd-trace/src/appsec/iast/taint-tracking/index.js +18 -0
  41. package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +125 -0
  42. package/packages/dd-trace/src/appsec/iast/taint-tracking/origin-types.js +4 -0
  43. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +38 -0
  44. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +66 -0
  45. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +52 -6
  46. package/packages/dd-trace/src/appsec/index.js +8 -0
  47. package/packages/dd-trace/src/appsec/remote_config/capabilities.js +7 -0
  48. package/packages/dd-trace/src/appsec/remote_config/index.js +34 -0
  49. package/packages/dd-trace/src/appsec/remote_config/manager.js +264 -0
  50. package/packages/dd-trace/src/{exporters → appsec/remote_config}/scheduler.js +9 -9
  51. package/packages/dd-trace/src/appsec/rule_manager.js +3 -0
  52. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +5 -7
  53. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-itr-configuration.js +3 -4
  54. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +3 -4
  55. package/packages/dd-trace/src/config.js +41 -20
  56. package/packages/dd-trace/src/constants.js +6 -1
  57. package/packages/dd-trace/src/exporters/common/request.js +7 -1
  58. package/packages/dd-trace/src/format.js +12 -10
  59. package/packages/dd-trace/src/opentracing/propagation/text_map.js +1 -5
  60. package/packages/dd-trace/src/opentracing/span_context.js +9 -0
  61. package/packages/dd-trace/src/plugin_manager.js +6 -1
  62. package/packages/dd-trace/src/plugins/ci_plugin.js +132 -0
  63. package/packages/dd-trace/src/plugins/database.js +46 -0
  64. package/packages/dd-trace/src/plugins/tracing.js +2 -0
  65. package/packages/dd-trace/src/plugins/util/test.js +61 -8
  66. package/packages/dd-trace/src/plugins/util/web.js +9 -8
  67. package/packages/dd-trace/src/proxy.js +4 -3
  68. package/packages/dd-trace/src/span_processor.js +1 -0
  69. 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
- this._timer = setInterval(this._callback, this._interval)
12
- this._timer.unref && this._timer.unref()
11
+ if (this._timer) return
13
12
 
14
- process.once('beforeExit', this._callback)
13
+ this.runAfterDelay(0)
15
14
  }
16
15
 
17
- stop () {
18
- clearInterval(this._timer)
16
+ runAfterDelay (interval = this._interval) {
17
+ this._timer = setTimeout(this._callback, interval, () => this.runAfterDelay())
19
18
 
20
- process.removeListener('beforeExit', this._callback)
19
+ this._timer.unref && this._timer.unref()
21
20
  }
22
21
 
23
- reset () {
24
- this.stop()
25
- this.start()
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
- protocol: url.protocol,
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, statusCode) => {
72
+ request(localCommitData, options, (err, response) => {
75
73
  if (err) {
76
- const error = new Error(`search_commits returned an error: status code ${statusCode}`)
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 search_commits response: ${e.message}`))
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)
@@ -2,6 +2,7 @@ const request = require('../../exporters/common/request')
2
2
  const id = require('../../id')
3
3
 
4
4
  function getItrConfiguration ({
5
+ url,
5
6
  site,
6
7
  env,
7
8
  service,
@@ -14,7 +15,7 @@ function getItrConfiguration ({
14
15
  runtimeVersion,
15
16
  branch
16
17
  }, done) {
17
- const url = new URL(`https://api.${site}`)
18
+ const intakeUrl = url || new URL(`https://api.${site}`)
18
19
 
19
20
  const apiKey = process.env.DATADOG_API_KEY || process.env.DD_API_KEY
20
21
  const appKey = process.env.DATADOG_APP_KEY ||
@@ -35,9 +36,7 @@ function getItrConfiguration ({
35
36
  'dd-application-key': appKey,
36
37
  'Content-Type': 'application/json'
37
38
  },
38
- protocol: url.protocol,
39
- hostname: url.hostname,
40
- port: url.port
39
+ url: intakeUrl
41
40
  }
42
41
 
43
42
  const data = JSON.stringify({
@@ -1,6 +1,7 @@
1
1
  const request = require('../../exporters/common/request')
2
2
 
3
3
  function getSkippableSuites ({
4
+ url,
4
5
  site,
5
6
  env,
6
7
  service,
@@ -12,7 +13,7 @@ function getSkippableSuites ({
12
13
  runtimeName,
13
14
  runtimeVersion
14
15
  }, done) {
15
- const url = new URL(`https://api.${site}`)
16
+ const intakeUrl = url || new URL(`https://api.${site}`)
16
17
 
17
18
  const apiKey = process.env.DATADOG_API_KEY || process.env.DD_API_KEY
18
19
  const appKey = process.env.DATADOG_APP_KEY ||
@@ -33,9 +34,7 @@ function getSkippableSuites ({
33
34
  'Content-Type': 'application/json'
34
35
  },
35
36
  timeout: 15000,
36
- protocol: url.protocol,
37
- hostname: url.hostname,
38
- port: url.port
37
+ url: intakeUrl
39
38
  }
40
39
 
41
40
  const data = JSON.stringify({
@@ -4,6 +4,7 @@ const fs = require('fs')
4
4
  const os = require('os')
5
5
  const URL = require('url').URL
6
6
  const path = require('path')
7
+ const log = require('./log')
7
8
  const pkg = require('./pkg')
8
9
  const coalesce = require('koalas')
9
10
  const tagger = require('./tagger')
@@ -44,6 +45,21 @@ class Config {
44
45
  constructor (options) {
45
46
  options = options || {}
46
47
 
48
+ // Configure the logger first so it can be used to warn about other configs
49
+ this.debug = isTrue(coalesce(
50
+ process.env.DD_TRACE_DEBUG,
51
+ false
52
+ ))
53
+ this.logger = options.logger
54
+ this.logLevel = coalesce(
55
+ options.logLevel,
56
+ process.env.DD_TRACE_LOG_LEVEL,
57
+ 'debug'
58
+ )
59
+
60
+ log.use(this.logger)
61
+ log.toggle(this.debug, this.logLevel, this)
62
+
47
63
  this.tags = {}
48
64
 
49
65
  tagger.add(this.tags, process.env.DD_TAGS)
@@ -76,6 +92,11 @@ class Config {
76
92
  process.env.DD_RUNTIME_METRICS_ENABLED,
77
93
  false
78
94
  )
95
+ const DD_DBM_PROPAGATION_MODE = coalesce(
96
+ options.dbmPropagationMode,
97
+ process.env.DD_DBM_PROPAGATION_MODE,
98
+ 'disabled'
99
+ )
79
100
  const DD_AGENT_HOST = coalesce(
80
101
  options.hostname,
81
102
  process.env.DD_AGENT_HOST,
@@ -94,6 +115,7 @@ class Config {
94
115
  null
95
116
  )
96
117
  const DD_CIVISIBILITY_AGENTLESS_URL = process.env.DD_CIVISIBILITY_AGENTLESS_URL
118
+ const DD_CIVISIBILITY_AGENTLESS_ENABLED = process.env.DD_CIVISIBILITY_AGENTLESS_ENABLED
97
119
 
98
120
  const DD_CIVISIBILITY_ITR_ENABLED = coalesce(
99
121
  process.env.DD_CIVISIBILITY_ITR_ENABLED,
@@ -128,10 +150,6 @@ class Config {
128
150
  process.env.DD_TRACE_TELEMETRY_ENABLED,
129
151
  !process.env.AWS_LAMBDA_FUNCTION_NAME
130
152
  )
131
- const DD_TRACE_DEBUG = coalesce(
132
- process.env.DD_TRACE_DEBUG,
133
- false
134
- )
135
153
  const DD_TRACE_AGENT_PROTOCOL_VERSION = coalesce(
136
154
  options.protocolVersion,
137
155
  process.env.DD_TRACE_AGENT_PROTOCOL_VERSION,
@@ -186,16 +204,21 @@ class Config {
186
204
  false
187
205
  )
188
206
 
189
- let appsec = options.appsec || (options.experimental && options.experimental.appsec)
207
+ let appsec = options.appsec != null ? options.appsec : options.experimental && options.experimental.appsec
208
+
209
+ if (typeof appsec === 'boolean') {
210
+ appsec = {
211
+ enabled: appsec
212
+ }
213
+ } else if (appsec == null) {
214
+ appsec = {}
215
+ }
190
216
 
191
217
  const DD_APPSEC_ENABLED = coalesce(
192
- appsec && (appsec === true || appsec.enabled === true), // TODO: remove when enabled by default
193
- process.env.DD_APPSEC_ENABLED,
194
- false
218
+ appsec.enabled,
219
+ process.env.DD_APPSEC_ENABLED && isTrue(process.env.DD_APPSEC_ENABLED)
195
220
  )
196
221
 
197
- appsec = appsec || {}
198
-
199
222
  const DD_APPSEC_RULES = coalesce(
200
223
  appsec.rules,
201
224
  process.env.DD_APPSEC_RULES,
@@ -295,7 +318,7 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
295
318
  const defaultFlushInterval = inAWSLambda ? 0 : 2000
296
319
 
297
320
  this.tracing = !isFalse(DD_TRACING_ENABLED)
298
- this.debug = isTrue(DD_TRACE_DEBUG)
321
+ this.dbmPropagationMode = DD_DBM_PROPAGATION_MODE
299
322
  this.logInjection = isTrue(DD_LOGS_INJECTION)
300
323
  this.env = DD_ENV
301
324
  this.url = DD_CIVISIBILITY_AGENTLESS_URL ? new URL(DD_CIVISIBILITY_AGENTLESS_URL)
@@ -309,7 +332,6 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
309
332
  this.clientIpHeaderDisabled = !isTrue(DD_APPSEC_ENABLED)
310
333
  this.clientIpHeader = DD_TRACE_CLIENT_IP_HEADER
311
334
  this.queryStringObfuscation = DD_TRACE_OBFUSCATION_QUERY_STRING_REGEXP
312
- this.logger = options.logger
313
335
  this.plugins = !!coalesce(options.plugins, true)
314
336
  this.service = DD_SERVICE
315
337
  this.serviceMapping = DD_SERVICE_MAPPING.length ? fromEntries(
@@ -331,11 +353,6 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
331
353
  this.sampler = sampler
332
354
  this.reportHostname = isTrue(coalesce(options.reportHostname, process.env.DD_TRACE_REPORT_HOSTNAME, false))
333
355
  this.scope = process.env.DD_TRACE_SCOPE
334
- this.logLevel = coalesce(
335
- options.logLevel,
336
- process.env.DD_TRACE_LOG_LEVEL,
337
- 'debug'
338
- )
339
356
  this.profiling = {
340
357
  enabled: isTrue(DD_PROFILING_ENABLED),
341
358
  sourceMap: !isFalse(DD_PROFILING_SOURCE_MAP),
@@ -348,7 +365,7 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
348
365
  this.protocolVersion = DD_TRACE_AGENT_PROTOCOL_VERSION
349
366
  this.tagsHeaderMaxLength = parseInt(DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH)
350
367
  this.appsec = {
351
- enabled: isTrue(DD_APPSEC_ENABLED),
368
+ enabled: DD_APPSEC_ENABLED,
352
369
  rules: DD_APPSEC_RULES,
353
370
  rateLimit: DD_APPSEC_TRACE_RATE_LIMIT,
354
371
  wafTimeout: DD_APPSEC_WAF_TIMEOUT,
@@ -361,8 +378,12 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
361
378
  maxConcurrentRequests: DD_IAST_MAX_CONCURRENT_REQUESTS,
362
379
  maxContextOperations: DD_IAST_MAX_CONTEXT_OPERATIONS
363
380
  }
364
- this.isGitUploadEnabled = isTrue(DD_CIVISIBILITY_GIT_UPLOAD_ENABLED)
365
- this.isIntelligentTestRunnerEnabled = isTrue(DD_CIVISIBILITY_ITR_ENABLED)
381
+
382
+ const isCiVisibilityAgentlessEnabled = isTrue(DD_CIVISIBILITY_AGENTLESS_ENABLED)
383
+ this.isIntelligentTestRunnerEnabled = isCiVisibilityAgentlessEnabled && isTrue(DD_CIVISIBILITY_ITR_ENABLED)
384
+ this.isGitUploadEnabled = this.isIntelligentTestRunnerEnabled ||
385
+ (isCiVisibilityAgentlessEnabled && isTrue(DD_CIVISIBILITY_GIT_UPLOAD_ENABLED))
386
+
366
387
  this.stats = {
367
388
  enabled: isTrue(DD_TRACE_STATS_COMPUTATION_ENABLED)
368
389
  }
@@ -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 error = new Error(`Error from the endpoint: ${res.statusCode} ${http.STATUS_CODES[res.statusCode]}`)
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 'error.type':
93
- case 'error.msg':
94
- case 'error.stack':
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, 'error.msg', error.message)
148
- addTag(trace.meta, trace.metrics, 'error.type', error.name)
149
- addTag(trace.meta, trace.metrics, 'error.stack', error.stack)
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
@@ -124,7 +124,9 @@ module.exports = class PluginManager {
124
124
  isIntelligentTestRunnerEnabled,
125
125
  site,
126
126
  experimental,
127
- queryStringObfuscation
127
+ queryStringObfuscation,
128
+ url,
129
+ dbmPropagationMode
128
130
  } = this._tracerConfig
129
131
 
130
132
  const sharedConfig = {}
@@ -151,11 +153,14 @@ module.exports = class PluginManager {
151
153
 
152
154
  sharedConfig.isIntelligentTestRunnerEnabled = isIntelligentTestRunnerEnabled
153
155
 
156
+ sharedConfig.dbmPropagationMode = dbmPropagationMode
157
+
154
158
  if (serviceMapping && serviceMapping[name]) {
155
159
  sharedConfig.service = serviceMapping[name]
156
160
  }
157
161
 
158
162
  sharedConfig.site = site
163
+ sharedConfig.url = url
159
164
 
160
165
  return sharedConfig
161
166
  }