dd-trace 6.7.0 → 6.8.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 (147) hide show
  1. package/ci/test-optimization-validation/command-output-policy.js +5 -5
  2. package/ci/test-optimization-validation/framework-adapters/playwright.js +5 -5
  3. package/ci/test-optimization-validation/generated-files.js +9 -9
  4. package/ci/test-optimization-validation/generated-test-contract.js +1 -3
  5. package/ci/test-optimization-validation/manifest-scaffold.js +1 -2
  6. package/ci/test-optimization-validation/offline-output.js +6 -6
  7. package/ci/test-optimization-validation/runner-command.js +1 -1
  8. package/ci/test-optimization-validation/safe-files.js +4 -4
  9. package/ci/test-optimization-validation/scenarios/basic-reporting.js +1 -1
  10. package/ci/test-optimization-validation/scenarios/test-management.js +2 -2
  11. package/ci/vitest-no-worker-init-setup.mjs +348 -51
  12. package/index.d.ts +77 -13
  13. package/package.json +9 -3
  14. package/packages/datadog-core/src/utils/src/kebabcase.js +8 -2
  15. package/packages/datadog-esbuild/index.js +4 -2
  16. package/packages/datadog-esbuild/src/utils.js +1 -1
  17. package/packages/datadog-instrumentations/src/claude-agent-sdk.js +4 -4
  18. package/packages/datadog-instrumentations/src/cucumber.js +9 -6
  19. package/packages/datadog-instrumentations/src/helpers/extract-package-and-module-path.js +10 -0
  20. package/packages/datadog-instrumentations/src/helpers/hook.js +19 -2
  21. package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
  22. package/packages/datadog-instrumentations/src/helpers/register.js +9 -3
  23. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +1 -0
  24. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
  25. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +57 -0
  26. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +50 -18
  27. package/packages/datadog-instrumentations/src/helpers/router-helper.js +1 -1
  28. package/packages/datadog-instrumentations/src/helpers/shared-utils.js +39 -0
  29. package/packages/datadog-instrumentations/src/http/client.js +1 -3
  30. package/packages/datadog-instrumentations/src/jest.js +8 -14
  31. package/packages/datadog-instrumentations/src/mocha/common.js +1 -3
  32. package/packages/datadog-instrumentations/src/mocha/main.js +2 -42
  33. package/packages/datadog-instrumentations/src/mocha/utils.js +68 -2
  34. package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +19 -0
  35. package/packages/datadog-instrumentations/src/mocha/worker.js +446 -42
  36. package/packages/datadog-instrumentations/src/moleculer/client.js +1 -1
  37. package/packages/datadog-instrumentations/src/playwright.js +3 -2
  38. package/packages/datadog-instrumentations/src/rhea.js +1 -1
  39. package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +525 -56
  40. package/packages/datadog-instrumentations/src/vitest-main.js +90 -10
  41. package/packages/datadog-instrumentations/src/webdriverio.js +914 -0
  42. package/packages/datadog-plugin-aerospike/src/index.js +1 -3
  43. package/packages/datadog-plugin-amqplib/src/client.js +1 -1
  44. package/packages/datadog-plugin-amqplib/src/producer.js +1 -1
  45. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +2 -2
  46. package/packages/datadog-plugin-aws-sdk/src/services/stepfunctions.js +2 -2
  47. package/packages/datadog-plugin-azure-event-hubs/src/producer.js +1 -3
  48. package/packages/datadog-plugin-azure-service-bus/src/producer.js +5 -3
  49. package/packages/datadog-plugin-bullmq/src/producer.js +3 -3
  50. package/packages/datadog-plugin-child_process/src/index.js +3 -3
  51. package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +5 -8
  52. package/packages/datadog-plugin-cypress/src/source-map-utils.js +1 -1
  53. package/packages/datadog-plugin-fastify/src/tracing.js +1 -1
  54. package/packages/datadog-plugin-fs/src/index.js +0 -4
  55. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +14 -7
  56. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +19 -10
  57. package/packages/datadog-plugin-graphql/src/execute.js +1 -0
  58. package/packages/datadog-plugin-graphql/src/tools/signature.js +1 -1
  59. package/packages/datadog-plugin-http/src/client.js +2 -1
  60. package/packages/datadog-plugin-jest/src/index.js +2 -3
  61. package/packages/datadog-plugin-jest/src/util.js +2 -1
  62. package/packages/datadog-plugin-langchain/src/tokens.js +2 -2
  63. package/packages/datadog-plugin-mocha/src/index.js +25 -6
  64. package/packages/datadog-plugin-prisma/src/index.js +5 -1
  65. package/packages/datadog-plugin-rhea/src/consumer.js +16 -13
  66. package/packages/datadog-plugin-rhea/src/producer.js +1 -1
  67. package/packages/datadog-plugin-undici/src/index.js +2 -1
  68. package/packages/datadog-plugin-vitest/src/index.js +84 -11
  69. package/packages/datadog-webpack/index.js +2 -2
  70. package/packages/dd-trace/src/appsec/downstream_requests.js +1 -1
  71. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-base-analyzer.js +1 -1
  72. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-password-analyzer.js +1 -1
  73. package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +1 -1
  74. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +1 -3
  75. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +1 -1
  76. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +2 -2
  77. package/packages/dd-trace/src/appsec/sdk/track_event.js +1 -1
  78. package/packages/dd-trace/src/appsec/waf/waf_manager.js +1 -1
  79. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/sink.js +7 -6
  80. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +2 -2
  81. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +2 -1
  82. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +4 -0
  83. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/webdriverio.js +26 -0
  84. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +9 -1
  85. package/packages/dd-trace/src/ci-visibility/requests/request.js +3 -3
  86. package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +1 -1
  87. package/packages/dd-trace/src/config/defaults.js +14 -6
  88. package/packages/dd-trace/src/config/generated-config-types.d.ts +2 -2
  89. package/packages/dd-trace/src/config/index.js +15 -0
  90. package/packages/dd-trace/src/config/parsers.js +19 -1
  91. package/packages/dd-trace/src/config/supported-configurations.json +5 -6
  92. package/packages/dd-trace/src/datastreams/encoding.js +3 -4
  93. package/packages/dd-trace/src/debugger/devtools_client/log.js +2 -1
  94. package/packages/dd-trace/src/debugger/devtools_client/probe_sampler.js +1 -4
  95. package/packages/dd-trace/src/debugger/devtools_client/send.js +1 -2
  96. package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +2 -2
  97. package/packages/dd-trace/src/debugger/devtools_client/snapshot/redaction.js +16 -2
  98. package/packages/dd-trace/src/encode/tags-processors.js +2 -2
  99. package/packages/dd-trace/src/exporters/common/url.js +3 -5
  100. package/packages/dd-trace/src/exporters/electron/index.js +4 -1
  101. package/packages/dd-trace/src/external-logger/src/index.js +1 -2
  102. package/packages/dd-trace/src/flare/index.js +2 -2
  103. package/packages/dd-trace/src/id.js +1 -1
  104. package/packages/dd-trace/src/llmobs/constants/tags.js +1 -1
  105. package/packages/dd-trace/src/llmobs/experiments/client.js +4 -2
  106. package/packages/dd-trace/src/llmobs/experiments/dataset.js +66 -14
  107. package/packages/dd-trace/src/llmobs/experiments/experiment.js +289 -95
  108. package/packages/dd-trace/src/llmobs/experiments/index.js +51 -12
  109. package/packages/dd-trace/src/llmobs/experiments/noop.js +95 -10
  110. package/packages/dd-trace/src/llmobs/experiments/result.js +13 -2
  111. package/packages/dd-trace/src/llmobs/experiments/util.js +218 -0
  112. package/packages/dd-trace/src/llmobs/plugins/anthropic/index.js +1 -1
  113. package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/index.js +1 -1
  114. package/packages/dd-trace/src/llmobs/plugins/genai/index.js +1 -1
  115. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +1 -1
  116. package/packages/dd-trace/src/llmobs/sdk.js +4 -11
  117. package/packages/dd-trace/src/llmobs/span_processor.js +9 -7
  118. package/packages/dd-trace/src/llmobs/tagger.js +1 -2
  119. package/packages/dd-trace/src/llmobs/writers/spans.js +12 -6
  120. package/packages/dd-trace/src/noop/proxy.js +2 -2
  121. package/packages/dd-trace/src/opentelemetry/metrics/otlp_transformer.js +1 -1
  122. package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +2 -1
  123. package/packages/dd-trace/src/opentracing/span.js +1 -1
  124. package/packages/dd-trace/src/opentracing/span_context.js +1 -1
  125. package/packages/dd-trace/src/plugins/ci_plugin.js +105 -20
  126. package/packages/dd-trace/src/plugins/index.js +1 -0
  127. package/packages/dd-trace/src/plugins/plugin.js +1 -1
  128. package/packages/dd-trace/src/plugins/tracing.js +1 -0
  129. package/packages/dd-trace/src/plugins/util/ci.js +7 -6
  130. package/packages/dd-trace/src/plugins/util/git.js +1 -1
  131. package/packages/dd-trace/src/plugins/util/http-otel-semantics.js +1 -1
  132. package/packages/dd-trace/src/plugins/util/llm.js +2 -2
  133. package/packages/dd-trace/src/plugins/util/tags.js +2 -0
  134. package/packages/dd-trace/src/plugins/util/test.js +38 -12
  135. package/packages/dd-trace/src/plugins/util/url.js +5 -5
  136. package/packages/dd-trace/src/plugins/util/user-provided-git.js +1 -1
  137. package/packages/dd-trace/src/plugins/util/web.js +1 -1
  138. package/packages/dd-trace/src/priority_sampler.js +6 -3
  139. package/packages/dd-trace/src/profiling/profilers/poisson.js +1 -1
  140. package/packages/dd-trace/src/profiling/profilers/shared.js +2 -2
  141. package/packages/dd-trace/src/ritm.js +5 -20
  142. package/packages/dd-trace/src/startup-log.js +3 -0
  143. package/packages/dd-trace/src/telemetry/logs/log-collector.js +3 -1
  144. package/packages/dd-trace/src/util.js +16 -0
  145. package/vendor/dist/@apm-js-collab/code-transformer/index.js +12 -12
  146. package/vendor/dist/pprof-format/index.js +1 -1
  147. package/vendor/dist/source-map/index.js +1 -1
