dd-trace 4.29.0 → 4.30.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 (52) hide show
  1. package/README.md +7 -0
  2. package/ci/cypress/after-spec.js +1 -0
  3. package/index.d.ts +1499 -1486
  4. package/package.json +3 -3
  5. package/packages/datadog-core/src/utils/src/get.js +11 -0
  6. package/packages/datadog-core/src/utils/src/has.js +14 -0
  7. package/packages/datadog-core/src/utils/src/set.js +16 -0
  8. package/packages/datadog-instrumentations/src/amqplib.js +1 -1
  9. package/packages/datadog-instrumentations/src/cucumber.js +2 -1
  10. package/packages/datadog-instrumentations/src/grpc/server.js +3 -1
  11. package/packages/datadog-instrumentations/src/jest.js +11 -5
  12. package/packages/datadog-instrumentations/src/mocha.js +4 -1
  13. package/packages/datadog-instrumentations/src/mongodb-core.js +34 -3
  14. package/packages/datadog-instrumentations/src/playwright.js +78 -16
  15. package/packages/datadog-plugin-amqplib/src/consumer.js +5 -4
  16. package/packages/datadog-plugin-amqplib/src/producer.js +3 -4
  17. package/packages/datadog-plugin-aws-sdk/src/base.js +3 -2
  18. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +4 -11
  19. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +3 -6
  20. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +5 -7
  21. package/packages/datadog-plugin-cypress/src/after-spec.js +3 -0
  22. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +123 -58
  23. package/packages/datadog-plugin-cypress/src/support.js +50 -3
  24. package/packages/datadog-plugin-graphql/src/index.js +1 -1
  25. package/packages/datadog-plugin-graphql/src/resolve.js +10 -8
  26. package/packages/datadog-plugin-grpc/src/util.js +1 -1
  27. package/packages/datadog-plugin-jest/src/index.js +11 -2
  28. package/packages/datadog-plugin-kafkajs/src/consumer.js +4 -3
  29. package/packages/datadog-plugin-kafkajs/src/producer.js +3 -5
  30. package/packages/datadog-plugin-playwright/src/index.js +34 -3
  31. package/packages/datadog-plugin-rhea/src/consumer.js +5 -3
  32. package/packages/datadog-plugin-rhea/src/producer.js +3 -4
  33. package/packages/dd-trace/src/appsec/iast/index.js +10 -0
  34. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +18 -5
  35. package/packages/dd-trace/src/appsec/recommended.json +67 -27
  36. package/packages/dd-trace/src/appsec/remote_config/index.js +1 -1
  37. package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +1 -3
  38. package/packages/dd-trace/src/config.js +451 -460
  39. package/packages/dd-trace/src/data_streams_context.js +1 -1
  40. package/packages/dd-trace/src/datastreams/pathway.js +58 -1
  41. package/packages/dd-trace/src/datastreams/processor.js +3 -5
  42. package/packages/dd-trace/src/format.js +0 -1
  43. package/packages/dd-trace/src/opentracing/propagation/text_map.js +1 -1
  44. package/packages/dd-trace/src/plugins/util/test.js +2 -0
  45. package/packages/dd-trace/src/plugins/util/web.js +1 -1
  46. package/packages/dd-trace/src/profiling/exporters/agent.js +38 -2
  47. package/packages/dd-trace/src/telemetry/index.js +22 -34
  48. package/packages/dd-trace/src/tracer.js +3 -3
  49. package/register.js +4 -0
  50. /package/packages/{utils → datadog-core/src/utils}/src/kebabcase.js +0 -0
  51. /package/packages/{utils → datadog-core/src/utils}/src/pick.js +0 -0
  52. /package/packages/{utils → datadog-core/src/utils}/src/uniq.js +0 -0
@@ -6,7 +6,7 @@ function getDataStreamsContext () {
6
6
  }
7
7
 
8
8
  function setDataStreamsContext (dataStreamsContext) {
9
- storage.enterWith({ ...(storage.getStore()), dataStreamsContext })
9
+ if (dataStreamsContext) storage.enterWith({ ...(storage.getStore()), dataStreamsContext })
10
10
  }
