dd-trace 5.102.0 → 5.103.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 (133) hide show
  1. package/ext/exporters.js +1 -0
  2. package/package.json +12 -11
  3. package/packages/datadog-esbuild/src/utils.js +2 -2
  4. package/packages/datadog-instrumentations/src/ai.js +1 -1
  5. package/packages/datadog-instrumentations/src/confluentinc-kafka-javascript.js +32 -15
  6. package/packages/datadog-instrumentations/src/couchbase.js +69 -220
  7. package/packages/datadog-instrumentations/src/cucumber.js +1 -1
  8. package/packages/datadog-instrumentations/src/electron/preload.js +42 -0
  9. package/packages/datadog-instrumentations/src/electron.js +240 -0
  10. package/packages/datadog-instrumentations/src/fetch.js +5 -5
  11. package/packages/datadog-instrumentations/src/graphql.js +13 -12
  12. package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +1 -1
  13. package/packages/datadog-instrumentations/src/helpers/hook.js +4 -1
  14. package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
  15. package/packages/datadog-instrumentations/src/helpers/instrument.js +2 -2
  16. package/packages/datadog-instrumentations/src/helpers/kafka.js +41 -0
  17. package/packages/datadog-instrumentations/src/ioredis.js +16 -12
  18. package/packages/datadog-instrumentations/src/jest.js +351 -50
  19. package/packages/datadog-instrumentations/src/kafkajs.js +164 -173
  20. package/packages/datadog-instrumentations/src/mocha/main.js +73 -1
  21. package/packages/datadog-instrumentations/src/mongodb-core.js +33 -8
  22. package/packages/datadog-instrumentations/src/pg.js +24 -10
  23. package/packages/datadog-instrumentations/src/playwright.js +427 -55
  24. package/packages/datadog-instrumentations/src/redis.js +19 -10
  25. package/packages/datadog-plugin-apollo/src/gateway/request.js +1 -21
  26. package/packages/datadog-plugin-aws-sdk/src/base.js +18 -24
  27. package/packages/datadog-plugin-aws-sdk/src/services/cloudwatchlogs.js +1 -1
  28. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +1 -1
  29. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +1 -1
  30. package/packages/datadog-plugin-aws-sdk/src/services/lambda.js +1 -1
  31. package/packages/datadog-plugin-aws-sdk/src/services/redshift.js +1 -1
  32. package/packages/datadog-plugin-aws-sdk/src/services/s3.js +1 -1
  33. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +2 -2
  34. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +1 -1
  35. package/packages/datadog-plugin-aws-sdk/src/services/stepfunctions.js +1 -1
  36. package/packages/datadog-plugin-couchbase/src/index.js +58 -52
  37. package/packages/datadog-plugin-cucumber/src/index.js +1 -0
  38. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +214 -22
  39. package/packages/datadog-plugin-cypress/src/support.js +13 -1
  40. package/packages/datadog-plugin-electron/src/index.js +17 -0
  41. package/packages/datadog-plugin-electron/src/ipc.js +143 -0
  42. package/packages/datadog-plugin-electron/src/net.js +82 -0
  43. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +27 -18
  44. package/packages/datadog-plugin-graphql/src/execute.js +6 -28
  45. package/packages/datadog-plugin-graphql/src/resolve.js +30 -35
  46. package/packages/datadog-plugin-graphql/src/tools/signature.js +32 -7
  47. package/packages/datadog-plugin-graphql/src/tools/transforms.js +118 -100
  48. package/packages/datadog-plugin-graphql/src/utils.js +29 -0
  49. package/packages/datadog-plugin-grpc/src/client.js +6 -7
  50. package/packages/datadog-plugin-grpc/src/util.js +57 -22
  51. package/packages/datadog-plugin-http/src/client.js +2 -2
  52. package/packages/datadog-plugin-jest/src/index.js +92 -50
  53. package/packages/datadog-plugin-mocha/src/index.js +1 -0
  54. package/packages/datadog-plugin-mongodb-core/src/index.js +36 -70
  55. package/packages/datadog-plugin-mysql/src/index.js +1 -1
  56. package/packages/datadog-plugin-openai/src/services.js +2 -1
  57. package/packages/datadog-plugin-pg/src/index.js +3 -3
  58. package/packages/datadog-plugin-playwright/src/index.js +4 -0
  59. package/packages/datadog-plugin-redis/src/index.js +18 -23
  60. package/packages/dd-trace/src/aiguard/index.js +3 -1
  61. package/packages/dd-trace/src/aiguard/sdk.js +36 -30
  62. package/packages/dd-trace/src/aiguard/tags.js +20 -11
  63. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +2 -2
  64. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +1 -1
  65. package/packages/dd-trace/src/azure_metadata.js +17 -6
  66. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +4 -4
  67. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +4 -2
  68. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +6 -4
  69. package/packages/dd-trace/src/ci-visibility/requests/fs-cache.js +1 -1
  70. package/packages/dd-trace/src/config/defaults.js +3 -14
  71. package/packages/dd-trace/src/config/generated-config-types.d.ts +3 -1
  72. package/packages/dd-trace/src/config/helper.js +4 -0
  73. package/packages/dd-trace/src/config/index.js +2 -2
  74. package/packages/dd-trace/src/config/major-overrides.js +98 -0
  75. package/packages/dd-trace/src/config/parsers.js +7 -1
  76. package/packages/dd-trace/src/config/supported-configurations.json +51 -38
  77. package/packages/dd-trace/src/datastreams/checkpointer.js +2 -2
  78. package/packages/dd-trace/src/datastreams/manager.js +1 -1
  79. package/packages/dd-trace/src/datastreams/processor.js +2 -2
  80. package/packages/dd-trace/src/debugger/devtools_client/snapshot/collector.js +2 -2
  81. package/packages/dd-trace/src/debugger/devtools_client/source-maps.js +1 -1
  82. package/packages/dd-trace/src/debugger/devtools_client/state.js +2 -1
  83. package/packages/dd-trace/src/debugger/index.js +7 -7
  84. package/packages/dd-trace/src/dogstatsd.js +2 -2
  85. package/packages/dd-trace/src/encode/0.4.js +45 -54
  86. package/packages/dd-trace/src/encode/0.5.js +34 -3
  87. package/packages/dd-trace/src/encode/agentless-json.js +1 -1
  88. package/packages/dd-trace/src/exporter.js +2 -0
  89. package/packages/dd-trace/src/exporters/agent/index.js +2 -1
  90. package/packages/dd-trace/src/exporters/agentless/index.js +3 -2
  91. package/packages/dd-trace/src/exporters/agentless/writer.js +2 -2
  92. package/packages/dd-trace/src/exporters/common/buffering-exporter.js +2 -1
  93. package/packages/dd-trace/src/exporters/common/request.js +1 -1
  94. package/packages/dd-trace/src/exporters/electron/index.js +49 -0
  95. package/packages/dd-trace/src/external-logger/src/index.js +2 -1
  96. package/packages/dd-trace/src/git_metadata.js +10 -8
  97. package/packages/dd-trace/src/lambda/handler-paths.js +52 -0
  98. package/packages/dd-trace/src/lambda/index.js +62 -14
  99. package/packages/dd-trace/src/lambda/runtime/patch.js +21 -46
  100. package/packages/dd-trace/src/llmobs/index.js +13 -2
  101. package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +45 -15
  102. package/packages/dd-trace/src/llmobs/writers/base.js +2 -1
  103. package/packages/dd-trace/src/openfeature/writers/base.js +2 -1
  104. package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +2 -1
  105. package/packages/dd-trace/src/opentracing/propagation/text_map.js +20 -9
  106. package/packages/dd-trace/src/payload-tagging/config/index.js +2 -2
  107. package/packages/dd-trace/src/plugins/ci_plugin.js +49 -4
  108. package/packages/dd-trace/src/plugins/database.js +54 -12
  109. package/packages/dd-trace/src/plugins/index.js +1 -0
  110. package/packages/dd-trace/src/plugins/plugin.js +2 -4
  111. package/packages/dd-trace/src/plugins/util/ci.js +8 -8
  112. package/packages/dd-trace/src/plugins/util/git-cache.js +20 -18
  113. package/packages/dd-trace/src/plugins/util/stacktrace.js +2 -2
  114. package/packages/dd-trace/src/plugins/util/test.js +37 -5
  115. package/packages/dd-trace/src/plugins/util/user-provided-git.js +17 -15
  116. package/packages/dd-trace/src/priority_sampler.js +1 -1
  117. package/packages/dd-trace/src/profiling/profiler.js +1 -1
  118. package/packages/dd-trace/src/profiling/profilers/wall.js +1 -1
  119. package/packages/dd-trace/src/profiling/ssi-heuristics.js +1 -1
  120. package/packages/dd-trace/src/rate_limiter.js +1 -1
  121. package/packages/dd-trace/src/remote_config/scheduler.js +1 -1
  122. package/packages/dd-trace/src/ritm.js +2 -1
  123. package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +5 -8
  124. package/packages/dd-trace/src/serverless.js +5 -2
  125. package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +20 -0
  126. package/packages/dd-trace/src/service-naming/schemas/v0/web.js +4 -0
  127. package/packages/dd-trace/src/service-naming/schemas/v1/messaging.js +20 -0
  128. package/packages/dd-trace/src/service-naming/schemas/v1/web.js +4 -0
  129. package/packages/dd-trace/src/span_stats.js +1 -1
  130. package/packages/dd-trace/src/telemetry/dependencies.js +1 -1
  131. package/packages/dd-trace/src/telemetry/endpoints.js +1 -1
  132. package/packages/dd-trace/src/telemetry/telemetry.js +2 -2
  133. package/packages/dd-trace/src/lambda/runtime/ritm.js +0 -133
