dd-trace 5.67.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.
- package/LICENSE-3rdparty.csv +0 -3
- package/README.md +0 -2
- package/ci/init.js +52 -54
- package/ext/exporters.d.ts +2 -1
- package/ext/exporters.js +2 -1
- package/index.d.ts +47 -2
- package/initialize.mjs +1 -1
- package/package.json +8 -11
- package/packages/datadog-esbuild/index.js +56 -0
- package/packages/datadog-instrumentations/src/aws-sdk.js +42 -4
- package/packages/datadog-instrumentations/src/azure-functions.js +1 -1
- package/packages/datadog-instrumentations/src/azure-service-bus.js +1 -1
- package/packages/datadog-instrumentations/src/cassandra-driver.js +2 -2
- package/packages/datadog-instrumentations/src/connect.js +6 -2
- package/packages/datadog-instrumentations/src/cucumber.js +31 -6
- package/packages/datadog-instrumentations/src/express.js +5 -6
- package/packages/datadog-instrumentations/src/fastify.js +3 -3
- package/packages/datadog-instrumentations/src/helpers/hook.js +28 -15
- package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
- package/packages/datadog-instrumentations/src/helpers/instrument.js +11 -2
- package/packages/datadog-instrumentations/src/helpers/register.js +10 -3
- package/packages/datadog-instrumentations/src/http2/client.js +1 -0
- package/packages/datadog-instrumentations/src/http2/server.js +0 -1
- package/packages/datadog-instrumentations/src/ioredis.js +12 -1
- package/packages/datadog-instrumentations/src/jest.js +48 -36
- package/packages/datadog-instrumentations/src/limitd-client.js +2 -1
- package/packages/datadog-instrumentations/src/mocha/main.js +15 -7
- package/packages/datadog-instrumentations/src/mocha/utils.js +3 -0
- package/packages/datadog-instrumentations/src/mongoose.js +2 -1
- package/packages/datadog-instrumentations/src/oracledb.js +19 -13
- package/packages/datadog-instrumentations/src/pg.js +9 -5
- package/packages/datadog-instrumentations/src/pino.js +18 -6
- package/packages/datadog-instrumentations/src/playwright.js +15 -1
- package/packages/datadog-instrumentations/src/sequelize.js +1 -1
- package/packages/datadog-instrumentations/src/vitest.js +155 -62
- package/packages/datadog-plugin-ai/src/tracing.js +3 -3
- package/packages/datadog-plugin-aws-sdk/src/base.js +23 -8
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/tracing.js +2 -2
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +101 -2
- package/packages/datadog-plugin-aws-sdk/src/util.js +1 -1
- package/packages/datadog-plugin-cucumber/src/index.js +4 -56
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +6 -2
- package/packages/datadog-plugin-cypress/src/support.js +4 -0
- package/packages/datadog-plugin-express/src/code_origin.js +2 -2
- package/packages/datadog-plugin-fastify/src/code_origin.js +1 -2
- package/packages/datadog-plugin-jest/src/index.js +0 -21
- package/packages/datadog-plugin-mocha/src/index.js +3 -57
- package/packages/datadog-plugin-mongodb-core/src/index.js +20 -7
- package/packages/datadog-plugin-playwright/src/index.js +11 -5
- package/packages/datadog-plugin-vitest/src/index.js +5 -1
- package/packages/datadog-plugin-ws/src/close.js +1 -1
- package/packages/datadog-plugin-ws/src/producer.js +6 -1
- package/packages/datadog-plugin-ws/src/receiver.js +6 -1
- package/packages/dd-trace/src/appsec/iast/security-controls/parser.js +1 -1
- package/packages/dd-trace/src/appsec/telemetry/waf.js +2 -2
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +4 -4
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +11 -3
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +10 -1
- package/packages/dd-trace/src/config.js +69 -304
- package/packages/dd-trace/src/config_defaults.js +186 -0
- package/packages/dd-trace/src/crashtracking/crashtracker.js +2 -1
- package/packages/dd-trace/src/datastreams/fnv.js +2 -2
- package/packages/dd-trace/src/datastreams/writer.js +3 -2
- package/packages/dd-trace/src/debugger/devtools_client/config.js +2 -1
- package/packages/dd-trace/src/dogstatsd.js +4 -3
- package/packages/dd-trace/src/encode/0.4.js +1 -5
- package/packages/dd-trace/src/exporter.js +1 -0
- package/packages/dd-trace/src/exporters/agent/index.js +3 -2
- package/packages/dd-trace/src/exporters/agent/writer.js +1 -1
- package/packages/dd-trace/src/exporters/common/agent-info-exporter.js +3 -2
- package/packages/dd-trace/src/exporters/common/request.js +2 -1
- package/packages/dd-trace/src/exporters/span-stats/index.js +3 -2
- package/packages/dd-trace/src/llmobs/constants/tags.js +2 -0
- package/packages/dd-trace/src/llmobs/plugins/ai/index.js +4 -3
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +12 -1
- package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +40 -13
- package/packages/dd-trace/src/llmobs/plugins/openai.js +7 -1
- package/packages/dd-trace/src/llmobs/tagger.js +8 -0
- package/packages/dd-trace/src/llmobs/telemetry.js +2 -1
- package/packages/dd-trace/src/log/index.js +28 -17
- package/packages/dd-trace/src/log/log.js +29 -5
- package/packages/dd-trace/src/log/writer.js +5 -5
- package/packages/dd-trace/src/noop/span.js +1 -0
- package/packages/dd-trace/src/opentelemetry/span.js +14 -3
- package/packages/dd-trace/src/opentracing/span.js +18 -4
- package/packages/dd-trace/src/plugin_manager.js +20 -2
- package/packages/dd-trace/src/plugins/ci_plugin.js +97 -3
- package/packages/dd-trace/src/plugins/index.js +2 -0
- package/packages/dd-trace/src/plugins/util/git-cache.js +129 -0
- package/packages/dd-trace/src/plugins/util/git.js +40 -26
- package/packages/dd-trace/src/plugins/util/test.js +37 -27
- package/packages/dd-trace/src/plugins/util/web.js +1 -1
- package/packages/dd-trace/src/profiler.js +4 -1
- package/packages/dd-trace/src/profiling/config.js +73 -42
- package/packages/dd-trace/src/profiling/profiler.js +3 -1
- package/packages/dd-trace/src/profiling/profilers/events.js +3 -8
- package/packages/dd-trace/src/profiling/profilers/space.js +1 -0
- package/packages/dd-trace/src/profiling/profilers/wall.js +196 -117
- package/packages/dd-trace/src/remote_config/capabilities.js +5 -0
- package/packages/dd-trace/src/remote_config/manager.js +3 -2
- package/packages/dd-trace/src/startup-log.js +2 -1
- package/packages/dd-trace/src/supported-configurations.json +3 -0
- package/packages/dd-trace/src/telemetry/logs/index.js +2 -2
- package/register.js +1 -1
|
@@ -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
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
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
|
-
|
|
250
|
-
|
|
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',
|
|
322
|
-
|
|
346
|
+
shimmer.wrap(this.ctx, 'exit', getFinishWrapper)
|
|
347
|
+
shimmer.wrap(this.ctx, 'close', getFinishWrapper)
|
|
323
348
|
|
|
324
|
-
|
|
325
|
-
|
|
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
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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',
|
|
354
|
-
|
|
355
|
-
|
|
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
|
-
|
|
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
|
|
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(
|
|
16
|
+
this.startSpan(name, {
|
|
17
17
|
meta: {
|
|
18
|
-
'resource.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
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
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
|
|
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
|
|
|
@@ -21,12 +21,6 @@ const {
|
|
|
21
21
|
TEST_EARLY_FLAKE_ABORT_REASON,
|
|
22
22
|
TEST_IS_NEW,
|
|
23
23
|
TEST_IS_RETRY,
|
|
24
|
-
TEST_SUITE_ID,
|
|
25
|
-
TEST_SESSION_ID,
|
|
26
|
-
TEST_COMMAND,
|
|
27
|
-
TEST_MODULE,
|
|
28
|
-
TEST_MODULE_ID,
|
|
29
|
-
TEST_SUITE,
|
|
30
24
|
CUCUMBER_IS_PARALLEL,
|
|
31
25
|
TEST_RETRY_REASON,
|
|
32
26
|
TEST_MANAGEMENT_ENABLED,
|
|
@@ -55,25 +49,11 @@ const {
|
|
|
55
49
|
TEST_BROWSER_DRIVER,
|
|
56
50
|
TELEMETRY_TEST_SESSION
|
|
57
51
|
} = require('../../dd-trace/src/ci-visibility/telemetry')
|
|
58
|
-
const id = require('../../dd-trace/src/id')
|
|
59
52
|
|
|
60
53
|
const BREAKPOINT_HIT_GRACE_PERIOD_MS = 200
|
|
61
54
|
const BREAKPOINT_SET_GRACE_PERIOD_MS = 200
|
|
62
55
|
const isCucumberWorker = !!getEnvironmentVariable('CUCUMBER_WORKER_ID')
|
|
63
56
|
|
|
64
|
-
function getTestSuiteTags (testSuiteSpan) {
|
|
65
|
-
const suiteTags = {
|
|
66
|
-
[TEST_SUITE_ID]: testSuiteSpan.context().toSpanId(),
|
|
67
|
-
[TEST_SESSION_ID]: testSuiteSpan.context().toTraceId(),
|
|
68
|
-
[TEST_COMMAND]: testSuiteSpan.context()._tags[TEST_COMMAND],
|
|
69
|
-
[TEST_MODULE]: 'cucumber'
|
|
70
|
-
}
|
|
71
|
-
if (testSuiteSpan.context()._parentId) {
|
|
72
|
-
suiteTags[TEST_MODULE_ID] = testSuiteSpan.context()._parentId.toString(10)
|
|
73
|
-
}
|
|
74
|
-
return suiteTags
|
|
75
|
-
}
|
|
76
|
-
|
|
77
57
|
class CucumberPlugin extends CiPlugin {
|
|
78
58
|
static id = 'cucumber'
|
|
79
59
|
|
|
@@ -82,8 +62,6 @@ class CucumberPlugin extends CiPlugin {
|
|
|
82
62
|
|
|
83
63
|
this.sourceRoot = process.cwd()
|
|
84
64
|
|
|
85
|
-
this.testSuiteSpanByPath = {}
|
|
86
|
-
|
|
87
65
|
this.addSub('ci:cucumber:session:finish', ({
|
|
88
66
|
status,
|
|
89
67
|
isSuitesSkipped,
|
|
@@ -185,7 +163,7 @@ class CucumberPlugin extends CiPlugin {
|
|
|
185
163
|
},
|
|
186
164
|
integrationName: this.constructor.id
|
|
187
165
|
})
|
|
188
|
-
this.
|
|
166
|
+
this._testSuiteSpansByTestSuite.set(testSuitePath, testSuiteSpan)
|
|
189
167
|
|
|
190
168
|
this.telemetry.ciVisEvent(TELEMETRY_EVENT_CREATED, 'suite')
|
|
191
169
|
if (this.libraryConfig?.isCodeCoverageEnabled) {
|
|
@@ -194,7 +172,7 @@ class CucumberPlugin extends CiPlugin {
|
|
|
194
172
|
})
|
|
195
173
|
|
|
196
174
|
this.addSub('ci:cucumber:test-suite:finish', ({ status, testSuitePath }) => {
|
|
197
|
-
const testSuiteSpan = this.
|
|
175
|
+
const testSuiteSpan = this._testSuiteSpansByTestSuite.get(testSuitePath)
|
|
198
176
|
testSuiteSpan.setTag(TEST_STATUS, status)
|
|
199
177
|
testSuiteSpan.finish()
|
|
200
178
|
this.telemetry.ciVisEvent(TELEMETRY_EVENT_FINISHED, 'suite')
|
|
@@ -207,7 +185,7 @@ class CucumberPlugin extends CiPlugin {
|
|
|
207
185
|
if (!coverageFiles.length) {
|
|
208
186
|
this.telemetry.count(TELEMETRY_CODE_COVERAGE_EMPTY)
|
|
209
187
|
}
|
|
210
|
-
const testSuiteSpan = this.
|
|
188
|
+
const testSuiteSpan = this._testSuiteSpansByTestSuite.get(testSuitePath)
|
|
211
189
|
|
|
212
190
|
const relativeCoverageFiles = [...coverageFiles, suiteFile]
|
|
213
191
|
.map(filename => getTestSuitePath(filename, this.repositoryRoot))
|
|
@@ -303,36 +281,6 @@ class CucumberPlugin extends CiPlugin {
|
|
|
303
281
|
return ctx.currentStore
|
|
304
282
|
})
|
|
305
283
|
|
|
306
|
-
this.addSub('ci:cucumber:worker-report:trace', (traces) => {
|
|
307
|
-
const formattedTraces = JSON.parse(traces).map(trace =>
|
|
308
|
-
trace.map(span => ({
|
|
309
|
-
...span,
|
|
310
|
-
span_id: id(span.span_id),
|
|
311
|
-
trace_id: id(span.trace_id),
|
|
312
|
-
parent_id: id(span.parent_id)
|
|
313
|
-
}))
|
|
314
|
-
)
|
|
315
|
-
|
|
316
|
-
// We have to update the test session, test module and test suite ids
|
|
317
|
-
// before we export them in the main process
|
|
318
|
-
formattedTraces.forEach(trace => {
|
|
319
|
-
trace.forEach(span => {
|
|
320
|
-
if (span.name === 'cucumber.test') {
|
|
321
|
-
const testSuite = span.meta[TEST_SUITE]
|
|
322
|
-
const testSuiteSpan = this.testSuiteSpanByPath[testSuite]
|
|
323
|
-
|
|
324
|
-
const testSuiteTags = getTestSuiteTags(testSuiteSpan)
|
|
325
|
-
span.meta = {
|
|
326
|
-
...span.meta,
|
|
327
|
-
...testSuiteTags
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
})
|
|
331
|
-
|
|
332
|
-
this.tracer._exporter.export(trace)
|
|
333
|
-
})
|
|
334
|
-
})
|
|
335
|
-
|
|
336
284
|
this.addSub('ci:cucumber:test:finish', ({
|
|
337
285
|
span,
|
|
338
286
|
isStep,
|
|
@@ -501,7 +449,7 @@ class CucumberPlugin extends CiPlugin {
|
|
|
501
449
|
}
|
|
502
450
|
|
|
503
451
|
startTestSpan (testName, testSuite, extraTags) {
|
|
504
|
-
const testSuiteSpan = this.
|
|
452
|
+
const testSuiteSpan = this._testSuiteSpansByTestSuite.get(testSuite)
|
|
505
453
|
return super.startTestSpan(
|
|
506
454
|
testName,
|
|
507
455
|
testSuite,
|