dd-trace 5.66.0 → 5.68.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 (107) hide show
  1. package/LICENSE-3rdparty.csv +0 -3
  2. package/README.md +0 -2
  3. package/ci/init.js +52 -54
  4. package/ext/exporters.d.ts +2 -1
  5. package/ext/exporters.js +2 -1
  6. package/index.d.ts +85 -2
  7. package/initialize.mjs +1 -1
  8. package/package.json +8 -11
  9. package/packages/datadog-esbuild/index.js +56 -0
  10. package/packages/datadog-instrumentations/src/aws-sdk.js +42 -4
  11. package/packages/datadog-instrumentations/src/azure-functions.js +1 -1
  12. package/packages/datadog-instrumentations/src/azure-service-bus.js +1 -1
  13. package/packages/datadog-instrumentations/src/cassandra-driver.js +2 -2
  14. package/packages/datadog-instrumentations/src/connect.js +6 -2
  15. package/packages/datadog-instrumentations/src/cucumber.js +31 -6
  16. package/packages/datadog-instrumentations/src/express.js +5 -6
  17. package/packages/datadog-instrumentations/src/fastify.js +3 -3
  18. package/packages/datadog-instrumentations/src/helpers/hook.js +28 -15
  19. package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
  20. package/packages/datadog-instrumentations/src/helpers/instrument.js +11 -2
  21. package/packages/datadog-instrumentations/src/helpers/register.js +10 -3
  22. package/packages/datadog-instrumentations/src/http2/client.js +1 -0
  23. package/packages/datadog-instrumentations/src/http2/server.js +0 -1
  24. package/packages/datadog-instrumentations/src/ioredis.js +12 -1
  25. package/packages/datadog-instrumentations/src/jest.js +48 -36
  26. package/packages/datadog-instrumentations/src/limitd-client.js +2 -1
  27. package/packages/datadog-instrumentations/src/mocha/main.js +15 -7
  28. package/packages/datadog-instrumentations/src/mocha/utils.js +3 -0
  29. package/packages/datadog-instrumentations/src/mongoose.js +2 -1
  30. package/packages/datadog-instrumentations/src/oracledb.js +19 -13
  31. package/packages/datadog-instrumentations/src/pg.js +9 -5
  32. package/packages/datadog-instrumentations/src/pino.js +18 -6
  33. package/packages/datadog-instrumentations/src/playwright.js +15 -1
  34. package/packages/datadog-instrumentations/src/sequelize.js +1 -1
  35. package/packages/datadog-instrumentations/src/vitest.js +155 -62
  36. package/packages/datadog-plugin-ai/src/tracing.js +3 -3
  37. package/packages/datadog-plugin-aws-sdk/src/base.js +23 -8
  38. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/tracing.js +2 -2
  39. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +101 -2
  40. package/packages/datadog-plugin-aws-sdk/src/util.js +1 -1
  41. package/packages/datadog-plugin-cucumber/src/index.js +4 -56
  42. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +6 -2
  43. package/packages/datadog-plugin-cypress/src/support.js +4 -0
  44. package/packages/datadog-plugin-express/src/code_origin.js +2 -2
  45. package/packages/datadog-plugin-fastify/src/code_origin.js +1 -2
  46. package/packages/datadog-plugin-jest/src/index.js +0 -21
  47. package/packages/datadog-plugin-mocha/src/index.js +3 -57
  48. package/packages/datadog-plugin-mongodb-core/src/index.js +20 -7
  49. package/packages/datadog-plugin-playwright/src/index.js +11 -5
  50. package/packages/datadog-plugin-vitest/src/index.js +5 -1
  51. package/packages/datadog-plugin-ws/src/close.js +1 -1
  52. package/packages/datadog-plugin-ws/src/producer.js +6 -1
  53. package/packages/datadog-plugin-ws/src/receiver.js +6 -1
  54. package/packages/dd-trace/src/appsec/iast/security-controls/parser.js +1 -1
  55. package/packages/dd-trace/src/appsec/telemetry/waf.js +2 -2
  56. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +4 -4
  57. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +11 -3
  58. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +10 -1
  59. package/packages/dd-trace/src/config.js +69 -304
  60. package/packages/dd-trace/src/config_defaults.js +186 -0
  61. package/packages/dd-trace/src/crashtracking/crashtracker.js +2 -1
  62. package/packages/dd-trace/src/datastreams/fnv.js +2 -2
  63. package/packages/dd-trace/src/datastreams/writer.js +3 -2
  64. package/packages/dd-trace/src/debugger/devtools_client/config.js +2 -1
  65. package/packages/dd-trace/src/dogstatsd.js +4 -3
  66. package/packages/dd-trace/src/encode/0.4.js +1 -5
  67. package/packages/dd-trace/src/exporter.js +1 -0
  68. package/packages/dd-trace/src/exporters/agent/index.js +3 -2
  69. package/packages/dd-trace/src/exporters/agent/writer.js +1 -1
  70. package/packages/dd-trace/src/exporters/common/agent-info-exporter.js +3 -2
  71. package/packages/dd-trace/src/exporters/common/request.js +2 -1
  72. package/packages/dd-trace/src/exporters/span-stats/index.js +3 -2
  73. package/packages/dd-trace/src/llmobs/constants/tags.js +2 -0
  74. package/packages/dd-trace/src/llmobs/index.js +7 -0
  75. package/packages/dd-trace/src/llmobs/plugins/ai/index.js +4 -3
  76. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +12 -1
  77. package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +40 -13
  78. package/packages/dd-trace/src/llmobs/plugins/openai.js +7 -1
  79. package/packages/dd-trace/src/llmobs/sdk.js +28 -0
  80. package/packages/dd-trace/src/llmobs/span_processor.js +124 -28
  81. package/packages/dd-trace/src/llmobs/tagger.js +8 -0
  82. package/packages/dd-trace/src/llmobs/telemetry.js +9 -2
  83. package/packages/dd-trace/src/log/index.js +28 -17
  84. package/packages/dd-trace/src/log/log.js +29 -5
  85. package/packages/dd-trace/src/log/writer.js +5 -5
  86. package/packages/dd-trace/src/noop/span.js +1 -0
  87. package/packages/dd-trace/src/opentelemetry/span.js +14 -3
  88. package/packages/dd-trace/src/opentracing/span.js +18 -4
  89. package/packages/dd-trace/src/plugin_manager.js +20 -2
  90. package/packages/dd-trace/src/plugins/ci_plugin.js +97 -3
  91. package/packages/dd-trace/src/plugins/index.js +2 -0
  92. package/packages/dd-trace/src/plugins/util/git-cache.js +129 -0
  93. package/packages/dd-trace/src/plugins/util/git.js +40 -26
  94. package/packages/dd-trace/src/plugins/util/test.js +37 -27
  95. package/packages/dd-trace/src/plugins/util/web.js +1 -1
  96. package/packages/dd-trace/src/profiler.js +4 -1
  97. package/packages/dd-trace/src/profiling/config.js +73 -42
  98. package/packages/dd-trace/src/profiling/profiler.js +3 -1
  99. package/packages/dd-trace/src/profiling/profilers/events.js +3 -8
  100. package/packages/dd-trace/src/profiling/profilers/space.js +1 -0
  101. package/packages/dd-trace/src/profiling/profilers/wall.js +196 -117
  102. package/packages/dd-trace/src/remote_config/capabilities.js +5 -0
  103. package/packages/dd-trace/src/remote_config/manager.js +3 -2
  104. package/packages/dd-trace/src/startup-log.js +2 -1
  105. package/packages/dd-trace/src/supported-configurations.json +3 -0
  106. package/packages/dd-trace/src/telemetry/logs/index.js +2 -2
  107. package/register.js +1 -1
