dd-trace 6.12.0 → 6.13.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/test-optimization-validation/framework-adapters/cypress.js +9 -11
- package/ci/test-optimization-validation/scenarios/ci-wiring.js +5 -4
- package/index.d.ts +127 -26
- package/package.json +10 -10
- package/packages/datadog-instrumentations/src/bunyan.js +4 -2
- package/packages/datadog-instrumentations/src/helpers/bunyan.js +12 -3
- package/packages/datadog-instrumentations/src/helpers/pool-acquire.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +28 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +1 -0
- package/packages/datadog-instrumentations/src/jest.js +140 -18
- package/packages/datadog-instrumentations/src/mariadb-bundle.js +1597 -0
- package/packages/datadog-instrumentations/src/mariadb.js +7 -0
- package/packages/datadog-instrumentations/src/pino.js +15 -4
- package/packages/datadog-instrumentations/src/playwright.js +34 -20
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +7 -4
- package/packages/datadog-instrumentations/src/vitest-worker.js +11 -0
- package/packages/datadog-instrumentations/src/webdriverio.js +26 -0
- package/packages/datadog-instrumentations/src/winston.js +6 -3
- package/packages/datadog-plugin-cypress/src/support.js +1 -0
- package/packages/datadog-plugin-http/src/client.js +2 -15
- package/packages/datadog-plugin-http2/src/client.js +2 -15
- package/packages/datadog-plugin-openai-agents/src/integration.js +15 -11
- package/packages/datadog-plugin-playwright/src/index.js +9 -1
- package/packages/datadog-plugin-undici/src/index.js +2 -15
- package/packages/dd-trace/src/aiguard/evaluation.js +94 -20
- package/packages/dd-trace/src/aiguard/integrations/vercel-ai.js +2 -3
- package/packages/dd-trace/src/aiguard/messages/anthropic.js +21 -9
- package/packages/dd-trace/src/aiguard/noop.js +9 -1
- package/packages/dd-trace/src/aiguard/redaction.js +183 -0
- package/packages/dd-trace/src/aiguard/sdk.js +7 -2
- package/packages/dd-trace/src/aiguard/tags.js +2 -0
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +10 -9
- package/packages/dd-trace/src/appsec/rule_manager.js +2 -0
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/request-tracker.js +51 -26
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +5 -11
- package/packages/dd-trace/src/ci-visibility/final-flush.js +20 -0
- package/packages/dd-trace/src/ci-visibility/log-submission/log-submission-plugin.js +196 -29
- package/packages/dd-trace/src/config/generated-config-types.d.ts +6 -0
- package/packages/dd-trace/src/config/index.js +2 -1
- package/packages/dd-trace/src/config/supported-configurations.json +27 -0
- package/packages/dd-trace/src/debugger/devtools_client/send.js +4 -3
- package/packages/dd-trace/src/dogstatsd.js +45 -18
- package/packages/dd-trace/src/encode/agentless-json.js +5 -4
- package/packages/dd-trace/src/exporters/agent/index.js +22 -2
- package/packages/dd-trace/src/exporters/agent/writer.js +4 -4
- package/packages/dd-trace/src/exporters/common/writer.js +24 -2
- package/packages/dd-trace/src/exporters/span-stats/index.js +23 -4
- package/packages/dd-trace/src/external-logger/src/index.js +4 -3
- package/packages/dd-trace/src/flush.js +102 -0
- package/packages/dd-trace/src/llmobs/experiments/client.js +4 -0
- package/packages/dd-trace/src/llmobs/experiments/dataset.js +51 -2
- package/packages/dd-trace/src/llmobs/experiments/experiment.js +420 -105
- package/packages/dd-trace/src/llmobs/experiments/index.js +54 -42
- package/packages/dd-trace/src/llmobs/experiments/noop.js +39 -8
- package/packages/dd-trace/src/llmobs/experiments/result.js +1 -0
- package/packages/dd-trace/src/llmobs/experiments/util.js +21 -0
- package/packages/dd-trace/src/llmobs/index.js +80 -17
- package/packages/dd-trace/src/llmobs/noop.js +2 -1
- package/packages/dd-trace/src/llmobs/plugins/anthropic/util.js +8 -4
- package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/index.js +6 -3
- package/packages/dd-trace/src/llmobs/plugins/openai/utils.js +13 -6
- package/packages/dd-trace/src/llmobs/plugins/openai-agents/utils.js +5 -7
- package/packages/dd-trace/src/llmobs/writers/base.js +60 -24
- package/packages/dd-trace/src/noop/span.js +5 -0
- package/packages/dd-trace/src/openfeature/writers/exposures.js +8 -1
- package/packages/dd-trace/src/opentelemetry/logs/batch_log_processor.js +45 -3
- package/packages/dd-trace/src/opentelemetry/logs/index.js +4 -1
- package/packages/dd-trace/src/opentelemetry/logs/logger_provider.js +7 -4
- package/packages/dd-trace/src/opentelemetry/metrics/index.js +3 -1
- package/packages/dd-trace/src/opentelemetry/metrics/meter_provider.js +8 -0
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_http_metric_exporter.js +4 -2
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_exporter.js +4 -2
- package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +25 -5
- package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +61 -25
- package/packages/dd-trace/src/opentelemetry/tracer.js +26 -2
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +410 -342
- package/packages/dd-trace/src/opentracing/span.js +28 -0
- package/packages/dd-trace/src/otel-thread-ctx.js +23 -5
- package/packages/dd-trace/src/plugin_manager.js +2 -0
- package/packages/dd-trace/src/plugins/util/status-validator.js +98 -0
- package/packages/dd-trace/src/plugins/util/test.js +74 -21
- package/packages/dd-trace/src/plugins/util/web.js +2 -65
- package/packages/dd-trace/src/profiling/oom.js +4 -3
- package/packages/dd-trace/src/profiling/profiler.js +7 -0
- package/packages/dd-trace/src/profiling/profilers/events.js +3 -3
- package/packages/dd-trace/src/profiling/profilers/wall.js +14 -14
- package/packages/dd-trace/src/proxy.js +36 -8
- package/packages/dd-trace/src/runtime_metrics/index.js +5 -0
- package/packages/dd-trace/src/runtime_metrics/otlp_runtime_metrics.js +5 -0
- package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +17 -6
- package/packages/dd-trace/src/serverless/telemetry-delivery-tracker.js +55 -0
- package/packages/dd-trace/src/serverless/vercel.js +122 -0
- package/packages/dd-trace/src/serverless.js +37 -20
- package/packages/dd-trace/src/span_stats.js +40 -3
- package/packages/dd-trace/src/tracer.js +22 -0
- package/packages/dd-trace/src/web-tags-cache.js +67 -13
- package/vendor/dist/@datadog/openfeature-node-server/index.js +1 -1
|
@@ -14,6 +14,7 @@ const {
|
|
|
14
14
|
takePoolWaitTime,
|
|
15
15
|
wrapPoolQueryMethod,
|
|
16
16
|
} = require('./helpers/pool-acquire')
|
|
17
|
+
const { wrapCallbackBundle, wrapPromiseBundle } = require('./mariadb-bundle')
|
|
17
18
|
|
|
18
19
|
const commandAddCh = channel('apm:mariadb:command:add')
|
|
19
20
|
const connectionStartCh = channel('apm:mariadb:connection:start')
|
|
@@ -443,3 +444,9 @@ addHook({ name, file: 'lib/connection.js', versions: ['>=2.0.4 <=2.5.1'] }, (Con
|
|
|
443
444
|
addHook({ name, file: 'lib/pool-base.js', versions: ['>=2.0.4 <3'] }, (PoolBase) => {
|
|
444
445
|
return shimmer.wrapFunction(PoolBase, wrapPoolBase)
|
|
445
446
|
})
|
|
447
|
+
|
|
448
|
+
// MariaDB 3.5.3 added single-file CommonJS bundles that do not load the original source modules at runtime.
|
|
449
|
+
// Matching their generated, minified internals would couple instrumentation to unstable bundle output, so wrap
|
|
450
|
+
// the runtime objects returned by the public factories instead.
|
|
451
|
+
addHook({ name, versions: ['>=3.5.3'] }, wrapPromiseBundle)
|
|
452
|
+
addHook({ name, file: 'dist/callback.cjs', versions: ['>=3.5.3'] }, wrapCallbackBundle)
|
|
@@ -6,6 +6,8 @@ const {
|
|
|
6
6
|
addHook,
|
|
7
7
|
} = require('./helpers/instrument')
|
|
8
8
|
|
|
9
|
+
const logSubmissionCh = channel('ci:log-submission:log')
|
|
10
|
+
|
|
9
11
|
/**
|
|
10
12
|
* @param {string} symbol
|
|
11
13
|
* @param {(original: Function) => Function} wrapper
|
|
@@ -36,13 +38,22 @@ function wrapAsJson (asJson) {
|
|
|
36
38
|
obj = arguments[0] = obj || {}
|
|
37
39
|
|
|
38
40
|
// Caller-provided `dd` wins -- skip the splice so a bespoke `dd` survives.
|
|
41
|
+
let line
|
|
39
42
|
if (!jsonCh.hasSubscribers || Object.hasOwn(obj, 'dd')) {
|
|
40
|
-
|
|
43
|
+
line = asJson.apply(this, arguments)
|
|
44
|
+
} else {
|
|
45
|
+
const payload = { line: asJson.apply(this, arguments) }
|
|
46
|
+
jsonCh.publish(payload)
|
|
47
|
+
line = payload.line
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Submit the serialized line for agentless log collection only when trace
|
|
51
|
+
// correlation is active, matching the Bunyan contract.
|
|
52
|
+
if (jsonCh.hasSubscribers && logSubmissionCh.hasSubscribers) {
|
|
53
|
+
logSubmissionCh.publish({ source: 'pino', message: line })
|
|
41
54
|
}
|
|
42
55
|
|
|
43
|
-
|
|
44
|
-
jsonCh.publish(payload)
|
|
45
|
-
return payload.line
|
|
56
|
+
return line
|
|
46
57
|
}
|
|
47
58
|
}
|
|
48
59
|
|
|
@@ -59,6 +59,7 @@ const testSuiteStartCh = channel('ci:playwright:test-suite:start')
|
|
|
59
59
|
const testSuiteFinishCh = channel('ci:playwright:test-suite:finish')
|
|
60
60
|
|
|
61
61
|
const workerReportCh = channel('ci:playwright:worker:report')
|
|
62
|
+
const logSubmissionFlushCh = channel('ci:log-submission:flush')
|
|
62
63
|
const workerReportTelemetryCh = channel('ci:playwright:worker-report:telemetry')
|
|
63
64
|
const testPageGotoCh = channel('ci:playwright:test:page-goto')
|
|
64
65
|
|
|
@@ -1085,7 +1086,7 @@ function onDispatcherCreateWorker (dispatcher, worker) {
|
|
|
1085
1086
|
|
|
1086
1087
|
const projects = getProjectsFromDispatcher(dispatcher)
|
|
1087
1088
|
sessionProjects = projects
|
|
1088
|
-
const
|
|
1089
|
+
const automaticFailureScreenshotsByTestId = new Map()
|
|
1089
1090
|
|
|
1090
1091
|
if (disabledTestIds.size && !worker[kDdPlaywrightWorkerHostInstrumented] &&
|
|
1091
1092
|
typeof worker.runTestGroup === 'function') {
|
|
@@ -1110,19 +1111,21 @@ function onDispatcherCreateWorker (dispatcher, worker) {
|
|
|
1110
1111
|
const test = getTestByTestId(dispatcher, testId)
|
|
1111
1112
|
if (!test) return
|
|
1112
1113
|
|
|
1114
|
+
automaticFailureScreenshotsByTestId.clear()
|
|
1113
1115
|
const browser = getBrowserNameFromProjects(projects, test)
|
|
1114
1116
|
const shouldCreateTestSpan = test.expectedStatus === 'skipped'
|
|
1115
1117
|
testBeginHandler(test, browser, shouldCreateTestSpan)
|
|
1116
1118
|
})
|
|
1117
|
-
worker.on('attach', (
|
|
1119
|
+
worker.on('attach', (attachment) => {
|
|
1120
|
+
const { testId, _ddIsAutomaticFailureScreenshot } = attachment
|
|
1118
1121
|
if (!_ddIsAutomaticFailureScreenshot) return
|
|
1119
1122
|
|
|
1120
|
-
let
|
|
1121
|
-
if (!
|
|
1122
|
-
|
|
1123
|
-
|
|
1123
|
+
let screenshots = automaticFailureScreenshotsByTestId.get(testId)
|
|
1124
|
+
if (!screenshots) {
|
|
1125
|
+
screenshots = []
|
|
1126
|
+
automaticFailureScreenshotsByTestId.set(testId, screenshots)
|
|
1124
1127
|
}
|
|
1125
|
-
|
|
1128
|
+
screenshots.push(attachment)
|
|
1126
1129
|
})
|
|
1127
1130
|
worker.on('testEnd', ({ testId, status, errors, annotations }) => {
|
|
1128
1131
|
const test = getTestByTestId(dispatcher, testId)
|
|
@@ -1146,19 +1149,20 @@ function onDispatcherCreateWorker (dispatcher, worker) {
|
|
|
1146
1149
|
}
|
|
1147
1150
|
)
|
|
1148
1151
|
const testResult = test.results.at(-1)
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1152
|
+
if (isFailureScreenshotUploadEnabled &&
|
|
1153
|
+
!shouldCreateTestSpan &&
|
|
1154
|
+
!test._ddShouldSkipEfdRetry &&
|
|
1155
|
+
!disabledTestIds.has(testId)) {
|
|
1156
|
+
let screenshots
|
|
1157
|
+
if (testStatus === 'fail') {
|
|
1158
|
+
screenshots = automaticFailureScreenshotsByTestId.get(testId)
|
|
1159
|
+
if (!screenshots) {
|
|
1160
|
+
screenshots = []
|
|
1161
|
+
automaticFailureScreenshotsByTestId.set(testId, screenshots)
|
|
1156
1162
|
}
|
|
1157
1163
|
}
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
worker[kDdPlaywrightFailureScreenshots].push(screenshots)
|
|
1161
|
-
}
|
|
1164
|
+
worker[kDdPlaywrightFailureScreenshots] ??= []
|
|
1165
|
+
worker[kDdPlaywrightFailureScreenshots].push(screenshots)
|
|
1162
1166
|
}
|
|
1163
1167
|
const isAtrRetry = testResult?.retry > 0 &&
|
|
1164
1168
|
isFlakyTestRetriesEnabled &&
|
|
@@ -2212,7 +2216,8 @@ addHook({
|
|
|
2212
2216
|
|
|
2213
2217
|
function instrumentWorkerMainMethods (workerMain) {
|
|
2214
2218
|
if (!workerMain || workerMain[kDdPlaywrightWorkerInstrumented] ||
|
|
2215
|
-
typeof workerMain._runTest !== 'function' || typeof workerMain.dispatchEvent !== 'function'
|
|
2219
|
+
typeof workerMain._runTest !== 'function' || typeof workerMain.dispatchEvent !== 'function' ||
|
|
2220
|
+
typeof workerMain.gracefullyClose !== 'function') {
|
|
2216
2221
|
return workerMain
|
|
2217
2222
|
}
|
|
2218
2223
|
|
|
@@ -2228,6 +2233,15 @@ function instrumentWorkerMainMethods (workerMain) {
|
|
|
2228
2233
|
return runTestGroup.apply(this, arguments)
|
|
2229
2234
|
})
|
|
2230
2235
|
|
|
2236
|
+
// Playwright >=1.60 creates WorkerMain through a runtime factory, which Orchestrion cannot wrap statically.
|
|
2237
|
+
shimmer.wrap(workerMain, 'gracefullyClose', gracefullyClose => async function () {
|
|
2238
|
+
try {
|
|
2239
|
+
return await gracefullyClose.apply(this, arguments)
|
|
2240
|
+
} finally {
|
|
2241
|
+
await getChannelPromise(logSubmissionFlushCh)
|
|
2242
|
+
}
|
|
2243
|
+
})
|
|
2244
|
+
|
|
2231
2245
|
shimmer.wrap(workerMain, '_runTest', _runTest => async function (test) {
|
|
2232
2246
|
if (this[kDdPlaywrightDisabledTestIds]?.has(test.id)) {
|
|
2233
2247
|
test._ddIsDisabled = true
|
|
@@ -2393,7 +2407,7 @@ function instrumentWorkerMainMethods (workerMain) {
|
|
|
2393
2407
|
// We reproduce what happens in `Dispatcher#_onStepBegin` and `Dispatcher#_onStepEnd`,
|
|
2394
2408
|
// since `startTime` and `duration` are not available directly in the worker process
|
|
2395
2409
|
shimmer.wrap(workerMain, 'dispatchEvent', dispatchEvent => function (event, payload) {
|
|
2396
|
-
if (event === 'testBegin'
|
|
2410
|
+
if (event === 'testBegin') {
|
|
2397
2411
|
automaticFailureScreenshotPaths.clear()
|
|
2398
2412
|
} else if (event === 'stepBegin') {
|
|
2399
2413
|
stepInfoByStepId[payload.stepId] = {
|
|
@@ -1602,15 +1602,18 @@ function splitNodeOptions (nodeOptions) {
|
|
|
1602
1602
|
}
|
|
1603
1603
|
|
|
1604
1604
|
function serializeNodeOptions (tokens) {
|
|
1605
|
-
|
|
1605
|
+
let serializedTokens = ''
|
|
1606
|
+
let hasSerializedToken = false
|
|
1606
1607
|
for (const token of tokens) {
|
|
1608
|
+
if (hasSerializedToken) serializedTokens += ' '
|
|
1607
1609
|
if (NODE_OPTIONS_QUOTE_RE.test(token)) {
|
|
1608
|
-
serializedTokens
|
|
1610
|
+
serializedTokens += JSON.stringify(token)
|
|
1609
1611
|
} else {
|
|
1610
|
-
serializedTokens
|
|
1612
|
+
serializedTokens += token
|
|
1611
1613
|
}
|
|
1614
|
+
hasSerializedToken = true
|
|
1612
1615
|
}
|
|
1613
|
-
return serializedTokens
|
|
1616
|
+
return serializedTokens
|
|
1614
1617
|
}
|
|
1615
1618
|
|
|
1616
1619
|
function getTestSpecificationProject (testSpecification) {
|
|
@@ -5,6 +5,7 @@ const { performance } = require('node:perf_hooks')
|
|
|
5
5
|
const { fileURLToPath } = require('node:url')
|
|
6
6
|
const { isMainThread, parentPort } = require('node:worker_threads')
|
|
7
7
|
|
|
8
|
+
const { channel } = require('dc-polyfill')
|
|
8
9
|
const shimmer = require('../../datadog-shimmer')
|
|
9
10
|
const log = require('../../dd-trace/src/log')
|
|
10
11
|
const { getEfdRetryCountForDuration } = require('../../dd-trace/src/ci-visibility/efd-retry-policy')
|
|
@@ -40,10 +41,12 @@ const {
|
|
|
40
41
|
} = require('./vitest-util')
|
|
41
42
|
|
|
42
43
|
const EFD_SUITE_ADMISSION_TIMEOUT_MS = 5000
|
|
44
|
+
const logSubmissionFlushCh = channel('ci:log-submission:flush')
|
|
43
45
|
const taskToCtx = new WeakMap()
|
|
44
46
|
const taskToTestProperties = new WeakMap()
|
|
45
47
|
const taskToStatuses = new WeakMap()
|
|
46
48
|
const taskToReportedErrorCount = new WeakMap()
|
|
49
|
+
const runnersWithLogSubmissionCleanup = new WeakSet()
|
|
47
50
|
const attemptToFixTaskToStatuses = new WeakMap()
|
|
48
51
|
const fileToHasConcurrentTests = new WeakMap()
|
|
49
52
|
const fileToEfdSuiteAdmission = new WeakMap()
|
|
@@ -954,6 +957,14 @@ addHook({
|
|
|
954
957
|
if (!testSuiteFinishCh.hasSubscribers) {
|
|
955
958
|
return startTests.apply(this, arguments)
|
|
956
959
|
}
|
|
960
|
+
const runner = arguments[1]
|
|
961
|
+
// Vitest 3+ exposes the only awaited worker-shutdown boundary; older versions keep timer/before-exit behavior.
|
|
962
|
+
if (logSubmissionFlushCh.hasSubscribers &&
|
|
963
|
+
typeof runner?.onCleanupWorkerContext === 'function' &&
|
|
964
|
+
!runnersWithLogSubmissionCleanup.has(runner)) {
|
|
965
|
+
runnersWithLogSubmissionCleanup.add(runner)
|
|
966
|
+
runner.onCleanupWorkerContext(() => getChannelPromise(logSubmissionFlushCh))
|
|
967
|
+
}
|
|
957
968
|
// From >=3.0.1, the first arguments changes from a string to an object containing the filepath
|
|
958
969
|
const testSuiteAbsolutePath = testPaths[0]?.filepath || testPaths[0]
|
|
959
970
|
const providedContext = getProvidedContext()
|
|
@@ -16,6 +16,7 @@ const {
|
|
|
16
16
|
MOCHA_WORKER_TRACE_PAYLOAD_CODE,
|
|
17
17
|
TEST_SUITE_EXECUTION_ID,
|
|
18
18
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
19
|
+
const { publishWithCompletion } = require('./helpers/channel')
|
|
19
20
|
const { addHook, channel, tracingChannel } = require('./helpers/instrument')
|
|
20
21
|
const {
|
|
21
22
|
CONFIGURATION_REQUEST,
|
|
@@ -38,6 +39,7 @@ const testSuiteStartCh = channel('ci:mocha:test-suite:start')
|
|
|
38
39
|
const testSuiteFinishCh = channel('ci:mocha:test-suite:finish')
|
|
39
40
|
const knownTestsCh = channel('ci:mocha:known-tests')
|
|
40
41
|
const libraryConfigurationCh = channel('ci:mocha:library-configuration')
|
|
42
|
+
const logSubmissionFlushCh = channel('ci:log-submission:flush')
|
|
41
43
|
const modifiedFilesCh = channel('ci:mocha:modified-files')
|
|
42
44
|
const testManagementTestsCh = channel('ci:mocha:test-management-tests')
|
|
43
45
|
const workerConfigurationCh = channel('ci:mocha:worker:configuration')
|
|
@@ -46,6 +48,7 @@ const workerReportTelemetryCh = channel('ci:mocha:worker-report:telemetry')
|
|
|
46
48
|
const workerReportTraceCh = channel('ci:mocha:worker-report:trace')
|
|
47
49
|
|
|
48
50
|
const jasmineAdapterInitCh = tracingChannel('orchestrion:@wdio/jasmine-framework:JasmineAdapter_init')
|
|
51
|
+
const baseReporterWaitForSyncCh = tracingChannel('orchestrion:@wdio/runner:BaseReporter_waitForSync')
|
|
49
52
|
const launcherStartInstanceCh = tracingChannel('orchestrion:@wdio/cli:Launcher_startInstance')
|
|
50
53
|
const localRunnerRunCh = tracingChannel('orchestrion:@wdio/local-runner:LocalRunner_run')
|
|
51
54
|
const localRunnerShutdownCh = tracingChannel('orchestrion:@wdio/local-runner:LocalRunner_shutdown')
|
|
@@ -1000,6 +1003,29 @@ function finishCoordinator (state, error, onDone) {
|
|
|
1000
1003
|
})
|
|
1001
1004
|
}
|
|
1002
1005
|
|
|
1006
|
+
/**
|
|
1007
|
+
* Delays WebdriverIO worker exit until pending log-submission requests settle.
|
|
1008
|
+
*
|
|
1009
|
+
* @param {{
|
|
1010
|
+
* resolveCallback?: (onDone: () => void) => void,
|
|
1011
|
+
* rejectCallback?: (onDone: () => void) => void
|
|
1012
|
+
* }} context
|
|
1013
|
+
* @returns {void}
|
|
1014
|
+
*/
|
|
1015
|
+
function waitForLogSubmissionAtWorkerExit (context) {
|
|
1016
|
+
if (!isWebdriverioWorker || !logSubmissionFlushCh.hasSubscribers) {
|
|
1017
|
+
return
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
const waitForLogs = onDone => publishWithCompletion(logSubmissionFlushCh, {}, onDone)
|
|
1021
|
+
context.resolveCallback = waitForLogs
|
|
1022
|
+
context.rejectCallback = waitForLogs
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
baseReporterWaitForSyncCh.asyncEnd.subscribe(
|
|
1026
|
+
/** @type {import('node:diagnostics_channel').ChannelListener} */ (waitForLogSubmissionAtWorkerExit)
|
|
1027
|
+
)
|
|
1028
|
+
|
|
1003
1029
|
// dc-polyfill supports partial tracing-channel subscribers, unlike the Node.js type definition.
|
|
1004
1030
|
// @ts-expect-error
|
|
1005
1031
|
jasmineAdapterInitCh.subscribe({
|
|
@@ -12,12 +12,15 @@ const patched = new WeakSet()
|
|
|
12
12
|
const configureCh = channel('ci:log-submission:winston:configure')
|
|
13
13
|
const addTransport = channel('ci:log-submission:winston:add-transport')
|
|
14
14
|
|
|
15
|
-
addHook({ name: 'winston',
|
|
15
|
+
addHook({ name: 'winston', versions: ['>=3'] }, winston => {
|
|
16
16
|
if (configureCh.hasSubscribers) {
|
|
17
|
-
configureCh.publish(
|
|
17
|
+
configureCh.publish({
|
|
18
|
+
createJsonFormat: winston.format.json,
|
|
19
|
+
StreamTransport: winston.transports.Stream,
|
|
20
|
+
})
|
|
18
21
|
}
|
|
19
22
|
|
|
20
|
-
return
|
|
23
|
+
return winston
|
|
21
24
|
})
|
|
22
25
|
|
|
23
26
|
addHook({ name: 'winston', file: 'lib/winston/logger.js', versions: ['>=3'] }, Logger => {
|
|
@@ -8,8 +8,8 @@ const tags = require('../../../ext/tags')
|
|
|
8
8
|
const formats = require('../../../ext/formats')
|
|
9
9
|
const HTTP_HEADERS = formats.HTTP_HEADERS
|
|
10
10
|
const urlFilter = require('../../dd-trace/src/plugins/util/urlfilter')
|
|
11
|
+
const { getClientStatusValidator } = require('../../dd-trace/src/plugins/util/status-validator')
|
|
11
12
|
const { buildClientHttpUrl } = require('../../dd-trace/src/plugins/util/url')
|
|
12
|
-
const log = require('../../dd-trace/src/log')
|
|
13
13
|
const { stripQueryAndFragment } = require('../../dd-trace/src/util')
|
|
14
14
|
const { CLIENT_PORT_KEY, COMPONENT, ERROR_MESSAGE, ERROR_TYPE, ERROR_STACK } = require('../../dd-trace/src/constants')
|
|
15
15
|
|
|
@@ -167,7 +167,7 @@ function addRequestHeaders (req, span, config) {
|
|
|
167
167
|
}
|
|
168
168
|
|
|
169
169
|
function normalizeClientConfig (config) {
|
|
170
|
-
const validateStatus =
|
|
170
|
+
const validateStatus = getClientStatusValidator(config)
|
|
171
171
|
const filter = getFilter(config)
|
|
172
172
|
const propagationFilter = getFilter({ blocklist: config.propagationBlocklist })
|
|
173
173
|
const headers = getHeaders(config)
|
|
@@ -183,19 +183,6 @@ function normalizeClientConfig (config) {
|
|
|
183
183
|
}
|
|
184
184
|
}
|
|
185
185
|
|
|
186
|
-
function is400ErrorCode (code) {
|
|
187
|
-
return code < 400 || code >= 500
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
function getStatusValidator (config) {
|
|
191
|
-
if (typeof config.validateStatus === 'function') {
|
|
192
|
-
return config.validateStatus
|
|
193
|
-
} else if (config.hasOwnProperty('validateStatus')) {
|
|
194
|
-
log.error('Expected `validateStatus` to be a function.')
|
|
195
|
-
}
|
|
196
|
-
return is400ErrorCode
|
|
197
|
-
}
|
|
198
|
-
|
|
199
186
|
function getFilter (config) {
|
|
200
187
|
config = { ...config, blocklist: config.blocklist || [] }
|
|
201
188
|
|
|
@@ -4,12 +4,12 @@ const URL = require('url').URL
|
|
|
4
4
|
|
|
5
5
|
const { storage } = require('../../datadog-core')
|
|
6
6
|
const ClientPlugin = require('../../dd-trace/src/plugins/client')
|
|
7
|
-
const log = require('../../dd-trace/src/log')
|
|
8
7
|
const tags = require('../../../ext/tags')
|
|
9
8
|
const kinds = require('../../../ext/kinds')
|
|
10
9
|
const formats = require('../../../ext/formats')
|
|
11
10
|
const { COMPONENT, CLIENT_PORT_KEY } = require('../../dd-trace/src/constants')
|
|
12
11
|
const urlFilter = require('../../dd-trace/src/plugins/util/urlfilter')
|
|
12
|
+
const { getClientStatusValidator } = require('../../dd-trace/src/plugins/util/status-validator')
|
|
13
13
|
const { buildClientHttpUrl } = require('../../dd-trace/src/plugins/util/url')
|
|
14
14
|
|
|
15
15
|
const HTTP_HEADERS = formats.HTTP_HEADERS
|
|
@@ -165,21 +165,8 @@ function hasAmazonSignature (headers, path) {
|
|
|
165
165
|
return false
|
|
166
166
|
}
|
|
167
167
|
|
|
168
|
-
function is400ErrorCode (code) {
|
|
169
|
-
return code < 400 || code >= 500
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
function getStatusValidator (config) {
|
|
173
|
-
if (typeof config.validateStatus === 'function') {
|
|
174
|
-
return config.validateStatus
|
|
175
|
-
} else if (config.hasOwnProperty('validateStatus')) {
|
|
176
|
-
log.error('Expected `validateStatus` to be a function.')
|
|
177
|
-
}
|
|
178
|
-
return is400ErrorCode
|
|
179
|
-
}
|
|
180
|
-
|
|
181
168
|
function normalizeConfig (config) {
|
|
182
|
-
const validateStatus =
|
|
169
|
+
const validateStatus = getClientStatusValidator(config)
|
|
183
170
|
const filter = getFilter(config)
|
|
184
171
|
const headers = getHeaders(config)
|
|
185
172
|
|
|
@@ -63,6 +63,7 @@ class OpenAIAgentsIntegration {
|
|
|
63
63
|
#tracer
|
|
64
64
|
#config
|
|
65
65
|
#enabled = false
|
|
66
|
+
#llmobsEnabled = true
|
|
66
67
|
#service
|
|
67
68
|
/**
|
|
68
69
|
* LLMObs is gated independently of APM tracing: when DD_LLMOBS_ENABLED is
|
|
@@ -95,10 +96,11 @@ class OpenAIAgentsIntegration {
|
|
|
95
96
|
/**
|
|
96
97
|
* Apply plugin lifecycle configuration.
|
|
97
98
|
*
|
|
98
|
-
* @param {{ enabled?: boolean, service?: string }} [config]
|
|
99
|
+
* @param {{ enabled?: boolean, llmobs?: boolean, service?: string }} [config]
|
|
99
100
|
*/
|
|
100
101
|
configure (config) {
|
|
101
102
|
this.#enabled = !!config?.enabled
|
|
103
|
+
this.#llmobsEnabled = config?.llmobs !== false
|
|
102
104
|
this.#service = config?.service
|
|
103
105
|
}
|
|
104
106
|
|
|
@@ -210,15 +212,17 @@ class OpenAIAgentsIntegration {
|
|
|
210
212
|
completionRequested: false,
|
|
211
213
|
})
|
|
212
214
|
|
|
213
|
-
this.#
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
215
|
+
if (this.#isLLMObsEnabled()) {
|
|
216
|
+
this.#tagger.registerLLMObsSpan(ddSpan, {
|
|
217
|
+
kind: 'workflow',
|
|
218
|
+
name,
|
|
219
|
+
integration: COMPONENT,
|
|
220
|
+
parent: llmobsParentStore?.span,
|
|
221
|
+
sessionId: oaiTrace.groupId || undefined,
|
|
222
|
+
})
|
|
223
|
+
if (LLMObsTagger.tagMap.has(ddSpan)) {
|
|
224
|
+
llmobsStorage.enterWith({ ...llmobsParentStore, span: ddSpan })
|
|
225
|
+
}
|
|
222
226
|
}
|
|
223
227
|
}
|
|
224
228
|
|
|
@@ -680,7 +684,7 @@ class OpenAIAgentsIntegration {
|
|
|
680
684
|
* @returns {boolean}
|
|
681
685
|
*/
|
|
682
686
|
#isLLMObsEnabled () {
|
|
683
|
-
return !!this.#config.llmobs?.DD_LLMOBS_ENABLED
|
|
687
|
+
return this.#llmobsEnabled && !!this.#config.llmobs?.DD_LLMOBS_ENABLED
|
|
684
688
|
}
|
|
685
689
|
|
|
686
690
|
/**
|
|
@@ -523,7 +523,15 @@ class PlaywrightPlugin extends CiPlugin {
|
|
|
523
523
|
|
|
524
524
|
finishAllTraceSpans(span)
|
|
525
525
|
if (this._tracerConfig.DD_PLAYWRIGHT_WORKER) {
|
|
526
|
-
|
|
526
|
+
try {
|
|
527
|
+
this.tracer._exporter.flush(onDone)
|
|
528
|
+
} catch (error) {
|
|
529
|
+
// A synchronous flush failure must still release the worker, otherwise it hangs.
|
|
530
|
+
// Log rather than rethrow: an exception from this diagnostics-channel subscriber
|
|
531
|
+
// would surface as an uncaught error in the worker and crash the user's test run.
|
|
532
|
+
onDone?.()
|
|
533
|
+
log.error('Error flushing traces at Playwright worker shutdown', error)
|
|
534
|
+
}
|
|
527
535
|
}
|
|
528
536
|
})
|
|
529
537
|
|
|
@@ -5,7 +5,7 @@ const { storage } = require('../../datadog-core')
|
|
|
5
5
|
const tags = require('../../../ext/tags')
|
|
6
6
|
const formats = require('../../../ext/formats')
|
|
7
7
|
const HTTP_HEADERS = formats.HTTP_HEADERS
|
|
8
|
-
const
|
|
8
|
+
const { getClientStatusValidator } = require('../../dd-trace/src/plugins/util/status-validator')
|
|
9
9
|
const { buildClientHttpUrl } = require('../../dd-trace/src/plugins/util/url')
|
|
10
10
|
const { stripQueryAndFragment } = require('../../dd-trace/src/util')
|
|
11
11
|
const { CLIENT_PORT_KEY } = require('../../dd-trace/src/constants')
|
|
@@ -302,7 +302,7 @@ function normalizeHeaders (headers) {
|
|
|
302
302
|
}
|
|
303
303
|
|
|
304
304
|
function normalizeConfig (config) {
|
|
305
|
-
const validateStatus =
|
|
305
|
+
const validateStatus = getClientStatusValidator(config)
|
|
306
306
|
const hooks = getHooks(config)
|
|
307
307
|
|
|
308
308
|
return {
|
|
@@ -312,19 +312,6 @@ function normalizeConfig (config) {
|
|
|
312
312
|
}
|
|
313
313
|
}
|
|
314
314
|
|
|
315
|
-
function getStatusValidator (config) {
|
|
316
|
-
if (typeof config.validateStatus === 'function') {
|
|
317
|
-
return config.validateStatus
|
|
318
|
-
} else if (Object.hasOwn(config, 'validateStatus')) {
|
|
319
|
-
log.error('Expected `validateStatus` to be a function.')
|
|
320
|
-
}
|
|
321
|
-
return defaultValidateStatus
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
function defaultValidateStatus (code) {
|
|
325
|
-
return code < 400 || code >= 500
|
|
326
|
-
}
|
|
327
|
-
|
|
328
315
|
function getHooks (config) {
|
|
329
316
|
const request = config.hooks?.request ?? noop
|
|
330
317
|
|