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.
Files changed (65) 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/helpers/hooks.js +5 -0
  8. package/packages/datadog-instrumentations/src/jest.js +102 -42
  9. package/packages/datadog-instrumentations/src/mocha.js +87 -6
  10. package/packages/datadog-instrumentations/src/pg.js +1 -2
  11. package/packages/datadog-instrumentations/src/qs.js +24 -0
  12. package/packages/datadog-plugin-cucumber/src/index.js +13 -32
  13. package/packages/datadog-plugin-cypress/src/plugin.js +2 -1
  14. package/packages/datadog-plugin-google-cloud-pubsub/src/client.js +0 -1
  15. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +0 -1
  16. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +0 -1
  17. package/packages/datadog-plugin-http/src/client.js +5 -3
  18. package/packages/datadog-plugin-http/src/server.js +3 -0
  19. package/packages/datadog-plugin-http2/src/client.js +2 -0
  20. package/packages/datadog-plugin-http2/src/server.js +3 -0
  21. package/packages/datadog-plugin-jest/src/index.js +11 -131
  22. package/packages/datadog-plugin-mocha/src/index.js +33 -46
  23. package/packages/datadog-plugin-net/src/index.js +4 -0
  24. package/packages/datadog-plugin-next/src/index.js +3 -0
  25. package/packages/datadog-plugin-pg/src/index.js +5 -2
  26. package/packages/datadog-plugin-router/src/index.js +2 -0
  27. package/packages/dd-trace/src/appsec/callbacks/ddwaf.js +3 -5
  28. package/packages/dd-trace/src/appsec/gateway/engine/index.js +1 -1
  29. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +3 -1
  30. package/packages/dd-trace/src/appsec/iast/analyzers/command-injection-analyzer.js +11 -0
  31. package/packages/dd-trace/src/appsec/iast/analyzers/injection-analyzer.js +19 -0
  32. package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +13 -0
  33. package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +1 -1
  34. package/packages/dd-trace/src/appsec/iast/index.js +6 -0
  35. package/packages/dd-trace/src/appsec/iast/path-line.js +8 -1
  36. package/packages/dd-trace/src/appsec/iast/taint-tracking/filter.js +16 -0
  37. package/packages/dd-trace/src/appsec/iast/taint-tracking/index.js +18 -0
  38. package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +125 -0
  39. package/packages/dd-trace/src/appsec/iast/taint-tracking/origin-types.js +4 -0
  40. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +38 -0
  41. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +66 -0
  42. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +52 -6
  43. package/packages/dd-trace/src/appsec/index.js +8 -0
  44. package/packages/dd-trace/src/appsec/remote_config/capabilities.js +7 -0
  45. package/packages/dd-trace/src/appsec/remote_config/index.js +34 -0
  46. package/packages/dd-trace/src/appsec/remote_config/manager.js +264 -0
  47. package/packages/dd-trace/src/{exporters → appsec/remote_config}/scheduler.js +9 -9
  48. package/packages/dd-trace/src/appsec/rule_manager.js +3 -0
  49. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +5 -7
  50. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-itr-configuration.js +1 -3
  51. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +1 -3
  52. package/packages/dd-trace/src/config.js +25 -9
  53. package/packages/dd-trace/src/constants.js +6 -1
  54. package/packages/dd-trace/src/exporters/common/request.js +7 -1
  55. package/packages/dd-trace/src/format.js +12 -10
  56. package/packages/dd-trace/src/opentracing/propagation/text_map.js +1 -5
  57. package/packages/dd-trace/src/opentracing/span_context.js +9 -0
  58. package/packages/dd-trace/src/plugin_manager.js +4 -1
  59. package/packages/dd-trace/src/plugins/ci_plugin.js +132 -0
  60. package/packages/dd-trace/src/plugins/database.js +46 -0
  61. package/packages/dd-trace/src/plugins/tracing.js +2 -0
  62. package/packages/dd-trace/src/plugins/util/test.js +61 -8
  63. package/packages/dd-trace/src/plugins/util/web.js +9 -8
  64. package/packages/dd-trace/src/proxy.js +5 -1
  65. 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)
@@ -36,9 +36,7 @@ function getItrConfiguration ({
36
36
  'dd-application-key': appKey,
37
37
  'Content-Type': 'application/json'
38
38
  },
39
- protocol: intakeUrl.protocol,
40
- hostname: intakeUrl.hostname,
41
- port: intakeUrl.port
39
+ url: intakeUrl
42
40
  }
43
41
 
44
42
  const data = JSON.stringify({
@@ -34,9 +34,7 @@ function getSkippableSuites ({
34
34
  'Content-Type': 'application/json'
35
35
  },
36
36
  timeout: 15000,
37
- protocol: intakeUrl.protocol,
38
- hostname: intakeUrl.hostname,
39
- port: intakeUrl.port
37
+ url: intakeUrl
40
38
  }
41
39
 
42
40
  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 || (options.experimental && options.experimental.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 && (appsec === true || appsec.enabled === true), // TODO: remove when enabled by default
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: isTrue(DD_APPSEC_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
- this.isGitUploadEnabled = isTrue(DD_CIVISIBILITY_GIT_UPLOAD_ENABLED)
373
- this.isIntelligentTestRunnerEnabled = isTrue(DD_CIVISIBILITY_ITR_ENABLED)
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 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
@@ -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
  }