@@ -67,9 +67,7 @@ function getMeta (resourceName, commandArgs) {
67
67
  const [ns, set, bin, exp, index] = commandArgs
68
68
 
69
69
  // The `ext` argument was added to IndexCreate in 6.3.0
70
- meta = commandArgs.length > 8
71
- ? getMetaForIndex(ns, set, bin, index)
72
- : getMetaForIndex(ns, set, bin, exp)
70
+ meta = getMetaForIndex(ns, set, bin, commandArgs.length > 8 ? index : exp)
73
71
  } else if (resourceName === 'Query') {
74
72
  const { ns, set } = commandArgs[2]
75
73
  meta = getMetaForQuery({ ns, set })
@@ -33,7 +33,7 @@ class AmqplibClientPlugin extends ClientPlugin {
33
33
  },
34
34
  }, ctx)
35
35
 
36
- fields.headers = fields.headers || {}
36
+ fields.headers ||= {}
37
37
 
38
38
  this.tracer.inject(span, TEXT_MAP, fields.headers)
39
39
 
@@ -52,7 +52,7 @@ class AmqplibProducerPlugin extends ProducerPlugin {
52
52
  },
53
53
  }, ctx)
54
54
 
55
- fields.headers = fields.headers || {}
55
+ fields.headers ||= {}
56
56
 
