dd-trace 5.116.0 → 5.118.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/diagnose.js +162 -21
- package/ci/init.js +0 -1
- package/ci/runbook.md +187 -180
- package/ci/test-optimization-validation/approval-artifacts.js +3 -1
- package/ci/test-optimization-validation/approval.js +52 -15
- package/ci/test-optimization-validation/ci-command-candidate.js +26 -32
- package/ci/test-optimization-validation/ci-discovery.js +1 -1
- package/ci/test-optimization-validation/ci-package-scripts.js +141 -0
- package/ci/test-optimization-validation/ci-remediation.js +112 -39
- package/ci/test-optimization-validation/cli.js +516 -681
- package/ci/test-optimization-validation/command-blocker.js +188 -33
- package/ci/test-optimization-validation/command-output-policy.js +3 -26
- package/ci/test-optimization-validation/command-runner.js +189 -245
- package/ci/test-optimization-validation/environment.js +90 -0
- package/ci/test-optimization-validation/executable.js +159 -388
- package/ci/test-optimization-validation/framework-adapters/cucumber.js +119 -0
- package/ci/test-optimization-validation/framework-adapters/cypress.js +107 -0
- package/ci/test-optimization-validation/framework-adapters/playwright.js +181 -0
- package/ci/test-optimization-validation/generated-files.js +75 -13
- package/ci/test-optimization-validation/generated-test-contract.js +283 -0
- package/ci/test-optimization-validation/generated-verifier.js +49 -16
- package/ci/test-optimization-validation/literal-environment.js +57 -0
- package/ci/test-optimization-validation/manifest-loader.js +2 -22
- package/ci/test-optimization-validation/manifest-scaffold.js +816 -515
- package/ci/test-optimization-validation/manifest-schema.js +494 -702
- package/ci/test-optimization-validation/offline-fixtures.js +4 -1
- package/ci/test-optimization-validation/plan-writer.js +243 -984
- package/ci/test-optimization-validation/preflight-runner.js +49 -55
- package/ci/test-optimization-validation/redaction.js +2 -1
- package/ci/test-optimization-validation/report-writer.js +391 -1357
- package/ci/test-optimization-validation/result-semantics.js +86 -0
- package/ci/test-optimization-validation/runner-command.js +249 -0
- package/ci/test-optimization-validation/runner-contract.js +664 -0
- package/ci/test-optimization-validation/scenarios/auto-test-retries.js +29 -3
- package/ci/test-optimization-validation/scenarios/basic-reporting.js +240 -543
- package/ci/test-optimization-validation/scenarios/ci-wiring.js +450 -670
- package/ci/test-optimization-validation/scenarios/early-flake-detection.js +4 -3
- package/ci/test-optimization-validation/scenarios/helpers.js +67 -9
- package/ci/test-optimization-validation/scenarios/test-management.js +4 -3
- package/ci/test-optimization-validation/source-text.js +87 -0
- package/ci/test-optimization-validation/test-output.js +12 -22
- package/ext/tags.d.ts +1 -0
- package/index.d.ts +7 -0
- package/package.json +3 -3
- package/packages/datadog-instrumentations/src/cucumber.js +11 -12
- package/packages/datadog-instrumentations/src/helpers/channel.js +74 -0
- package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/openai-agents.js +31 -0
- package/packages/datadog-instrumentations/src/jest.js +18 -17
- package/packages/datadog-instrumentations/src/mocha/main.js +79 -30
- package/packages/datadog-instrumentations/src/openai-agents.js +159 -0
- package/packages/datadog-instrumentations/src/playwright.js +3 -24
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +1 -1
- package/packages/datadog-instrumentations/src/vitest-main.js +14 -26
- package/packages/datadog-instrumentations/src/vitest-util.js +0 -7
- package/packages/datadog-instrumentations/src/vitest-worker.js +5 -8
- package/packages/datadog-plugin-cucumber/src/index.js +2 -1
- package/packages/datadog-plugin-mocha/src/index.js +2 -1
- package/packages/datadog-plugin-openai-agents/src/index.js +74 -0
- package/packages/datadog-plugin-openai-agents/src/integration.js +503 -0
- package/packages/datadog-plugin-openai-agents/src/processor.js +108 -0
- package/packages/datadog-plugin-openai-agents/src/util.js +60 -0
- package/packages/datadog-plugin-playwright/src/index.js +4 -1
- package/packages/datadog-plugin-vitest/src/index.js +5 -5
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +48 -49
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +161 -33
- package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +6 -4
- package/packages/dd-trace/src/config/generated-config-types.d.ts +2 -0
- package/packages/dd-trace/src/config/supported-configurations.json +7 -0
- package/packages/dd-trace/src/encode/span-stats.js +7 -1
- package/packages/dd-trace/src/exporter.js +16 -9
- package/packages/dd-trace/src/llmobs/index.js +9 -1
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +104 -22
- package/packages/dd-trace/src/llmobs/plugins/openai/index.js +5 -9
- package/packages/dd-trace/src/llmobs/plugins/openai/utils.js +20 -0
- package/packages/dd-trace/src/llmobs/plugins/openai-agents/utils.js +321 -0
- package/packages/dd-trace/src/llmobs/sdk.js +2 -1
- package/packages/dd-trace/src/llmobs/span_processor.js +7 -2
- package/packages/dd-trace/src/llmobs/tagger.js +23 -3
- package/packages/dd-trace/src/llmobs/util.js +56 -3
- package/packages/dd-trace/src/openfeature/agentless_configuration_source.js +3 -6
- package/packages/dd-trace/src/openfeature/configuration_source.js +5 -8
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_transformer.js +5 -1
- package/packages/dd-trace/src/plugins/ci_plugin.js +9 -3
- package/packages/dd-trace/src/plugins/index.js +1 -0
- package/packages/dd-trace/src/plugins/outbound.js +4 -1
- package/packages/dd-trace/src/profiling/profilers/space.js +1 -1
- package/packages/dd-trace/src/profiling/profilers/wall.js +1 -0
- package/packages/dd-trace/src/span_processor.js +1 -1
- package/packages/dd-trace/src/span_stats.js +22 -4
- package/ci/test-optimization-validation/command-suitability.js +0 -471
- package/ci/test-optimization-validation/init-probe-preload.js +0 -163
- package/ci/test-optimization-validation/init-probe.js +0 -246
- package/ci/test-optimization-validation/late-initialization.js +0 -63
- package/ci/test-optimization-validation/local-command.js +0 -163
- package/ci/test-optimization-validation/setup-runner.js +0 -97
- package/ci/test-optimization-validation-manifest.schema.json +0 -1
|
@@ -7,6 +7,7 @@ const {
|
|
|
7
7
|
failWithDebugRerun,
|
|
8
8
|
pass,
|
|
9
9
|
prepareGeneratedScenario,
|
|
10
|
+
reportMissingGeneratedTest,
|
|
10
11
|
requireGeneratedScenario,
|
|
11
12
|
runInstrumentedCommand,
|
|
12
13
|
skip,
|
|
@@ -28,14 +29,14 @@ async function runEarlyFlakeDetection ({ framework, out, options }) {
|
|
|
28
29
|
|
|
29
30
|
const discovery = await discoverScenarioTests({ framework, out, scenarioName, scenario, options })
|
|
30
31
|
if (discovery.tests.length === 0) {
|
|
31
|
-
return
|
|
32
|
+
return reportMissingGeneratedTest({
|
|
32
33
|
command: scenario.runCommand,
|
|
33
34
|
diagnosis: 'The generated new-test candidate was not reported during baseline identity discovery.',
|
|
34
|
-
|
|
35
|
+
discovery,
|
|
35
36
|
framework,
|
|
36
37
|
options,
|
|
37
38
|
out,
|
|
38
|
-
|
|
39
|
+
scenario,
|
|
39
40
|
scenarioName,
|
|
40
41
|
})
|
|
41
42
|
}
|
|
@@ -4,7 +4,7 @@ const fs = require('node:fs')
|
|
|
4
4
|
const path = require('path')
|
|
5
5
|
|
|
6
6
|
const { getArtifactId } = require('../artifact-id')
|
|
7
|
-
const {
|
|
7
|
+
const { buildDatadogEnv, buildOfflineCaptureEnv, runCommand } = require('../command-runner')
|
|
8
8
|
const {
|
|
9
9
|
cleanupGeneratedRuntimeFiles,
|
|
10
10
|
findGeneratedScenario,
|
|
@@ -14,10 +14,10 @@ const {
|
|
|
14
14
|
eventsOfType,
|
|
15
15
|
findTestsByIdentity,
|
|
16
16
|
} = require('../payload-normalizer')
|
|
17
|
-
const { getLocalValidationCommand } = require('../local-command')
|
|
18
17
|
const { cleanupOfflineFixture, createOfflineFixture } = require('../offline-fixtures')
|
|
19
18
|
const { readOfflineOutput } = require('../offline-output')
|
|
20
19
|
const { sanitizeForReport, sanitizeString } = require('../redaction')
|
|
20
|
+
const { getGeneratedCommand } = require('../runner-command')
|
|
21
21
|
const { ensureSafeDirectory, writeFileSafely } = require('../safe-files')
|
|
22
22
|
|
|
23
23
|
const ANSI_PATTERN = new RegExp(`${String.fromCharCode(27)}${String.raw`\[[0-?]*[ -/]*[@-~]`}`, 'g')
|
|
@@ -34,7 +34,7 @@ async function runInstrumentedCommand ({
|
|
|
34
34
|
options,
|
|
35
35
|
extraEnv,
|
|
36
36
|
fixtureConfig,
|
|
37
|
-
|
|
37
|
+
injectInitialization = true,
|
|
38
38
|
allowMissingInitialization = false,
|
|
39
39
|
}) {
|
|
40
40
|
const outDir = frameworkOutDir(out, framework, scenarioName)
|
|
@@ -52,9 +52,9 @@ async function runInstrumentedCommand ({
|
|
|
52
52
|
scenarioName,
|
|
53
53
|
...fixtureConfig,
|
|
54
54
|
})
|
|
55
|
-
const validationEnv =
|
|
56
|
-
?
|
|
57
|
-
:
|
|
55
|
+
const validationEnv = injectInitialization
|
|
56
|
+
? buildDatadogEnv({ fixture, outputRoot: rawOutputRoot, scenario: scenarioName, framework })
|
|
57
|
+
: buildOfflineCaptureEnv({ fixture, outputRoot: rawOutputRoot })
|
|
58
58
|
result = await runCommand(command, {
|
|
59
59
|
env: {
|
|
60
60
|
...validationEnv,
|
|
@@ -82,7 +82,7 @@ async function runInstrumentedCommand ({
|
|
|
82
82
|
`${JSON.stringify(sanitizeForReport(result), null, 2)}\n`,
|
|
83
83
|
'scenario result artifact'
|
|
84
84
|
)
|
|
85
|
-
if (!offline.initialized &&
|
|
85
|
+
if (!offline.initialized && injectInitialization && !allowMissingInitialization) {
|
|
86
86
|
const stderr = sanitizeString(result.stderr).trim().slice(-2000)
|
|
87
87
|
throw new Error(
|
|
88
88
|
'Offline Test Optimization exporter did not initialize or write completion evidence. ' +
|
|
@@ -180,11 +180,11 @@ async function prepareGeneratedScenario (framework, scenarioId) {
|
|
|
180
180
|
const scenario = findGeneratedScenario(framework, scenarioId)
|
|
181
181
|
if (!scenario) return { scenario: null, written: [] }
|
|
182
182
|
cleanupGeneratedRuntimeFiles(framework)
|
|
183
|
-
const written = await writeGeneratedFiles(framework)
|
|
183
|
+
const written = await writeGeneratedFiles(framework, scenario)
|
|
184
184
|
return {
|
|
185
185
|
scenario: {
|
|
186
186
|
...scenario,
|
|
187
|
-
runCommand:
|
|
187
|
+
runCommand: getGeneratedCommand(framework, scenario),
|
|
188
188
|
},
|
|
189
189
|
written,
|
|
190
190
|
}
|
|
@@ -314,6 +314,63 @@ async function discoverScenarioTests ({ framework, out, scenarioName, scenario,
|
|
|
314
314
|
}
|
|
315
315
|
}
|
|
316
316
|
|
|
317
|
+
/**
|
|
318
|
+
* Reports a missing generated test without blaming dd-trace when clean execution was unproven.
|
|
319
|
+
*
|
|
320
|
+
* @param {object} input missing-test evidence
|
|
321
|
+
* @param {object} input.command generated scenario command
|
|
322
|
+
* @param {string} input.diagnosis diagnosis used when clean execution was proven
|
|
323
|
+
* @param {object} input.discovery instrumented baseline result
|
|
324
|
+
* @param {object} input.framework framework manifest entry
|
|
325
|
+
* @param {object} input.options execution options
|
|
326
|
+
* @param {string} input.out validation output root
|
|
327
|
+
* @param {object} input.scenario generated scenario
|
|
328
|
+
* @param {string} input.scenarioName advanced scenario name
|
|
329
|
+
* @returns {object|Promise<object>} incomplete or confirmed failure result
|
|
330
|
+
*/
|
|
331
|
+
function reportMissingGeneratedTest ({
|
|
332
|
+
command,
|
|
333
|
+
diagnosis,
|
|
334
|
+
discovery,
|
|
335
|
+
framework,
|
|
336
|
+
options,
|
|
337
|
+
out,
|
|
338
|
+
scenario,
|
|
339
|
+
scenarioName,
|
|
340
|
+
}) {
|
|
341
|
+
const verification = framework.generatedTestStrategy?.verification?.observedScenarios
|
|
342
|
+
?.find(observed => observed.id === scenario.id)
|
|
343
|
+
const evidence = {
|
|
344
|
+
...discoveryEvidence(discovery),
|
|
345
|
+
generatedVerificationObservedTestCount: verification?.observedTestCount,
|
|
346
|
+
}
|
|
347
|
+
if (verification?.observedTestCount === null) {
|
|
348
|
+
return inconclusive(
|
|
349
|
+
framework,
|
|
350
|
+
scenarioName,
|
|
351
|
+
'The clean temporary validation command exited as expected without a parseable test count, and the ' +
|
|
352
|
+
'instrumented baseline emitted no matching test event. The validator cannot prove that the generated test ' +
|
|
353
|
+
'executed, so no advanced-feature conclusion was reached.',
|
|
354
|
+
{
|
|
355
|
+
...evidence,
|
|
356
|
+
reasonCode: 'generated-test-execution-unproven',
|
|
357
|
+
},
|
|
358
|
+
discovery.outDir
|
|
359
|
+
)
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
return failWithDebugRerun({
|
|
363
|
+
command,
|
|
364
|
+
diagnosis,
|
|
365
|
+
evidence,
|
|
366
|
+
framework,
|
|
367
|
+
options,
|
|
368
|
+
out,
|
|
369
|
+
outDir: discovery.outDir,
|
|
370
|
+
scenarioName,
|
|
371
|
+
})
|
|
372
|
+
}
|
|
373
|
+
|
|
317
374
|
function testsForDiscoveredScenario (events, scenario, discovery) {
|
|
318
375
|
if (discovery?.testIdentities?.length > 0) {
|
|
319
376
|
return findTestsByIdentity(events, discovery.testIdentities)
|
|
@@ -528,6 +585,7 @@ module.exports = {
|
|
|
528
585
|
inconclusive,
|
|
529
586
|
pass,
|
|
530
587
|
prepareGeneratedScenario,
|
|
588
|
+
reportMissingGeneratedTest,
|
|
531
589
|
requireGeneratedScenario,
|
|
532
590
|
runDebugInstrumentedCommand,
|
|
533
591
|
runInstrumentedCommand,
|
|
@@ -9,6 +9,7 @@ const {
|
|
|
9
9
|
failWithDebugRerun,
|
|
10
10
|
pass,
|
|
11
11
|
prepareGeneratedScenario,
|
|
12
|
+
reportMissingGeneratedTest,
|
|
12
13
|
requireGeneratedScenario,
|
|
13
14
|
runInstrumentedCommand,
|
|
14
15
|
testEventSamples,
|
|
@@ -25,14 +26,14 @@ async function runTestManagement ({ framework, out, options }) {
|
|
|
25
26
|
const { scenario } = await prepareGeneratedScenario(framework, 'test-management-target')
|
|
26
27
|
const discovery = await discoverScenarioTests({ framework, out, scenarioName, scenario, options })
|
|
27
28
|
if (discovery.tests.length === 0) {
|
|
28
|
-
return
|
|
29
|
+
return reportMissingGeneratedTest({
|
|
29
30
|
command: scenario.runCommand,
|
|
30
31
|
diagnosis: 'The test-management target was not reported during baseline identity discovery.',
|
|
31
|
-
|
|
32
|
+
discovery,
|
|
32
33
|
framework,
|
|
33
34
|
options,
|
|
34
35
|
out,
|
|
35
|
-
|
|
36
|
+
scenario,
|
|
36
37
|
scenarioName,
|
|
37
38
|
})
|
|
38
39
|
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Replaces JavaScript comments with spaces while preserving line structure and string literals.
|
|
5
|
+
*
|
|
6
|
+
* @param {string} source JavaScript or TypeScript source
|
|
7
|
+
* @returns {string} source with comments masked
|
|
8
|
+
*/
|
|
9
|
+
function maskJavaScriptComments (source) {
|
|
10
|
+
return maskJavaScriptSource(source, false)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Replaces JavaScript comments and string literals with spaces while preserving line structure.
|
|
15
|
+
*
|
|
16
|
+
* @param {string} source JavaScript or TypeScript source
|
|
17
|
+
* @returns {string} source with non-code text masked
|
|
18
|
+
*/
|
|
19
|
+
function maskJavaScriptNonCode (source) {
|
|
20
|
+
return maskJavaScriptSource(source, true)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Masks comments and optionally string literals in JavaScript-like source.
|
|
25
|
+
*
|
|
26
|
+
* @param {string} source JavaScript or TypeScript source
|
|
27
|
+
* @param {boolean} maskStrings whether string and template literal contents should be masked
|
|
28
|
+
* @returns {string} masked source
|
|
29
|
+
*/
|
|
30
|
+
function maskJavaScriptSource (source, maskStrings) {
|
|
31
|
+
const characters = [...source]
|
|
32
|
+
let blockComment = false
|
|
33
|
+
let lineComment = false
|
|
34
|
+
let quote = ''
|
|
35
|
+
|
|
36
|
+
for (let index = 0; index < characters.length; index++) {
|
|
37
|
+
const character = characters[index]
|
|
38
|
+
const next = characters[index + 1]
|
|
39
|
+
if (lineComment) {
|
|
40
|
+
if (character === '\n') {
|
|
41
|
+
lineComment = false
|
|
42
|
+
} else {
|
|
43
|
+
characters[index] = ' '
|
|
44
|
+
}
|
|
45
|
+
continue
|
|
46
|
+
}
|
|
47
|
+
if (blockComment) {
|
|
48
|
+
if (character === '*' && next === '/') {
|
|
49
|
+
characters[index] = ' '
|
|
50
|
+
characters[++index] = ' '
|
|
51
|
+
blockComment = false
|
|
52
|
+
} else if (character !== '\r' && character !== '\n') {
|
|
53
|
+
characters[index] = ' '
|
|
54
|
+
}
|
|
55
|
+
continue
|
|
56
|
+
}
|
|
57
|
+
if (quote) {
|
|
58
|
+
if (maskStrings && character !== '\r' && character !== '\n') characters[index] = ' '
|
|
59
|
+
if (character.charCodeAt(0) === 92) {
|
|
60
|
+
if (maskStrings && index + 1 < characters.length &&
|
|
61
|
+
characters[index + 1] !== '\r' && characters[index + 1] !== '\n') {
|
|
62
|
+
characters[index + 1] = ' '
|
|
63
|
+
}
|
|
64
|
+
index++
|
|
65
|
+
} else if (character === quote) {
|
|
66
|
+
quote = ''
|
|
67
|
+
}
|
|
68
|
+
continue
|
|
69
|
+
}
|
|
70
|
+
if (character === '"' || character === '\'' || character === '`') {
|
|
71
|
+
quote = character
|
|
72
|
+
if (maskStrings) characters[index] = ' '
|
|
73
|
+
} else if (character === '/' && next === '/') {
|
|
74
|
+
characters[index] = ' '
|
|
75
|
+
characters[++index] = ' '
|
|
76
|
+
lineComment = true
|
|
77
|
+
} else if (character === '/' && next === '*') {
|
|
78
|
+
characters[index] = ' '
|
|
79
|
+
characters[++index] = ' '
|
|
80
|
+
blockComment = true
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return characters.join('')
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
module.exports = { maskJavaScriptComments, maskJavaScriptNonCode }
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const cypressAdapter = require('./framework-adapters/cypress')
|
|
4
|
+
const cucumberAdapter = require('./framework-adapters/cucumber')
|
|
5
|
+
const playwrightAdapter = require('./framework-adapters/playwright')
|
|
6
|
+
|
|
3
7
|
const ANSI_PATTERN = new RegExp(`${String.fromCharCode(27)}${String.raw`\[[0-?]*[ -/]*[@-~]`}`, 'g')
|
|
4
8
|
|
|
5
9
|
/**
|
|
@@ -11,16 +15,14 @@ const ANSI_PATTERN = new RegExp(`${String.fromCharCode(27)}${String.raw`\[[0-?]*
|
|
|
11
15
|
* @returns {number|null} observed count when a supported summary was found
|
|
12
16
|
*/
|
|
13
17
|
function getObservedTestCount (framework, stdout = '', stderr = '') {
|
|
14
|
-
const output = `${stdout}\n${stderr}
|
|
18
|
+
const output = stripAnsi(`${stdout}\n${stderr}`)
|
|
19
|
+
if (framework === 'cucumber') return cucumberAdapter.getObservedTestCount(output)
|
|
20
|
+
if (framework === 'cypress') return cypressAdapter.getObservedTestCount(output)
|
|
21
|
+
if (framework === 'playwright') return playwrightAdapter.getObservedTestCount(output)
|
|
15
22
|
if (framework === 'jest') return getJestObservedTestCount(output)
|
|
16
23
|
if (framework === 'vitest') return getVitestObservedTestCount(output)
|
|
17
|
-
if (framework === 'playwright') return getPlaywrightObservedTestCount(output)
|
|
18
24
|
|
|
19
|
-
const totalPatterns = framework === 'node:test'
|
|
20
|
-
? [/^# tests\s+(\d+)\s*$/gim]
|
|
21
|
-
: framework === 'cucumber'
|
|
22
|
-
? [/\b(\d+)\s+scenarios?\b/gi]
|
|
23
|
-
: []
|
|
25
|
+
const totalPatterns = framework === 'node:test' ? [/^# tests\s+(\d+)\s*$/gim] : []
|
|
24
26
|
|
|
25
27
|
for (const pattern of totalPatterns) {
|
|
26
28
|
const count = getLastMatchCount(output, pattern)
|
|
@@ -38,20 +40,8 @@ function getObservedTestCount (framework, stdout = '', stderr = '') {
|
|
|
38
40
|
return getLastMatchCount(output, /\b(\d+)\s+tests?\s+(?:passed|failed)\b/gi)
|
|
39
41
|
}
|
|
40
42
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
*
|
|
44
|
-
* @param {string} output test output without ANSI codes
|
|
45
|
-
* @returns {number|null} executed test count
|
|
46
|
-
*/
|
|
47
|
-
function getPlaywrightObservedTestCount (output) {
|
|
48
|
-
const observed = sumLastMatchCounts(output, [
|
|
49
|
-
/^\s*(\d+)\s+passed\b/gim,
|
|
50
|
-
/^\s*(\d+)\s+failed\b/gim,
|
|
51
|
-
/^\s*(\d+)\s+flaky\b/gim,
|
|
52
|
-
])
|
|
53
|
-
if (observed !== null) return observed
|
|
54
|
-
return /^\s*\d+\s+skipped\b/im.test(output) ? 0 : null
|
|
43
|
+
function stripAnsi (value) {
|
|
44
|
+
return String(value || '').replaceAll(ANSI_PATTERN, '')
|
|
55
45
|
}
|
|
56
46
|
|
|
57
47
|
/**
|
|
@@ -126,4 +116,4 @@ function sumLastMatchCounts (output, patterns) {
|
|
|
126
116
|
return found ? count : null
|
|
127
117
|
}
|
|
128
118
|
|
|
129
|
-
module.exports = { getObservedTestCount }
|
|
119
|
+
module.exports = { getObservedTestCount, stripAnsi }
|
package/ext/tags.d.ts
CHANGED
package/index.d.ts
CHANGED
|
@@ -293,6 +293,7 @@ interface Plugins {
|
|
|
293
293
|
"next": tracer.plugins.next;
|
|
294
294
|
"nyc": tracer.plugins.nyc;
|
|
295
295
|
"openai": tracer.plugins.openai;
|
|
296
|
+
"openai-agents": tracer.plugins.openai_agents;
|
|
296
297
|
"opensearch": tracer.plugins.opensearch;
|
|
297
298
|
"oracledb": tracer.plugins.oracledb;
|
|
298
299
|
"playwright": tracer.plugins.playwright;
|
|
@@ -3138,6 +3139,12 @@ declare namespace tracer {
|
|
|
3138
3139
|
*/
|
|
3139
3140
|
interface openai extends Instrumentation {}
|
|
3140
3141
|
|
|
3142
|
+
/**
|
|
3143
|
+
* This plugin automatically instruments the
|
|
3144
|
+
* [@openai/agents](https://www.npmjs.com/package/@openai/agents) library.
|
|
3145
|
+
*/
|
|
3146
|
+
interface openai_agents extends Instrumentation {}
|
|
3147
|
+
|
|
3141
3148
|
/**
|
|
3142
3149
|
* This plugin automatically instruments the
|
|
3143
3150
|
* [opensearch](https://github.com/opensearch-project/opensearch-js) module.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dd-trace",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.118.0",
|
|
4
4
|
"description": "Datadog APM tracing client for JavaScript",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"typings": "index.d.ts",
|
|
@@ -179,7 +179,7 @@
|
|
|
179
179
|
"@datadog/native-iast-taint-tracking": "4.2.0",
|
|
180
180
|
"@datadog/native-metrics": "3.1.2",
|
|
181
181
|
"@datadog/openfeature-node-server": "2.0.0",
|
|
182
|
-
"@datadog/pprof": "5.
|
|
182
|
+
"@datadog/pprof": "5.17.0",
|
|
183
183
|
"@datadog/wasm-js-rewriter": "5.0.1",
|
|
184
184
|
"@opentelemetry/api": ">=1.0.0 <1.10.0",
|
|
185
185
|
"@opentelemetry/api-logs": "<1.0.0",
|
|
@@ -198,7 +198,7 @@
|
|
|
198
198
|
"@types/mocha": "^10.0.10",
|
|
199
199
|
"@types/node": "^18.19.106",
|
|
200
200
|
"@types/sinon": "^22.0.0",
|
|
201
|
-
"@vercel/nft": "^
|
|
201
|
+
"@vercel/nft": "^1.10.2",
|
|
202
202
|
"axios": "^1.18.1",
|
|
203
203
|
"benchmark": "^2.1.4",
|
|
204
204
|
"body-parser": "^2.3.0",
|
|
@@ -28,6 +28,7 @@ const {
|
|
|
28
28
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
29
29
|
const { writeCoverageBackfillToCache } = require('../../dd-trace/src/ci-visibility/test-optimization-cache')
|
|
30
30
|
const satisfies = require('../../../vendor/dist/semifies')
|
|
31
|
+
const { getChannelPromise } = require('./helpers/channel')
|
|
31
32
|
const { addHook, channel } = require('./helpers/instrument')
|
|
32
33
|
|
|
33
34
|
const cucumberWorkerThreadsPatchModule = require.resolve('./cucumber-worker-threads')
|
|
@@ -563,12 +564,6 @@ function getErrorFromCucumberResult (cucumberResult) {
|
|
|
563
564
|
return error
|
|
564
565
|
}
|
|
565
566
|
|
|
566
|
-
function getChannelPromise (channelToPublishTo, frameworkVersion = null) {
|
|
567
|
-
return new Promise(resolve => {
|
|
568
|
-
channelToPublishTo.publish({ onDone: resolve, frameworkVersion })
|
|
569
|
-
})
|
|
570
|
-
}
|
|
571
|
-
|
|
572
567
|
function getShouldBeSkippedSuite (pickle, suitesToSkip) {
|
|
573
568
|
const testSuitePath = getTestSuitePath(pickle.uri, process.cwd())
|
|
574
569
|
const isUnskippable = isMarkedAsUnskippable(pickle)
|
|
@@ -1056,7 +1051,7 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
|
|
|
1056
1051
|
}
|
|
1057
1052
|
let errorSkippableRequest
|
|
1058
1053
|
|
|
1059
|
-
const configurationResponse = await getChannelPromise(libraryConfigurationCh, frameworkVersion)
|
|
1054
|
+
const configurationResponse = await getChannelPromise(libraryConfigurationCh, { frameworkVersion }) || {}
|
|
1060
1055
|
|
|
1061
1056
|
repositoryRoot = configurationResponse.repositoryRoot
|
|
1062
1057
|
isItrEnabled = configurationResponse.libraryConfig?.isItrEnabled
|
|
@@ -1089,7 +1084,7 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
|
|
|
1089
1084
|
|
|
1090
1085
|
if (isKnownTestsEnabled) {
|
|
1091
1086
|
const currentKnownTestsResponse = knownTestsResponse || await getChannelPromise(knownTestsCh)
|
|
1092
|
-
if (currentKnownTestsResponse.err) {
|
|
1087
|
+
if (!currentKnownTestsResponse || currentKnownTestsResponse.err) {
|
|
1093
1088
|
isEarlyFlakeDetectionEnabled = false
|
|
1094
1089
|
isKnownTestsEnabled = false
|
|
1095
1090
|
} else {
|
|
@@ -1098,7 +1093,9 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
|
|
|
1098
1093
|
}
|
|
1099
1094
|
|
|
1100
1095
|
if (isSuitesSkippingEnabled) {
|
|
1101
|
-
const skippableResponse = skippableSuitesResponse ||
|
|
1096
|
+
const skippableResponse = skippableSuitesResponse ||
|
|
1097
|
+
await getChannelPromise(skippableSuitesCh) ||
|
|
1098
|
+
{ err: true }
|
|
1102
1099
|
|
|
1103
1100
|
errorSkippableRequest = skippableResponse.err
|
|
1104
1101
|
skippableSuites = skippableResponse.skippableSuites ?? []
|
|
@@ -1147,7 +1144,7 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
|
|
|
1147
1144
|
if (isTestManagementTestsEnabled) {
|
|
1148
1145
|
const currentTestManagementTestsResponse =
|
|
1149
1146
|
testManagementTestsResponse || await getChannelPromise(testManagementTestsCh)
|
|
1150
|
-
if (currentTestManagementTestsResponse.err) {
|
|
1147
|
+
if (!currentTestManagementTestsResponse || currentTestManagementTestsResponse.err) {
|
|
1151
1148
|
isTestManagementTestsEnabled = false
|
|
1152
1149
|
} else {
|
|
1153
1150
|
testManagementTests = currentTestManagementTestsResponse.testManagementTests
|
|
@@ -1156,7 +1153,7 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
|
|
|
1156
1153
|
|
|
1157
1154
|
if (isImpactedTestsEnabled) {
|
|
1158
1155
|
const impactedTestsResponse = await getChannelPromise(modifiedFilesCh)
|
|
1159
|
-
if (!impactedTestsResponse.err) {
|
|
1156
|
+
if (impactedTestsResponse && !impactedTestsResponse.err) {
|
|
1160
1157
|
modifiedFiles = impactedTestsResponse.modifiedFiles
|
|
1161
1158
|
}
|
|
1162
1159
|
}
|
|
@@ -1215,7 +1212,7 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
|
|
|
1215
1212
|
global.__coverage__ = fromCoverageMapToCoverage(originalCoverageMap)
|
|
1216
1213
|
}
|
|
1217
1214
|
|
|
1218
|
-
sessionFinishCh
|
|
1215
|
+
const flushPromise = getChannelPromise(sessionFinishCh, {
|
|
1219
1216
|
status: success ? 'pass' : 'fail',
|
|
1220
1217
|
isSuitesSkipped,
|
|
1221
1218
|
testCodeCoverageLinesTotal,
|
|
@@ -1228,9 +1225,11 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
|
|
|
1228
1225
|
isTestManagementTestsEnabled,
|
|
1229
1226
|
isParallel,
|
|
1230
1227
|
})
|
|
1228
|
+
|
|
1231
1229
|
logTestOptimizationSummary({ attemptToFixExecutions })
|
|
1232
1230
|
loggedAttemptToFixTests.clear()
|
|
1233
1231
|
eventDataCollector = null
|
|
1232
|
+
await flushPromise
|
|
1234
1233
|
return result
|
|
1235
1234
|
}
|
|
1236
1235
|
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @template {unknown[]} T
|
|
5
|
+
* @param {(...args: T) => void} onDone
|
|
6
|
+
* @returns {(...args: T) => void}
|
|
7
|
+
*/
|
|
8
|
+
function getCompletion (onDone) {
|
|
9
|
+
let hasCompleted = false
|
|
10
|
+
return (...args) => {
|
|
11
|
+
if (hasCompleted) return
|
|
12
|
+
|
|
13
|
+
hasCompleted = true
|
|
14
|
+
onDone(...args)
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @template {unknown[]} T
|
|
20
|
+
* @param {import('node:diagnostics_channel').Channel} channel
|
|
21
|
+
* @param {Record<string, unknown>} payload
|
|
22
|
+
* @param {(...args: T) => void} onDone
|
|
23
|
+
* @returns {void}
|
|
24
|
+
*/
|
|
25
|
+
function publishWithCompletion (channel, payload, onDone) {
|
|
26
|
+
const complete = getCompletion(onDone)
|
|
27
|
+
channel.publish({ ...payload, onDone: complete })
|
|
28
|
+
if (!channel.hasSubscribers) complete()
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @template {unknown[]} T
|
|
33
|
+
* @param {import('node:diagnostics_channel').Channel} channel
|
|
34
|
+
* @param {Record<string, unknown> & { onDone?: (...args: T) => void }} payload
|
|
35
|
+
* @param {(...args: T) => void} onDone
|
|
36
|
+
* @returns {void}
|
|
37
|
+
*/
|
|
38
|
+
function runStoresWithCompletion (channel, payload, onDone) {
|
|
39
|
+
const complete = getCompletion(onDone)
|
|
40
|
+
payload.onDone = complete
|
|
41
|
+
channel.runStores(payload, () => {})
|
|
42
|
+
if (!channel.hasSubscribers) complete()
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* @template T
|
|
47
|
+
* @param {import('node:diagnostics_channel').Channel} channel
|
|
48
|
+
* @param {Record<string, unknown>} [payload]
|
|
49
|
+
* @returns {Promise<T>}
|
|
50
|
+
*/
|
|
51
|
+
function getChannelPromise (channel, payload = {}) {
|
|
52
|
+
return new Promise(resolve => {
|
|
53
|
+
publishWithCompletion(channel, payload, resolve)
|
|
54
|
+
})
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* @template T
|
|
59
|
+
* @param {import('node:diagnostics_channel').Channel} channel
|
|
60
|
+
* @param {Record<string, unknown>} [payload]
|
|
61
|
+
* @returns {Promise<T>}
|
|
62
|
+
*/
|
|
63
|
+
function getRunStoresPromise (channel, payload = {}) {
|
|
64
|
+
return new Promise(resolve => {
|
|
65
|
+
runStoresWithCompletion(channel, { ...payload }, resolve)
|
|
66
|
+
})
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
module.exports = {
|
|
70
|
+
getChannelPromise,
|
|
71
|
+
getRunStoresPromise,
|
|
72
|
+
publishWithCompletion,
|
|
73
|
+
runStoresWithCompletion,
|
|
74
|
+
}
|
|
@@ -21,6 +21,8 @@ module.exports = {
|
|
|
21
21
|
'@apollo/gateway': () => require('../apollo'),
|
|
22
22
|
'@langchain/langgraph': { esmFirst: true, fn: () => require('../langgraph') },
|
|
23
23
|
'@modelcontextprotocol/sdk': { esmFirst: true, fn: () => require('../modelcontextprotocol-sdk') },
|
|
24
|
+
'@openai/agents': () => require('../openai-agents'),
|
|
25
|
+
'@openai/agents-openai': () => require('../openai-agents'),
|
|
24
26
|
'apollo-server-core': () => require('../apollo-server-core'),
|
|
25
27
|
'@aws-sdk/smithy-client': () => require('../aws-sdk'),
|
|
26
28
|
'@aws/durable-execution-sdk-js': () => require('../aws-durable-execution-sdk-js'),
|
package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/openai-agents.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const moduleName = '@openai/agents-openai'
|
|
4
|
+
const versionRange = '>=0.7.0'
|
|
5
|
+
const functionQuery = {
|
|
6
|
+
methodName: 'constructor',
|
|
7
|
+
className: 'OpenAIChatCompletionsModel',
|
|
8
|
+
kind: 'Sync',
|
|
9
|
+
}
|
|
10
|
+
const channelName = 'OpenAIChatCompletionsModel_constructor'
|
|
11
|
+
|
|
12
|
+
module.exports = [
|
|
13
|
+
{
|
|
14
|
+
module: {
|
|
15
|
+
name: moduleName,
|
|
16
|
+
versionRange,
|
|
17
|
+
filePath: 'dist/openaiChatCompletionsModel.js',
|
|
18
|
+
},
|
|
19
|
+
functionQuery,
|
|
20
|
+
channelName,
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
module: {
|
|
24
|
+
name: moduleName,
|
|
25
|
+
versionRange,
|
|
26
|
+
filePath: 'dist/openaiChatCompletionsModel.mjs',
|
|
27
|
+
},
|
|
28
|
+
functionQuery,
|
|
29
|
+
channelName,
|
|
30
|
+
},
|
|
31
|
+
]
|