dd-trace 4.14.0 → 4.16.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 (46) hide show
  1. package/LICENSE-3rdparty.csv +1 -0
  2. package/ext/tags.d.ts +1 -0
  3. package/ext/tags.js +1 -0
  4. package/index.d.ts +5 -4
  5. package/package.json +7 -5
  6. package/packages/datadog-esbuild/index.js +30 -25
  7. package/packages/datadog-instrumentations/src/body-parser.js +2 -2
  8. package/packages/datadog-instrumentations/src/cookie-parser.js +37 -0
  9. package/packages/datadog-instrumentations/src/express.js +1 -1
  10. package/packages/datadog-instrumentations/src/graphql.js +10 -4
  11. package/packages/datadog-instrumentations/src/helpers/hooks.js +3 -0
  12. package/packages/datadog-instrumentations/src/http/server.js +1 -1
  13. package/packages/datadog-instrumentations/src/mysql.js +39 -1
  14. package/packages/datadog-instrumentations/src/next.js +22 -80
  15. package/packages/datadog-instrumentations/src/pg.js +14 -15
  16. package/packages/datadog-instrumentations/src/playwright.js +15 -3
  17. package/packages/datadog-plugin-graphql/src/resolve.js +27 -2
  18. package/packages/datadog-plugin-mysql/src/index.js +2 -2
  19. package/packages/datadog-plugin-next/src/index.js +14 -5
  20. package/packages/datadog-plugin-pg/src/index.js +2 -2
  21. package/packages/dd-trace/src/appsec/addresses.js +1 -0
  22. package/packages/dd-trace/src/appsec/channels.js +2 -0
  23. package/packages/dd-trace/src/appsec/iast/analyzers/ldap-injection-analyzer.js +7 -0
  24. package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +28 -32
  25. package/packages/dd-trace/src/appsec/index.js +42 -7
  26. package/packages/dd-trace/src/appsec/recommended.json +549 -24
  27. package/packages/dd-trace/src/appsec/remote_config/capabilities.js +2 -1
  28. package/packages/dd-trace/src/appsec/remote_config/index.js +2 -0
  29. package/packages/dd-trace/src/appsec/reporter.js +26 -0
  30. package/packages/dd-trace/src/appsec/telemetry.js +132 -0
  31. package/packages/dd-trace/src/appsec/waf/index.js +1 -1
  32. package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +13 -5
  33. package/packages/dd-trace/src/appsec/waf/waf_manager.js +12 -14
  34. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-itr-configuration.js +1 -14
  35. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +1 -13
  36. package/packages/dd-trace/src/datastreams/processor.js +6 -2
  37. package/packages/dd-trace/src/format.js +6 -1
  38. package/packages/dd-trace/src/opentracing/propagation/text_map.js +2 -2
  39. package/packages/dd-trace/src/opentracing/tracer.js +0 -2
  40. package/packages/dd-trace/src/plugin_manager.js +1 -2
  41. package/packages/dd-trace/src/plugins/database.js +14 -4
  42. package/packages/dd-trace/src/plugins/index.js +1 -0
  43. package/packages/dd-trace/src/plugins/outbound.js +4 -3
  44. package/packages/dd-trace/src/plugins/tracing.js +1 -1
  45. package/packages/dd-trace/src/telemetry/index.js +10 -1
  46. package/packages/dd-trace/src/util.js +1 -1
@@ -8,5 +8,6 @@ module.exports = {
8
8
  ASM_REQUEST_BLOCKING: 1n << 5n,
9
9
  ASM_USER_BLOCKING: 1n << 7n,
10
10
  ASM_CUSTOM_RULES: 1n << 8n,
11
- ASM_CUSTOM_BLOCKING_RESPONSE: 1n << 9n
11
+ ASM_CUSTOM_BLOCKING_RESPONSE: 1n << 9n,
12
+ ASM_TRUSTED_IPS: 1n << 10n
12
13
  }