57
57
  this.tracer.inject(span, TEXT_MAP, fields.headers)
58
58
 
@@ -39,9 +39,9 @@ class EventBridge extends BaseAwsSdkPlugin {
39
39
  const rulename = params.Name ?? ''
40
40
  return {
41
41
  'resource.name': operation ? `${operation} ${params.source}` : params.source,
42
- 'aws.eventbridge.source': `${params.source}`,
42
+ 'aws.eventbridge.source': params.source,
43
43
  'messaging.system': 'aws_eventbridge',
44
- rulename: `${rulename}`,
44
+ rulename,
45
45
  }
46
46
  }
47
47
 
@@ -29,9 +29,9 @@ class Stepfunctions extends BaseAwsSdkPlugin {
29
29
 
30
30
  generateTags (params, operation, response) {
31
31
  if (!params) return
32
- const tags = { 'resource.name': params.name ? `${operation} ${params.name}` : `${operation}` }
32
+ const tags = { 'resource.name': params.name ? `${operation} ${params.name}` : operation }
33
33
  if (operation === 'startExecution' || operation === 'startSyncExecution') {
34
- tags.statemachinearn = `${params.stateMachineArn}`
34
+ tags.statemachinearn = params.stateMachineArn
35
35
  }
36
36
  return tags
37
37
  }
@@ -46,9 +46,7 @@ class AzureEventHubsProducerPlugin extends ProducerPlugin {
46
46
  }
47
47
  injectTraceContext(this.tracer, span, ctx.eventData)
48
48
  }
49
- }
50
-
51
- if (ctx.functionName === 'sendBatch') {
49
+ } else if (ctx.functionName === 'sendBatch') {
52
50
  const eventData = ctx.eventData
53
51
  const eventDataLength = eventData.length || eventData._context.connection._eventsCount
54
52
  span.setTag('messaging.operation', 'send')
@@ -45,9 +45,11 @@ class AzureServiceBusProducerPlugin extends ProducerPlugin {
45
45
  }
46
46
  injectTraceContext(this.tracer, span, ctx.msg)
47
47
  }
