dd-trace 6.9.0 → 6.10.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/ci/vitest-no-worker-init-setup.mjs +112 -10
- package/index.d.ts +42 -0
- package/package.json +4 -3
- package/packages/datadog-instrumentations/src/confluentinc-kafka-javascript.js +111 -6
- package/packages/datadog-instrumentations/src/helpers/pool-acquire.js +629 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +2 -1
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +81 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +1 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +83 -1
- package/packages/datadog-instrumentations/src/jest.js +1 -1
- package/packages/datadog-instrumentations/src/mocha/main.js +1 -1
- package/packages/datadog-instrumentations/src/mocha/utils.js +2 -8
- package/packages/datadog-instrumentations/src/mysql.js +45 -15
- package/packages/datadog-instrumentations/src/mysql2.js +119 -18
- package/packages/datadog-instrumentations/src/path-to-regexp.js +67 -1
- package/packages/datadog-instrumentations/src/pg.js +116 -92
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +43 -4
- package/packages/datadog-instrumentations/src/vitest-main.js +169 -17
- package/packages/datadog-instrumentations/src/vitest-util.js +64 -5
- package/packages/datadog-instrumentations/src/vitest-worker.js +150 -25
- package/packages/datadog-instrumentations/src/webdriverio.js +31 -17
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/trace-checkpoint.js +12 -6
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +2 -5
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +1 -5
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +1 -1
- package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +31 -17
- package/packages/datadog-plugin-jest/src/index.js +5 -4
- package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +2 -3
- package/packages/datadog-plugin-kafkajs/src/consumer.js +2 -3
- package/packages/datadog-plugin-kafkajs/src/producer.js +3 -2
- package/packages/datadog-plugin-kafkajs/src/utils.js +65 -7
- package/packages/datadog-plugin-mocha/src/index.js +550 -39
- package/packages/datadog-plugin-mysql/src/index.js +37 -0
- package/packages/datadog-plugin-next/src/index.js +1 -19
- package/packages/datadog-plugin-openai-agents/src/integration.js +278 -69
- package/packages/datadog-plugin-openai-agents/src/processor.js +16 -4
- package/packages/datadog-plugin-pg/src/index.js +1 -0
- package/packages/datadog-plugin-vitest/src/index.js +8 -20
- package/packages/datadog-plugin-ws/src/util.js +2 -1
- package/packages/dd-trace/src/appsec/api_security/normalized-route.js +453 -0
- package/packages/dd-trace/src/appsec/handlers/http-request.js +13 -0
- package/packages/dd-trace/src/carrier.js +356 -0
- package/packages/dd-trace/src/config/generated-config-types.d.ts +3 -0
- package/packages/dd-trace/src/config/supported-configurations.json +10 -0
- package/packages/dd-trace/src/datastreams/context.js +6 -1
- package/packages/dd-trace/src/datastreams/manager.js +5 -1
- package/packages/dd-trace/src/datastreams/pathway.js +23 -22
- package/packages/dd-trace/src/datastreams/processor.js +3 -2
- package/packages/dd-trace/src/llmobs/constants/tags.js +5 -0
- package/packages/dd-trace/src/llmobs/index.js +34 -2
- package/packages/dd-trace/src/llmobs/span_processor.js +16 -0
- package/packages/dd-trace/src/llmobs/tagger.js +96 -0
- package/packages/dd-trace/src/llmobs/util.js +78 -0
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +126 -120
- package/packages/dd-trace/src/opentracing/propagation/text_map_dsm.js +4 -8
- package/packages/dd-trace/src/plugin_manager.js +2 -0
- package/packages/{datadog-plugin-jest/src/util.js → dd-trace/src/plugins/util/jest.js} +1 -62
- package/packages/dd-trace/src/plugins/util/test.js +84 -5
- package/packages/dd-trace/src/plugins/util/web.js +53 -2
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
const path = require('node:path')
|
|
4
4
|
const { performance } = require('node:perf_hooks')
|
|
5
5
|
const { fileURLToPath } = require('node:url')
|
|
6
|
+
const { isMainThread, parentPort } = require('node:worker_threads')
|
|
6
7
|
|
|
7
8
|
const shimmer = require('../../datadog-shimmer')
|
|
8
9
|
const log = require('../../dd-trace/src/log')
|
|
@@ -12,6 +13,8 @@ const {
|
|
|
12
13
|
getTestSuitePath,
|
|
13
14
|
recordAttemptToFixExecution,
|
|
14
15
|
logAttemptToFixTestExecution,
|
|
16
|
+
VITEST_WORKER_EFD_SUITE_ADMISSION_REQUEST_CODE,
|
|
17
|
+
VITEST_WORKER_EFD_SUITE_ADMISSION_RESPONSE_CODE,
|
|
15
18
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
16
19
|
const { getChannelPromise } = require('./helpers/channel')
|
|
17
20
|
const { addHook } = require('./helpers/instrument')
|
|
@@ -36,12 +39,15 @@ const {
|
|
|
36
39
|
getVitestTestProperties,
|
|
37
40
|
} = require('./vitest-util')
|
|
38
41
|
|
|
42
|
+
const EFD_SUITE_ADMISSION_TIMEOUT_MS = 5000
|
|
39
43
|
const taskToCtx = new WeakMap()
|
|
40
44
|
const taskToTestProperties = new WeakMap()
|
|
41
45
|
const taskToStatuses = new WeakMap()
|
|
42
46
|
const taskToReportedErrorCount = new WeakMap()
|
|
43
47
|
const attemptToFixTaskToStatuses = new WeakMap()
|
|
44
48
|
const fileToHasConcurrentTests = new WeakMap()
|
|
49
|
+
const fileToEfdSuiteAdmission = new WeakMap()
|
|
50
|
+
const pendingEfdSuiteAdmissionRequests = new Map()
|
|
45
51
|
const originalHookFns = new WeakMap()
|
|
46
52
|
const newTasks = new WeakSet()
|
|
47
53
|
const dynamicNameTasks = new WeakSet()
|
|
@@ -62,6 +68,9 @@ let vitestGetFn = null
|
|
|
62
68
|
let vitestSetFn = null
|
|
63
69
|
let vitestGetHooks = null
|
|
64
70
|
let preciseCoverageSession
|
|
71
|
+
let didInitializeEfdSuiteAdmissionTransport = false
|
|
72
|
+
let nextEfdSuiteAdmissionRequestId = 0
|
|
73
|
+
let sendEfdSuiteAdmissionMessage
|
|
65
74
|
let isPreciseCoverageUnavailable = false
|
|
66
75
|
let vitestCoverageSnapshot
|
|
67
76
|
const wrappedCoverageWorkerStates = new WeakSet()
|
|
@@ -348,6 +357,123 @@ function hasConcurrentTests (file) {
|
|
|
348
357
|
return hasConcurrent
|
|
349
358
|
}
|
|
350
359
|
|
|
360
|
+
/**
|
|
361
|
+
* Returns whether a collected Vitest file contains a runnable new test eligible for EFD.
|
|
362
|
+
*
|
|
363
|
+
* @param {{ filepath: string, tasks?: object[] }} file
|
|
364
|
+
* @param {object} providedContext
|
|
365
|
+
* @returns {boolean}
|
|
366
|
+
*/
|
|
367
|
+
function hasRunnableNewTest (file, providedContext) {
|
|
368
|
+
for (const task of getTypeTasks(file.tasks)) {
|
|
369
|
+
if (task.mode === 'skip' || task.mode === 'todo') continue
|
|
370
|
+
|
|
371
|
+
const testProperties = getVitestTestProperties(providedContext, file.filepath, getTestName(task))
|
|
372
|
+
if (testProperties.isNew && !testProperties.isAttemptToFix && !testProperties.isDisabled) {
|
|
373
|
+
return true
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
return false
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Resolves and removes one pending EFD suite admission request.
|
|
381
|
+
*
|
|
382
|
+
* @param {number} requestId
|
|
383
|
+
* @param {boolean} allowed
|
|
384
|
+
* @returns {void}
|
|
385
|
+
*/
|
|
386
|
+
function finishEfdSuiteAdmissionRequest (requestId, allowed) {
|
|
387
|
+
const request = pendingEfdSuiteAdmissionRequests.get(requestId)
|
|
388
|
+
if (!request) return
|
|
389
|
+
|
|
390
|
+
clearTimeout(request.timeout)
|
|
391
|
+
pendingEfdSuiteAdmissionRequests.delete(requestId)
|
|
392
|
+
request.resolve(allowed)
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Handles an EFD suite admission response from the Vitest main process.
|
|
397
|
+
*
|
|
398
|
+
* @param {unknown} message
|
|
399
|
+
* @returns {void}
|
|
400
|
+
*/
|
|
401
|
+
function handleEfdSuiteAdmissionResponse (message) {
|
|
402
|
+
if (!Array.isArray(message) || message[0] !== VITEST_WORKER_EFD_SUITE_ADMISSION_RESPONSE_CODE) return
|
|
403
|
+
|
|
404
|
+
const { allowed, requestId } = message[1] || {}
|
|
405
|
+
if (Number.isSafeInteger(requestId)) {
|
|
406
|
+
finishEfdSuiteAdmissionRequest(requestId, allowed === true)
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Returns the child-process or worker-thread sender used by the current Vitest worker.
|
|
412
|
+
*
|
|
413
|
+
* @returns {((message: unknown) => void)|undefined}
|
|
414
|
+
*/
|
|
415
|
+
function getEfdSuiteAdmissionSender () {
|
|
416
|
+
if (didInitializeEfdSuiteAdmissionTransport) return sendEfdSuiteAdmissionMessage
|
|
417
|
+
didInitializeEfdSuiteAdmissionTransport = true
|
|
418
|
+
|
|
419
|
+
if (typeof process.send === 'function') {
|
|
420
|
+
process.on('message', handleEfdSuiteAdmissionResponse)
|
|
421
|
+
sendEfdSuiteAdmissionMessage = process.send.bind(process)
|
|
422
|
+
} else if (!isMainThread && parentPort) {
|
|
423
|
+
parentPort.on('message', handleEfdSuiteAdmissionResponse)
|
|
424
|
+
sendEfdSuiteAdmissionMessage = parentPort.postMessage.bind(parentPort)
|
|
425
|
+
}
|
|
426
|
+
return sendEfdSuiteAdmissionMessage
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* Requests permission from the Vitest main process to schedule EFD retries for one suite.
|
|
431
|
+
*
|
|
432
|
+
* @param {string} testSuite
|
|
433
|
+
* @param {boolean} hasNewTest
|
|
434
|
+
* @returns {Promise<boolean>}
|
|
435
|
+
*/
|
|
436
|
+
function requestEfdSuiteAdmission (testSuite, hasNewTest) {
|
|
437
|
+
const sendMessage = getEfdSuiteAdmissionSender()
|
|
438
|
+
if (!sendMessage) return Promise.resolve(false)
|
|
439
|
+
|
|
440
|
+
const requestId = ++nextEfdSuiteAdmissionRequestId
|
|
441
|
+
return new Promise(resolve => {
|
|
442
|
+
const timeout = setTimeout(
|
|
443
|
+
() => finishEfdSuiteAdmissionRequest(requestId, false),
|
|
444
|
+
EFD_SUITE_ADMISSION_TIMEOUT_MS
|
|
445
|
+
)
|
|
446
|
+
timeout.unref?.()
|
|
447
|
+
pendingEfdSuiteAdmissionRequests.set(requestId, { resolve, timeout })
|
|
448
|
+
|
|
449
|
+
try {
|
|
450
|
+
sendMessage([VITEST_WORKER_EFD_SUITE_ADMISSION_REQUEST_CODE, { hasNewTest, requestId, testSuite }])
|
|
451
|
+
} catch {
|
|
452
|
+
finishEfdSuiteAdmissionRequest(requestId, false)
|
|
453
|
+
}
|
|
454
|
+
})
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* Requests a single EFD admission decision for all tests collected in a Vitest file.
|
|
459
|
+
*
|
|
460
|
+
* @param {{ file: { filepath: string, tasks?: object[] } }} task
|
|
461
|
+
* @param {object} providedContext
|
|
462
|
+
* @param {string|undefined} testSuite
|
|
463
|
+
* @returns {Promise<boolean>}
|
|
464
|
+
*/
|
|
465
|
+
function isEfdSuiteAdmissionAllowed (task, providedContext, testSuite) {
|
|
466
|
+
let admission = fileToEfdSuiteAdmission.get(task.file)
|
|
467
|
+
if (admission) return admission
|
|
468
|
+
|
|
469
|
+
admission = requestEfdSuiteAdmission(
|
|
470
|
+
testSuite || task.file.filepath,
|
|
471
|
+
hasRunnableNewTest(task.file, providedContext)
|
|
472
|
+
)
|
|
473
|
+
fileToEfdSuiteAdmission.set(task.file, admission)
|
|
474
|
+
return admission
|
|
475
|
+
}
|
|
476
|
+
|
|
351
477
|
/**
|
|
352
478
|
* Gets the task associated with a Vitest hook invocation.
|
|
353
479
|
*
|
|
@@ -383,7 +509,7 @@ function wrapSuiteHookFn (hookType, fn, fallbackTask) {
|
|
|
383
509
|
function wrapVitestTestRunner (VitestTestRunner) {
|
|
384
510
|
// `onBeforeRunTask` is run before any repetition or attempt is run
|
|
385
511
|
// `onBeforeRunTask` is an async function
|
|
386
|
-
shimmer.wrap(VitestTestRunner.prototype, 'onBeforeRunTask', onBeforeRunTask => function (task) {
|
|
512
|
+
shimmer.wrap(VitestTestRunner.prototype, 'onBeforeRunTask', onBeforeRunTask => async function (task) {
|
|
387
513
|
const testName = getTestName(task)
|
|
388
514
|
|
|
389
515
|
const providedContext = getProvidedContext()
|
|
@@ -426,35 +552,38 @@ function wrapVitestTestRunner (VitestTestRunner) {
|
|
|
426
552
|
}
|
|
427
553
|
|
|
428
554
|
if (isImpactedTestsEnabled && testProperties.isModified) {
|
|
429
|
-
if (isEarlyFlakeDetectionEnabled) {
|
|
430
|
-
efdRetryTasks.add(task)
|
|
431
|
-
disableFrameworkRetries(task)
|
|
432
|
-
task.repeats = earlyFlakeDetectionRetryPolicy.schedulingRetryCount
|
|
433
|
-
}
|
|
434
555
|
modifiedTasks.add(task)
|
|
435
|
-
taskToStatuses.set(task, [])
|
|
436
556
|
}
|
|
437
557
|
|
|
438
558
|
if (isKnownTestsEnabled && testProperties.isNew && !attemptToFixTasks.has(task)) {
|
|
439
|
-
if (isEarlyFlakeDetectionEnabled && !modifiedTasks.has(task)) {
|
|
440
|
-
efdRetryTasks.add(task)
|
|
441
|
-
disableFrameworkRetries(task)
|
|
442
|
-
task.repeats = earlyFlakeDetectionRetryPolicy.schedulingRetryCount
|
|
443
|
-
}
|
|
444
559
|
newTasks.add(task)
|
|
445
|
-
taskToStatuses.set(task, [])
|
|
446
560
|
if (DYNAMIC_NAME_RE.test(testName)) {
|
|
447
561
|
dynamicNameTasks.add(task)
|
|
448
562
|
}
|
|
449
563
|
}
|
|
450
564
|
|
|
565
|
+
const isEfdCandidate = isEarlyFlakeDetectionEnabled &&
|
|
566
|
+
!attemptToFixTasks.has(task) &&
|
|
567
|
+
!disabledTasks.has(task) &&
|
|
568
|
+
(modifiedTasks.has(task) || newTasks.has(task))
|
|
569
|
+
if (isEfdCandidate) {
|
|
570
|
+
const isAdmissionAllowed = !providedContext.isEfdSuiteAdmissionEnabled ||
|
|
571
|
+
await isEfdSuiteAdmissionAllowed(task, providedContext, testProperties.testSuite)
|
|
572
|
+
if (isAdmissionAllowed) {
|
|
573
|
+
efdRetryTasks.add(task)
|
|
574
|
+
disableFrameworkRetries(task)
|
|
575
|
+
task.repeats = earlyFlakeDetectionRetryPolicy.schedulingRetryCount
|
|
576
|
+
taskToStatuses.set(task, [])
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
|
|
451
580
|
return onBeforeRunTask.apply(this, arguments)
|
|
452
581
|
})
|
|
453
582
|
|
|
454
583
|
// `onAfterRunTask` is run after all repetitions or attempts are run
|
|
455
584
|
// `onAfterRunTask` is an async function
|
|
456
585
|
shimmer.wrap(VitestTestRunner.prototype, 'onAfterRunTask', onAfterRunTask => function (task) {
|
|
457
|
-
const {
|
|
586
|
+
const { isTestManagementTestsEnabled } = getProvidedContext()
|
|
458
587
|
|
|
459
588
|
if (isTestManagementTestsEnabled) {
|
|
460
589
|
const isAttemptingToFix = attemptToFixTasks.has(task)
|
|
@@ -476,7 +605,7 @@ function wrapVitestTestRunner (VitestTestRunner) {
|
|
|
476
605
|
}
|
|
477
606
|
}
|
|
478
607
|
|
|
479
|
-
if (
|
|
608
|
+
if (efdRetryTasks.has(task)) {
|
|
480
609
|
const statuses = taskToStatuses.get(task)
|
|
481
610
|
// If the test has passed at least once, we consider it passed
|
|
482
611
|
if (statuses.includes('pass')) {
|
|
@@ -501,7 +630,6 @@ function wrapVitestTestRunner (VitestTestRunner) {
|
|
|
501
630
|
const providedContext = getProvidedContext()
|
|
502
631
|
const {
|
|
503
632
|
isKnownTestsEnabled,
|
|
504
|
-
isEarlyFlakeDetectionEnabled,
|
|
505
633
|
isDiEnabled,
|
|
506
634
|
earlyFlakeDetectionRetryPolicy,
|
|
507
635
|
} = providedContext
|
|
@@ -512,7 +640,7 @@ function wrapVitestTestRunner (VitestTestRunner) {
|
|
|
512
640
|
|
|
513
641
|
const { retry: numAttempt, repeats: numRepetition } = retryInfo
|
|
514
642
|
const isFailedTestReplayAllowed = !hasConcurrentTests(task.file)
|
|
515
|
-
const isEfdManagedTask =
|
|
643
|
+
const isEfdManagedTask = efdRetryTasks.has(task)
|
|
516
644
|
|
|
517
645
|
if (isEfdManagedTask && numRepetition > 0 && !efdDeterminedRetries.has(task)) {
|
|
518
646
|
const previousExecutionStart = efdExecutionStartByTask.get(task)
|
|
@@ -574,8 +702,9 @@ function wrapVitestTestRunner (VitestTestRunner) {
|
|
|
574
702
|
|
|
575
703
|
const lastExecutionStatus = task.result.state
|
|
576
704
|
const isAtf = attemptToFixTasks.has(task)
|
|
577
|
-
const
|
|
578
|
-
const
|
|
705
|
+
const isEfd = efdRetryTasks.has(task)
|
|
706
|
+
const shouldTrackStatuses = isEfd || isAtf
|
|
707
|
+
const shouldFlipStatus = isEfd || isAtf
|
|
579
708
|
const statuses = isAtf ? attemptToFixTaskToStatuses.get(task) : taskToStatuses.get(task)
|
|
580
709
|
|
|
581
710
|
// These clauses handle task.repeats, whether EFD is enabled or not
|
|
@@ -697,7 +826,6 @@ function wrapVitestTestRunner (VitestTestRunner) {
|
|
|
697
826
|
const result = await onAfterTryTask.apply(this, arguments)
|
|
698
827
|
|
|
699
828
|
const {
|
|
700
|
-
isEarlyFlakeDetectionEnabled,
|
|
701
829
|
testManagementAttemptToFixRetries,
|
|
702
830
|
earlyFlakeDetectionRetryPolicy,
|
|
703
831
|
} = getProvidedContext()
|
|
@@ -719,10 +847,8 @@ function wrapVitestTestRunner (VitestTestRunner) {
|
|
|
719
847
|
}
|
|
720
848
|
|
|
721
849
|
if (
|
|
722
|
-
|
|
850
|
+
efdRetryTasks.has(task) &&
|
|
723
851
|
(retryInfo.repeats ?? 0) === 0 &&
|
|
724
|
-
taskToStatuses.has(task) &&
|
|
725
|
-
!attemptToFixTasks.has(task) &&
|
|
726
852
|
!efdDeterminedRetries.has(task)
|
|
727
853
|
) {
|
|
728
854
|
const executionStart = efdExecutionStartByTask.get(task)
|
|
@@ -921,8 +1047,7 @@ addHook({
|
|
|
921
1047
|
}
|
|
922
1048
|
|
|
923
1049
|
// Check if all EFD retries failed
|
|
924
|
-
const isEfdRetry =
|
|
925
|
-
providedContext.isEarlyFlakeDetectionEnabled && (newTasks.has(task) || modifiedTasks.has(task))
|
|
1050
|
+
const isEfdRetry = efdRetryTasks.has(task)
|
|
926
1051
|
if (isEfdRetry) {
|
|
927
1052
|
const statuses = taskToStatuses.get(task)
|
|
928
1053
|
const efdRetryCount = efdDeterminedRetries.get(task) ??
|
|
@@ -171,7 +171,7 @@ function createWorkerConfiguration () {
|
|
|
171
171
|
}
|
|
172
172
|
|
|
173
173
|
/**
|
|
174
|
-
* Configures a Jasmine worker
|
|
174
|
+
* Configures a Jasmine worker and waits for its coordinator-owned optimization settings.
|
|
175
175
|
*
|
|
176
176
|
* @param {{_jrunner?: {env?: {addReporter?: (reporter: object) => void}}, _specs?: string[]}} adapter
|
|
177
177
|
* @param {{
|
|
@@ -185,13 +185,7 @@ function initializeJasmineWorker (adapter, context) {
|
|
|
185
185
|
return
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
-
|
|
189
|
-
libraryConfig: createWorkerConfiguration(),
|
|
190
|
-
repositoryRoot: undefined,
|
|
191
|
-
specs: adapter?._specs || [],
|
|
192
|
-
testFramework: TEST_FRAMEWORK,
|
|
193
|
-
testFrameworkAdapter: JASMINE_FRAMEWORK_ADAPTER,
|
|
194
|
-
})
|
|
188
|
+
const specs = adapter?._specs || []
|
|
195
189
|
|
|
196
190
|
if (jasmineDoneCh.hasSubscribers) {
|
|
197
191
|
adapter?._jrunner?.env?.addReporter?.({
|
|
@@ -220,9 +214,10 @@ function initializeJasmineWorker (adapter, context) {
|
|
|
220
214
|
/**
|
|
221
215
|
* Releases Jasmine initialization exactly once.
|
|
222
216
|
*
|
|
217
|
+
* @param {object} [configuration]
|
|
223
218
|
* @returns {void}
|
|
224
219
|
*/
|
|
225
|
-
function finish () {
|
|
220
|
+
function finish (configuration = createWorkerConfiguration()) {
|
|
226
221
|
if (finished) {
|
|
227
222
|
return
|
|
228
223
|
}
|
|
@@ -230,6 +225,13 @@ function initializeJasmineWorker (adapter, context) {
|
|
|
230
225
|
clearTimeout(timeout)
|
|
231
226
|
process.off('message', onMessage)
|
|
232
227
|
process.off('disconnect', finish)
|
|
228
|
+
workerConfigurationCh.publish({
|
|
229
|
+
libraryConfig: configuration,
|
|
230
|
+
repositoryRoot: configuration.repositoryRoot,
|
|
231
|
+
specs,
|
|
232
|
+
testFramework: TEST_FRAMEWORK,
|
|
233
|
+
testFrameworkAdapter: JASMINE_FRAMEWORK_ADAPTER,
|
|
234
|
+
})
|
|
233
235
|
onDone()
|
|
234
236
|
}
|
|
235
237
|
|
|
@@ -241,7 +243,7 @@ function initializeJasmineWorker (adapter, context) {
|
|
|
241
243
|
*/
|
|
242
244
|
function onMessage (message) {
|
|
243
245
|
if (message?.name === WORKER_READY_RESPONSE && message.content?.requestId === requestId) {
|
|
244
|
-
finish()
|
|
246
|
+
finish(message.content.configuration)
|
|
245
247
|
}
|
|
246
248
|
}
|
|
247
249
|
|
|
@@ -446,6 +448,18 @@ function getMochaFrameworkData (frameworkData) {
|
|
|
446
448
|
return frameworkData?.[TEST_FRAMEWORK] ?? frameworkData?.mocha
|
|
447
449
|
}
|
|
448
450
|
|
|
451
|
+
/**
|
|
452
|
+
* Applies the worker configuration for an EFD session with faulty known-tests data.
|
|
453
|
+
*
|
|
454
|
+
* @param {object} configuration
|
|
455
|
+
* @returns {void}
|
|
456
|
+
*/
|
|
457
|
+
function setEarlyFlakeDetectionFaulty (configuration) {
|
|
458
|
+
configuration.isEarlyFlakeDetectionEnabled = false
|
|
459
|
+
configuration.isEarlyFlakeDetectionFaulty = true
|
|
460
|
+
configuration.isKnownTestsEnabled = false
|
|
461
|
+
}
|
|
462
|
+
|
|
449
463
|
/**
|
|
450
464
|
* Applies settings and requests the enabled non-TIA datasets once for the whole run.
|
|
451
465
|
*
|
|
@@ -498,9 +512,11 @@ function configureCoordinator (state, response) {
|
|
|
498
512
|
pendingRequests++
|
|
499
513
|
requestCoordinatorData(state, knownTestsCh, ({ err, knownTests } = {}) => {
|
|
500
514
|
const mochaKnownTests = getMochaFrameworkData(knownTests)
|
|
501
|
-
if (err
|
|
515
|
+
if (err) {
|
|
502
516
|
configuration.isEarlyFlakeDetectionEnabled = false
|
|
503
517
|
configuration.isKnownTestsEnabled = false
|
|
518
|
+
} else if (mochaKnownTests === undefined) {
|
|
519
|
+
setEarlyFlakeDetectionFaulty(configuration)
|
|
504
520
|
} else {
|
|
505
521
|
configuration.knownTests = { mocha: mochaKnownTests }
|
|
506
522
|
}
|
|
@@ -564,7 +580,6 @@ function initializeCoordinator (state, onDone) {
|
|
|
564
580
|
|
|
565
581
|
try {
|
|
566
582
|
libraryConfigurationCh.runStores({
|
|
567
|
-
basicReportingOnly: state.testFrameworkAdapter === JASMINE_FRAMEWORK_ADAPTER,
|
|
568
583
|
disableTestImpactAnalysis: true,
|
|
569
584
|
frameworkVersion: state.frameworkVersion,
|
|
570
585
|
isParallel: state.maxActiveWorkers > 1,
|
|
@@ -727,9 +742,7 @@ function updateEarlyFlakeDetectionFaultyState (state, files) {
|
|
|
727
742
|
configuration.earlyFlakeDetectionFaultyThreshold
|
|
728
743
|
)
|
|
729
744
|
if (isFaulty) {
|
|
730
|
-
configuration
|
|
731
|
-
configuration.isEarlyFlakeDetectionFaulty = true
|
|
732
|
-
configuration.isKnownTestsEnabled = false
|
|
745
|
+
setEarlyFlakeDetectionFaulty(configuration)
|
|
733
746
|
}
|
|
734
747
|
}
|
|
735
748
|
|
|
@@ -809,15 +822,16 @@ function handleWorkerMessage (state, workerRecord, message) {
|
|
|
809
822
|
}
|
|
810
823
|
|
|
811
824
|
if (message.name === WORKER_READY) {
|
|
812
|
-
initializeCoordinator(state,
|
|
825
|
+
initializeCoordinator(state, configuration => {
|
|
813
826
|
if (state.testFrameworkAdapter === JASMINE_FRAMEWORK_ADAPTER) {
|
|
827
|
+
updateEarlyFlakeDetectionFaultyState(state, workerRecord.specs)
|
|
814
828
|
startWorkerSuites(workerRecord, workerRecord.specs)
|
|
815
829
|
}
|
|
816
830
|
if (message.content?.requestId) {
|
|
817
831
|
sendWorkerMessage(workerRecord, {
|
|
818
832
|
origin: 'datadog',
|
|
819
833
|
name: WORKER_READY_RESPONSE,
|
|
820
|
-
content: { requestId: message.content.requestId },
|
|
834
|
+
content: { configuration, requestId: message.content.requestId },
|
|
821
835
|
})
|
|
822
836
|
}
|
|
823
837
|
})
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const crypto = require('crypto')
|
|
4
|
+
const {
|
|
5
|
+
deleteDatadogParentId,
|
|
6
|
+
readDatadogParentId,
|
|
7
|
+
readDatadogTraceId,
|
|
8
|
+
writeDatadogParentId,
|
|
9
|
+
} = require('../../dd-trace/src/carrier')
|
|
4
10
|
const log = require('../../dd-trace/src/log')
|
|
5
11
|
const TextMapPropagator = require('../../dd-trace/src/opentracing/propagation/text_map')
|
|
6
12
|
|
|
@@ -37,7 +43,7 @@ function getDatadogOnlyPropagator (tracer) {
|
|
|
37
43
|
* @returns {Record<string, string>}
|
|
38
44
|
*/
|
|
39
45
|
function injectHeaders (tracer, span) {
|
|
40
|
-
const headers = {}
|
|
46
|
+
const headers = /** @type {Record<string, string>} */ ({})
|
|
41
47
|
const propagator = getDatadogOnlyPropagator(tracer)
|
|
42
48
|
const ctx = typeof span?.context === 'function' ? span.context() : span
|
|
43
49
|
propagator.inject(ctx, headers)
|
|
@@ -51,8 +57,8 @@ function injectHeaders (tracer, span) {
|
|
|
51
57
|
*/
|
|
52
58
|
function overrideParentId (headers, parentId) {
|
|
53
59
|
if (!parentId) return
|
|
54
|
-
if (headers
|
|
55
|
-
headers
|
|
60
|
+
if (readDatadogTraceId(headers)) {
|
|
61
|
+
writeDatadogParentId(headers, String(parentId))
|
|
56
62
|
}
|
|
57
63
|
}
|
|
58
64
|
|
|
@@ -192,7 +198,7 @@ async function saveTraceContextCheckpointIfUpdated (
|
|
|
192
198
|
if (typeof checkpointManager?.checkpoint !== 'function') return
|
|
193
199
|
|
|
194
200
|
const currentHeaders = injectHeaders(tracer, span)
|
|
195
|
-
if (currentHeaders
|
|
201
|
+
if (readDatadogTraceId(currentHeaders) === undefined) return
|
|
196
202
|
|
|
197
203
|
const latest = findLastCheckpoint(event)
|
|
198
204
|
|
|
@@ -204,8 +210,8 @@ async function saveTraceContextCheckpointIfUpdated (
|
|
|
204
210
|
// x-datadog-parent-id reflects the active span at save time and always differs, so exclude it
|
|
205
211
|
// from the comparison. Capture the previous anchor first to carry it forward on a real update.
|
|
206
212
|
// needsCheckpointUpdate only reads currentHeaders' keys, so deleting it from there is enough.
|
|
207
|
-
const anchoredSpanId = previousHeaders
|
|
208
|
-
|
|
213
|
+
const anchoredSpanId = readDatadogParentId(previousHeaders)
|
|
214
|
+
deleteDatadogParentId(currentHeaders)
|
|
209
215
|
if (!needsCheckpointUpdate(currentHeaders, previousHeaders)) return
|
|
210
216
|
|
|
211
217
|
newNumber = latest.checkpointNumber + 1
|
|
@@ -196,14 +196,11 @@ class Kinesis extends BaseAwsSdkPlugin {
|
|
|
196
196
|
try {
|
|
197
197
|
parsedAttributes = JSON.parse(recordDataAsString(record.Data))
|
|
198
198
|
} catch {
|
|
199
|
-
// Non-JSON record
|
|
200
|
-
// checkpoint payload size below is still reported.
|
|
199
|
+
// Non-JSON record: it carries no context, so the checkpoint below starts a new pathway.
|
|
201
200
|
}
|
|
202
201
|
|
|
203
202
|
const payloadSize = getSizeOrZero(record.Data)
|
|
204
|
-
|
|
205
|
-
this.tracer.decodeDataStreamsContext(parsedAttributes._datadog)
|
|
206
|
-
}
|
|
203
|
+
this.tracer.decodeDataStreamsContext(parsedAttributes?._datadog)
|
|
207
204
|
this.tracer.setCheckpoint(tags, span, payloadSize)
|
|
208
205
|
}
|
|
209
206
|
}
|
|
@@ -275,11 +275,7 @@ class Sqs extends BaseAwsSdkPlugin {
|
|
|
275
275
|
for (let i = 0; i < messages.length; i++) {
|
|
276
276
|
const message = messages[i]
|
|
277
277
|
const carrier = carriers === undefined ? this.parseMessageCarrier(message) : carriers[i]
|
|
278
|
-
|
|
279
|
-
// Inert for EventBridge until its producer emits a pathway (separate
|
|
280
|
-
// change) — no `dd-pathway-ctx-base64` to decode yet; SQS/SNS decode now.
|
|
281
|
-
this.tracer.decodeDataStreamsContext(carrier)
|
|
282
|
-
}
|
|
278
|
+
this.tracer.decodeDataStreamsContext(carrier)
|
|
283
279
|
const payloadSize = getHeadersSize({
|
|
284
280
|
Body: message.Body,
|
|
285
281
|
MessageAttributes: message.MessageAttributes,
|
|
@@ -78,6 +78,7 @@ const {
|
|
|
78
78
|
TEST_HAS_DYNAMIC_NAME,
|
|
79
79
|
getIsFaultyEarlyFlakeDetection,
|
|
80
80
|
DYNAMIC_NAME_RE,
|
|
81
|
+
isMarkedAsUnskippable,
|
|
81
82
|
recordAttemptToFixExecution,
|
|
82
83
|
recordTestManagementExecution,
|
|
83
84
|
logAttemptToFixTestExecution,
|
|
@@ -86,7 +87,6 @@ const {
|
|
|
86
87
|
TEST_FINAL_STATUS,
|
|
87
88
|
getTestOptimizationRequestResults,
|
|
88
89
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
89
|
-
const { isMarkedAsUnskippable } = require('../../datadog-plugin-jest/src/util')
|
|
90
90
|
const { ORIGIN_KEY, COMPONENT } = require('../../dd-trace/src/constants')
|
|
91
91
|
const { RESOURCE_NAME } = require('../../../ext/tags')
|
|
92
92
|
const getConfig = require('../../dd-trace/src/config')
|
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const {
|
|
4
|
+
readDatadogParentId,
|
|
5
|
+
readDatadogSamplingPriority,
|
|
6
|
+
readDatadogTraceId,
|
|
7
|
+
readTraceparent,
|
|
8
|
+
writeDatadogParentId,
|
|
9
|
+
writeDatadogSamplingPriority,
|
|
10
|
+
writeDatadogTraceId,
|
|
11
|
+
} = require('../../dd-trace/src/carrier')
|
|
4
12
|
const { DsmPathwayCodec, getHeadersSize } = require('../../dd-trace/src/datastreams')
|
|
5
13
|
const id = require('../../dd-trace/src/id')
|
|
14
|
+
const ProducerPlugin = require('../../dd-trace/src/plugins/producer')
|
|
6
15
|
|
|
7
16
|
class GoogleCloudPubsubProducerPlugin extends ProducerPlugin {
|
|
8
17
|
static id = 'google-cloud-pubsub'
|
|
@@ -21,7 +30,7 @@ class GoogleCloudPubsubProducerPlugin extends ProducerPlugin {
|
|
|
21
30
|
|
|
22
31
|
handleMessagePublish ({ attributes, pubsub, topicName }) {
|
|
23
32
|
// Skip if message already has trace context from upstream
|
|
24
|
-
if (attributes
|
|
33
|
+
if (readDatadogTraceId(attributes) || readTraceparent(attributes)) return
|
|
25
34
|
|
|
26
35
|
const activeSpan = this.tracer.scope().active()
|
|
27
36
|
if (!activeSpan) return
|
|
@@ -62,7 +71,7 @@ class GoogleCloudPubsubProducerPlugin extends ProducerPlugin {
|
|
|
62
71
|
const messages = request.messages || []
|
|
63
72
|
const topic = request.topic
|
|
64
73
|
const messageCount = messages.length
|
|
65
|
-
const hasTraceContext = messages[0]?.attributes
|
|
74
|
+
const hasTraceContext = messages[0]?.attributes && readDatadogTraceId(messages[0].attributes)
|
|
66
75
|
|
|
67
76
|
/**
|
|
68
77
|
* Batch Publishing Strategy:
|
|
@@ -82,12 +91,14 @@ class GoogleCloudPubsubProducerPlugin extends ProducerPlugin {
|
|
|
82
91
|
}
|
|
83
92
|
|
|
84
93
|
const firstAttrs = messages[0]?.attributes
|
|
85
|
-
const
|
|
94
|
+
const traceId = firstAttrs && readDatadogTraceId(firstAttrs)
|
|
95
|
+
const spanId = firstAttrs && readDatadogParentId(firstAttrs)
|
|
96
|
+
const parentData = traceId && spanId
|
|
86
97
|
? {
|
|
87
|
-
traceId
|
|
88
|
-
spanId
|
|
98
|
+
traceId,
|
|
99
|
+
spanId,
|
|
89
100
|
traceIdUpper: firstAttrs['_dd.p.tid'],
|
|
90
|
-
samplingPriority: firstAttrs
|
|
101
|
+
samplingPriority: readDatadogSamplingPriority(firstAttrs),
|
|
91
102
|
}
|
|
92
103
|
: null
|
|
93
104
|
|
|
@@ -174,33 +185,36 @@ class GoogleCloudPubsubProducerPlugin extends ProducerPlugin {
|
|
|
174
185
|
}
|
|
175
186
|
|
|
176
187
|
#extractSpanLink (attrs) {
|
|
177
|
-
if (!attrs
|
|
188
|
+
if (!attrs) return null
|
|
189
|
+
const traceId = readDatadogTraceId(attrs)
|
|
190
|
+
const spanId = readDatadogParentId(attrs)
|
|
191
|
+
if (!traceId || !spanId) return null
|
|
178
192
|
|
|
179
193
|
// Convert to hex strings
|
|
180
|
-
const lowerHex = id(
|
|
181
|
-
const spanIdHex = id(
|
|
194
|
+
const lowerHex = id(traceId).toString(16)
|
|
195
|
+
const spanIdHex = id(spanId).toString(16)
|
|
182
196
|
|
|
183
197
|
// Build full 128-bit trace ID
|
|
184
198
|
const traceIdHex = attrs['_dd.p.tid']
|
|
185
199
|
? attrs['_dd.p.tid'] + lowerHex
|
|
186
200
|
: lowerHex.padStart(32, '0')
|
|
187
201
|
|
|
202
|
+
const samplingPriority = readDatadogSamplingPriority(attrs)
|
|
188
203
|
return {
|
|
189
204
|
traceId: traceIdHex,
|
|
190
205
|
spanId: spanIdHex,
|
|
191
|
-
samplingPriority:
|
|
192
|
-
? Number.parseInt(
|
|
206
|
+
samplingPriority: samplingPriority
|
|
207
|
+
? Number.parseInt(samplingPriority, 10)
|
|
193
208
|
: undefined,
|
|
194
209
|
}
|
|
195
210
|
}
|
|
196
211
|
|
|
197
212
|
#extractParentContext (data) {
|
|
198
|
-
const carrier = {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
}
|
|
213
|
+
const carrier = /** @type {Record<string, unknown>} */ ({})
|
|
214
|
+
writeDatadogTraceId(carrier, data.traceId)
|
|
215
|
+
writeDatadogParentId(carrier, data.spanId)
|
|
202
216
|
if (data.traceIdUpper) carrier['_dd.p.tid'] = data.traceIdUpper
|
|
203
|
-
if (data.samplingPriority) carrier
|
|
217
|
+
if (data.samplingPriority) writeDatadogSamplingPriority(carrier, String(data.samplingPriority))
|
|
204
218
|
|
|
205
219
|
return this.tracer.extract('text_map', carrier)
|
|
206
220
|
}
|
|
@@ -5,6 +5,7 @@ const realSetTimeout = setTimeout
|
|
|
5
5
|
|
|
6
6
|
const CiPlugin = require('../../dd-trace/src/plugins/ci_plugin')
|
|
7
7
|
const { storage } = require('../../datadog-core')
|
|
8
|
+
const { writeDatadogParentId, writeDatadogTraceId } = require('../../dd-trace/src/carrier')
|
|
8
9
|
const { getEnvironmentVariable } = require('../../dd-trace/src/config/helper')
|
|
9
10
|
const { appClosing: appClosingTelemetry } = require('../../dd-trace/src/telemetry')
|
|
10
11
|
|
|
@@ -230,10 +231,10 @@ class JestPlugin extends CiPlugin {
|
|
|
230
231
|
_ddItrSkippingEnabledTags: itrSkippingEnabledTags,
|
|
231
232
|
} = testEnvironmentOptions
|
|
232
233
|
|
|
233
|
-
const
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
234
|
+
const carrier = /** @type {Record<string, unknown>} */ ({})
|
|
235
|
+
writeDatadogTraceId(carrier, testSessionId)
|
|
236
|
+
writeDatadogParentId(carrier, testModuleId)
|
|
237
|
+
const testSessionSpanContext = this.tracer.extract('text_map', carrier)
|
|
237
238
|
|
|
238
239
|
const testSuiteMetadata = {
|
|
239
240
|
...getTestSuiteCommonTags(testCommand, frameworkVersion, testSuite, 'jest'),
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const ConsumerPlugin = require('../../dd-trace/src/plugins/consumer')
|
|
4
|
-
const {
|
|
5
|
-
const { convertToTextMap } = require('./utils')
|
|
4
|
+
const { convertToTextMap, getKafkaMessageSize } = require('./utils')
|
|
6
5
|
|
|
7
6
|
class KafkajsBatchConsumerPlugin extends ConsumerPlugin {
|
|
8
7
|
static id = 'kafkajs'
|
|
@@ -39,7 +38,7 @@ class KafkajsBatchConsumerPlugin extends ConsumerPlugin {
|
|
|
39
38
|
}
|
|
40
39
|
|
|
41
40
|
if (!this.config.dsmEnabled) continue
|
|
42
|
-
const payloadSize =
|
|
41
|
+
const payloadSize = getKafkaMessageSize(message)
|
|
43
42
|
this.tracer.decodeDataStreamsContext(headers)
|
|
44
43
|
const edgeTags = ['direction:in', `group:${groupId}`, `topic:${topic}`, 'type:kafka']
|
|
45
44
|
if (clusterId) {
|