@@ -46,6 +46,7 @@ function enableWafUpdate (appsecConfig) {
46
46
  rc.updateCapabilities(RemoteConfigCapabilities.ASM_REQUEST_BLOCKING, true)
47
47
  rc.updateCapabilities(RemoteConfigCapabilities.ASM_CUSTOM_RULES, true)
48
48
  rc.updateCapabilities(RemoteConfigCapabilities.ASM_CUSTOM_BLOCKING_RESPONSE, true)
49
+ rc.updateCapabilities(RemoteConfigCapabilities.ASM_TRUSTED_IPS, true)
49
50
 
50
51
  rc.on('ASM_DATA', noop)
51
52
  rc.on('ASM_DD', noop)
@@ -66,6 +67,7 @@ function disableWafUpdate () {
66
67
  rc.updateCapabilities(RemoteConfigCapabilities.ASM_REQUEST_BLOCKING, false)
67
68
  rc.updateCapabilities(RemoteConfigCapabilities.ASM_CUSTOM_RULES, false)
68
69
  rc.updateCapabilities(RemoteConfigCapabilities.ASM_CUSTOM_BLOCKING_RESPONSE, false)
70
+ rc.updateCapabilities(RemoteConfigCapabilities.ASM_TRUSTED_IPS, false)
69
71
 
70
72
  rc.off('ASM_DATA', noop)
71
73
  rc.off('ASM_DD', noop)
@@ -3,6 +3,12 @@
3
3
  const Limiter = require('../rate_limiter')
4
4
  const { storage } = require('../../../datadog-core')
5
5
  const web = require('../plugins/util/web')
6
+ const {
7
+ incrementWafInitMetric,
8
+ updateWafRequestsMetricTags,
9
+ incrementWafUpdatesMetric,
10
+ incrementWafRequestsMetric
11
+ } = require('./telemetry')
6
12
 
7
13
  // default limiter, configurable with setRateLimit()
8
14
  let limiter = new Limiter(100)
@@ -63,6 +69,20 @@ function formatHeaderName (name) {
63
69
  .toLowerCase()
64
70
  }
65
71
 
72
+ function reportWafInit (wafVersion, rulesVersion, diagnosticsRules = {}) {
73
+ metricsQueue.set('_dd.appsec.waf.version', wafVersion)
74
+
75
+ metricsQueue.set('_dd.appsec.event_rules.loaded', diagnosticsRules.loaded?.length || 0)
76
+ metricsQueue.set('_dd.appsec.event_rules.error_count', diagnosticsRules.failed?.length || 0)
77
+ if (diagnosticsRules.failed?.length) {
78
+ metricsQueue.set('_dd.appsec.event_rules.errors', JSON.stringify(diagnosticsRules.errors))
79
+ }
80
+
81
+ metricsQueue.set('manual.keep', 'true')
82
+
83
+ incrementWafInitMetric(wafVersion, rulesVersion)
84
+ }
85
+
66
86
  function reportMetrics (metrics) {
67
87
  // TODO: metrics should be incremental, there already is an RFC to report metrics
68
88
  const store = storage.getStore()
@@ -80,6 +100,8 @@ function reportMetrics (metrics) {
80
100
  if (metrics.rulesVersion) {
81
101
  rootSpan.setTag('_dd.appsec.event_rules.version', metrics.rulesVersion)
82
102
  }
103
+
104
+ updateWafRequestsMetricTags(metrics, store.req)
83
105
  }
84
106
 
85
107
  function reportAttack (attackData) {
@@ -132,6 +154,8 @@ function finishRequest (req, res) {
132
154
  metricsQueue.clear()
133
155
  }
134
156
 
157
+ incrementWafRequestsMetric(req)
158
+
135
159
  if (!rootSpan.context()._tags['appsec.event']) return
136
160
 
137
161
  const newTags = filterHeaders(res.getHeaders(), RESPONSE_HEADERS_PASSLIST, 'http.response.headers.')
@@ -151,8 +175,10 @@ module.exports = {
151
175
  metricsQueue,
152
176
  filterHeaders,
153
177
  formatHeaderName,
178
+ reportWafInit,
154
179
  reportMetrics,
155
180
  reportAttack,
181
+ reportWafUpdate: incrementWafUpdatesMetric,
156
182
  finishRequest,
157
183
  setRateLimit
158
184
  }
@@ -0,0 +1,132 @@
1
+ 'use strict'
2
+
3
+ const telemetryMetrics = require('../telemetry/metrics')
4
+
5
+ const appsecMetrics = telemetryMetrics.manager.namespace('appsec')
6
+
7
+ const DD_TELEMETRY_WAF_RESULT_TAGS = Symbol('_dd.appsec.telemetry.waf.result.tags')
8
+
9
+ const tags = {
10
+ REQUEST_BLOCKED: 'request_blocked',
11
+ RULE_TRIGGERED: 'rule_triggered',
12
+ WAF_TIMEOUT: 'waf_timeout',
13
+ WAF_VERSION: 'waf_version',
14
+ EVENT_RULES_VERSION: 'event_rules_version'
15
+ }
16
+
17
+ const metricsStoreMap = new WeakMap()
18
+
19
+ let enabled = false
20
+
21
+ function enable (telemetryConfig) {
22
+ enabled = telemetryConfig?.enabled && telemetryConfig.metrics
23
+ }
24
+
25
+ function disable () {
26
+ enabled = false
27
+ }
28
+
29
+ function getStore (req) {
30
+ let store = metricsStoreMap.get(req)
31
+ if (!store) {
32
+ store = {}
33
+ metricsStoreMap.set(req, store)
34
+ }
35
+ return store
36
+ }
37
+
38
+ function getVersionsTags (wafVersion, rulesVersion) {
39
+ return {
40
+ [tags.WAF_VERSION]: wafVersion,
41
+ [tags.EVENT_RULES_VERSION]: rulesVersion
42
+ }
43
+ }
44
+
45
+ function trackWafDurations (metrics, versionsTags) {
46
+ if (metrics.duration) {
47
+ appsecMetrics.distribution('waf.duration', versionsTags).track(metrics.duration)
48
+ }
49
+ if (metrics.durationExt) {
50
+ appsecMetrics.distribution('waf.duration_ext', versionsTags).track(metrics.durationExt)
51
+ }
52
+ }
53
+
54
+ function getOrCreateMetricTags (req, versionsTags) {
55
+ const store = getStore(req)
56
+
57
+ let metricTags = store[DD_TELEMETRY_WAF_RESULT_TAGS]
58
+ if (!metricTags) {
59
+ metricTags = {
60
+ [tags.REQUEST_BLOCKED]: false,
61
+ [tags.RULE_TRIGGERED]: false,
62
+ [tags.WAF_TIMEOUT]: false,
63
+
64
+ ...versionsTags
65
+ }
66
+ store[DD_TELEMETRY_WAF_RESULT_TAGS] = metricTags
67
+ }
68
+ return metricTags
69
+ }
70
+
71
+ function updateWafRequestsMetricTags (metrics, req) {
72
+ if (!req || !enabled) return
73
+
74
+ const versionsTags = getVersionsTags(metrics.wafVersion, metrics.rulesVersion)
75
+
76
+ trackWafDurations(metrics, versionsTags)
77
+
78
+ const metricTags = getOrCreateMetricTags(req, versionsTags)
79
+
80
+ const { blockTriggered, ruleTriggered, wafTimeout } = metrics
81
+
82
+ if (blockTriggered) {
83
+ metricTags[tags.REQUEST_BLOCKED] = blockTriggered
84
+ }
85
+ if (ruleTriggered) {
86
+ metricTags[tags.RULE_TRIGGERED] = ruleTriggered
87
+ }
88
+ if (wafTimeout) {
89
+ metricTags[tags.WAF_TIMEOUT] = wafTimeout
90
+ }
91
+
92
+ return metricTags
93
+ }
94
+
95
+ function incrementWafInitMetric (wafVersion, rulesVersion) {
96
+ if (!enabled) return
97
+
98
+ const versionsTags = getVersionsTags(wafVersion, rulesVersion)
99
+
100
+ appsecMetrics.count('waf.init', versionsTags).inc()
101
+ }
102
+
103
+ function incrementWafUpdatesMetric (wafVersion, rulesVersion) {
104
+ if (!enabled) return
105
+
106
+ const versionsTags = getVersionsTags(wafVersion, rulesVersion)
107
+
108
+ appsecMetrics.count('waf.updates', versionsTags).inc()
109
+ }
110
+
111
+ function incrementWafRequestsMetric (req) {
112
+ if (!req || !enabled) return
113
+
114
+ const store = getStore(req)
115
+
116
+ const metricTags = store[DD_TELEMETRY_WAF_RESULT_TAGS]
117
+ if (metricTags) {
118
+ appsecMetrics.count('waf.requests', metricTags).inc()
119
+ }
120
+
121
+ metricsStoreMap.delete(req)
122
+ }
123
+
124
+ module.exports = {
125
+ enable,
126
+ disable,
127
+
128
+ updateWafRequestsMetricTags,
129
+ incrementWafInitMetric,
130
+ incrementWafUpdatesMetric,
131
+ incrementWafRequestsMetric
132
+ }
@@ -39,7 +39,7 @@ function update (newRules) {
39
39
  if (!waf.wafManager) throw new Error('Cannot update disabled WAF')
40
40
 
41
41
  try {
42
- waf.wafManager.ddwaf.update(newRules)
42
+ waf.wafManager.update(newRules)
43
43
  } catch (err) {
44
44
  log.error('Could not apply rules from remote config')
45
45
  throw err
@@ -4,11 +4,12 @@ const log = require('../../log')
4
4
  const Reporter = require('../reporter')
5
5
 
6
6
  class WAFContextWrapper {
7
- constructor (ddwafContext, requiredAddresses, wafTimeout, rulesInfo) {
7
+ constructor (ddwafContext, requiredAddresses, wafTimeout, wafVersion, rulesVersion) {
8
8
  this.ddwafContext = ddwafContext
9
9
  this.requiredAddresses = requiredAddresses
10
10
  this.wafTimeout = wafTimeout
11
- this.rulesInfo = rulesInfo
11
+ this.wafVersion = wafVersion
12
+ this.rulesVersion = rulesVersion
12
13
  }
13
14
 
14
15
  run (params) {
@@ -32,14 +33,21 @@ class WAFContextWrapper {
32
33
 
33
34
  const end = process.hrtime.bigint()
34
35
 
36
+ const ruleTriggered = !!result.events?.length
37
+ const blockTriggered = result.actions?.includes('block')
38
+
35
39
  Reporter.reportMetrics({
36
40
  duration: result.totalRuntime / 1e3,
37
41
  durationExt: parseInt(end - start) / 1e3,
38
- rulesVersion: this.rulesInfo.version
42
+ rulesVersion: this.rulesVersion,
43
+ ruleTriggered,
44
+ blockTriggered,
45
+ wafVersion: this.wafVersion,
46
+ wafTimeout: result.timeout
39
47
  })
40
48
 
41
- if (result.data && result.data !== '[]') {
42
- Reporter.reportAttack(result.data)
49
+ if (ruleTriggered) {
50
+ Reporter.reportAttack(JSON.stringify(result.events))
43
51
  }
44
52
 
45
53
  return result.actions
@@ -11,7 +11,10 @@ class WAFManager {
11
11
  this.config = config
12
12
  this.wafTimeout = config.wafTimeout
13
13
  this.ddwaf = this._loadDDWAF(rules)
14
- this._reportMetrics()
14
+ this.ddwafVersion = this.ddwaf.constructor.version()
15
+ this.rulesVersion = this.ddwaf.diagnostics.ruleset_version
16
+
17
+ Reporter.reportWafInit(this.ddwafVersion, this.rulesVersion, this.ddwaf.diagnostics.rules)
15
18
  }
16
19
 
17
20
  _loadDDWAF (rules) {
@@ -28,18 +31,6 @@ class WAFManager {
28
31
  }
29
32
  }
30
33
 
31
- _reportMetrics () {
32
- Reporter.metricsQueue.set('_dd.appsec.waf.version', this.ddwaf.constructor.version())
33
-
34
- const { loaded, failed, errors } = this.ddwaf.rulesInfo
35
-
36
- Reporter.metricsQueue.set('_dd.appsec.event_rules.loaded', loaded)
37
- Reporter.metricsQueue.set('_dd.appsec.event_rules.error_count', failed)
38
- if (failed) Reporter.metricsQueue.set('_dd.appsec.event_rules.errors', JSON.stringify(errors))
39
-
40
- Reporter.metricsQueue.set('manual.keep', 'true')
41
- }
42
-
43
34
  getWAFContext (req) {
44
35
  let wafContext = contexts.get(req)
45
36
 
@@ -48,7 +39,8 @@ class WAFManager {
48
39
  this.ddwaf.createContext(),
49
40
  this.ddwaf.requiredAddresses,
50
41
  this.wafTimeout,
51
- this.ddwaf.rulesInfo
42
+ this.ddwafVersion,
43
+ this.rulesVersion
52
44
  )
53
45
  contexts.set(req, wafContext)
54
46
  }
@@ -56,6 +48,12 @@ class WAFManager {
56
48
  return wafContext
57
49
  }
58
50
 
51
+ update (newRules) {
52
+ this.ddwaf.update(newRules)
53
+
54
+ Reporter.reportWafUpdate(this.ddwafVersion, this.rulesVersion)
55
+ }
56
+
59
57
  destroy () {
60
58
  if (this.ddwaf) {
61
59
  this.ddwaf.dispose()
@@ -28,25 +28,12 @@ function getItrConfiguration ({
28
28
  if (isEvpProxy) {
29
29
  options.path = '/evp_proxy/v2/api/v2/libraries/tests/services/setting'
30
30
  options.headers['X-Datadog-EVP-Subdomain'] = 'api'
31
- options.headers['X-Datadog-NeedsAppKey'] = 'true'
32
31
  } else {
33
32
  const apiKey = process.env.DATADOG_API_KEY || process.env.DD_API_KEY
34
- const appKey = process.env.DATADOG_APP_KEY ||
35
- process.env.DD_APP_KEY ||
36
- process.env.DATADOG_APPLICATION_KEY ||
37
- process.env.DD_APPLICATION_KEY
38
-
39
- const messagePrefix = 'Request to settings endpoint was not done because Datadog'
40
-
41
- if (!appKey) {
42
- return done(new Error(`${messagePrefix} application key is not defined.`))
43
- }
44
33
  if (!apiKey) {
45
- return done(new Error(`${messagePrefix} API key is not defined.`))
34
+ return done(new Error('Request to settings endpoint was not done because Datadog API key is not defined.'))
46
35
  }
47
-
48
36
  options.headers['dd-api-key'] = apiKey
49
- options.headers['dd-application-key'] = appKey
50
37
  }
51
38
 
52
39
  const data = JSON.stringify({
@@ -28,25 +28,13 @@ function getSkippableSuites ({
28
28
  if (isEvpProxy) {
29
29
  options.path = '/evp_proxy/v2/api/v2/ci/tests/skippable'
30
30
  options.headers['X-Datadog-EVP-Subdomain'] = 'api'
31
- options.headers['X-Datadog-NeedsAppKey'] = 'true'
32
31
  } else {
33
32
  const apiKey = process.env.DATADOG_API_KEY || process.env.DD_API_KEY
34
- const appKey = process.env.DATADOG_APP_KEY ||
35
- process.env.DD_APP_KEY ||
36
- process.env.DATADOG_APPLICATION_KEY ||
37
- process.env.DD_APPLICATION_KEY
38
-
39
- const messagePrefix = 'Skippable suites were not fetched because Datadog'
40
-
41
- if (!appKey) {
42
- return done(new Error(`${messagePrefix} application key is not defined.`))
43
- }
44
33
  if (!apiKey) {
45
- return done(new Error(`${messagePrefix} API key is not defined.`))
34
+ return done(new Error('Skippable suites were not fetched because Datadog API key is not defined.'))
46
35
  }
47
36
 
48
37
  options.headers['dd-api-key'] = apiKey
49
- options.headers['dd-application-key'] = appKey
50
38
  }
51
39
 
52
40
  const data = JSON.stringify({
@@ -66,7 +66,9 @@ class DataStreamsProcessor {
66
66
  port,
67
67
  url,
68
68
  env,
69
- tags
69
+ tags,
70
+ version,
71
+ service
70
72
  } = {}) {
71
73
  this.writer = new DataStreamsWriter({
72
74
  hostname,
@@ -79,7 +81,8 @@ class DataStreamsProcessor {
79
81
  this.enabled = dsmEnabled
80
82
  this.env = env
81
83
  this.tags = tags || {}
82
- this.service = this.tags.service || 'unnamed-nodejs-service'
84
+ this.service = service || 'unnamed-nodejs-service'
85
+ this.version = version || ''
83
86
  this.sequence = 0
84
87
 
85
88
  if (this.enabled) {
@@ -96,6 +99,7 @@ class DataStreamsProcessor {
96
99
  Service: this.service,
97
100
  Stats: serialized,
98
101
  TracerVersion: pkg.version,
102
+ Version: this.version,
99
103
  Lang: 'javascript'
100
104
  }
101
105
  this.writer.flush(payload)
@@ -13,7 +13,7 @@ const SPAN_SAMPLING_MECHANISM = constants.SPAN_SAMPLING_MECHANISM
13
13
  const SPAN_SAMPLING_RULE_RATE = constants.SPAN_SAMPLING_RULE_RATE
14
14
  const SPAN_SAMPLING_MAX_PER_SECOND = constants.SPAN_SAMPLING_MAX_PER_SECOND
15
15
  const SAMPLING_MECHANISM_SPAN = constants.SAMPLING_MECHANISM_SPAN
16
- const MEASURED = tags.MEASURED
16
+ const { MEASURED, BASE_SERVICE } = tags
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
@@ -73,6 +73,11 @@ function extractTags (trace, span) {
73
73
  addTag({}, trace.metrics, MEASURED, 1)
74
74
  }
75
75
 
76
+ const tracerService = span.tracer()._service.toLowerCase()
77
+ if (tags['service.name']?.toLowerCase() !== tracerService) {
78
+ span.setTag(BASE_SERVICE, tracerService)
79
+ }
80
+
76
81
  for (const tag in tags) {
77
82
  switch (tag) {
78
83
  case 'service.name':
@@ -343,10 +343,10 @@ class TextMapPropagator {
343
343
  spanContext._trace.origin = value
344
344
  break
345
345
  case 't.dm': {
346
- const mechanism = -Math.abs(parseInt(value, 10))
346
+ const mechanism = Math.abs(parseInt(value, 10))
347
347
  if (Number.isInteger(mechanism)) {
348
348
  spanContext._sampling.mechanism = mechanism
349
- spanContext._trace.tags['_dd.p.dm'] = String(mechanism)
349
+ spanContext._trace.tags['_dd.p.dm'] = `-${mechanism}`
350
350
  }
351
351
  break
352
352
  }
@@ -26,8 +26,6 @@ class DatadogTracer {
26
26
  this._version = config.version
27
27
  this._env = config.env
28
28
  this._tags = config.tags
29
- this._computePeerService = config.spanComputePeerService
30
- this._peerServiceMapping = config.peerServiceMapping
31
29
  this._logInjection = config.logInjection
32
30
  this._debug = config.debug
33
31
  this._prioritySampler = new PrioritySampler(config.env, config.sampler)
@@ -72,11 +72,10 @@ module.exports = class PluginManager {
72
72
  const Plugin = pluginClasses[name]
73
73
 
74
74
  if (!Plugin) return
75
+ if (!this._tracerConfig) return // TODO: don't wait for tracer to be initialized
75
76
  if (!this._pluginsByName[name]) {
76
77
  this._pluginsByName[name] = new Plugin(this._tracer, this._tracerConfig)
77
78
  }
78
- if (!this._tracerConfig) return // TODO: don't wait for tracer to be initialized
79
-
80
79
  const pluginConfig = this._configsByName[name] || {
81
80
  enabled: this._tracerConfig.plugins !== false
82
81
  }
@@ -1,6 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  const StoragePlugin = require('./storage')
4
+ const { PEER_SERVICE_KEY } = require('../constants')
4
5
 
5
6
  class DatabasePlugin extends StoragePlugin {
6
7
  static get operation () { return 'query' }
@@ -38,20 +39,29 @@ class DatabasePlugin extends StoragePlugin {
38
39
  `ddps='${encodedDdps}',ddpv='${encodedDdpv}'`
39
40
  }
40
41
 
41
- injectDbmQuery (query, serviceName, isPreparedStatement = false) {
42
+ getDbmServiceName (span, tracerService) {
43
+ if (this._tracerConfig.spanComputePeerService) {
44
+ const peerData = this.getPeerService(span.context()._tags)
45
+ return this.getPeerServiceRemap(peerData)[PEER_SERVICE_KEY] || tracerService
46
+ }
47
+ return tracerService
48
+ }
49
+
50
+ injectDbmQuery (span, query, serviceName, isPreparedStatement = false) {
42
51
  const mode = this.config.dbmPropagationMode
52
+ const dbmService = this.getDbmServiceName(span, serviceName)
43
53
 
44
54
  if (mode === 'disabled') {
45
55
  return query
46
56
  }
47
57
 
48
- const servicePropagation = this.createDBMPropagationCommentService(serviceName)
58
+ const servicePropagation = this.createDBMPropagationCommentService(dbmService)
49
59
 
50
60
  if (isPreparedStatement || mode === 'service') {
51
61
  return `/*${servicePropagation}*/ ${query}`
52
62
  } else if (mode === 'full') {
53
- this.activeSpan.setTag('_dd.dbm_trace_injected', 'true')
54
- const traceparent = this.activeSpan._spanContext.toTraceparent()
63
+ span.setTag('_dd.dbm_trace_injected', 'true')
64
+ const traceparent = span._spanContext.toTraceparent()
55
65
  return `/*${servicePropagation},traceparent='${traceparent}'*/ ${query}`
56
66
  }
57
67
  }
@@ -64,6 +64,7 @@ module.exports = {
64
64
  get 'pg' () { return require('../../../datadog-plugin-pg/src') },
65
65
  get 'pino' () { return require('../../../datadog-plugin-pino/src') },
66
66
  get 'pino-pretty' () { return require('../../../datadog-plugin-pino/src') },
67
+ get 'playwright' () { return require('../../../datadog-plugin-playwright/src') },
67
68
  get 'redis' () { return require('../../../datadog-plugin-redis/src') },
68
69
  get 'restify' () { return require('../../../datadog-plugin-restify/src') },
69
70
  get 'rhea' () { return require('../../../datadog-plugin-rhea/src') },
@@ -64,10 +64,11 @@ class OutboundPlugin extends TracingPlugin {
64
64
  * peer service and add the value we overrode.
65
65
  */
66
66
  const peerService = peerData[PEER_SERVICE_KEY]
67
- if (peerService && this.tracer._peerServiceMapping[peerService]) {
67
+ const mappedService = this._tracerConfig.peerServiceMapping?.[peerService]
68
+ if (peerService && mappedService) {
68
69
  return {
69
70
  ...peerData,
70
- [PEER_SERVICE_KEY]: this.tracer._peerServiceMapping[peerService],
71
+ [PEER_SERVICE_KEY]: mappedService,
71
72
  [PEER_SERVICE_REMAP_KEY]: peerService
72
73
  }
73
74
  }
@@ -80,7 +81,7 @@ class OutboundPlugin extends TracingPlugin {
80
81
  }
81
82
 
82
83
  tagPeerService (span) {
83
- if (this.tracer._computePeerService) {
84
+ if (this._tracerConfig.spanComputePeerService) {
84
85
  const peerData = this.getPeerService(span.context()._tags)
85
86
  if (peerData !== undefined) {
86
87
  span.addTags(this.getPeerServiceRemap(peerData))
@@ -55,7 +55,7 @@ class TracingPlugin extends Plugin {
55
55
  start () {} // implemented by individual plugins
56
56
 
57
57
  finish () {
58
- this.activeSpan.finish()
58
+ this.activeSpan?.finish()
59
59
  }
60
60
 
61
61
  error (error) {
@@ -57,11 +57,20 @@ function appStarted () {
57
57
  return {
58
58
  integrations: getIntegrations(),
59
59
  dependencies: [],
60
- configuration: flatten(config),
60
+ configuration: flatten(formatConfig(config)),
61
61
  additional_payload: []
62
62
  }
63
63
  }
64
64
 
65
+ function formatConfig (config) {
66
+ // format peerServiceMapping from an object to a string map in order for
67
+ // telemetry intake to accept the configuration
68
+ config.peerServiceMapping = config.peerServiceMapping
69
+ ? Object.entries(config.peerServiceMapping).map(([key, value]) => `${key}:${value}`).join(',')
70
+ : ''
71
+ return config
72
+ }
73
+
65
74
  function onBeforeExit () {
66
75
  process.removeListener('beforeExit', onBeforeExit)
67
76
  sendData(config, application, host, 'app-closing')
@@ -66,7 +66,7 @@ function globMatch (pattern, subject) {
66
66
  function calculateDDBasePath (dirname) {
67
67
  const dirSteps = dirname.split(path.sep)
68
68
  const packagesIndex = dirSteps.lastIndexOf('packages')
69
- return dirSteps.slice(0, packagesIndex).join(path.sep) + path.sep
69
+ return dirSteps.slice(0, packagesIndex + 1).join(path.sep) + path.sep
70
70
  }
71
71
 
72
72
  module.exports = {