@@ -73,19 +73,31 @@ function wrapPrettyFactory (prettyFactory) {
73
73
  }
74
74
  }
75
75
 
76
- addHook({ name: 'pino', versions: ['2 - 3', '4', '>=5 <5.14.0'] }, pino => {
76
+ addHook({ name: 'pino', versions: ['2 - 3', '4'], patchDefault: true }, (pino) => {
77
77
  const asJsonSym = (pino.symbols && pino.symbols.asJsonSym) || 'asJson'
78
78
 
79
- return shimmer.wrapFunction(pino, pino => wrapPino(asJsonSym, wrapAsJson, pino))
79
+ const wrapped = shimmer.wrapFunction(pino, pino => wrapPino(asJsonSym, wrapAsJson, pino))
80
+
81
+ return wrapped
80
82
  })
81
83
 
82
- addHook({ name: 'pino', versions: ['>=5.14.0 <6.8.0'] }, pino => {
83
- const mixinSym = pino.symbols.mixinSym
84
+ addHook({ name: 'pino', versions: ['>=5 <5.14.0'], patchDefault: true }, (pino) => {
85
+ const asJsonSym = ((pino.default || pino)?.symbols.asJsonSym) || 'asJson'
86
+
87
+ const wrapped = shimmer.wrapFunction(pino, pino => wrapPino(asJsonSym, wrapAsJson, pino))
88
+
89
+ return wrapped
90
+ })
91
+
92
+ addHook({ name: 'pino', versions: ['>=5.14.0 <6.8.0'] }, (pino) => {
93
+ const mixinSym = (pino.default || pino).symbols.mixinSym
84
94
 
85
- return shimmer.wrapFunction(pino, pino => wrapPino(mixinSym, wrapMixin, pino))
95
+ const wrapped = shimmer.wrapFunction(pino, pino => wrapPino(mixinSym, wrapMixin, pino.default || pino))
96
+
97
+ return wrapped
86
98
  })
87
99
 
88
- addHook({ name: 'pino', versions: ['>=6.8.0'] }, pino => {
100
+ addHook({ name: 'pino', versions: ['>=6.8.0'], patchDefault: false }, (pino, _1, _2, isIitm) => {
89
101
  const mixinSym = pino.symbols.mixinSym
90
102
 
91
103
  const wrapped = shimmer.wrapFunction(pino, pino => wrapPino(mixinSym, wrapMixin, pino))
@@ -51,6 +51,7 @@ let remainingTestsByFile = {}
51
51
  let isKnownTestsEnabled = false
52
52
  let isEarlyFlakeDetectionEnabled = false
53
53
  let earlyFlakeDetectionNumRetries = 0
54
+ let isEarlyFlakeDetectionFaulty = false
54
55
  let isFlakyTestRetriesEnabled = false
55
56
  let flakyTestRetriesCount = 0
56
57
  let knownTests = {}
@@ -64,6 +65,10 @@ let quarantinedButNotAttemptToFixFqns = new Set()
64
65
  let rootDir = ''
65
66
  const MINIMUM_SUPPORTED_VERSION_RANGE_EFD = '>=1.38.0' // TODO: remove this once we drop support for v5
66
67
 
68
+ function isValidKnownTests (receivedKnownTests) {
69
+ return !!receivedKnownTests.playwright
70
+ }
71
+
67
72
  function getTestFullyQualifiedName (test) {
68
73
  const fullname = getTestFullname(test)
69
74
  return `${test._requireFile} ${fullname}`
@@ -79,8 +84,11 @@ function getTestProperties (test) {
79
84
  }
80
85
 
81
86
  function isNewTest (test) {
87
+ if (!isValidKnownTests(knownTests)) {
88
+ return false
89
+ }
82
90
  const testSuite = getTestSuitePath(test._requireFile, rootDir)
83
- const testsForSuite = knownTests?.playwright?.[testSuite] || []
91
+ const testsForSuite = knownTests.playwright[testSuite] || []
84
92
 
85
93
  return !testsForSuite.includes(getTestFullname(test))
86
94
  }
@@ -557,6 +565,11 @@ function runAllTestsWrapper (runAllTests, playwrightVersion) {
557
565
  } else {
558
566
  knownTests = receivedKnownTests
559
567
  }
568
+ if (!isValidKnownTests(receivedKnownTests)) {
569
+ isEarlyFlakeDetectionFaulty = true
570
+ isEarlyFlakeDetectionEnabled = false
571
+ isKnownTestsEnabled = false
572
+ }
560
573
  } catch (err) {
561
574
  isEarlyFlakeDetectionEnabled = false
562
575
  isKnownTestsEnabled = false
@@ -652,6 +665,7 @@ function runAllTestsWrapper (runAllTests, playwrightVersion) {
652
665
  testSessionFinishCh.publish({
653
666
  status: STATUS_TO_TEST_STATUS[sessionStatus],
654
667
  isEarlyFlakeDetectionEnabled,
668
+ isEarlyFlakeDetectionFaulty,
655
669
  isTestManagementTestsEnabled,
656
670
  onDone
657
671
  })
@@ -7,7 +7,7 @@ const {
7
7
 
8
8
  const shimmer = require('../../datadog-shimmer')
9
9
 
10
- addHook({ name: 'sequelize', versions: ['>=4'] }, Sequelize => {
10
+ addHook({ name: 'sequelize', versions: ['>=4'], file: ['lib/sequelize.js'] }, Sequelize => {
11
11
  const startCh = channel('datadog:sequelize:query:start')
12
12
  const finishCh = channel('datadog:sequelize:query:finish')
13
13
 
@@ -3,6 +3,10 @@
3
3
  const { addHook, channel } = require('./helpers/instrument')
4
4
  const shimmer = require('../../datadog-shimmer')
5
5
  const log = require('../../dd-trace/src/log')
6
+ const {
7
+ VITEST_WORKER_TRACE_PAYLOAD_CODE,
8
+ VITEST_WORKER_LOGS_PAYLOAD_CODE
9
+ } = require('../../dd-trace/src/plugins/util/test')
6
10
 
7
11
  // test hooks
8
12
  const testStartCh = channel('ci:vitest:test:start')
@@ -30,6 +34,9 @@ const isEarlyFlakeDetectionFaultyCh = channel('ci:vitest:is-early-flake-detectio
30
34
  const testManagementTestsCh = channel('ci:vitest:test-management-tests')
31
35
  const impactedTestsCh = channel('ci:vitest:modified-tests')
32
36
 
37
+ const workerReportTraceCh = channel('ci:vitest:worker-report:trace')
38
+ const workerReportLogsCh = channel('ci:vitest:worker-report:logs')
39
+
33
40
  const taskToCtx = new WeakMap()
34
41
  const taskToStatuses = new WeakMap()
35
42
  const newTasks = new WeakSet()
@@ -40,9 +47,26 @@ const modifiedTasks = new WeakSet()
40
47
  let isRetryReasonEfd = false
41
48
  let isRetryReasonAttemptToFix = false
42
49
  const switchedStatuses = new WeakSet()
50
+ const workerProcesses = new WeakSet()
51
+ let isFlakyTestRetriesEnabled = false
52
+ let flakyTestRetriesCount = 0
53
+ let isEarlyFlakeDetectionEnabled = false
54
+ let earlyFlakeDetectionNumRetries = 0
55
+ let isEarlyFlakeDetectionFaulty = false
56
+ let isKnownTestsEnabled = false
57
+ let isTestManagementTestsEnabled = false
58
+ let isImpactedTestsEnabled = false
59
+ let testManagementAttemptToFixRetries = 0
60
+ let isDiEnabled = false
61
+ let testCodeCoverageLinesTotal
62
+ let isSessionStarted = false
43
63
 
44
64
  const BREAKPOINT_HIT_GRACE_PERIOD_MS = 400
45
65
 
66
+ function getTestCommand () {
67
+ return `vitest ${process.argv.slice(2).join(' ')}`
68
+ }
69
+
46
70
  function waitForHitProbe () {
47
71
  return new Promise(resolve => {
48
72
  setTimeout(() => {
@@ -51,6 +75,10 @@ function waitForHitProbe () {
51
75
  })
52
76
  }
53
77
 
78
+ function isValidKnownTests (receivedKnownTests) {
79
+ return !!receivedKnownTests.vitest
80
+ }
81
+
54
82
  function getProvidedContext () {
55
83
  try {
56
84
  const {
@@ -121,6 +149,10 @@ function getChannelPromise (channelToPublishTo, frameworkVersion) {
121
149
  })
122
150
  }
123
151
 
152
+ function isCliApiPackage (vitestPackage) {
153
+ return vitestPackage.s?.name === 'startVitest'
154
+ }
155
+
124
156
  function getSessionStatus (state) {
125
157
  if (state.getCountOfFailedTests() > 0) {
126
158
  return 'fail'
@@ -183,16 +215,6 @@ function getSortWrapper (sort, frameworkVersion) {
183
215
  // There isn't any other async function that we seem to be able to hook into
184
216
  // So we will use the sort from BaseSequencer. This means that a custom sequencer
185
217
  // will not work. This will be a known limitation.
186
- let isFlakyTestRetriesEnabled = false
187
- let flakyTestRetriesCount = 0
188
- let isEarlyFlakeDetectionEnabled = false
189
- let earlyFlakeDetectionNumRetries = 0
190
- let isEarlyFlakeDetectionFaulty = false
191
- let isKnownTestsEnabled = false
192
- let isTestManagementTestsEnabled = false
193
- let isImpactedTestsEnabled = false
194
- let testManagementAttemptToFixRetries = 0
195
- let isDiEnabled = false
196
218
 
197
219
  try {
198
220
  const { err, libraryConfig } = await getChannelPromise(libraryConfigurationCh, frameworkVersion)
@@ -235,28 +257,33 @@ function getSortWrapper (sort, frameworkVersion) {
235
257
 
236
258
  const testFilepaths = await getFilePaths.call(this.ctx)
237
259
 
238
- isEarlyFlakeDetectionFaultyCh.publish({
239
- knownTests: knownTests.vitest || {},
240
- testFilepaths,
241
- onDone: (isFaulty) => {
242
- isEarlyFlakeDetectionFaulty = isFaulty
260
+ if (isValidKnownTests(knownTests)) {
261
+ isEarlyFlakeDetectionFaultyCh.publish({
262
+ knownTests: knownTests.vitest,
263
+ testFilepaths,
264
+ onDone: (isFaulty) => {
265
+ isEarlyFlakeDetectionFaulty = isFaulty
266
+ }
267
+ })
268
+ if (isEarlyFlakeDetectionFaulty) {
269
+ isEarlyFlakeDetectionEnabled = false
270
+ log.warn('New test detection is disabled because the number of new tests is too high.')
271
+ } else {
272
+ // TODO: use this to pass session and module IDs to the worker, instead of polluting process.env
273
+ // Note: setting this.ctx.config.provide directly does not work because it's cached
274
+ try {
275
+ const workspaceProject = this.ctx.getCoreWorkspaceProject()
276
+ workspaceProject._provided._ddIsKnownTestsEnabled = isKnownTestsEnabled
277
+ workspaceProject._provided._ddKnownTests = knownTests
278
+ workspaceProject._provided._ddIsEarlyFlakeDetectionEnabled = isEarlyFlakeDetectionEnabled
279
+ workspaceProject._provided._ddEarlyFlakeDetectionNumRetries = earlyFlakeDetectionNumRetries
280
+ } catch {
281
+ log.warn('Could not send known tests to workers so Early Flake Detection will not work.')
282
+ }
243
283
  }
244
- })
245
- if (isEarlyFlakeDetectionFaulty) {
246
- isEarlyFlakeDetectionEnabled = false
247
- log.warn('New test detection is disabled because the number of new tests is too high.')
248
284
  } else {
249
- // TODO: use this to pass session and module IDs to the worker, instead of polluting process.env
250
- // Note: setting this.ctx.config.provide directly does not work because it's cached
251
- try {
252
- const workspaceProject = this.ctx.getCoreWorkspaceProject()
253
- workspaceProject._provided._ddIsKnownTestsEnabled = isKnownTestsEnabled
254
- workspaceProject._provided._ddKnownTests = knownTests.vitest || {}
255
- workspaceProject._provided._ddIsEarlyFlakeDetectionEnabled = isEarlyFlakeDetectionEnabled
256
- workspaceProject._provided._ddEarlyFlakeDetectionNumRetries = earlyFlakeDetectionNumRetries
257
- } catch {
258
- log.warn('Could not send known tests to workers so Early Flake Detection will not work.')
259
- }
285
+ isEarlyFlakeDetectionFaulty = true
286
+ isEarlyFlakeDetectionEnabled = false
260
287
  }
261
288
  }
262
289
  }
@@ -303,8 +330,6 @@ function getSortWrapper (sort, frameworkVersion) {
303
330
  }
304
331
  }
305
332
 
306
- let testCodeCoverageLinesTotal
307
-
308
333
  if (this.ctx.coverageProvider?.generateCoverage) {
309
334
  shimmer.wrap(this.ctx.coverageProvider, 'generateCoverage', generateCoverage => async function () {
310
335
  const totalCodeCoverage = await generateCoverage.apply(this, arguments)
@@ -318,48 +343,104 @@ function getSortWrapper (sort, frameworkVersion) {
318
343
  })
319
344
  }
320
345
 
321
- shimmer.wrap(this.ctx, 'exit', exit => async function () {
322
- let onFinish
346
+ shimmer.wrap(this.ctx, 'exit', getFinishWrapper)
347
+ shimmer.wrap(this.ctx, 'close', getFinishWrapper)
323
348
 
324
- const flushPromise = new Promise(resolve => {
325
- onFinish = resolve
326
- })
327
- const failedSuites = this.state.getFailedFilepaths()
328
- let error
329
- if (failedSuites.length) {
330
- error = new Error(`Test suites failed: ${failedSuites.length}.`)
331
- }
349
+ return sort.apply(this, arguments)
350
+ }
351
+ }
332
352
 
333
- testSessionFinishCh.publish({
334
- status: getSessionStatus(this.state),
335
- testCodeCoverageLinesTotal,
336
- error,
337
- isEarlyFlakeDetectionEnabled,
338
- isEarlyFlakeDetectionFaulty,
339
- isTestManagementTestsEnabled,
340
- onFinish
341
- })
353
+ function getFinishWrapper (exitOrClose) {
354
+ let isClosed = false
355
+ return async function () {
356
+ if (isClosed) { // needed because exit calls close
357
+ return exitOrClose.apply(this, arguments)
358
+ }
359
+ isClosed = true
360
+ let onFinish
342
361
 
343
- await flushPromise
362
+ const flushPromise = new Promise(resolve => {
363
+ onFinish = resolve
364
+ })
365
+ const failedSuites = this.state.getFailedFilepaths()
366
+ let error
367
+ if (failedSuites.length) {
368
+ error = new Error(`Test suites failed: ${failedSuites.length}.`)
369
+ }
344
370
 
345
- return exit.apply(this, arguments)
371
+ testSessionFinishCh.publish({
372
+ status: getSessionStatus(this.state),
373
+ testCodeCoverageLinesTotal,
374
+ error,
375
+ isEarlyFlakeDetectionEnabled,
376
+ isEarlyFlakeDetectionFaulty,
377
+ isTestManagementTestsEnabled,
378
+ onFinish
346
379
  })
347
380
 
348
- return sort.apply(this, arguments)
381
+ await flushPromise
382
+
383
+ return exitOrClose.apply(this, arguments)
384
+ }
385
+ }
386
+
387
+ function getCliOrStartVitestWrapper (frameworkVersion) {
388
+ return function (oldCliOrStartVitest) {
389
+ return function () {
390
+ if (!testSessionStartCh.hasSubscribers || isSessionStarted) {
391
+ return oldCliOrStartVitest.apply(this, arguments)
392
+ }
393
+ isSessionStarted = true
394
+ testSessionStartCh.publish({ command: getTestCommand(), frameworkVersion })
395
+ return oldCliOrStartVitest.apply(this, arguments)
396
+ }
349
397
  }
350
398
  }
351
399
 
352
400
  function getCreateCliWrapper (vitestPackage, frameworkVersion) {
353
- shimmer.wrap(vitestPackage, 'c', oldCreateCli => function () {
354
- if (!testSessionStartCh.hasSubscribers) {
355
- return oldCreateCli.apply(this, arguments)
401
+ shimmer.wrap(vitestPackage, 'c', getCliOrStartVitestWrapper(frameworkVersion))
402
+
403
+ return vitestPackage
404
+ }
405
+
406
+ function threadHandler (thread) {
407
+ if (workerProcesses.has(thread.process)) {
408
+ return
409
+ }
410
+ workerProcesses.add(thread.process)
411
+ thread.process.on('message', (message) => {
412
+ if (message.__tinypool_worker_message__ && message.data) {
413
+ if (message.interprocessCode === VITEST_WORKER_TRACE_PAYLOAD_CODE) {
414
+ workerReportTraceCh.publish(message.data)
415
+ } else if (message.interprocessCode === VITEST_WORKER_LOGS_PAYLOAD_CODE) {
416
+ workerReportLogsCh.publish(message.data)
417
+ }
356
418
  }
357
- const processArgv = process.argv.slice(2).join(' ')
358
- testSessionStartCh.publish({ command: `vitest ${processArgv}`, frameworkVersion })
359
- return oldCreateCli.apply(this, arguments)
360
419
  })
420
+ }
361
421
 
362
- return vitestPackage
422
+ addHook({
423
+ name: 'tinypool',
424
+ versions: ['>=1.0.0'],
425
+ file: 'dist/index.js'
426
+ }, (TinyPool) => {
427
+ shimmer.wrap(TinyPool.prototype, 'run', run => async function () {
428
+ // We have to do this before and after because the threads list gets recycled, that is, the processes are re-created
429
+ this.threads.forEach(threadHandler)
430
+ const runResult = await run.apply(this, arguments)
431
+ this.threads.forEach(threadHandler)
432
+ return runResult
433
+ })
434
+
435
+ return TinyPool
436
+ })
437
+
438
+ function getStartVitestWrapper (cliApiPackage, frameworkVersion) {
439
+ if (!isCliApiPackage(cliApiPackage)) {
440
+ return cliApiPackage
441
+ }
442
+ shimmer.wrap(cliApiPackage, 's', getCliOrStartVitestWrapper(frameworkVersion))
443
+ return cliApiPackage
363
444
  }
364
445
 
365
446
  addHook({
@@ -735,6 +816,7 @@ addHook({
735
816
  })
736
817
 
737
818
  // Can't specify file because compiled vitest includes hashes in their files
819
+ // Following 3 wrappers are for test session start
738
820
  addHook({
739
821
  name: 'vitest',
740
822
  versions: ['>=1.6.0 <2.0.5'],
@@ -747,6 +829,18 @@ addHook({
747
829
  filePattern: 'dist/chunks/cac.*'
748
830
  }, getCreateCliWrapper)
749
831
 
832
+ addHook({
833
+ name: 'vitest',
834
+ versions: ['>=1.6.0 <2.0.5'],
835
+ filePattern: 'dist/vendor/cli-api.*'
836
+ }, getStartVitestWrapper)
837
+
838
+ addHook({
839
+ name: 'vitest',
840
+ versions: ['>=2.0.5'],
841
+ filePattern: 'dist/chunks/cli-api.*'
842
+ }, getStartVitestWrapper)
843
+
750
844
  // test suite start and finish
751
845
  // only relevant for workers
752
846
  addHook({
@@ -857,7 +951,6 @@ addHook({
857
951
 
858
952
  testSuiteFinishCh.publish({ status: testSuiteResult.state, onFinish, ...testSuiteCtx.currentStore })
859
953
 
860
- // TODO: fix too frequent flushes
861
954
  await onFinishPromise
862
955
 
863
956
  return startTestsResponse
@@ -8,14 +8,14 @@ class VercelAITracingPlugin extends TracingPlugin {
8
8
  static prefix = 'tracing:dd-trace:vercel-ai'
9
9
 
10
10
  bindStart (ctx) {
11
- const attributes = ctx.attributes
11
+ const { attributes, name } = ctx
12
12
 
13
13
  const model = attributes['ai.model.id']
14
14
  const modelProvider = getModelProvider(attributes)
15
15
 
16
- this.startSpan(ctx.name, {
16
+ this.startSpan(name, {
17
17
  meta: {
18
- 'resource.name': ctx.name,
18
+ 'resource.name': attributes['resource.name'] ?? name,
19
19
  'ai.request.model': model,
20
20
  'ai.request.model_provider': modelProvider
21
21
  }
@@ -4,7 +4,6 @@ const analyticsSampler = require('../../dd-trace/src/analytics_sampler')
4
4
  const ClientPlugin = require('../../dd-trace/src/plugins/client')
5
5
  const { storage } = require('../../datadog-core')
6
6
  const { isTrue } = require('../../dd-trace/src/util')
7
- const coalesce = require('koalas')
8
7
  const { tagsFromRequest, tagsFromResponse } = require('../../dd-trace/src/payload-tagging')
9
8
  const { getEnvironmentVariable } = require('../../dd-trace/src/config-helper')
10
9
 
@@ -59,6 +58,7 @@ class BaseAwsSdkPlugin extends ClientPlugin {
59
58
  'aws.operation': operation,
60
59
  'aws.region': awsRegion,
61
60
  region: awsRegion,
61
+ 'aws.partition': getPartition(awsRegion),
62
62
  aws_service: awsService,
63
63
  'aws.service': awsService,
64
64
  component: 'aws-sdk'
@@ -115,6 +115,11 @@ class BaseAwsSdkPlugin extends ClientPlugin {
115
115
  span.setTag('aws.region', region)
116
116
  span.setTag('region', region)
117
117
 
118
+ const partition = getPartition(region)
119
+ if (partition) {
120
+ span.setTag('aws.partition', partition)
121
+ }
122
+
118
123
  if (!this._tracerConfig?._isInServerlessEnvironment()) return
119
124
 
120
125
  const hostname = getHostname(store, region)
@@ -267,13 +272,10 @@ function normalizeConfig (config, serviceIdentifier) {
267
272
  // check if AWS batch propagation or AWS_[SERVICE] batch propagation is enabled via env variable
268
273
  const serviceId = serviceIdentifier.toUpperCase()
269
274
  const batchPropagationEnabled = isTrue(
270
- coalesce(
271
- specificConfig.batchPropagationEnabled,
272
- getEnvironmentVariable(`DD_TRACE_AWS_SDK_${serviceId}_BATCH_PROPAGATION_ENABLED`),
273
- config.batchPropagationEnabled,
274
- getEnvironmentVariable('DD_TRACE_AWS_SDK_BATCH_PROPAGATION_ENABLED'),
275
- false
276
- )
275
+ specificConfig.batchPropagationEnabled ??
276
+ getEnvironmentVariable(`DD_TRACE_AWS_SDK_${serviceId}_BATCH_PROPAGATION_ENABLED`) ??
277
+ config.batchPropagationEnabled ??
278
+ getEnvironmentVariable('DD_TRACE_AWS_SDK_BATCH_PROPAGATION_ENABLED')
277
279
  )
278
280
 
279
281
  // Merge the specific config back into the main config
@@ -317,4 +319,17 @@ function getHostname (store, region) {
317
319
  }
318
320
  }
319
321
 
322
+ function getPartition (region) {
323
+ if (!region) return
324
+
325
+ let partition = 'aws'
326
+ if (region.startsWith('cn-')) {
327
+ partition = 'aws-cn'
328
+ } else if (region.startsWith('us-gov-')) {
329
+ partition = 'aws-us-gov'
330
+ }
331
+
332
+ return partition
333
+ }
334
+
320
335
  module.exports = BaseAwsSdkPlugin
@@ -3,7 +3,7 @@
3
3
  const BaseAwsSdkPlugin = require('../../base')
4
4
  const { parseModelId } = require('./utils')
5
5
 
6
- const enabledOperations = new Set(['invokeModel'])
6
+ const enabledOperations = new Set(['invokeModel', 'invokeModelWithResponseStream'])
7
7
 
8
8
  class BedrockRuntime extends BaseAwsSdkPlugin {
9
9
  static id = 'bedrockruntime'
@@ -17,7 +17,7 @@ class BedrockRuntime extends BaseAwsSdkPlugin {
17
17
  return super.isEnabled(request)
18
18
  }
19
19
 
20
- generateTags (params, operation, response) {
20
+ generateTags (params, operation) {
21
21
  const { modelProvider, modelName } = parseModelId(params.modelId)
22
22
 
23
23
  return {
@@ -23,6 +23,100 @@ const PROVIDER = {
23
23
  MISTRAL: 'MISTRAL'
24
24
  }
25
25
 
26
+ /**
27
+ * Coerce the chunks into a single response body.
28
+ *
29
+ * @param {Array<{ chunk: { bytes: Buffer } }>} chunks
30
+ * @param {string} provider
31
+ * @returns {Object}
32
+ */
33
+ function extractTextAndResponseReasonFromStream (chunks, modelProvider, modelName) {
34
+ const modelProviderUpper = modelProvider.toUpperCase()
35
+
36
+ // streaming unsupported for AMAZON embedding models, COHERE embedding models, STABILITY
37
+ if (
38
+ (modelProviderUpper === PROVIDER.AMAZON && modelName.includes('embed')) ||
39
+ (modelProviderUpper === PROVIDER.COHERE && modelName.includes('embed')) ||
40
+ modelProviderUpper === PROVIDER.STABILITY
41
+ ) {
42
+ return {}
43
+ }
44
+
45
+ let message = ''
46
+ let inputTokens = 0
47
+ let outputTokens = 0
48
+ let cacheReadTokens = 0
49
+ let cacheWriteTokens = 0
50
+
51
+ for (const { chunk: { bytes } } of chunks) {
52
+ const body = JSON.parse(Buffer.from(bytes).toString('utf8'))
53
+
54
+ switch (modelProviderUpper) {
55
+ case PROVIDER.AMAZON: {
56
+ message += body?.outputText
57
+
58
+ inputTokens = body?.inputTextTokenCount
59
+ outputTokens = body?.totalOutputTextTokenCount
60
+
61
+ break
62
+ }
63
+ case PROVIDER.AI21: {
64
+ const content = body?.choices?.[0]?.delta?.content
65
+ if (content) {
66
+ message += content
67
+ }
68
+
69
+ break
70
+ }
71
+ case PROVIDER.ANTHROPIC: {
72
+ if (body.completion) {
73
+ message += body.completion
74
+ } else if (body.delta?.text) {
75
+ message += body.delta.text
76
+ }
77
+
78
+ if (body.message?.usage?.input_tokens) inputTokens = body.message.usage.input_tokens
79
+ if (body.message?.usage?.output_tokens) outputTokens = body.message.usage.output_tokens
80
+
81
+ break
82
+ }
83
+ case PROVIDER.COHERE: {
84
+ if (body?.event_type === 'stream-end') {
85
+ message = body.response?.text
86
+ }
87
+
88
+ break
89
+ }
90
+ case PROVIDER.META: {
91
+ message += body?.generation
92
+ break
93
+ }
94
+ case PROVIDER.MISTRAL: {
95
+ message += body?.outputs?.[0]?.text
96
+ break
97
+ }
98
+ }
99
+
100
+ // by default, it seems newer versions of the AWS SDK include the input/output token counts in the response body
101
+ const invocationMetrics = body['amazon-bedrock-invocationMetrics']
102
+ if (invocationMetrics) {
103
+ inputTokens = invocationMetrics.inputTokenCount
104
+ outputTokens = invocationMetrics.outputTokenCount
105
+ cacheReadTokens = invocationMetrics.cacheReadInputTokenCount
106
+ cacheWriteTokens = invocationMetrics.cacheWriteInputTokenCount
107
+ }
108
+ }
109
+
110
+ return new Generation({
111
+ message,
112
+ role: 'assistant',
113
+ inputTokens,
114
+ outputTokens,
115
+ cacheReadTokens,
116
+ cacheWriteTokens
117
+ })
118
+ }
119
+
26
120
  class Generation {
27
121
  constructor ({
28
122
  message = '',
@@ -30,7 +124,9 @@ class Generation {
30
124
  choiceId = '',
31
125
  role,
32
126
  inputTokens,
33
- outputTokens
127
+ outputTokens,
128
+ cacheReadTokens,
129
+ cacheWriteTokens
34
130
  } = {}) {
35
131
  // stringify message as it could be a single generated message as well as a list of embeddings
36
132
  this.message = typeof message === 'string' ? message : JSON.stringify(message) || ''
@@ -39,7 +135,9 @@ class Generation {
39
135
  this.role = role
40
136
  this.usage = {
41
137
  inputTokens,
42
- outputTokens
138
+ outputTokens,
139
+ cacheReadTokens,
140
+ cacheWriteTokens
43
141
  }
44
142
  }
45
143
  }
@@ -334,6 +432,7 @@ function extractTextAndResponseReason (response, provider, modelName) {
334
432
  module.exports = {
335
433
  Generation,
336
434
  RequestParams,
435
+ extractTextAndResponseReasonFromStream,
337
436
  parseModelId,
338
437
  extractRequestParams,
339
438
  extractTextAndResponseReason,
@@ -135,7 +135,7 @@ const extractQueueMetadata = queueURL => {
135
135
  let partition = 'aws'
136
136
  if (region.startsWith('cn-')) {
137
137
  partition = 'aws-cn'
138
- } else if (region.startsWith('us-gov')) {
138
+ } else if (region.startsWith('us-gov-')) {
139
139
  partition = 'aws-us-gov'
140
140
  }
141
141