48
- }
49
-
50
- if (ctx.functionName === 'send' || ctx.functionName === 'sendBatch' || ctx.functionName === 'scheduleMessages') {
48
+ } else if (
49
+ ctx.functionName === 'send' ||
50
+ ctx.functionName === 'sendBatch' ||
51
+ ctx.functionName === 'scheduleMessages'
52
+ ) {
51
53
  const messages = ctx.msg
52
54
  const isBatch = messages.constructor?.name === 'ServiceBusMessageBatchImpl'
53
55
  if (isBatch) {
@@ -222,7 +222,7 @@ class QueueAddBulkPlugin extends BaseBullmqProducerPlugin {
222
222
  for (let i = 0; i < jobs.length; i++) {
223
223
  const job = jobs[i]
224
224
  if (!job) continue
225
- job.opts = job.opts || {}
225
+ job.opts ||= {}
226
226
  cache[i] = this._injectIntoOpts(span, job.opts)
227
227
  }
228
228
  ctx._ddMetadata = cache
@@ -274,7 +274,7 @@ class FlowProducerAddPlugin extends BaseBullmqProducerPlugin {
274
274
  injectTraceContext (span, ctx) {
275
275
  const flow = ctx.arguments?.[0]
276
276
  if (!flow) return
277
- flow.opts = flow.opts || {}
277
+ flow.opts ||= {}
278
278
  ctx._ddMetadata = this._injectIntoOpts(span, flow.opts)
279
279
  }
280
280
 
@@ -283,7 +283,7 @@ class FlowProducerAddPlugin extends BaseBullmqProducerPlugin {
283
283
  if (!flow) {
284
284
  return { queueName: 'bullmq', payloadSize: 0, optsTarget: undefined }
285
285
  }
286
- flow.opts = flow.opts || {}
286
+ flow.opts ||= {}
287
287
  return {
288
288
  queueName: flow.queueName || 'bullmq',
289
289
  payloadSize: flow.data ? getMessageSize(flow.data) : 0,
@@ -52,7 +52,7 @@ class ChildProcessPlugin extends TracingPlugin {
52
52
  }
53
53
 
54
54
  if (truncated) {
55
- meta['cmd.truncated'] = `${truncated}`
55
+ meta['cmd.truncated'] = 'true'
56
56
  }
57
57
 
58
58
  this.startSpan('command_execution', {
@@ -81,7 +81,7 @@ class ChildProcessPlugin extends TracingPlugin {
81
81
 
82
82
  const span = ctx.currentStore?.span || this.activeSpan
83
83
 
84
- span?.setTag('cmd.exit_code', `${exitCode}`)
84
+ span?.setTag('cmd.exit_code', String(exitCode))
85
85
  span?.finish()
86
86
 
87
87
  return ctx.parentStore
@@ -112,7 +112,7 @@ class ChildProcessPlugin extends TracingPlugin {
112
112
 
113
113
  const span = ctx.currentStore?.span || this.activeSpan
114
114
 
115
- span?.setTag('cmd.exit_code', `${exitCode}`)
115
+ span?.setTag('cmd.exit_code', String(exitCode))
116
116
  span?.finish()
117
117
 
118
118
  return ctx.parentStore
@@ -5,7 +5,7 @@ const shellParser = require('../../../vendor/dist/shell-quote').parse
5
5
  const ALLOWED_ENV_VARIABLES = new Set(['LD_PRELOAD', 'LD_LIBRARY_PATH', 'PATH'])
6
6
  const PROCESS_DENYLIST = new Set(['md5'])
7
7
 
8
- const VARNAMES_REGEX = /\$(\w*)(?:[^\w]|$)/gmi
8
+ const VARNAMES_REGEX = /\$(\w*)(?:[^\w]|$)/gm
9
9
  // eslint-disable-next-line @stylistic/max-len
10
10
  const PARAM_PATTERN = '^-{0,2}(?:p(?:ass(?:w(?:or)?d)?)?|address|api[-_]?key|e?mail|secret(?:[-_]?key)?|a(?:ccess|uth)[-_]?token|mysql_pwd|credentials|(?:stripe)?token)$'
11
11
  const regexParam = new RegExp(PARAM_PATTERN, 'i')
@@ -14,18 +14,15 @@ const envVarRegex = new RegExp(ENV_PATTERN)
14
14
  const REDACTED = '?'
15
15
 
16
16
  function extractVarNames (expression) {
17
- const varNames = new Set()
17
+ const varNames = {}
18
18
  let match
19
19
 
20
20
  while ((match = VARNAMES_REGEX.exec(expression))) {
21
- varNames.add(match[1])
21
+ const name = match[1]
22
+ varNames[name] = `$${name}`
22
23
  }
23
24
 
24
- const varNamesObject = {}
25
- for (const varName of varNames.keys()) {
26
- varNamesObject[varName] = `$${varName}`
27
- }
28
- return varNamesObject
25
+ return varNames
29
26
  }
30
27
 
31
28
  function getTokensByExpression (expressionTokens) {
@@ -61,7 +61,7 @@ function decodeVLQ (str, cursor) {
61
61
  * @returns {string | null}
62
62
  */
63
63
  function resolveSourcePath (mapDir, sourceRoot, sourcePath) {
64
- const cleanSourcePath = sourcePath.replace(/[?#].*$/, '')
64
+ const cleanSourcePath = sourcePath.split(/[?#]/)[0]
65
65
  if (/^[A-Za-z][A-Za-z\d+.-]*:\/\//.test(cleanSourcePath)) {
66
66
  // Virtual sources may use URL-like schemes (e.g. file://, webpack://, vite://).
67
67
  // If they encode an absolute local path in the URL pathname, use it.
@@ -27,7 +27,7 @@ class FastifyTracingPlugin extends RouterPlugin {
27
27
  }
28
28
 
29
29
  function getParentStore (ctx) {
30
- ctx.parentStore = ctx.parentStore ?? storage('legacy').getStore()
30
+ ctx.parentStore ??= storage('legacy').getStore()
31
31
  return ctx.parentStore
32
32
  }
33
33
 
@@ -7,10 +7,6 @@ class FsPlugin extends TracingPlugin {
7
7
  static operation = 'operation'
8
8
  static experimental = true
9
9
 
10
- configure (...args) {
11
- return super.configure(...args)
12
- }
13
-
14
10
  bindStart (ctx) {
15
11
  if (!this.activeSpan) return { noop: true }
16
12
 
@@ -96,6 +96,20 @@ class GoogleCloudPubsubConsumerPlugin extends ConsumerPlugin {
96
96
  })
97
97
  }
98
98
 
99
+ start (ctx) {
100
+ if (!this.config.dsmEnabled) return
101
+ const { message } = ctx
102
+ if (!message?.attributes) return
103
+
104
+ const { span } = ctx.currentStore
105
+ const subscription = message._subscriber._subscription
106
+ const topic = subscription?.metadata?.topic || message.attributes?.['pubsub.topic']
107
+ const payloadSize = getMessageSize(message)
108
+ this.tracer.decodeDataStreamsContext(message.attributes)
109
+ this.tracer
110
+ .setCheckpoint(['direction:in', `topic:${topic}`, 'type:google-pubsub'], span, payloadSize)
111
+ }
112
+
99
113
  bindStart (ctx) {
100
114
  const { message } = ctx
101
115
  const subscription = message._subscriber._subscription
@@ -181,13 +195,6 @@ class GoogleCloudPubsubConsumerPlugin extends ConsumerPlugin {
181
195
  }
182
196
  }
183
197
 
184
- if (this.config.dsmEnabled && message?.attributes) {
185
- const payloadSize = getMessageSize(message)
186
- this.tracer.decodeDataStreamsContext(message.attributes)
187
- this.tracer
188
- .setCheckpoint(['direction:in', `topic:${topic}`, 'type:google-pubsub'], span, payloadSize)
189
- }
190
-
191
198
  return ctx.currentStore
192
199
  }
193
200
 
@@ -36,6 +36,25 @@ class GoogleCloudPubsubProducerPlugin extends ProducerPlugin {
36
36
  if (topicName) attributes['pubsub.topic'] = topicName
37
37
  }
38
38
 
39
+ start (ctx) {
40
+ if (!this.config.dsmEnabled) return
41
+ if (ctx.api !== 'publish' || !ctx.currentStore) return
42
+ const { request } = ctx
43
+ const messages = request.messages || []
44
+ const topic = request.topic
45
+ const { span } = ctx.currentStore
46
+
47
+ for (const msg of messages) {
48
+ const attributes = msg.attributes ??= {}
49
+ const dataStreamsContext = this.tracer.setCheckpoint(
50
+ ['direction:out', `topic:${topic}`, 'type:google-pubsub'],
51
+ span,
52
+ getHeadersSize(msg)
53
+ )
54
+ DsmPathwayCodec.encode(dataStreamsContext, attributes)
55
+ }
56
+ }
57
+
39
58
  bindStart (ctx) {
40
59
  const { request, api, projectId } = ctx
41
60
  if (api !== 'publish') return
@@ -113,7 +132,6 @@ class GoogleCloudPubsubProducerPlugin extends ProducerPlugin {
113
132
 
114
133
  const messageCountStr = String(messageCount)
115
134
  const startTimeStr = String(Math.floor(batchSpan._startTime))
116
- const dsmEnabled = this.config.dsmEnabled
117
135
 
118
136
  for (let i = 0; i < messageCount; i++) {
119
137
  const msg = messages[i]
@@ -137,15 +155,6 @@ class GoogleCloudPubsubProducerPlugin extends ProducerPlugin {
137
155
  if (batchTraceIdUpper) {
138
156
  attributes['_dd.pubsub_request.p.tid'] = batchTraceIdUpper
139
157
  }
140
-
141
- if (dsmEnabled) {
142
- const dataStreamsContext = this.tracer.setCheckpoint(
143
- ['direction:out', `topic:${topic}`, 'type:google-pubsub'],
144
- batchSpan,
145
- getHeadersSize(msg)
146
- )
147
- DsmPathwayCodec.encode(dataStreamsContext, attributes)
148
- }
149
158
  }
150
159
 
151
160
  ctx.batchSpan = batchSpan
@@ -495,6 +495,7 @@ function wrapResolve (resolve) {
495
495
  // run in the parent store, not field.currentStore: the first sibling's
496
496
  // synchronous resolver already finished the shared graphql.resolve span, so
497
497
  // re-entering its store would parent user spans to a closed span.
498
+ // eslint-disable-next-line unicorn/prefer-else-if -- Keep sibling early return outside first-field setup.
498
499
  if (!isFirst) {
499
500
  return callInAsyncScope(resolve, this, arguments, rootCtx.abortController, field.parentStore, (err) => {
500
501
  if (updateFieldCh.hasSubscribers) {
@@ -11,7 +11,7 @@ const transforms = require('./transforms')
11
11
  const cache = new WeakMap()
12
12
 
13
13
  function defaultEngineReportingSignature (ast, operationName) {
14
- const key = operationName == null ? '' : operationName
14
+ const key = operationName ?? ''
15
15
  let inner = cache.get(ast)
16
16
  if (inner !== undefined) {
17
17
  const cached = inner.get(key)
@@ -10,6 +10,7 @@ const HTTP_HEADERS = formats.HTTP_HEADERS
10
10
  const urlFilter = require('../../dd-trace/src/plugins/util/urlfilter')
11
11
  const { buildClientHttpUrl } = require('../../dd-trace/src/plugins/util/url')
12
12
  const log = require('../../dd-trace/src/log')
13
+ const { stripQueryAndFragment } = require('../../dd-trace/src/util')
13
14
  const { CLIENT_PORT_KEY, COMPONENT, ERROR_MESSAGE, ERROR_TYPE, ERROR_STACK } = require('../../dd-trace/src/constants')
14
15
 
15
16
  const HTTP_STATUS_CODE = tags.HTTP_STATUS_CODE
@@ -32,7 +33,7 @@ class HttpClientPlugin extends ClientPlugin {
32
33
  // A URL object (e.g. from the fetch integration) carries the query in
33
34
  // `options.search`, not `options.path`; keep it so url.full retains the query.
34
35
  const pathname = options.path || `${options.pathname || ''}${options.search || ''}`
35
- const path = pathname ? pathname.split(/[?#]/)[0] : '/'
36
+ const path = pathname ? stripQueryAndFragment(pathname) : '/'
36
37
  const uri = `${base}${path}`
37
38
 
38
39
  const allowed = this.config.filter(uri)
@@ -237,9 +237,8 @@ class JestPlugin extends CiPlugin {
237
237
 
238
238
  const testSuiteMetadata = {
239
239
  ...getTestSuiteCommonTags(testCommand, frameworkVersion, testSuite, 'jest'),
240
- // requestErrorTags from test env options may be undefined
241
- ...(requestErrorTags !== undefined && requestErrorTags !== null ? requestErrorTags : {}),
242
- ...(itrSkippingEnabledTags !== undefined && itrSkippingEnabledTags !== null ? itrSkippingEnabledTags : {}),
240
+ ...requestErrorTags,
241
+ ...itrSkippingEnabledTags,
243
242
  }
244
243
 
245
244
  if (_ddUnskippable) {
@@ -43,7 +43,8 @@ function getFormattedJestTestParameters (testParameters) {
43
43
 
44
44
  // @fast-check/jest appends a random seed to the reported test name. A test name that keeps changing
45
45
  // breaks some Test Optimization features, so normalize this narrow suffix regardless of import style.
46
- const SEED_SUFFIX_RE = /\s*\(with seed=-?\d+\)\s*$/i
46
+ // fast-check emits exactly one space before the suffix.
47
+ const SEED_SUFFIX_RE = / ?\(with seed=-?\d+\) ?$/i
47
48
 
48
49
  function removeSeedSuffixFromTestName (testName) {
49
50
  return testName.replace(SEED_SUFFIX_RE, '')
@@ -9,7 +9,7 @@ function getTokensFromLlmOutput (result) {
9
9
  const { llmOutput } = result
10
10
  if (!llmOutput) return tokens
11
11
 
12
- const tokenUsage = llmOutput.tokenUsage || llmOutput.usage_metadata || llmOutput.usage_metadata
12
+ const tokenUsage = llmOutput.tokenUsage || llmOutput.usage_metadata
13
13
  if (!tokenUsage) return tokens
14
14
 
15
15
  for (const tokenNames of [['input', 'prompt'], ['output', 'completion'], ['total']]) {
@@ -25,7 +25,7 @@ function getTokensFromLlmOutput (result) {
25
25
  }
26
26
 
27
27
  // assign total_tokens again in case it was improperly set the first time, or was not on tokenUsage
28
- tokens.total = tokens.total || tokens.input + tokens.output
28
+ tokens.total ||= tokens.input + tokens.output
29
29
 
30
30
  return tokens
31
31
  }
@@ -34,6 +34,8 @@ const {
34
34
  TEST_IS_MODIFIED,
35
35
  TEST_FINAL_STATUS,
36
36
  TEST_HAS_DYNAMIC_NAME,
37
+ TEST_FRAMEWORK_ADAPTER,
38
+ getTestSuiteExecutionKey,
37
39
  isModifiedTest,
38
40
  } = require('../../dd-trace/src/plugins/util/test')
39
41
  const { COMPONENT } = require('../../dd-trace/src/constants')
@@ -58,6 +60,12 @@ class MochaPlugin extends CiPlugin {
58
60
  this._testTitleToParams = {}
59
61
  this.sourceRoot = process.cwd()
60
62
 
63
+ this.addSub('ci:mocha:worker:configuration', ({ libraryConfig, repositoryRoot, testFramework }) => {
64
+ this.libraryConfig = libraryConfig
65
+ this.testFramework = testFramework
66
+ this._setRepositoryRoot(repositoryRoot)
67
+ })
68
+
61
69
  this.addSub('ci:mocha:test-suite:code-coverage', ({ coverageFiles, suiteFile }) => {
62
70
  if (!this.libraryConfig?.isCodeCoverageEnabled) {
63
71
  return
@@ -88,23 +96,33 @@ class MochaPlugin extends CiPlugin {
88
96
  })
89
97
 
90
98
  this.addBind('ci:mocha:test-suite:start', (ctx) => {
91
- const { testSuiteAbsolutePath, isUnskippable, isForcedToRun, itrCorrelationId } = ctx
99
+ const {
100
+ testSuiteAbsolutePath,
101
+ testSuiteExecutionId,
102
+ isUnskippable,
103
+ isForcedToRun,
104
+ itrCorrelationId,
105
+ } = ctx
92
106
 
93
107
  // If the test module span is undefined, the plugin has not been initialized correctly and we bail out
94
108
  if (!this.testModuleSpan) {
95
109
  return
96
110
  }
97
111
  const testSuite = getTestSuitePath(testSuiteAbsolutePath, this.sourceRoot)
112
+ const testFramework = this.testFramework || this.constructor.id
98
113
  const testSuiteMetadata = {
99
114
  ...getTestSuiteCommonTags(
100
115
  this.command,
101
116
  this.frameworkVersion,
102
117
  testSuite,
103
- 'mocha'
118
+ testFramework
104
119
  ),
105
120
  ...this.getSessionRequestErrorTags(),
106
121
  ...this.getSessionItrSkippingEnabledTags(),
107
122
  }
123
+ if (this.testFrameworkAdapter) {
124
+ testSuiteMetadata[TEST_FRAMEWORK_ADAPTER] = this.testFrameworkAdapter
125
+ }
108
126
  if (isUnskippable) {
109
127
  testSuiteMetadata[TEST_ITR_UNSKIPPABLE] = 'true'
110
128
  this.telemetry.count(TELEMETRY_ITR_UNSKIPPABLE, { testLevel: 'suite' })
@@ -144,8 +162,9 @@ class MochaPlugin extends CiPlugin {
144
162
  const store = storage('legacy').getStore()
145
163
  ctx.parentStore = store
146
164
  ctx.currentStore = { ...store, testSuiteSpan }
147
- this._testSuiteSpansByTestSuite.set(testSuite, testSuiteSpan)
148
- this._exportPendingWorkerTracesForTestSuite(testSuite)
165
+ const testSuiteKey = getTestSuiteExecutionKey(testSuite, testSuiteExecutionId)
166
+ this._testSuiteSpansByTestSuite.set(testSuiteKey, testSuiteSpan)
167
+ this._exportPendingWorkerTracesForTestSuite(testSuiteKey)
149
168
  })
150
169
 
151
170
  this.addSub('ci:mocha:test-suite:finish', ({ testSuiteSpan, status }) => {
@@ -203,8 +222,8 @@ class MochaPlugin extends CiPlugin {
203
222
  return ctx.currentStore
204
223
  })
205
224
 
206
- this.addSub('ci:mocha:worker:finish', () => {
207
- this.tracer._exporter.flush()
225
+ this.addSub('ci:mocha:worker:finish', ({ onDone } = {}) => {
226
+ this.tracer._exporter.flush(onDone)
208
227
  })
209
228
 
210
229
  this.addSub('ci:mocha:test:finish', ({
@@ -125,9 +125,13 @@ class PrismaPlugin extends DatabasePlugin {
125
125
  }
126
126
  }
127
127
 
128
+ /**
129
+ * @param {string} resource
130
+ * @param {{ name?: string, model?: string, method?: string }} [attributes]
131
+ */
128
132
  function formatResourceName (resource, attributes) {
129
133
  if (attributes?.name) {
130
- return `${attributes.name}`.trim()
134
+ return attributes.name.trim()
131
135
  }
132
136
  if (attributes?.model && attributes.method) {
133
137
  return `${attributes.model}.${attributes.method}`.trim()
@@ -15,12 +15,27 @@ class RheaConsumerPlugin extends ConsumerPlugin {
15
15
  })
16
16
  }
17
17
 
18
+ start (ctx) {
19
+ if (!this.config.dsmEnabled) return
20
+ const { msgObj } = ctx
21
+ if (!msgObj?.message?.delivery_annotations) return
22
+
23
+ const { span } = ctx.currentStore
24
+ const name = getResourceNameFromMessage(msgObj)
25
+ const payloadSize = getAmqpMessageSize(
26
+ { headers: msgObj.message.delivery_annotations, content: msgObj.message.body }
27
+ )
28
+ this.tracer.decodeDataStreamsContext(msgObj.message.delivery_annotations)
29
+ this.tracer
30
+ .setCheckpoint(['direction:in', `topic:${name}`, 'type:rabbitmq'], span, payloadSize)
31
+ }
32
+
18
33
  bindStart (ctx) {
19
34
  const { msgObj } = ctx
20
35
  const name = getResourceNameFromMessage(msgObj)
21
36
  const childOf = extractTextMap(msgObj, this.tracer)
22
37
 
23
- const span = this.startSpan({
38
+ this.startSpan({
24
39
  childOf,
25
40
  resource: name,
26
41
  type: 'worker',
@@ -31,18 +46,6 @@ class RheaConsumerPlugin extends ConsumerPlugin {
31
46
  },
32
47
  }, ctx)
33
48
 
34
- if (
35
- this.config.dsmEnabled &&
36
- msgObj?.message?.delivery_annotations
37
- ) {
38
- const payloadSize = getAmqpMessageSize(
39
- { headers: msgObj.message.delivery_annotations, content: msgObj.message.body }
40
- )
41
- this.tracer.decodeDataStreamsContext(msgObj.message.delivery_annotations)
42
- this.tracer
43
- .setCheckpoint(['direction:in', `topic:${name}`, 'type:rabbitmq'], span, payloadSize)
44
- }
45
-
46
49
  return ctx.currentStore
47
50
  }
48
51
  }
@@ -37,7 +37,7 @@ class RheaProducerPlugin extends ProducerPlugin {
37
37
 
38
38
  function addDeliveryAnnotations (msg, tracer, span) {
39
39
  if (msg) {
40
- msg.delivery_annotations = msg.delivery_annotations || {}
40
+ msg.delivery_annotations ||= {}
41
41
 
42
42
  tracer.inject(span, 'text_map', msg.delivery_annotations)
43
43
 
@@ -7,6 +7,7 @@ const formats = require('../../../ext/formats')
7
7
  const HTTP_HEADERS = formats.HTTP_HEADERS
8
8
  const log = require('../../dd-trace/src/log')
9
9
  const { buildClientHttpUrl } = require('../../dd-trace/src/plugins/util/url')
10
+ const { stripQueryAndFragment } = require('../../dd-trace/src/util')
10
11
  const { CLIENT_PORT_KEY } = require('../../dd-trace/src/constants')
11
12
 
12
13
  const {
@@ -62,7 +63,7 @@ class UndiciPlugin extends HttpClientPlugin {
62
63
 
63
64
  const host = port ? `${hostname}:${port}` : hostname
64
65
  const base = `${protocol}//${host}`
65
- const pathname = path.split(/[?#]/)[0]
66
+ const pathname = stripQueryAndFragment(path)
66
67
  const uri = `${base}${pathname}`
67
68
 
68
69
  const allowed = this.config.filter(uri)