@@ -49,6 +49,7 @@ const {
49
49
  getTestSuiteCommonTags,
50
50
  TEST_STATUS,
51
51
  TEST_SKIPPED_BY_ITR,
52
+ TEST_ITR_SKIPPING_ENABLED,
52
53
  ITR_CORRELATION_ID,
53
54
  TEST_SOURCE_FILE,
54
55
  TEST_LEVEL_EVENT_TYPES,
@@ -64,7 +65,11 @@ const {
64
65
  getModifiedFilesFromDiff,
65
66
  getPullRequestBaseBranch,
66
67
  getSessionRequestErrorTags,
67
- DD_CI_LIBRARY_CONFIGURATION_ERROR,
68
+ DD_CI_LIBRARY_CONFIGURATION_ERROR_SETTINGS,
69
+ DD_CI_LIBRARY_CONFIGURATION_ERROR_SKIPPABLE_TESTS,
70
+ DD_CI_LIBRARY_CONFIGURATION_ERROR_KNOWN_TESTS,
71
+ DD_CI_LIBRARY_CONFIGURATION_ERROR_TEST_MANAGEMENT_TESTS,
72
+ getSessionItrSkippingEnabledTags,
68
73
  TEST_IS_TEST_FRAMEWORK_WORKER,
69
74
  TEST_IS_NEW,
70
75
  TEST_IS_RUM_ACTIVE,
@@ -74,6 +79,7 @@ const {
74
79
  TEST_IS_MODIFIED,
75
80
  TEST_IS_RETRY,
76
81
  TEST_RETRY_REASON,
82
+ DD_CAPABILITIES_TEST_IMPACT_ANALYSIS,
77
83
  } = require('./util/test')
78
84
 
79
85
  const FRAMEWORK_TO_TRIMMED_COMMAND = {
@@ -99,6 +105,21 @@ const TEST_FRAMEWORKS_TO_SKIP_GIT_METADATA_EXTRACTION = new Set([
99
105
  'cucumber',
100
106
  ])
101
107
 
108
+ function setItrSkippingEnabledTagFromLibraryConfig (plugin, frameworkVersion) {
109
+ const libraryCapabilitiesTags = getLibraryCapabilitiesTags(plugin.constructor.id, frameworkVersion)
110
+
111
+ if (!libraryCapabilitiesTags[DD_CAPABILITIES_TEST_IMPACT_ANALYSIS] ||
112
+ !plugin.libraryConfig ||
113
+ !plugin.testSessionSpan ||
114
+ !plugin.testModuleSpan) {
115
+ return
116
+ }
117
+
118
+ const skippingEnabled = plugin.libraryConfig.isSuitesSkippingEnabled ? 'true' : 'false'
119
+ plugin.testSessionSpan.setTag(TEST_ITR_SKIPPING_ENABLED, skippingEnabled)
120
+ plugin.testModuleSpan.setTag(TEST_ITR_SKIPPING_ENABLED, skippingEnabled)
121
+ }
122
+
102
123
  function getTestSuiteLevelVisibilityTags (testSuiteSpan, testFramework) {
103
124
  const testSuiteSpanContext = testSuiteSpan.context()
104
125
 
@@ -134,9 +155,10 @@ module.exports = class CiPlugin extends Plugin {
134
155
  this.tracer._exporter.getLibraryConfiguration(this.testConfiguration, (err, libraryConfig) => {
135
156
  if (err) {
136
157
  log.error('Library configuration could not be fetched. %s', err.message)
137
- this._addRequestErrorTag(DD_CI_LIBRARY_CONFIGURATION_ERROR, err)
158
+ this._addRequestErrorTag(DD_CI_LIBRARY_CONFIGURATION_ERROR_SETTINGS, err)
138
159
  } else {
139
160
  this.libraryConfig = libraryConfig
161
+ setItrSkippingEnabledTagFromLibraryConfig(this, frameworkVersion)
140
162
  }
141
163
 
142
164
  const requestErrorTags = this.testSessionSpan
@@ -165,6 +187,7 @@ module.exports = class CiPlugin extends Plugin {
165
187
  this.tracer._exporter.getSkippableSuites(this.testConfiguration, (err, skippableSuites, itrCorrelationId) => {
166
188
  if (err) {
167
189
  log.error('Skippable suites could not be fetched. %s', err.message)
190
+ this._addRequestErrorTag(DD_CI_LIBRARY_CONFIGURATION_ERROR_SKIPPABLE_TESTS, err)
168
191
  } else {
169
192
  this.itrCorrelationId = itrCorrelationId
170
193
  }
@@ -225,6 +248,7 @@ module.exports = class CiPlugin extends Plugin {
225
248
  },
226
249
  integrationName: this.constructor.id,
227
250
  })
251
+ setItrSkippingEnabledTagFromLibraryConfig(this, frameworkVersion)
228
252
  // only for vitest
229
253
  // These are added for the worker threads to use
230
254
  if (this.constructor.id === 'vitest') {
@@ -246,6 +270,7 @@ module.exports = class CiPlugin extends Plugin {
246
270
  const testSuiteMetadata = {
247
271
  ...getTestSuiteCommonTags(testCommand, frameworkVersion, testSuite, this.constructor.id),
248
272
  ...getSessionRequestErrorTags(this.testSessionSpan),
273
+ ...getSessionItrSkippingEnabledTags(this.testSessionSpan),
249
274
  }
250
275
  if (this.itrCorrelationId) {
251
276
  testSuiteMetadata[ITR_CORRELATION_ID] = this.itrCorrelationId
@@ -277,6 +302,7 @@ module.exports = class CiPlugin extends Plugin {
277
302
  this.tracer._exporter.getKnownTests(this.testConfiguration, (err, knownTests) => {
278
303
  if (err) {
279
304
  log.error('Known tests could not be fetched. %s', err.message)
305
+ this._addRequestErrorTag(DD_CI_LIBRARY_CONFIGURATION_ERROR_KNOWN_TESTS, err)
280
306
  if (this.libraryConfig) {
281
307
  this.libraryConfig.isEarlyFlakeDetectionEnabled = false
282
308
  this.libraryConfig.isKnownTestsEnabled = false
@@ -297,6 +323,7 @@ module.exports = class CiPlugin extends Plugin {
297
323
  this.tracer._exporter.getTestManagementTests(this.testConfiguration, (err, testManagementTests) => {
298
324
  if (err) {
299
325
  log.error('Test management tests could not be fetched. %s', err.message)
326
+ this._addRequestErrorTag(DD_CI_LIBRARY_CONFIGURATION_ERROR_TEST_MANAGEMENT_TESTS, err)
300
327
  if (this.libraryConfig) {
301
328
  this.libraryConfig.isTestManagementEnabled = false
302
329
  }
@@ -342,6 +369,9 @@ module.exports = class CiPlugin extends Plugin {
342
369
 
343
370
  if (span.name?.startsWith(`${this.constructor.id}.`)) {
344
371
  span.meta[TEST_IS_TEST_FRAMEWORK_WORKER] = 'true'
372
+ if (span.name === `${this.constructor.id}.test` || span.name === `${this.constructor.id}.test_suite`) {
373
+ Object.assign(span.meta, getSessionItrSkippingEnabledTags(this.testSessionSpan))
374
+ }
345
375
  // augment with git information (since it will not be available in the worker)
346
376
  for (const key in this.testEnvironmentMetadata) {
347
377
  // CAREFUL: this bypasses the metadata/metrics distinction
@@ -372,7 +402,8 @@ module.exports = class CiPlugin extends Plugin {
372
402
 
373
403
  // Jest and Vitest worker test spans are serialized in the worker and may not include
374
404
  // request error tags; add them from the session span in the main process.
375
- if ((span.name === 'jest.test' || span.name === 'vitest.test') && this.testSessionSpan) {
405
+ if ((span.name === 'jest.test' || span.name === 'vitest.test' || span.name === 'vitest.test_suite') &&
406
+ this.testSessionSpan) {
376
407
  Object.assign(span.meta, getSessionRequestErrorTags(this.testSessionSpan))
377
408
  }
378
409
  }
@@ -449,13 +480,16 @@ module.exports = class CiPlugin extends Plugin {
449
480
  * Adds a hidden _dd tag to the test session span when a test-optimization request fails.
450
481
  * If the session span does not exist yet (e.g. library-configuration failed before session:start),
451
482
  * the tag is queued and applied when the span is created.
452
- * @param {string} tag - Tag name (e.g. DD_CI_LIBRARY_CONFIGURATION_ERROR)
483
+ * @param {string} tag - Tag name (e.g. DD_CI_LIBRARY_CONFIGURATION_ERROR_SETTINGS)
453
484
  * @param {Error} err - Request error
454
485
  */
455
486
  _addRequestErrorTag (tag, err) {
456
487
  const value = 'true'
457
488
  if (this.testSessionSpan) {
458
489
  this.testSessionSpan.setTag(tag, value)
490
+ if (this.testModuleSpan) {
491
+ this.testModuleSpan.setTag(tag, value)
492
+ }
459
493
  } else {
460
494
  this._pendingRequestErrorTags.push({ tag, value })
461
495
  }
@@ -469,6 +503,15 @@ module.exports = class CiPlugin extends Plugin {
469
503
  return getSessionRequestErrorTags(this.testSessionSpan)
470
504
  }
471
505
 
506
+ /**
507
+ * Returns ITR skipping-enabled tags from the test session span for propagation to child events.
508
+ *
509
+ * @returns {Record<string, string>}
510
+ */
511
+ getSessionItrSkippingEnabledTags () {
512
+ return getSessionItrSkippingEnabledTags(this.testSessionSpan)
513
+ }
514
+
472
515
  /**
473
516
  * @param {import('../config/config-base')} config - Tracer configuration
474
517
  * @param {boolean} shouldGetEnvironmentData - Whether to get environment data
@@ -596,6 +639,8 @@ module.exports = class CiPlugin extends Plugin {
596
639
  }
597
640
  }
598
641
 
642
+ Object.assign(testTags, getSessionItrSkippingEnabledTags(this.testSessionSpan))
643
+
599
644
  this.telemetry.ciVisEvent(TELEMETRY_EVENT_CREATED, 'test', { hasCodeOwners: !!codeOwners })
600
645
 
601
646
  const testSpan = this.tracer
@@ -1,13 +1,47 @@
1
1
  'use strict'
2
2
 
3
+ const { LRUCache } = require('../../../../vendor/dist/lru-cache')
3
4
  const { PEER_SERVICE_KEY, PEER_SERVICE_SOURCE_KEY } = require('../constants')
4
5
  const propagationHash = require('../propagation-hash')
5
6
  const StoragePlugin = require('./storage')
6
7
 
8
+ // Unreserved RFC 3986 set that `encodeURIComponent` leaves untouched (a conservative subset:
9
+ // `! * ' ( )` are also untouched but rarely appear in db / host / service names so we skip them).
10
+ const SAFE_ENCODE_RE = /^[\w\-.~]*$/
11
+
12
+ // Cap `#dbmPrefixCache` so a high-cardinality `db.name` (MongoDB sets it to
13
+ // `${database}.${collection}`) cannot grow the map without bound. Steady-state working sets
14
+ // fit well below the cap; cache misses cost a few hundred nanoseconds, so an evicted entry
15
+ // rebuilds cheaply on the next query.
16
+ const DBM_PREFIX_CACHE_MAX = 256
17
+
7
18
  class DatabasePlugin extends StoragePlugin {
8
19
  static operation = 'query'
9
20
  static peerServicePrecursors = ['db.name']
10
21
 
22
+ // dde / ddps / ddpv are tracer-process constants. They are baked in at `configure()` time as
23
+ // two pre-templated fragments — `dbmEnvFragment` splices between dddbs and ddh; `dbmEndFragment`
24
+ // trails ddh — so per-query work shrinks to encoding dddb / dddbs / ddh and concatenating.
25
+ #dbmEnvFragment
26
+ #dbmEndFragment
27
+ // Cache the rendered prefix per `${db.name}\0${out.host}\0${dbmService}`. The triple is
28
+ // connection-stable for a real workload, so the steady state is one `LRUCache.get` plus the
29
+ // optional per-call `,ddprs='...'` suffix.
30
+ #dbmPrefixCache = new LRUCache({ max: DBM_PREFIX_CACHE_MAX })
31
+
32
+ /**
33
+ * @override
34
+ * @param {boolean | import('../config/config-base') & {enabled: boolean}} config
35
+ */
36
+ configure (config) {
37
+ super.configure(config)
38
+ // Match the previous shape exactly: `dde` is `encode`d; `ddps` / `ddpv` are template-literal
39
+ // coerced so `undefined` renders as the literal `'undefined'` the way the original did.
40
+ this.#dbmEnvFragment = `,dde='${encode(this.tracer._env)}',`
41
+ this.#dbmEndFragment = `,ddps='${this.tracer._service ?? ''}',ddpv='${this.tracer._version}'`
42
+ this.#dbmPrefixCache.clear()
43
+ }
44
+
11
45
  /**
12
46
  * @param {string} serviceName
13
47
  * @param {import('../../../..').Span} span
@@ -16,20 +50,21 @@ class DatabasePlugin extends StoragePlugin {
16
50
  */
17
51
  #createDBMPropagationCommentService (serviceName, span, peerData) {
18
52
  const spanTags = span.context()._tags
19
- const encodedDddb = encode(spanTags['db.name'])
20
- const encodedDddbs = encode(serviceName)
21
- const encodedDde = encode(this.tracer._env)
22
- const encodedDdh = encode(spanTags['out.host'])
23
- const encodedDdps = this.tracer._service ?? ''
24
- const encodedDdpv = this.tracer._version
25
-
26
- let dbmComment = `dddb='${encodedDddb}',dddbs='${encodedDddbs}',dde='${encodedDde}',ddh='${encodedDdh}',` +
27
- `ddps='${encodedDdps}',ddpv='${encodedDdpv}'`
53
+ const dddb = spanTags['db.name']
54
+ const ddh = spanTags['out.host']
55
+ const cacheKey = `${dddb ?? ''}\0${ddh ?? ''}\0${serviceName ?? ''}`
56
+
57
+ let prefix = this.#dbmPrefixCache.get(cacheKey)
58
+ if (prefix === undefined) {
59
+ prefix = `dddb='${encode(dddb)}',dddbs='${encode(serviceName)}'${this.#dbmEnvFragment}` +
60
+ `ddh='${encode(ddh)}'${this.#dbmEndFragment}`
61
+ this.#dbmPrefixCache.set(cacheKey, prefix)
62
+ }
28
63
 
29
64
  if (peerData !== undefined && peerData[PEER_SERVICE_SOURCE_KEY] === PEER_SERVICE_KEY) {
30
- dbmComment += `,ddprs='${encode(peerData[PEER_SERVICE_KEY])}'`
65
+ return `${prefix},ddprs='${encode(peerData[PEER_SERVICE_KEY])}'`
31
66
  }
32
- return dbmComment
67
+ return prefix
33
68
  }
34
69
 
35
70
  /**
@@ -118,6 +153,13 @@ class DatabasePlugin extends StoragePlugin {
118
153
  }
119
154
  }
120
155
 
121
- const encode = value => value ? encodeURIComponent(value) : ''
156
+ /**
157
+ * @param {string | number | undefined | null} value
158
+ * @returns {string}
159
+ */
160
+ function encode (value) {
161
+ if (!value) return ''
162
+ return SAFE_ENCODE_RE.test(value) ? value : encodeURIComponent(value)
163
+ }
122
164
 
123
165
  module.exports = DatabasePlugin
@@ -49,6 +49,7 @@ const plugins = {
49
49
  get dns () { return require('../../../datadog-plugin-dns/src') },
50
50
  get 'dd-trace-api' () { return require('../../../datadog-plugin-dd-trace-api/src') },
51
51
  get elasticsearch () { return require('../../../datadog-plugin-elasticsearch/src') },
52
+ get electron () { return require('../../../datadog-plugin-electron/src') },
52
53
  get express () { return require('../../../datadog-plugin-express/src') },
53
54
  get fastify () { return require('../../../datadog-plugin-fastify/src') },
54
55
  get 'find-my-way' () { return require('../../../datadog-plugin-find-my-way/src') },
@@ -160,14 +160,12 @@ module.exports = class Plugin {
160
160
  /**
161
161
  * Enable or disable the plugin and (re)apply its configuration.
162
162
  *
163
- * TODO: Remove the overloading with `enabled` and use the config object directly.
164
- *
165
- * @param {boolean | import('../config/config-base') & {enabled: boolean}} config Either a boolean to
163
+ * @param {boolean | Record<string, unknown> & {enabled: boolean}} config Either a boolean to
166
164
  * enable/disable or a configuration object containing at least `{ enabled: boolean }`.
167
165
  */
168
166
  configure (config) {
169
167
  if (typeof config === 'boolean') {
170
- config = /** @type {import('../config/config-base') & {enabled: boolean}} */ ({ enabled: config })
168
+ config = { enabled: config }
171
169
  }
172
170
  this.config = config
173
171
  if (config.enabled) {
@@ -2,7 +2,8 @@
2
2
 
3
3
  const { readFileSync, readdirSync, existsSync } = require('fs')
4
4
  const path = require('path')
5
- const { getEnvironmentVariable, getEnvironmentVariables, getValueFromEnvSources } = require('../../config/helper')
5
+ const getConfig = require('../../config')
6
+ const { getEnvironmentVariable, getEnvironmentVariables } = require('../../config/helper')
6
7
  const {
7
8
  GIT_BRANCH,
8
9
  GIT_COMMIT_SHA,
@@ -217,7 +218,7 @@ const githubWellKnownDiagnosticDirPatternsWin = ['C:/actions-runner/*/_diag', 'C
217
218
  const githubJobIDRegex = /"job":\s*{[\s\S]*?"v"\s*:\s*(\d+)(?:\.0)?/
218
219
 
219
220
  function getJobIDFromDiagFile () {
220
- const runnerTemp = getValueFromEnvSources('RUNNER_TEMP')
221
+ const runnerTemp = getEnvironmentVariable('RUNNER_TEMP')
221
222
  if (!runnerTemp || !existsSync(runnerTemp)) { return null }
222
223
 
223
224
  const isWin = process.platform === 'win32'
@@ -298,7 +299,7 @@ module.exports = {
298
299
  CHANGE_ID,
299
300
  CHANGE_TARGET,
300
301
  } = env
301
- const DD_CUSTOM_TRACE_ID = getValueFromEnvSources('DD_CUSTOM_TRACE_ID')
302
+ const { DD_CUSTOM_TRACE_ID, DD_CUSTOM_PARENT_ID } = getConfig()
302
303
 
303
304
  tags = {
304
305
  [CI_PIPELINE_ID]: BUILD_TAG,
@@ -308,7 +309,7 @@ module.exports = {
308
309
  [GIT_COMMIT_SHA]: JENKINS_GIT_COMMIT,
309
310
  [GIT_REPOSITORY_URL]: JENKINS_GIT_REPOSITORY_URL || JENKINS_GIT_REPOSITORY_URL_1,
310
311
  [CI_WORKSPACE_PATH]: WORKSPACE,
311
- [CI_ENV_VARS]: JSON.stringify({ DD_CUSTOM_TRACE_ID }),
312
+ [CI_ENV_VARS]: JSON.stringify({ DD_CUSTOM_TRACE_ID, DD_CUSTOM_PARENT_ID }),
312
313
  [CI_NODE_NAME]: NODE_NAME,
313
314
  [PR_NUMBER]: CHANGE_ID,
314
315
  [GIT_PULL_REQUEST_BASE_BRANCH]: CHANGE_TARGET,
@@ -738,11 +739,11 @@ module.exports = {
738
739
  }),
739
740
  [CI_NODE_NAME]: BUILDKITE_AGENT_ID,
740
741
  [CI_NODE_LABELS]: JSON.stringify(extraTags),
741
- [PR_NUMBER]: BUILDKITE_PULL_REQUEST,
742
742
  [CI_JOB_ID]: BUILDKITE_JOB_ID,
743
743
  }
744
744
 
745
- if (BUILDKITE_PULL_REQUEST) {
745
+ if (BUILDKITE_PULL_REQUEST && BUILDKITE_PULL_REQUEST !== 'false') {
746
+ tags[PR_NUMBER] = BUILDKITE_PULL_REQUEST
746
747
  tags[GIT_PULL_REQUEST_BASE_BRANCH] = BUILDKITE_PULL_REQUEST_BASE_BRANCH
747
748
  }
748
749
  }
@@ -868,8 +869,7 @@ module.exports = {
868
869
  }
869
870
 
870
871
  if (env.CODEBUILD_INITIATOR?.startsWith('codepipeline/')) {
871
- const DD_ACTION_EXECUTION_ID = getValueFromEnvSources('DD_ACTION_EXECUTION_ID')
872
- const DD_PIPELINE_EXECUTION_ID = getValueFromEnvSources('DD_PIPELINE_EXECUTION_ID')
872
+ const { DD_ACTION_EXECUTION_ID, DD_PIPELINE_EXECUTION_ID } = getConfig()
873
873
  tags = {
874
874
  [CI_PROVIDER_NAME]: 'awscodepipeline',
875
875
  [CI_PIPELINE_ID]: DD_PIPELINE_EXECUTION_ID,
@@ -7,24 +7,31 @@ const crypto = require('crypto')
7
7
  const cp = require('child_process')
8
8
 
9
9
  const log = require('../../log')
10
- const { getValueFromEnvSources } = require('../../config/helper')
11
- const { isTrue } = require('../../util')
10
+ const getConfig = require('../../config')
12
11
 
13
- let isGitEnabled = isTrue(getValueFromEnvSources('DD_EXPERIMENTAL_TEST_OPT_GIT_CACHE_ENABLED'))
14
- const GIT_CACHE_DIR = getValueFromEnvSources('DD_EXPERIMENTAL_TEST_OPT_GIT_CACHE_DIR') ||
15
- path.join(os.tmpdir(), 'dd-trace-git-cache')
12
+ let isGitEnabled
13
+ let gitCacheDir
16
14
 
17
15
  function ensureCacheDir () {
16
+ if (isGitEnabled === undefined) {
17
+ const config = getConfig()
18
+ isGitEnabled = config.DD_EXPERIMENTAL_TEST_OPT_GIT_CACHE_ENABLED
19
+ // TODO: Move the default to config/index.js applyCalculated
20
+ // when using the config singleton.
21
+ gitCacheDir = config.DD_EXPERIMENTAL_TEST_OPT_GIT_CACHE_DIR ||
22
+ path.join(os.tmpdir(), 'dd-trace-git-cache')
23
+ }
24
+
18
25
  if (!isGitEnabled) return false
19
26
 
20
27
  try {
21
- if (fs.existsSync(GIT_CACHE_DIR)) {
22
- const stats = fs.statSync(GIT_CACHE_DIR)
28
+ if (fs.existsSync(gitCacheDir)) {
29
+ const stats = fs.statSync(gitCacheDir)
23
30
  if (!stats.isDirectory()) {
24
- throw new Error(`Cache directory path exists but is not a directory: ${GIT_CACHE_DIR}`)
31
+ throw new Error(`Cache directory path exists but is not a directory: ${gitCacheDir}`)
25
32
  }
26
33
  } else {
27
- fs.mkdirSync(GIT_CACHE_DIR, { recursive: true })
34
+ fs.mkdirSync(gitCacheDir, { recursive: true })
28
35
  }
29
36
  return true
30
37
  } catch (err) {
@@ -34,9 +41,6 @@ function ensureCacheDir () {
34
41
  }
35
42
  }
36
43
 
37
- // Initialize cache directory at module load time
38
- ensureCacheDir()
39
-
40
44
  function getCacheKey (cmd, flags) {
41
45
  // Create a hash of the command and flags to use as cache key
42
46
  const commandString = `${cmd} ${flags.join(' ')}`
@@ -44,11 +48,12 @@ function getCacheKey (cmd, flags) {
44
48
  }
45
49
 
46
50
  function getCacheFilePath (cacheKey) {
47
- return path.join(GIT_CACHE_DIR, `${cacheKey}.cache`)
51
+ ensureCacheDir()
52
+ return path.join(gitCacheDir, `${cacheKey}.cache`)
48
53
  }
49
54
 
50
55
  function getCache (cacheKey) {
51
- if (!isGitEnabled) return null
56
+ if (!ensureCacheDir()) return null
52
57
 
53
58
  try {
54
59
  const cacheFilePath = getCacheFilePath(cacheKey)
@@ -63,9 +68,6 @@ function getCache (cacheKey) {
63
68
  }
64
69
 
65
70
  function setCache (cacheKey, result) {
66
- if (!isGitEnabled) return
67
-
68
- // Ensure cache directory exists
69
71
  if (!ensureCacheDir()) return
70
72
 
71
73
  try {
@@ -80,7 +82,7 @@ function cachedExec (cmd, flags, options) {
80
82
  if (options === undefined) {
81
83
  options = { stdio: 'pipe' }
82
84
  }
83
- if (!isGitEnabled) {
85
+ if (!ensureCacheDir()) {
84
86
  return cp.execFileSync(cmd, flags, options)
85
87
  }
86
88
  const cacheKey = getCacheKey(cmd, flags)
@@ -14,7 +14,7 @@ const NODE_MODULES_PATTERN_START = `node_modules${sep}`
14
14
  * In production, these frames are already filtered by isNodeModulesFrame.
15
15
  */
16
16
  const SHOULD_FILTER_DD_TRACE_INSTRUMENTAION = __filename.endsWith(
17
- join(sep, 'dd-trace-js', 'packages', 'dd-trace', 'src', 'plugins', 'util', 'stacktrace.js')
17
+ join('packages', 'dd-trace', 'src', 'plugins', 'util', 'stacktrace.js')
18
18
  )
19
19
 
20
20
  module.exports = {
@@ -46,7 +46,7 @@ function getCallSites (constructorOpt) {
46
46
  * Get stack trace of user-land frames.
47
47
  *
48
48
  * @param {string} stack - The stack trace to parse
49
- * @param {number} [limit=Infinity] - The maximum number of frames to return
49
+ * @param {number} [limit] - The maximum number of frames to return
50
50
  * @returns {StackFrame[]} - A list of stack frames from user-land code
51
51
  */
52
52
  function parseUserLandFrames (stack, limit = Infinity) {
@@ -163,8 +163,12 @@ const DD_CAPABILITIES_TEST_MANAGEMENT_DISABLE = '_dd.library_capabilities.test_m
163
163
  const DD_CAPABILITIES_TEST_MANAGEMENT_ATTEMPT_TO_FIX = '_dd.library_capabilities.test_management.attempt_to_fix'
164
164
  const DD_CAPABILITIES_FAILED_TEST_REPLAY = '_dd.library_capabilities.failed_test_replay'
165
165
 
166
- // Library configuration request error tag
167
- const DD_CI_LIBRARY_CONFIGURATION_ERROR = '_dd.ci.library_configuration_error'
166
+ // Library configuration request error tags
167
+ const DD_CI_LIBRARY_CONFIGURATION_ERROR_SETTINGS = '_dd.ci.library_configuration_error.settings'
168
+ const DD_CI_LIBRARY_CONFIGURATION_ERROR_SKIPPABLE_TESTS = '_dd.ci.library_configuration_error.skippable_tests'
169
+ const DD_CI_LIBRARY_CONFIGURATION_ERROR_KNOWN_TESTS = '_dd.ci.library_configuration_error.known_tests'
170
+ const DD_CI_LIBRARY_CONFIGURATION_ERROR_TEST_MANAGEMENT_TESTS =
171
+ '_dd.ci.library_configuration_error.test_management_tests'
168
172
 
169
173
  const UNSUPPORTED_TIA_FRAMEWORKS = new Set(['playwright', 'vitest'])
170
174
  const MINIMUM_FRAMEWORK_VERSION_FOR_EFD = {
@@ -230,10 +234,34 @@ const BASE_LIKE_BRANCH_FILTER = /^(main|master|preprod|prod|dev|development|trun
230
234
  */
231
235
  function getSessionRequestErrorTags (sessionSpan) {
232
236
  const tags = sessionSpan?.context()._tags
237
+ const sessionRequestErrorTags = {}
233
238
  if (!tags || typeof tags !== 'object') return {}
234
- if (tags[DD_CI_LIBRARY_CONFIGURATION_ERROR] === 'true') {
239
+ if (tags[DD_CI_LIBRARY_CONFIGURATION_ERROR_SETTINGS] === 'true') {
240
+ sessionRequestErrorTags[DD_CI_LIBRARY_CONFIGURATION_ERROR_SETTINGS] = 'true'
241
+ }
242
+ if (tags[DD_CI_LIBRARY_CONFIGURATION_ERROR_SKIPPABLE_TESTS] === 'true') {
243
+ sessionRequestErrorTags[DD_CI_LIBRARY_CONFIGURATION_ERROR_SKIPPABLE_TESTS] = 'true'
244
+ }
245
+ if (tags[DD_CI_LIBRARY_CONFIGURATION_ERROR_KNOWN_TESTS] === 'true') {
246
+ sessionRequestErrorTags[DD_CI_LIBRARY_CONFIGURATION_ERROR_KNOWN_TESTS] = 'true'
247
+ }
248
+ if (tags[DD_CI_LIBRARY_CONFIGURATION_ERROR_TEST_MANAGEMENT_TESTS] === 'true') {
249
+ sessionRequestErrorTags[DD_CI_LIBRARY_CONFIGURATION_ERROR_TEST_MANAGEMENT_TESTS] = 'true'
250
+ }
251
+ return sessionRequestErrorTags
252
+ }
253
+
254
+ /**
255
+ * Returns ITR skipping-enabled tags from a test session span for propagation to child events.
256
+ * @param {{ context: () => { _tags?: Record<string, string> } } | undefined} sessionSpan
257
+ * @returns {Record<string, string>}
258
+ */
259
+ function getSessionItrSkippingEnabledTags (sessionSpan) {
260
+ const tags = sessionSpan?.context()._tags
261
+ if (!tags || typeof tags !== 'object') return {}
262
+ if (tags[TEST_ITR_SKIPPING_ENABLED] !== undefined) {
235
263
  return {
236
- [DD_CI_LIBRARY_CONFIGURATION_ERROR]: 'true',
264
+ [TEST_ITR_SKIPPING_ENABLED]: tags[TEST_ITR_SKIPPING_ENABLED],
237
265
  }
238
266
  }
239
267
  return {}
@@ -350,7 +378,11 @@ module.exports = {
350
378
  TEST_MANAGEMENT_ATTEMPT_TO_FIX_PASSED,
351
379
  getLibraryCapabilitiesTags,
352
380
  getSessionRequestErrorTags,
353
- DD_CI_LIBRARY_CONFIGURATION_ERROR,
381
+ DD_CI_LIBRARY_CONFIGURATION_ERROR_SETTINGS,
382
+ DD_CI_LIBRARY_CONFIGURATION_ERROR_SKIPPABLE_TESTS,
383
+ DD_CI_LIBRARY_CONFIGURATION_ERROR_KNOWN_TESTS,
384
+ DD_CI_LIBRARY_CONFIGURATION_ERROR_TEST_MANAGEMENT_TESTS,
385
+ getSessionItrSkippingEnabledTags,
354
386
  checkShaDiscrepancies,
355
387
  getPullRequestDiff,
356
388
  getPullRequestBaseBranch,
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const { getValueFromEnvSources } = require('../../config/helper')
3
+ const getConfig = require('../../config')
4
4
  const {
5
5
  GIT_COMMIT_SHA,
6
6
  GIT_BRANCH,
@@ -46,20 +46,22 @@ function validateGitCommitSha (gitCommitSha) {
46
46
  }
47
47
 
48
48
  function getUserProviderGitMetadata () {
49
- const DD_GIT_COMMIT_SHA = getValueFromEnvSources('DD_GIT_COMMIT_SHA')
50
- const DD_GIT_BRANCH = getValueFromEnvSources('DD_GIT_BRANCH')
51
- const DD_GIT_REPOSITORY_URL = getValueFromEnvSources('DD_GIT_REPOSITORY_URL')
52
- const DD_GIT_TAG = getValueFromEnvSources('DD_GIT_TAG')
53
- const DD_GIT_COMMIT_MESSAGE = getValueFromEnvSources('DD_GIT_COMMIT_MESSAGE')
54
- const DD_GIT_COMMIT_COMMITTER_NAME = getValueFromEnvSources('DD_GIT_COMMIT_COMMITTER_NAME')
55
- const DD_GIT_COMMIT_COMMITTER_EMAIL = getValueFromEnvSources('DD_GIT_COMMIT_COMMITTER_EMAIL')
56
- const DD_GIT_COMMIT_COMMITTER_DATE = getValueFromEnvSources('DD_GIT_COMMIT_COMMITTER_DATE')
57
- const DD_GIT_COMMIT_AUTHOR_NAME = getValueFromEnvSources('DD_GIT_COMMIT_AUTHOR_NAME')
58
- const DD_GIT_COMMIT_AUTHOR_EMAIL = getValueFromEnvSources('DD_GIT_COMMIT_AUTHOR_EMAIL')
59
- const DD_GIT_COMMIT_AUTHOR_DATE = getValueFromEnvSources('DD_GIT_COMMIT_AUTHOR_DATE')
60
- const DD_GIT_PULL_REQUEST_BASE_BRANCH = getValueFromEnvSources('DD_GIT_PULL_REQUEST_BASE_BRANCH')
61
- const DD_GIT_PULL_REQUEST_BASE_BRANCH_SHA = getValueFromEnvSources('DD_GIT_PULL_REQUEST_BASE_BRANCH_SHA')
62
- const DD_GIT_COMMIT_HEAD_SHA = getValueFromEnvSources('DD_GIT_COMMIT_HEAD_SHA')
49
+ const {
50
+ DD_GIT_COMMIT_SHA,
51
+ DD_GIT_BRANCH,
52
+ DD_GIT_REPOSITORY_URL,
53
+ DD_GIT_TAG,
54
+ DD_GIT_COMMIT_MESSAGE,
55
+ DD_GIT_COMMIT_COMMITTER_NAME,
56
+ DD_GIT_COMMIT_COMMITTER_EMAIL,
57
+ DD_GIT_COMMIT_COMMITTER_DATE,
58
+ DD_GIT_COMMIT_AUTHOR_NAME,
59
+ DD_GIT_COMMIT_AUTHOR_EMAIL,
60
+ DD_GIT_COMMIT_AUTHOR_DATE,
61
+ DD_GIT_PULL_REQUEST_BASE_BRANCH,
62
+ DD_GIT_PULL_REQUEST_BASE_BRANCH_SHA,
63
+ DD_GIT_COMMIT_HEAD_SHA,
64
+ } = getConfig()
63
65
 
64
66
  const branch = normalizeRef(DD_GIT_BRANCH)
65
67
  let tag = normalizeRef(DD_GIT_TAG)
@@ -110,7 +110,7 @@ class PrioritySampler {
110
110
  * Assigns a sampling priority to a span if not already set.
111
111
  *
112
112
  * @param {DatadogSpan} span
113
- * @param {boolean} [auto=true] - Whether to use automatic sampling if no manual tags are present.
113
+ * @param {boolean} [auto] - Whether to use automatic sampling if no manual tags are present.
114
114
  * @returns {void}
115
115
  */
116
116
  sample (span, auto = true) {
@@ -260,7 +260,7 @@ class Profiler extends EventEmitter {
260
260
  this.#lastStart = start
261
261
  if (!this.#timer || timeout !== this._timeoutInterval) {
262
262
  this.#timer = setTimeout(() => this._collect(snapshotKinds.PERIODIC), timeout)
263
- this.#timer.unref()
263
+ this.#timer.unref?.()
264
264
  } else {
265
265
  this.#timer.refresh()
266
266
  }
@@ -223,7 +223,7 @@ class NativeWallProfiler {
223
223
  asyncContextsLiveGauge.mark(totalAsyncContextCount)
224
224
  asyncContextsUsedGauge.mark(usedAsyncContextCount)
225
225
  }, this.#telemetryHeartbeatIntervalMillis)
226
- this._contextCountGaugeUpdater.unref()
226
+ this._contextCountGaugeUpdater.unref?.()
227
227
  }
228
228
 
229
229
  #enter () {
@@ -39,7 +39,7 @@ class SSIHeuristics {
39
39
  setTimeout(() => {
40
40
  this.shortLived = false
41
41
  this._maybeTriggered()
42
- }, this.longLivedThreshold).unref()
42
+ }, this.longLivedThreshold).unref?.()
43
43
 
44
44
  this._onSpanCreated = this._onSpanCreated.bind(this)
45
45
  dc.subscribe('dd-trace:span:start', this._onSpanCreated)
@@ -5,7 +5,7 @@ const limiter = require('../../../vendor/dist/limiter')
5
5
  class RateLimiter {
6
6
  /**
7
7
  * @param {number} rateLimit - Allowed units per interval. Negative means unlimited, 0 disables.
8
- * @param {'second'|'minute'|'hour'|'day'} [interval='second'] - Time window for the limiter.
8
+ * @param {'second'|'minute'|'hour'|'day'} [interval] - Time window for the limiter.
9
9
  */
10
10
  constructor (rateLimit, interval = 'second') {
11
11
  // TODO: Change rateLimit to integers. Right now these are sometimes strings, sometimes numbers.
@@ -17,7 +17,7 @@ class Scheduler {
17
17
  runAfterDelay (interval = this._interval) {
18
18
  this._timer = setTimeout(this._callback, interval, () => this.runAfterDelay())
19
19
 
20
- this._timer.unref()
20
+ this._timer.unref?.()
21
21
  }
22
22
 
23
23
  stop () {
@@ -31,6 +31,7 @@ const builtinModules = new Set(Module.builtinModules.map(stripNodePrefix))
31
31
 
32
32
  function isBuiltinModuleName (name) {
33
33
  if (typeof name !== 'string') return false
34
+ if (name === 'electron') return true
34
35
  return builtinModules.has(stripNodePrefix(name))
35
36
  }
36
37
 
@@ -101,7 +102,7 @@ function Hook (modules, options, onrequire) {
101
102
  if (cache[moduleId]) {
102
103
  // require.cache was potentially altered externally
103
104
  const cacheEntry = require.cache[filename]
104
- if (cacheEntry && cacheEntry.exports !== cache[filename].original) {
105
+ if (cacheEntry && cacheEntry.exports !== cache[moduleId].original) {
105
106
  return cacheEntry.exports
106
107
  }
107
108