dd-trace 5.54.0 → 5.55.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 (178) hide show
  1. package/ci/cypress/plugin.js +8 -0
  2. package/ci/cypress/polyfills.js +23 -0
  3. package/ci/init.js +8 -7
  4. package/initialize.mjs +2 -2
  5. package/package.json +6 -6
  6. package/packages/datadog-code-origin/index.js +22 -4
  7. package/packages/datadog-core/src/utils/src/kebabcase.js +3 -3
  8. package/packages/datadog-instrumentations/src/cassandra-driver.js +5 -6
  9. package/packages/datadog-instrumentations/src/confluentinc-kafka-javascript.js +2 -3
  10. package/packages/datadog-instrumentations/src/cookie-parser.js +1 -1
  11. package/packages/datadog-instrumentations/src/couchbase.js +3 -6
  12. package/packages/datadog-instrumentations/src/cucumber.js +21 -28
  13. package/packages/datadog-instrumentations/src/dns.js +4 -4
  14. package/packages/datadog-instrumentations/src/elasticsearch.js +9 -10
  15. package/packages/datadog-instrumentations/src/fastify.js +7 -9
  16. package/packages/datadog-instrumentations/src/google-cloud-pubsub.js +14 -16
  17. package/packages/datadog-instrumentations/src/hapi.js +10 -11
  18. package/packages/datadog-instrumentations/src/helpers/fetch.js +4 -5
  19. package/packages/datadog-instrumentations/src/helpers/hook.js +1 -2
  20. package/packages/datadog-instrumentations/src/helpers/register.js +6 -5
  21. package/packages/datadog-instrumentations/src/jest.js +67 -98
  22. package/packages/datadog-instrumentations/src/koa.js +2 -3
  23. package/packages/datadog-instrumentations/src/mariadb.js +11 -4
  24. package/packages/datadog-instrumentations/src/mocha/main.js +79 -75
  25. package/packages/datadog-instrumentations/src/mocha.js +3 -1
  26. package/packages/datadog-instrumentations/src/mysql.js +11 -2
  27. package/packages/datadog-instrumentations/src/nyc.js +2 -1
  28. package/packages/datadog-instrumentations/src/openai.js +2 -2
  29. package/packages/datadog-instrumentations/src/otel-sdk-trace.js +4 -3
  30. package/packages/datadog-instrumentations/src/pg.js +2 -3
  31. package/packages/datadog-instrumentations/src/playwright.js +19 -22
  32. package/packages/datadog-instrumentations/src/protobufjs.js +3 -4
  33. package/packages/datadog-instrumentations/src/redis.js +1 -1
  34. package/packages/datadog-instrumentations/src/restify.js +9 -13
  35. package/packages/datadog-instrumentations/src/router.js +12 -11
  36. package/packages/datadog-instrumentations/src/tedious.js +1 -2
  37. package/packages/datadog-instrumentations/src/vitest.js +15 -29
  38. package/packages/datadog-plugin-avsc/src/schema_iterator.js +12 -12
  39. package/packages/datadog-plugin-aws-sdk/src/base.js +12 -8
  40. package/packages/datadog-plugin-aws-sdk/src/services/cloudwatchlogs.js +3 -5
  41. package/packages/datadog-plugin-aws-sdk/src/services/dynamodb.js +12 -20
  42. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +4 -5
  43. package/packages/datadog-plugin-aws-sdk/src/services/lambda.js +3 -5
  44. package/packages/datadog-plugin-aws-sdk/src/services/redshift.js +3 -5
  45. package/packages/datadog-plugin-aws-sdk/src/services/s3.js +3 -5
  46. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +1 -2
  47. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +7 -10
  48. package/packages/datadog-plugin-cucumber/src/index.js +3 -2
  49. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +2 -1
  50. package/packages/datadog-plugin-dd-trace-api/src/index.js +2 -1
  51. package/packages/datadog-plugin-elasticsearch/src/index.js +1 -1
  52. package/packages/datadog-plugin-google-cloud-vertexai/src/tracing.js +1 -1
  53. package/packages/datadog-plugin-graphql/src/index.js +3 -2
  54. package/packages/datadog-plugin-graphql/src/resolve.js +17 -10
  55. package/packages/datadog-plugin-http/src/client.js +5 -6
  56. package/packages/datadog-plugin-http2/src/client.js +7 -8
  57. package/packages/datadog-plugin-jest/src/index.js +3 -2
  58. package/packages/datadog-plugin-mocha/src/index.js +6 -1
  59. package/packages/datadog-plugin-mongodb-core/src/index.js +2 -1
  60. package/packages/datadog-plugin-mysql/src/index.js +11 -0
  61. package/packages/datadog-plugin-next/src/index.js +1 -1
  62. package/packages/datadog-plugin-openai/src/tracing.js +2 -4
  63. package/packages/datadog-plugin-playwright/src/index.js +3 -2
  64. package/packages/datadog-plugin-protobufjs/src/schema_iterator.js +8 -9
  65. package/packages/datadog-plugin-redis/src/index.js +1 -3
  66. package/packages/datadog-plugin-vitest/src/index.js +5 -4
  67. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +0 -1
  68. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-password-rules.js +0 -1
  69. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secret-rules.js +0 -1
  70. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secrets-rules.js +0 -1
  71. package/packages/dd-trace/src/appsec/iast/analyzers/missing-header-analyzer.js +1 -2
  72. package/packages/dd-trace/src/appsec/iast/security-controls/index.js +11 -12
  73. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +1 -1
  74. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +2 -1
  75. package/packages/dd-trace/src/appsec/iast/telemetry/span-tags.js +1 -1
  76. package/packages/dd-trace/src/appsec/iast/telemetry/verbosity.js +1 -2
  77. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/range-utils.js +10 -11
  78. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +0 -4
  79. package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +0 -1
  80. package/packages/dd-trace/src/appsec/index.js +4 -4
  81. package/packages/dd-trace/src/appsec/reporter.js +5 -7
  82. package/packages/dd-trace/src/appsec/sdk/set_user.js +2 -2
  83. package/packages/dd-trace/src/appsec/sdk/track_event.js +3 -3
  84. package/packages/dd-trace/src/appsec/telemetry/index.js +31 -1
  85. package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +6 -2
  86. package/packages/dd-trace/src/azure_metadata.js +8 -3
  87. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +8 -7
  88. package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +2 -1
  89. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +2 -1
  90. package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +2 -1
  91. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +2 -1
  92. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +4 -3
  93. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +7 -6
  94. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +2 -1
  95. package/packages/dd-trace/src/ci-visibility/log-submission/log-submission-plugin.js +4 -3
  96. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +4 -3
  97. package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +2 -1
  98. package/packages/dd-trace/src/config-helper.js +89 -0
  99. package/packages/dd-trace/src/config.js +77 -78
  100. package/packages/dd-trace/src/config_stable.js +7 -4
  101. package/packages/dd-trace/src/datastreams/fnv.js +1 -1
  102. package/packages/dd-trace/src/datastreams/schemas/schema_builder.js +6 -6
  103. package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +1 -2
  104. package/packages/dd-trace/src/debugger/devtools_client/condition.js +1 -2
  105. package/packages/dd-trace/src/debugger/devtools_client/index.js +2 -1
  106. package/packages/dd-trace/src/debugger/devtools_client/send.js +3 -2
  107. package/packages/dd-trace/src/debugger/devtools_client/snapshot/collector.js +1 -2
  108. package/packages/dd-trace/src/debugger/devtools_client/snapshot/processor.js +3 -4
  109. package/packages/dd-trace/src/debugger/devtools_client/snapshot/redaction.js +1 -1
  110. package/packages/dd-trace/src/debugger/index.js +1 -0
  111. package/packages/dd-trace/src/dogstatsd.js +2 -2
  112. package/packages/dd-trace/src/encode/0.4.js +5 -2
  113. package/packages/dd-trace/src/encode/0.5.js +3 -5
  114. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +5 -5
  115. package/packages/dd-trace/src/exporter.js +2 -1
  116. package/packages/dd-trace/src/exporters/common/docker.js +3 -2
  117. package/packages/dd-trace/src/exporters/common/request.js +4 -1
  118. package/packages/dd-trace/src/exporters/common/util.js +3 -1
  119. package/packages/dd-trace/src/id.js +3 -3
  120. package/packages/dd-trace/src/index.js +4 -3
  121. package/packages/dd-trace/src/lambda/handler.js +2 -1
  122. package/packages/dd-trace/src/lambda/index.js +2 -1
  123. package/packages/dd-trace/src/lambda/runtime/patch.js +3 -2
  124. package/packages/dd-trace/src/lambda/runtime/ritm.js +3 -2
  125. package/packages/dd-trace/src/llmobs/constants/tags.js +1 -0
  126. package/packages/dd-trace/src/llmobs/index.js +21 -5
  127. package/packages/dd-trace/src/llmobs/noop.js +18 -20
  128. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +11 -13
  129. package/packages/dd-trace/src/llmobs/plugins/openai.js +1 -2
  130. package/packages/dd-trace/src/llmobs/sdk.js +2 -1
  131. package/packages/dd-trace/src/llmobs/span_processor.js +1 -1
  132. package/packages/dd-trace/src/llmobs/tagger.js +19 -6
  133. package/packages/dd-trace/src/llmobs/writers/base.js +1 -1
  134. package/packages/dd-trace/src/log/index.js +5 -4
  135. package/packages/dd-trace/src/log/writer.js +1 -2
  136. package/packages/dd-trace/src/msgpack/encoder.js +3 -3
  137. package/packages/dd-trace/src/noop/span.js +1 -1
  138. package/packages/dd-trace/src/opentelemetry/tracer.js +1 -1
  139. package/packages/dd-trace/src/opentracing/propagation/log.js +4 -5
  140. package/packages/dd-trace/src/opentracing/propagation/text_map.js +17 -18
  141. package/packages/dd-trace/src/opentracing/span.js +7 -6
  142. package/packages/dd-trace/src/payload-tagging/config/index.js +17 -21
  143. package/packages/dd-trace/src/plugin_manager.js +4 -3
  144. package/packages/dd-trace/src/plugins/ci_plugin.js +25 -1
  145. package/packages/dd-trace/src/plugins/plugin.js +1 -1
  146. package/packages/dd-trace/src/plugins/util/ci.js +7 -7
  147. package/packages/dd-trace/src/plugins/util/git.js +1 -1
  148. package/packages/dd-trace/src/plugins/util/llm.js +2 -2
  149. package/packages/dd-trace/src/plugins/util/stacktrace.js +8 -1
  150. package/packages/dd-trace/src/plugins/util/test.js +4 -3
  151. package/packages/dd-trace/src/plugins/util/user-provided-git.js +2 -1
  152. package/packages/dd-trace/src/plugins/util/web.js +3 -4
  153. package/packages/dd-trace/src/priority_sampler.js +46 -35
  154. package/packages/dd-trace/src/profiling/config.js +12 -32
  155. package/packages/dd-trace/src/profiling/exporter_cli.js +20 -20
  156. package/packages/dd-trace/src/profiling/exporters/agent.js +1 -1
  157. package/packages/dd-trace/src/profiling/exporters/event_serializer.js +2 -1
  158. package/packages/dd-trace/src/profiling/index.js +2 -1
  159. package/packages/dd-trace/src/profiling/profiler.js +7 -4
  160. package/packages/dd-trace/src/profiling/ssi-telemetry-mock-profiler.js +3 -1
  161. package/packages/dd-trace/src/profiling/tagger.js +22 -12
  162. package/packages/dd-trace/src/proxy.js +2 -1
  163. package/packages/dd-trace/src/ritm.js +4 -4
  164. package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +3 -2
  165. package/packages/dd-trace/src/sampler.js +10 -2
  166. package/packages/dd-trace/src/serverless.js +11 -4
  167. package/packages/dd-trace/src/span_processor.js +2 -1
  168. package/packages/dd-trace/src/standalone/tracesource.js +1 -2
  169. package/packages/dd-trace/src/standalone/tracesource_priority_sampler.js +1 -2
  170. package/packages/dd-trace/src/startup-log.js +5 -17
  171. package/packages/dd-trace/src/supported-configurations.json +439 -0
  172. package/packages/dd-trace/src/telemetry/dependencies.js +62 -57
  173. package/packages/dd-trace/src/telemetry/send-data.js +7 -6
  174. package/packages/dd-trace/src/telemetry/telemetry.js +12 -25
  175. package/packages/dd-trace/src/tracer.js +3 -7
  176. package/packages/dd-trace/src/util.js +0 -5
  177. package/packages/dd-trace/src/appsec/iast/analyzers/header-injection-analyzer.js +0 -120
  178. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/header-sensitive-analyzer.js +0 -20