11
11
 
12
12
  module.exports = {
@@ -8,6 +8,9 @@ const LRUCache = require('lru-cache')
8
8
  const options = { max: 500 }
9
9
  const cache = new LRUCache(options)
10
10
 
11
+ const CONTEXT_PROPAGATION_KEY = 'dd-pathway-ctx'
12
+ const CONTEXT_PROPAGATION_KEY_BASE64 = 'dd-pathway-ctx-base64'
13
+
11
14
  function shaHash (checkpointString) {
12
15
  const hash = crypto.createHash('md5').update(checkpointString).digest('hex').slice(0, 16)
13
16
  return Buffer.from(hash, 'hex')
@@ -33,6 +36,11 @@ function encodePathwayContext (dataStreamsContext) {
33
36
  ], 20)
34
37
  }
35
38
 
39
+ function encodePathwayContextBase64 (dataStreamsContext) {
40
+ const encodedPathway = encodePathwayContext(dataStreamsContext)
41
+ return encodedPathway.toString('base64')
42
+ }
43
+
36
44
  function decodePathwayContext (pathwayContext) {
37
45
  if (pathwayContext == null || pathwayContext.length < 8) {
38
46
  return null
@@ -51,8 +59,57 @@ function decodePathwayContext (pathwayContext) {
51
59
  return { hash: pathwayHash, pathwayStartNs: pathwayStartMs * 1e6, edgeStartNs: edgeStartMs * 1e6 }
52
60
  }
53
61
 
62
+ function decodePathwayContextBase64 (pathwayContext) {
63
+ if (pathwayContext == null || pathwayContext.length < 8) {
64
+ return
65
+ }
66
+ if (Buffer.isBuffer(pathwayContext)) {
67
+ pathwayContext = pathwayContext.toString()
68
+ }
69
+ const encodedPathway = Buffer.from(pathwayContext, 'base64')
70
+ return decodePathwayContext(encodedPathway)
71
+ }
72
+
73
+ class DsmPathwayCodec {
74
+ // we use a class for encoding / decoding in case we update our encoding/decoding. A class will make updates easier
75
+ // instead of using individual functions.
76
+ static encode (dataStreamsContext, carrier) {
77
+ if (!dataStreamsContext || !dataStreamsContext.hash) {
78
+ return
79
+ }
80
+ carrier[CONTEXT_PROPAGATION_KEY_BASE64] = encodePathwayContextBase64(dataStreamsContext)
81
+ }
82
+
83
+ static decode (carrier) {
84
+ if (carrier == null) return
85
+
86
+ let ctx
87
+ if (CONTEXT_PROPAGATION_KEY_BASE64 in carrier) {
88
+ // decode v2 encoding of base64
89
+ ctx = decodePathwayContextBase64(carrier[CONTEXT_PROPAGATION_KEY_BASE64])
90
+ } else if (CONTEXT_PROPAGATION_KEY in carrier) {
91
+ try {
92
+ // decode v1 encoding
93
+ ctx = decodePathwayContext(carrier[CONTEXT_PROPAGATION_KEY])
94
+ } catch {
95
+ // pass
96
+ }
97
+ // cover case where base64 context was received under wrong key
98
+ if (!ctx) ctx = decodePathwayContextBase64(carrier[CONTEXT_PROPAGATION_KEY])
99
+ }
100
+ return ctx
101
+ }
102
+
103
+ static contextExists (carrier) {
104
+ return CONTEXT_PROPAGATION_KEY_BASE64 in carrier || CONTEXT_PROPAGATION_KEY in carrier
105
+ }
106
+ }
107
+
54
108
  module.exports = {
55
109
  computePathwayHash: computeHash,
56
110
  encodePathwayContext,
57
- decodePathwayContext
111
+ decodePathwayContext,
112
+ encodePathwayContextBase64,
113
+ decodePathwayContextBase64,
114
+ DsmPathwayCodec
58
115
  }
@@ -4,7 +4,7 @@ const pkg = require('../../../../package.json')
4
4
  const Uint64 = require('int64-buffer').Uint64BE
5
5
 
6
6
  const { LogCollapsingLowestDenseDDSketch } = require('@datadog/sketches-js')
7
- const { encodePathwayContext } = require('./pathway')
7
+ const { DsmPathwayCodec } = require('./pathway')
8
8
  const { DataStreamsWriter } = require('./writer')
9
9
  const { computePathwayHash } = require('./pathway')
10
10
  const { types } = require('util')
@@ -13,7 +13,6 @@ const { PATHWAY_HASH } = require('../../../../ext/tags')
13
13
  const ENTRY_PARENT_HASH = Buffer.from('0000000000000000', 'hex')
14
14
 
15
15
  const HIGH_ACCURACY_DISTRIBUTION = 0.0075
16
- const CONTEXT_PROPAGATION_KEY = 'dd-pathway-ctx'
17
16
 
18
17
  class StatsPoint {
19
18
  constructor (hash, parentHash, edgeTags) {
@@ -285,7 +284,7 @@ class DataStreamsProcessor {
285
284
  // Add the header for this now, as the callee doesn't have access to context when producing
286
285
  // - 1 to account for extra byte for {
287
286
  const ddInfoContinued = {}
288
- ddInfoContinued[CONTEXT_PROPAGATION_KEY] = encodePathwayContext(dataStreamsContext).toJSON()
287
+ DsmPathwayCodec.encode(dataStreamsContext, ddInfoContinued)
289
288
  payloadSize += getSizeOrZero(JSON.stringify(ddInfoContinued)) - 1
290
289
  }
291
290
  const checkpoint = {
@@ -364,6 +363,5 @@ module.exports = {
364
363
  getHeadersSize,
365
364
  getSizeOrZero,
366
365
  getAmqpMessageSize,
367
- ENTRY_PARENT_HASH,
368
- CONTEXT_PROPAGATION_KEY
366
+ ENTRY_PARENT_HASH
369
367
  }
@@ -108,7 +108,6 @@ function extractTags (trace, span) {
108
108
 
109
109
  for (const tag in tags) {
110
110
  switch (tag) {
111
- case 'operation.name':
112
111
  case 'service.name':
113
112
  case 'span.type':
114
113
  case 'resource.name':
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const pick = require('../../../../utils/src/pick')
3
+ const pick = require('../../../../datadog-core/src/utils/src/pick')
4
4
  const id = require('../../id')
5
5
  const DatadogSpanContext = require('../span_context')
6
6
  const log = require('../../log')
@@ -58,6 +58,7 @@ const TEST_EARLY_FLAKE_IS_ENABLED = 'test.early_flake.is_enabled'
58
58
  const CI_APP_ORIGIN = 'ciapp-test'
59
59
 
60
60
  const JEST_TEST_RUNNER = 'test.jest.test_runner'
61
+ const JEST_DISPLAY_NAME = 'test.jest.display_name'
61
62
 
62
63
  const TEST_ITR_TESTS_SKIPPED = '_dd.ci.itr.tests_skipped'
63
64
  const TEST_ITR_SKIPPING_ENABLED = 'test.itr.tests_skipping.enabled'
@@ -83,6 +84,7 @@ module.exports = {
83
84
  TEST_FRAMEWORK,
84
85
  TEST_FRAMEWORK_VERSION,
85
86
  JEST_TEST_RUNNER,
87
+ JEST_DISPLAY_NAME,
86
88
  TEST_TYPE,
87
89
  TEST_NAME,
88
90
  TEST_SUITE,
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const uniq = require('../../../../utils/src/uniq')
3
+ const uniq = require('../../../../datadog-core/src/utils/src/uniq')
4
4
  const analyticsSampler = require('../../analytics_sampler')
5
5
  const FORMAT_HTTP_HEADERS = 'http_headers'
6
6
  const log = require('../../log')
@@ -9,6 +9,8 @@ const docker = require('../../exporters/common/docker')
9
9
  const FormData = require('../../exporters/common/form-data')
10
10
  const { storage } = require('../../../../datadog-core')
11
11
  const version = require('../../../../../package.json').version
12
+ const os = require('os')
13
+ const perf = require('perf_hooks').performance
12
14
 
13
15
  const containerId = docker.id()
14
16
 
@@ -50,7 +52,7 @@ function computeRetries (uploadTimeout) {
50
52
  }
51
53
 
52
54
  class AgentExporter {
53
- constructor ({ url, logger, uploadTimeout } = {}) {
55
+ constructor ({ url, logger, uploadTimeout, env, host, service, version } = {}) {
54
56
  this._url = url
55
57
  this._logger = logger
56
58
 
@@ -58,6 +60,10 @@ class AgentExporter {
58
60
 
59
61
  this._backoffTime = backoffTime
60
62
  this._backoffTries = backoffTries
63
+ this._env = env
64
+ this._host = host
65
+ this._service = service
66
+ this._appVersion = version
61
67
  }
62
68
 
63
69
  export ({ profiles, start, end, tags }) {
@@ -83,7 +89,37 @@ class AgentExporter {
83
89
  `profiler_version:${version}`,
84
90
  'format:pprof',
85
91
  ...Object.entries(tags).map(([key, value]) => `${key}:${value}`)
86
- ].join(',')
92
+ ].join(','),
93
+ info: {
94
+ application: {
95
+ env: this._env,
96
+ service: this._service,
97
+ start_time: new Date(perf.nodeTiming.nodeStart + perf.timeOrigin).toISOString(),
98
+ version: this._appVersion
99
+ },
100
+ platform: {
101
+ hostname: this._host,
102
+ kernel_name: os.type(),
103
+ kernel_release: os.release(),
104
+ kernel_version: os.version()
105
+ },
106
+ profiler: {
107
+ version
108
+ },
109
+ runtime: {
110
+ // Using `nodejs` for consistency with the existing `runtime` tag.
111
+ // Note that the event `family` property uses `node`, as that's what's
112
+ // proscribed by the Intake API, but that's an internal enum and is
113
+ // not customer visible.
114
+ engine: 'nodejs',
115
+ // strip off leading 'v'. This makes the format consistent with other
116
+ // runtimes (e.g. Ruby) but not with the existing `runtime_version` tag.
117
+ // We'll keep it like this as we want cross-engine consistency. We
118
+ // also aren't changing the format of the existing tag as we don't want
119
+ // to break it.
120
+ version: process.version.substring(1)
121
+ }
122
+ }
87
123
  })
88
124
 
89
125
  fields.push(['event', event, {
@@ -20,6 +20,7 @@ let heartbeatTimeout
20
20
  let heartbeatInterval
21
21
  let extendedInterval
22
22
  let integrations
23
+ let configWithOrigin = []
23
24
  let retryData = null
24
25
  const extendedHeartbeatPayload = {}
25
26
 
@@ -96,23 +97,6 @@ function getProducts (config) {
96
97
  return products
97
98
  }
98
99
 
99
- function flatten (input, result = [], prefix = [], traversedObjects = null) {
100
- traversedObjects = traversedObjects || new WeakSet()
101
- if (traversedObjects.has(input)) {
102
- return
103
- }
104
- traversedObjects.add(input)
105
- for (const [key, value] of Object.entries(input)) {
106
- if (typeof value === 'object' && value !== null) {
107
- flatten(value, result, [...prefix, key], traversedObjects)
108
- } else {
109
- // TODO: add correct origin value
110
- result.push({ name: [...prefix, key].join('.'), value, origin: 'unknown' })
111
- }
112
- }
113
- return result
114
- }
115
-
116
100
  function getInstallSignature (config) {
117
101
  const { installSignature: sig } = config
118
102
  if (sig && (sig.id || sig.time || sig.type)) {
@@ -127,7 +111,7 @@ function getInstallSignature (config) {
127
111
  function appStarted (config) {
128
112
  const app = {
129
113
  products: getProducts(config),
130
- configuration: flatten(config)
114
+ configuration: configWithOrigin
131
115
  }
132
116
  const installSignature = getInstallSignature(config)
133
117
  if (installSignature) {
@@ -305,13 +289,18 @@ function updateIntegrations () {
305
289
  sendData(config, application, host, reqType, payload, updateRetryData)
306
290
  }
307
291
 
292
+ function formatMapForTelemetry (map) {
293
+ // format from an object to a string map in order for
294
+ // telemetry intake to accept the configuration
295
+ return map
296
+ ? Object.entries(map).map(([key, value]) => `${key}:${value}`).join(',')
297
+ : ''
298
+ }
299
+
308
300
  function updateConfig (changes, config) {
309
301
  if (!config.telemetry.enabled) return
310
302
  if (changes.length === 0) return
311
303
 
312
- // Hack to make system tests happy until we ship telemetry v2
313
- if (process.env.DD_INTERNAL_TELEMETRY_V2_ENABLED !== '1') return
314
-
315
304
  const application = createAppObject(config)
316
305
  const host = createHostObject()
317
306
 
@@ -325,24 +314,23 @@ function updateConfig (changes, config) {
325
314
  const configuration = []
326
315
 
327
316
  for (const change of changes) {
328
- if (!names.hasOwnProperty(change.name)) continue
329
-
330
- const name = names[change.name]
317
+ const name = names[change.name] || change.name
331
318
  const { origin, value } = change
332
- const entry = { name, origin, value }
319
+ const entry = { name, value, origin }
333
320
 
334
- if (Array.isArray(value)) {
335
- entry.value = value.join(',')
336
- } else if (name === 'DD_TAGS') {
337
- entry.value = Object.entries(value).map(([key, value]) => `${key}:${value}`)
338
- }
321
+ if (Array.isArray(value)) entry.value = value.join(',')
322
+ if (entry.name === 'DD_TAGS') entry.value = formatMapForTelemetry(entry.value)
323
+ if (entry.name === 'url' && entry.value) entry.value = entry.value.toString()
324
+ if (entry.name === 'peerServiceMapping' || entry.name === 'tags') entry.value = formatMapForTelemetry(entry.value)
339
325
 
340
326
  configuration.push(entry)
341
327
  }
342
-
343
- const { reqType, payload } = createPayload('app-client-configuration-change', { configuration })
344
-
345
- sendData(config, application, host, reqType, payload, updateRetryData)
328
+ if (!configWithOrigin.length) {
329
+ configWithOrigin = configuration
330
+ } else {
331
+ const { reqType, payload } = createPayload('app-client-configuration-change', { configuration })
332
+ sendData(config, application, host, reqType, payload, updateRetryData)
333
+ }
346
334
  }
347
335
 
348
336
  module.exports = {
@@ -8,7 +8,7 @@ const { isError } = require('./util')
8
8
  const { setStartupLogConfig } = require('./startup-log')
9
9
  const { ERROR_MESSAGE, ERROR_TYPE, ERROR_STACK } = require('../../dd-trace/src/constants')
10
10
  const { DataStreamsProcessor } = require('./datastreams/processor')
11
- const { decodePathwayContext } = require('./datastreams/pathway')
11
+ const { DsmPathwayCodec } = require('./datastreams/pathway')
12
12
  const { DD_MAJOR } = require('../../../version')
13
13
  const DataStreamsContext = require('./data_streams_context')
14
14
 
@@ -39,8 +39,8 @@ class DatadogTracer extends Tracer {
39
39
  return ctx
40
40
  }
41
41
 
42
- decodeDataStreamsContext (data) {
43
- const ctx = decodePathwayContext(data)
42
+ decodeDataStreamsContext (carrier) {
43
+ const ctx = DsmPathwayCodec.decode(carrier)
44
44
  // we erase the previous context everytime we decode a new one
45
45
  DataStreamsContext.setDataStreamsContext(ctx)
46
46
  return ctx
package/register.js ADDED
@@ -0,0 +1,4 @@
1
+ const { register } = require('node:module')
2
+ const { pathToFileURL } = require('node:url')
3
+
4
+ register('./loader-hook.mjs', pathToFileURL(__filename))