@@ -239,8 +239,8 @@ class TextMapPropagator {
239
239
 
240
240
  if (typeof origin === 'string') {
241
241
  const originValue = origin
242
- .replace(tracestateOriginFilter, '_')
243
- .replace(/[\x3D]/g, '~')
242
+ .replaceAll(tracestateOriginFilter, '_')
243
+ .replaceAll(/[\x3D]/g, '~')
244
244
 
245
245
  state.set('o', originValue)
246
246
  }
@@ -249,12 +249,12 @@ class TextMapPropagator {
249
249
  if (!tags[key] || !key.startsWith('_dd.p.')) continue
250
250
 
251
251
  const tagKey = 't.' + key.slice(6)
252
- .replace(tracestateTagKeyFilter, '_')
252
+ .replaceAll(tracestateTagKeyFilter, '_')
253
253
 
254
254
  const tagValue = tags[key]
255
255
  .toString()
256
- .replace(tracestateTagValueFilter, '_')
257
- .replace(/[\x3D]/g, '~')
256
+ .replaceAll(tracestateTagValueFilter, '_')
257
+ .replaceAll(/[\x3D]/g, '~')
258
258
 
259
259
  state.set(tagKey, tagValue)
260
260
  }
@@ -508,7 +508,7 @@ class TextMapPropagator {
508
508
  default: {
509
509
  if (!key.startsWith('t.')) continue
510
510
  const subKey = key.slice(2) // e.g. t.tid -> tid
511
- const transformedValue = value.replace(/[\x7E]/gm, '=')
511
+ const transformedValue = value.replaceAll(/[\x7E]/gm, '=')
512
512
 
513
513
  // If subkey is tid then do nothing because trace header tid should always be preserved
514
514
  if (subKey === 'tid') {
@@ -581,22 +581,21 @@ class TextMapPropagator {
581
581
  return {
582
582
  [b3SampledKey]: parts[0]
583
583
  }
584
- } else {
585
- const b3 = {
586
- [b3TraceKey]: parts[0],
587
- [b3SpanKey]: parts[1]
588
- }
584
+ }
585
+ const b3 = {
586
+ [b3TraceKey]: parts[0],
587
+ [b3SpanKey]: parts[1]
588
+ }
589
589
 
590
- if (parts[2]) {
591
- b3[b3SampledKey] = parts[2] === '0' ? '0' : '1'
590
+ if (parts[2]) {
591
+ b3[b3SampledKey] = parts[2] === '0' ? '0' : '1'
592
592
 
593
- if (parts[2] === 'd') {
594
- b3[b3FlagsKey] = '1'
595
- }
593
+ if (parts[2] === 'd') {
594
+ b3[b3FlagsKey] = '1'
596
595
  }
597
-
598
- return b3
599
596
  }
597
+
598
+ return b3
600
599
  }
601
600
 
602
601
  _extractOrigin (carrier, spanContext) {
@@ -13,18 +13,17 @@ const { storage } = require('../../../datadog-core')
13
13
  const telemetryMetrics = require('../telemetry/metrics')
14
14
  const { channel } = require('dc-polyfill')
15
15
  const util = require('util')
16
+ const { getEnvironmentVariable } = require('../config-helper')
16
17
 
17
18
  const tracerMetrics = telemetryMetrics.manager.namespace('tracers')
18
19
 
19
- const {
20
- DD_TRACE_EXPERIMENTAL_STATE_TRACKING,
21
- DD_TRACE_EXPERIMENTAL_SPAN_COUNTS
22
- } = process.env
20
+ const DD_TRACE_EXPERIMENTAL_STATE_TRACKING = getEnvironmentVariable('DD_TRACE_EXPERIMENTAL_STATE_TRACKING')
21
+ const DD_TRACE_EXPERIMENTAL_SPAN_COUNTS = getEnvironmentVariable('DD_TRACE_EXPERIMENTAL_SPAN_COUNTS')
23
22
 
24
23
  const unfinishedRegistry = createRegistry('unfinished')
25
24
  const finishedRegistry = createRegistry('finished')
26
25
 
27
- const OTEL_ENABLED = !!process.env.DD_TRACE_OTEL_ENABLED
26
+ const OTEL_ENABLED = !!getEnvironmentVariable('DD_TRACE_OTEL_ENABLED')
28
27
  const ALLOWED = new Set(['string', 'number', 'boolean'])
29
28
 
30
29
  const integrationCounters = {
@@ -56,6 +55,8 @@ class DatadogSpan {
56
55
  constructor (tracer, processor, prioritySampler, fields, debug) {
57
56
  const operationName = fields.operationName
58
57
  const parent = fields.parent || null
58
+ // TODO(BridgeAR): Investigate why this is causing a performance regression
59
+ // eslint-disable-next-line prefer-object-spread
59
60
  const tags = Object.assign({}, fields.tags)
60
61
  const hostname = fields.hostname
61
62
 
@@ -333,7 +334,7 @@ class DatadogSpan {
333
334
  spanId: id(),
334
335
  parentId: parent._spanId,
335
336
  sampling: parent._sampling,
336
- baggageItems: Object.assign({}, parent._baggageItems),
337
+ baggageItems: { ...parent._baggageItems },
337
338
  trace: parent._trace,
338
339
  tracestate: parent._tracestate
339
340
  })
@@ -2,29 +2,25 @@ const aws = require('./aws.json')
2
2
  const sdks = { aws }
3
3
 
4
4
  function getSDKRules (sdk, requestInput, responseInput) {
5
- return Object.fromEntries(
6
- Object.entries(sdk).map(([service, serviceRules]) => {
7
- return [
8
- service,
9
- {
10
- request: serviceRules.request.concat(requestInput || []),
11
- response: serviceRules.response.concat(responseInput || []),
12
- expand: serviceRules.expand || []
13
- }
14
- ]
15
- })
16
- )
5
+ const sdkServiceRules = {}
6
+ for (const [service, serviceRules] of Object.entries(sdk)) {
7
+ sdkServiceRules[service] = {
8
+ // Make a copy. Otherwise calling the function multiple times would append
9
+ // the rules to the same object.
10
+ request: [...serviceRules.request, ...requestInput],
11
+ response: [...serviceRules.response, ...responseInput],
12
+ expand: serviceRules.expand
13
+ }
14
+ }
15
+ return sdkServiceRules
17
16
  }
18
17
 
19
- function appendRules (requestInput, responseInput) {
20
- return Object.fromEntries(
21
- Object.entries(sdks).map(([name, sdk]) => {
22
- return [
23
- name,
24
- getSDKRules(sdk, requestInput, responseInput)
25
- ]
26
- })
27
- )
18
+ function appendRules (requestInput = [], responseInput = []) {
19
+ const sdkRules = {}
20
+ for (const [name, sdk] of Object.entries(sdks)) {
21
+ sdkRules[name] = getSDKRules(sdk, requestInput, responseInput)
22
+ }
23
+ return sdkRules
28
24
  }
29
25
 
30
26
  module.exports = { appendRules }
@@ -4,17 +4,18 @@ const { channel } = require('dc-polyfill')
4
4
  const { isFalse } = require('./util')
5
5
  const plugins = require('./plugins')
6
6
  const log = require('./log')
7
+ const { getEnvironmentVariable } = require('../../dd-trace/src/config-helper')
7
8
 
8
9
  const loadChannel = channel('dd-trace:instrumentation:load')
9
10
 
10
11
  // instrument everything that needs Plugin System V2 instrumentation
11
12
  require('../../datadog-instrumentations')
12
- if (process.env.AWS_LAMBDA_FUNCTION_NAME !== undefined) {
13
+ if (getEnvironmentVariable('AWS_LAMBDA_FUNCTION_NAME') !== undefined) {
13
14
  // instrument lambda environment
14
15
  require('./lambda')
15
16
  }
16
17
 
17
- const { DD_TRACE_DISABLED_PLUGINS } = process.env
18
+ const DD_TRACE_DISABLED_PLUGINS = getEnvironmentVariable('DD_TRACE_DISABLED_PLUGINS')
18
19
 
19
20
  const disabledPlugins = new Set(
20
21
  DD_TRACE_DISABLED_PLUGINS && DD_TRACE_DISABLED_PLUGINS.split(',').map(plugin => plugin.trim())
@@ -32,7 +33,7 @@ function maybeEnable (Plugin) {
32
33
  if (!Plugin || typeof Plugin !== 'function') return
33
34
  if (!pluginClasses[Plugin.id]) {
34
35
  const envName = `DD_TRACE_${Plugin.id.toUpperCase()}_ENABLED`
35
- const enabled = process.env[envName.replace(/[^a-z0-9_]/ig, '_')]
36
+ const enabled = getEnvironmentVariable(envName.replaceAll(/[^a-z0-9_]/ig, '_'))
36
37
 
37
38
  // TODO: remove the need to load the plugin class in order to disable the plugin
38
39
  if (isFalse(enabled) || disabledPlugins.has(Plugin.id)) {
@@ -1,3 +1,4 @@
1
+ const { storage } = require('../../../datadog-core')
1
2
  const {
2
3
  getTestEnvironmentMetadata,
3
4
  getTestSessionName,
@@ -73,7 +74,10 @@ module.exports = class CiPlugin extends Plugin {
73
74
  this.fileLineToProbeId = new Map()
74
75
  this.rootDir = process.cwd() // fallback in case :session:start events are not emitted
75
76
 
76
- this.addSub(`ci:${this.constructor.id}:library-configuration`, ({ onDone, isParallel }) => {
77
+ this.addSub(`ci:${this.constructor.id}:library-configuration`, (ctx) => {
78
+ const { onDone, isParallel } = ctx
79
+ ctx.currentStore = storage('legacy').getStore()
80
+
77
81
  if (!this.tracer._exporter || !this.tracer._exporter.getLibraryConfiguration) {
78
82
  return onDone({ err: new Error('Test optimization was not initialized correctly') })
79
83
  }
@@ -95,6 +99,10 @@ module.exports = class CiPlugin extends Plugin {
95
99
  })
96
100
  })
97
101
 
102
+ this.addBind(`ci:${this.constructor.id}:test-suite:skippable`, (ctx) => {
103
+ return ctx.currentStore
104
+ })
105
+
98
106
  this.addSub(`ci:${this.constructor.id}:test-suite:skippable`, ({ onDone }) => {
99
107
  if (!this.tracer._exporter?.getSkippableSuites) {
100
108
  return onDone({ err: new Error('Test optimization was not initialized correctly') })
@@ -158,8 +166,12 @@ module.exports = class CiPlugin extends Plugin {
158
166
  // only for vitest
159
167
  // These are added for the worker threads to use
160
168
  if (this.constructor.id === 'vitest') {
169
+ // TODO: Figure out alternative ways to pass this information to the worker threads
170
+ // eslint-disable-next-line eslint-rules/eslint-process-env
161
171
  process.env.DD_CIVISIBILITY_TEST_SESSION_ID = this.testSessionSpan.context().toTraceId()
172
+ // eslint-disable-next-line eslint-rules/eslint-process-env
162
173
  process.env.DD_CIVISIBILITY_TEST_MODULE_ID = this.testModuleSpan.context().toSpanId()
174
+ // eslint-disable-next-line eslint-rules/eslint-process-env
163
175
  process.env.DD_CIVISIBILITY_TEST_COMMAND = this.command
164
176
  }
165
177
 
@@ -188,6 +200,10 @@ module.exports = class CiPlugin extends Plugin {
188
200
  this.telemetry.count(TELEMETRY_ITR_SKIPPED, { testLevel: 'suite' }, skippedSuites.length)
189
201
  })
190
202
 
203
+ this.addBind(`ci:${this.constructor.id}:known-tests`, (ctx) => {
204
+ return ctx.currentStore
205
+ })
206
+
191
207
  this.addSub(`ci:${this.constructor.id}:known-tests`, ({ onDone }) => {
192
208
  if (!this.tracer._exporter?.getKnownTests) {
193
209
  return onDone({ err: new Error('Test optimization was not initialized correctly') })
@@ -202,6 +218,10 @@ module.exports = class CiPlugin extends Plugin {
202
218
  })
203
219
  })
204
220
 
221
+ this.addBind(`ci:${this.constructor.id}:test-management-tests`, (ctx) => {
222
+ return ctx.currentStore
223
+ })
224
+
205
225
  this.addSub(`ci:${this.constructor.id}:test-management-tests`, ({ onDone }) => {
206
226
  if (!this.tracer._exporter?.getTestManagementTests) {
207
227
  return onDone({ err: new Error('Test optimization was not initialized correctly') })
@@ -215,6 +235,10 @@ module.exports = class CiPlugin extends Plugin {
215
235
  })
216
236
  })
217
237
 
238
+ this.addBind(`ci:${this.constructor.id}:modified-tests`, (ctx) => {
239
+ return ctx.currentStore
240
+ })
241
+
218
242
  this.addSub(`ci:${this.constructor.id}:modified-tests`, ({ onDone }) => {
219
243
  const {
220
244
  [GIT_PULL_REQUEST_BASE_BRANCH]: pullRequestBaseBranch,
@@ -34,7 +34,7 @@ class StoreBinding {
34
34
  this._transform = data => {
35
35
  const store = storage('legacy').getStore()
36
36
 
37
- return !store || !store.noop || data?.currentStore
37
+ return !store || !store.noop || (data && Object.hasOwn(data, 'currentStore'))
38
38
  ? transform(data)
39
39
  : store
40
40
  }
@@ -27,6 +27,7 @@ const {
27
27
  CI_NODE_NAME
28
28
  } = require('./tags')
29
29
  const { filterSensitiveInfoFromRepository } = require('./url')
30
+ const { getEnvironmentVariable } = require('../../config-helper')
30
31
 
31
32
  // Receives a string with the form 'John Doe <john.doe@gmail.com>'
32
33
  // and returns { name: 'John Doe', email: 'john.doe@gmail.com' }
@@ -67,7 +68,7 @@ function normalizeRef (ref) {
67
68
  if (!ref) {
68
69
  return ref
69
70
  }
70
- return ref.replace(/origin\/|refs\/heads\/|tags\//gm, '')
71
+ return ref.replaceAll(/origin\/|refs\/heads\/|tags\//gm, '')
71
72
  }
72
73
 
73
74
  function resolveTilde (filePath) {
@@ -76,16 +77,16 @@ function resolveTilde (filePath) {
76
77
  }
77
78
  // '~/folder/path' or '~'
78
79
  if (filePath[0] === '~' && (filePath[1] === '/' || filePath.length === 1)) {
79
- return filePath.replace('~', process.env.HOME)
80
+ return filePath.replace('~', getEnvironmentVariable('HOME'))
80
81
  }
81
82
  return filePath
82
83
  }
83
84
 
84
85
  function getGitHubEventPayload () {
85
- if (!process.env.GITHUB_EVENT_PATH) {
86
+ if (!getEnvironmentVariable('GITHUB_EVENT_PATH')) {
86
87
  return
87
88
  }
88
- return JSON.parse(readFileSync(process.env.GITHUB_EVENT_PATH, 'utf8'))
89
+ return JSON.parse(readFileSync(getEnvironmentVariable('GITHUB_EVENT_PATH'), 'utf8'))
89
90
  }
90
91
 
91
92
  module.exports = {
@@ -139,11 +140,10 @@ module.exports = {
139
140
 
140
141
  tags[refKey] = ref
141
142
 
142
- let finalPipelineName = ''
143
143
  if (JOB_NAME) {
144
144
  // Job names can contain parameters, e.g. jobName/KEY1=VALUE1,KEY2=VALUE2/branchName
145
145
  const jobNameAndParams = JOB_NAME.split('/')
146
- finalPipelineName = jobNameAndParams.length > 1 && jobNameAndParams[1].includes('=')
146
+ const finalPipelineName = jobNameAndParams.length > 1 && jobNameAndParams[1].includes('=')
147
147
  ? jobNameAndParams[0]
148
148
  : JOB_NAME.replace(`/${ref}`, '')
149
149
  tags[CI_PIPELINE_NAME] = finalPipelineName
@@ -432,7 +432,7 @@ module.exports = {
432
432
  [GIT_TAG]: BITBUCKET_TAG,
433
433
  [GIT_REPOSITORY_URL]: BITBUCKET_GIT_SSH_ORIGIN || BITBUCKET_GIT_HTTP_ORIGIN,
434
434
  [CI_WORKSPACE_PATH]: BITBUCKET_CLONE_DIR,
435
- [CI_PIPELINE_ID]: BITBUCKET_PIPELINE_UUID && BITBUCKET_PIPELINE_UUID.replace(/{|}/gm, ''),
435
+ [CI_PIPELINE_ID]: BITBUCKET_PIPELINE_UUID && BITBUCKET_PIPELINE_UUID.replaceAll(/{|}/gm, ''),
436
436
  [GIT_PULL_REQUEST_BASE_BRANCH]: BITBUCKET_PR_DESTINATION_BRANCH
437
437
  }
438
438
  }
@@ -51,7 +51,7 @@ function sanitizedExec (
51
51
  try {
52
52
  let result = cp.execFileSync(cmd, flags, { stdio: 'pipe' }).toString()
53
53
  if (shouldTrim) {
54
- result = result.replace(/(\r\n|\n|\r)/gm, '')
54
+ result = result.replaceAll(/(\r\n|\n|\r)/gm, '')
55
55
  }
56
56
  if (durationMetric) {
57
57
  distributionMetric(durationMetric.name, durationMetric.tags, Date.now() - startTime)
@@ -11,8 +11,8 @@ function normalize (text, limit = 128) {
11
11
  }
12
12
 
13
13
  text = text
14
- .replace(RE_NEWLINE, String.raw`\n`)
15
- .replace(RE_TAB, String.raw`\t`)
14
+ .replaceAll(RE_NEWLINE, String.raw`\n`)
15
+ .replaceAll(RE_TAB, String.raw`\t`)
16
16
 
17
17
  // In case the replace above matched, more characters were added that must now be considered.
18
18
  if (text.length > limit) {
@@ -34,7 +34,14 @@ function getCallSites (constructorOpt) {
34
34
  *
35
35
  * @param {Function} constructorOpt - Function to pass along to Error.captureStackTrace
36
36
  * @param {number} [limit=Infinity] - The maximum number of frames to return
37
- * @returns {{ file: string, line: number, method: (string|undefined), type: (string|undefined) }[]} - A
37
+ * @returns {StackFrame[]} - A list of stack frames from user-land code
38
+ *
39
+ * @typedef {Object} StackFrame
40
+ * @property {string} file - The file path of the frame
41
+ * @property {number} line - The line number in the file
42
+ * @property {number} column - The column number in the file
43
+ * @property {string} [method] - The function name, if available
44
+ * @property {string} [type] - The type name, if available
38
45
  */
39
46
  function getUserLandFrames (constructorOpt, limit = Infinity) {
40
47
  const callsites = getCallSites(constructorOpt)
@@ -2,6 +2,7 @@ const path = require('path')
2
2
  const fs = require('fs')
3
3
  const { URL } = require('url')
4
4
  const log = require('../../log')
5
+ const { getEnvironmentVariable } = require('../../config-helper')
5
6
 
6
7
  const istanbul = require('istanbul-lib-coverage')
7
8
  const ignore = require('ignore')
@@ -284,7 +285,7 @@ module.exports = {
284
285
  // Returns pkg manager and its version, separated by '-', e.g. npm-8.15.0 or yarn-1.22.19
285
286
  function getPkgManager () {
286
287
  try {
287
- return process.env.npm_config_user_agent.split(' ')[0].replace('/', '-')
288
+ return getEnvironmentVariable('npm_config_user_agent').split(' ')[0].replace('/', '-')
288
289
  } catch {
289
290
  return ''
290
291
  }
@@ -789,11 +790,11 @@ function addAttemptToFixStringToTestName (testName, numAttempt) {
789
790
  }
790
791
 
791
792
  function removeEfdStringFromTestName (testName) {
792
- return testName.replace(EFD_TEST_NAME_REGEX, '')
793
+ return testName.replaceAll(EFD_TEST_NAME_REGEX, '')
793
794
  }
794
795
 
795
796
  function removeAttemptToFixStringFromTestName (testName) {
796
- return testName.replace(ATTEMPT_TEST_NAME_REGEX, '')
797
+ return testName.replaceAll(ATTEMPT_TEST_NAME_REGEX, '')
797
798
  }
798
799
 
799
800
  function getIsFaultyEarlyFlakeDetection (projectSuites, testsBySuiteName, faultyThresholdPercentage) {
@@ -17,6 +17,7 @@ const {
17
17
 
18
18
  const { normalizeRef } = require('./ci')
19
19
  const { filterSensitiveInfoFromRepository } = require('./url')
20
+ const { getEnvironmentVariables } = require('../../config-helper')
20
21
 
21
22
  function removeEmptyValues (tags) {
22
23
  return Object.keys(tags).reduce((filteredTags, tag) => {
@@ -59,7 +60,7 @@ function getUserProviderGitMetadata () {
59
60
  DD_GIT_PULL_REQUEST_BASE_BRANCH,
60
61
  DD_GIT_PULL_REQUEST_BASE_BRANCH_SHA,
61
62
  DD_GIT_COMMIT_HEAD_SHA
62
- } = process.env
63
+ } = getEnvironmentVariables()
63
64
 
64
65
  const branch = normalizeRef(DD_GIT_BRANCH)
65
66
  let tag = normalizeRef(DD_GIT_TAG)
@@ -421,7 +421,7 @@ function addAllowHeaders (req, res, headers) {
421
421
  ]
422
422
 
423
423
  for (const header of contextHeaders) {
424
- if (~requestHeaders.indexOf(header)) {
424
+ if (requestHeaders.includes(header)) {
425
425
  allowHeaders.push(header)
426
426
  }
427
427
  }
@@ -530,10 +530,9 @@ function extractURL (req) {
530
530
 
531
531
  if (req.stream) {
532
532
  return `${headers[HTTP2_HEADER_SCHEME]}://${headers[HTTP2_HEADER_AUTHORITY]}${headers[HTTP2_HEADER_PATH]}`
533
- } else {
534
- const protocol = getProtocol(req)
535
- return `${protocol}://${req.headers.host}${req.originalUrl || req.url}`
536
533
  }
534
+ const protocol = getProtocol(req)
535
+ return `${protocol}://${req.headers.host}${req.originalUrl || req.url}`
537
536
  }
538
537
 
539
538
  function getProtocol (req) {
@@ -5,7 +5,6 @@ const RateLimiter = require('./rate_limiter')
5
5
  const Sampler = require('./sampler')
6
6
  const { setSamplingRules } = require('./startup-log')
7
7
  const SamplingRule = require('./sampling_rule')
8
- const { hasOwn } = require('./util')
9
8
 
10
9
  const {
11
10
  SAMPLING_MECHANISM_DEFAULT,
@@ -40,16 +39,28 @@ const DEFAULT_KEY = 'service:,env:'
40
39
  const defaultSampler = new Sampler(AUTO_KEEP)
41
40
 
42
41
  /**
43
- * from config.js
44
- * @typedef { sampleRate: number, provenance: string, rateLimit: number, rules: SamplingRule[] } SamplingConfig
42
+ * PrioritySampler is responsible for determining whether a span should be sampled
43
+ * based on various rules, rate limits, and priorities. It supports manual and
44
+ * automatic sampling mechanisms and integrates with Datadog's tracing system.
45
45
  *
46
- * empirically defined
47
- * @typedef {2|-1|1|0} SamplingPriority
46
+ * @class PrioritySampler
47
+ * @typedef {import('./opentracing/span')} DatadogSpan
48
+ * @typedef {import('./opentracing/span_context')} DatadogSpanContext
49
+ * @typedef {import('./standalone/product')} PRODUCTS
50
+ * @typedef {2|-1|1|0} SamplingPriority Empirically defined sampling priorities.
48
51
  */
49
52
  class PrioritySampler {
50
53
  /**
51
- * @param env {string}
52
- * @param config {SamplingConfig}
54
+ * Creates an instance of PrioritySampler.
55
+ *
56
+ * @typedef {Object} SamplingConfig
57
+ * @property {number} [sampleRate] - The default sample rate for traces.
58
+ * @property {string} [provenance] - The provenance of the sampling rule (e.g., "customer", "dynamic").
59
+ * @property {number} [rateLimit=100] - The maximum number of traces to sample per second.
60
+ * @property {Array<SamplingRule>} [rules=[]] - An array of sampling rules to apply.
61
+ *
62
+ * @param {string} env - The environment name (e.g., "production", "staging").
63
+ * @param {SamplingConfig} config - The configuration object for sampling.
53
64
  */
54
65
  constructor (env, config) {
55
66
  this.configure(env, config)
@@ -62,9 +73,9 @@ class PrioritySampler {
62
73
  * @param opts {SamplingConfig}
63
74
  */
64
75
  configure (env, opts = {}) {
65
- const { sampleRate, provenance, rateLimit = 100, rules = [] } = opts
76
+ const { sampleRate, provenance, rateLimit = 100, rules } = opts
66
77
  this._env = env
67
- this._rules = this.#normalizeRules(rules, sampleRate, rateLimit, provenance)
78
+ this._rules = this.#normalizeRules(rules || [], sampleRate, rateLimit, provenance)
68
79
  this._limiter = new RateLimiter(rateLimit)
69
80
 
70
81
  log.trace(env, opts)
@@ -154,7 +165,7 @@ class PrioritySampler {
154
165
  *
155
166
  * @param span {DatadogSpan}
156
167
  * @param samplingPriority {SamplingPriority}
157
- * @param product {import('./standalone/product').PRODUCTS}
168
+ * @param product {import('./standalone/product')}
158
169
  */
159
170
  setPriority (span, samplingPriority, product) {
160
171
  if (!span || !this.validate(samplingPriority)) return
@@ -208,18 +219,17 @@ class PrioritySampler {
208
219
  * @returns {SamplingPriority}
209
220
  */
210
221
  _getPriorityFromTags (tags, _context) {
211
- if (hasOwn(tags, MANUAL_KEEP) && tags[MANUAL_KEEP] !== false) {
222
+ if (Object.hasOwn(tags, MANUAL_KEEP) && tags[MANUAL_KEEP] !== false) {
212
223
  return USER_KEEP
213
- } else if (hasOwn(tags, MANUAL_DROP) && tags[MANUAL_DROP] !== false) {
224
+ } else if (Object.hasOwn(tags, MANUAL_DROP) && tags[MANUAL_DROP] !== false) {
214
225
  return USER_REJECT
215
- } else {
216
- const priority = Number.parseInt(tags[SAMPLING_PRIORITY], 10)
226
+ }
227
+ const priority = Number.parseInt(tags[SAMPLING_PRIORITY], 10)
217
228
 
218
- if (priority === 1 || priority === 2) {
219
- return USER_KEEP
220
- } else if (priority === 0 || priority === -1) {
221
- return USER_REJECT
222
- }
229
+ if (priority === 1 || priority === 2) {
230
+ return USER_KEEP
231
+ } else if (priority === 0 || priority === -1) {
232
+ return USER_REJECT
223
233
  }
224
234
  }
225
235
 
@@ -258,7 +268,6 @@ class PrioritySampler {
258
268
  *
259
269
  * @param context {DatadogSpanContext}
260
270
  * @returns {SamplingPriority}
261
- * @private
262
271
  */
263
272
  #getPriorityByAgent (context) {
264
273
  const key = `service:${context._tags[SERVICE_NAME]},env:${this._env}`
@@ -274,7 +283,6 @@ class PrioritySampler {
274
283
  /**
275
284
  *
276
285
  * @param span {DatadogSpan}
277
- * @private
278
286
  * @returns {void}
279
287
  */
280
288
  #addDecisionMaker (span) {
@@ -293,30 +301,33 @@ class PrioritySampler {
293
301
  }
294
302
 
295
303
  /**
296
- *
297
- * @param rules {SamplingRule[]}
298
- * @param sampleRate {number}
299
- * @param rateLimit {number}
300
- * @param provenance {string}
304
+ * @param {Record<string, unknown>[] | Record<string, unknown>} rules - The sampling rules to normalize.
305
+ * @param {number} sampleRate
306
+ * @param {number} rateLimit
307
+ * @param {string} provenance
301
308
  * @returns {SamplingRule[]}
302
- * @private
303
309
  */
304
310
  #normalizeRules (rules, sampleRate, rateLimit, provenance) {
305
- rules = [].concat(rules || [])
311
+ rules = Array.isArray(rules) ? rules.flat() : [rules]
306
312
 
307
313
  rules.push({ sampleRate, maxPerSecond: rateLimit, provenance })
308
314
 
309
- return rules
310
- .map(rule => ({ ...rule, sampleRate: Number.parseFloat(rule.sampleRate) }))
311
- .filter(rule => !Number.isNaN(rule.sampleRate))
312
- .map(SamplingRule.from)
315
+ const result = []
316
+ for (const rule of rules) {
317
+ const sampleRate = Number.parseFloat(rule.sampleRate)
318
+ // TODO(BridgeAR): Debug logging invalid rules fails our tests.
319
+ // Should we definitely not know about these?
320
+ if (!Number.isNaN(sampleRate)) {
321
+ result.push(SamplingRule.from({ ...rule, sampleRate }))
322
+ }
323
+ }
324
+ return result
313
325
  }
314
326
 
315
327
  /**
316
328
  *
317
329
  * @param span {DatadogSpan}
318
- * @returns {SamplingRule}
319
- * @private
330
+ * @returns {SamplingRule|undefined}
320
331
  */
321
332
  #findRule (span) {
322
333
  for (const rule of this._rules) {
@@ -330,7 +341,7 @@ class PrioritySampler {
330
341
  /**
331
342
  *
332
343
  * @param span {DatadogSpan}
333
- * @param product {import('./standalone/product').PRODUCTS}
344
+ * @param product {import('./standalone/product')}
334
345
  */
335
346
  static keepTrace (span, product) {
336
347
  span?._prioritySampler?.setPriority(span, USER_KEEP, product)