dd-trace 6.9.0 → 6.11.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/README.md +0 -17
- package/ci/vitest-no-worker-init-setup.mjs +112 -10
- package/index.d.ts +150 -3
- package/initialize.mjs +28 -17
- package/openfeature.js +2 -2
- package/package.json +14 -10
- package/packages/datadog-esbuild/index.js +0 -34
- package/packages/datadog-instrumentations/src/anthropic.js +210 -15
- package/packages/datadog-instrumentations/src/aws-sdk.js +9 -1
- package/packages/datadog-instrumentations/src/browser-bunyan.js +11 -0
- package/packages/datadog-instrumentations/src/bunyan.js +3 -16
- package/packages/datadog-instrumentations/src/confluentinc-kafka-javascript.js +111 -6
- package/packages/datadog-instrumentations/src/cucumber.js +26 -11
- package/packages/datadog-instrumentations/src/cypress-config.js +182 -16
- package/packages/datadog-instrumentations/src/cypress-legacy-finalizers.js +30 -0
- package/packages/datadog-instrumentations/src/cypress.js +2 -0
- package/packages/datadog-instrumentations/src/fastify.js +2 -0
- package/packages/datadog-instrumentations/src/helpers/bunyan.js +22 -0
- package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -1
- package/packages/datadog-instrumentations/src/helpers/pool-acquire.js +634 -0
- package/packages/datadog-instrumentations/src/helpers/register.js +10 -8
- 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 +26 -18
- package/packages/datadog-instrumentations/src/mariadb.js +278 -21
- package/packages/datadog-instrumentations/src/mocha/main.js +540 -56
- package/packages/datadog-instrumentations/src/mocha/utils.js +132 -25
- 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/playwright-reporter.js +99 -0
- package/packages/datadog-instrumentations/src/playwright.js +149 -2
- package/packages/datadog-instrumentations/src/router.js +2 -0
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +43 -4
- package/packages/datadog-instrumentations/src/vitest-main.js +180 -20
- 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/base.js +1 -0
- package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +163 -44
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +4 -13
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +1 -5
- package/packages/datadog-plugin-azure-functions/src/index.js +1 -1
- package/packages/datadog-plugin-browser-bunyan/src/index.js +9 -0
- package/packages/datadog-plugin-bunyan/src/index.js +5 -8
- package/packages/datadog-plugin-cucumber/src/index.js +11 -0
- package/packages/datadog-plugin-cypress/src/after-run.js +5 -1
- package/packages/datadog-plugin-cypress/src/after-spec.js +5 -1
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +82 -30
- package/packages/datadog-plugin-cypress/src/finalization.js +76 -0
- package/packages/datadog-plugin-cypress/src/index.js +12 -6
- package/packages/datadog-plugin-cypress/src/plugin.js +16 -3
- package/packages/datadog-plugin-dd-trace-api/src/index.js +4 -0
- package/packages/datadog-plugin-electron/src/index.js +2 -0
- package/packages/datadog-plugin-fs/src/index.js +1 -1
- package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +31 -17
- package/packages/datadog-plugin-jest/src/index.js +11 -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 +606 -40
- package/packages/datadog-plugin-mysql/src/index.js +37 -0
- package/packages/datadog-plugin-nats/src/index.js +1 -1
- package/packages/datadog-plugin-next/src/index.js +1 -19
- package/packages/datadog-plugin-openai/src/tracing.js +41 -30
- package/packages/datadog-plugin-openai-agents/src/integration.js +279 -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-playwright/src/index.js +42 -13
- package/packages/datadog-plugin-vitest/src/index.js +14 -20
- package/packages/datadog-plugin-ws/src/util.js +2 -1
- package/packages/datadog-webpack/index.js +0 -11
- package/packages/dd-trace/index.js +0 -1
- package/packages/dd-trace/src/agent/info.js +6 -5
- package/packages/dd-trace/src/aiguard/client.js +100 -1
- package/packages/dd-trace/src/aiguard/errors.js +41 -0
- package/packages/dd-trace/src/aiguard/evaluation.js +357 -0
- package/packages/dd-trace/src/aiguard/integrations/anthropic.js +70 -0
- package/packages/dd-trace/src/aiguard/integrations/index.js +4 -0
- package/packages/dd-trace/src/aiguard/messages/anthropic.js +423 -0
- package/packages/dd-trace/src/aiguard/messages/openai.js +1 -24
- package/packages/dd-trace/src/aiguard/messages/utils.js +28 -0
- package/packages/dd-trace/src/aiguard/messages/vercel-ai.js +1 -11
- package/packages/dd-trace/src/aiguard/sdk.js +22 -278
- 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/appsec/iast/taint-tracking/rewriter.js +9 -12
- package/packages/dd-trace/src/carrier.js +356 -0
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +1 -0
- package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +27 -3
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +22 -6
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +21 -5
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/request-tracker.js +164 -0
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +22 -6
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +365 -32
- package/packages/dd-trace/src/ci-visibility/exporters/request.js +201 -0
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +5 -3
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +9 -5
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +2 -1
- package/packages/dd-trace/src/ci-visibility/requests/rate-limit.js +39 -0
- package/packages/dd-trace/src/ci-visibility/requests/request.js +3 -6
- package/packages/dd-trace/src/ci-visibility/requests/upload-test-screenshot.js +6 -2
- package/packages/dd-trace/src/config/generated-config-types.d.ts +7 -0
- package/packages/dd-trace/src/config/index.js +13 -2
- package/packages/dd-trace/src/config/major-overrides.js +7 -0
- package/packages/dd-trace/src/config/supported-configurations.json +24 -0
- package/packages/dd-trace/src/datastreams/context.js +6 -1
- package/packages/dd-trace/src/datastreams/index.js +2 -0
- package/packages/dd-trace/src/datastreams/manager.js +14 -3
- package/packages/dd-trace/src/datastreams/pathway.js +23 -22
- package/packages/dd-trace/src/datastreams/processor.js +16 -13
- package/packages/dd-trace/src/datastreams/size.js +5 -0
- package/packages/dd-trace/src/debugger/devtools_client/index.js +3 -2
- package/packages/dd-trace/src/exporters/agent/writer.js +49 -9
- package/packages/dd-trace/src/exporters/common/buffering-exporter.js +6 -4
- package/packages/dd-trace/src/exporters/common/writer.js +11 -6
- package/packages/dd-trace/src/llmobs/constants/tags.js +5 -0
- package/packages/dd-trace/src/llmobs/experiments/client.js +163 -5
- package/packages/dd-trace/src/llmobs/experiments/dataset.js +241 -87
- package/packages/dd-trace/src/llmobs/experiments/experiment.js +280 -20
- package/packages/dd-trace/src/llmobs/experiments/index.js +58 -59
- package/packages/dd-trace/src/llmobs/experiments/noop.js +71 -3
- package/packages/dd-trace/src/llmobs/experiments/result.js +1 -0
- package/packages/dd-trace/src/llmobs/experiments/util.js +41 -5
- package/packages/dd-trace/src/llmobs/index.js +34 -2
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +12 -3
- package/packages/dd-trace/src/llmobs/plugins/base.js +4 -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/noop/proxy.js +3 -4
- package/packages/dd-trace/src/openfeature/flagging_provider.js +18 -2
- package/packages/dd-trace/src/openfeature/remote_config.js +1 -1
- package/packages/dd-trace/src/opentelemetry/context_manager.js +7 -7
- package/packages/dd-trace/src/opentelemetry/logs/batch_log_processor.js +2 -1
- package/packages/dd-trace/src/opentelemetry/logs/logger.js +67 -11
- package/packages/dd-trace/src/opentelemetry/logs/otlp_transformer.js +14 -3
- package/packages/dd-trace/src/opentelemetry/metrics/index.js +25 -12
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_exporter.js +2 -5
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_transformer.js +96 -43
- 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/opentracing/tracer.js +5 -2
- package/packages/dd-trace/src/otel-thread-ctx.js +387 -0
- package/packages/dd-trace/src/plugin_manager.js +5 -3
- package/packages/dd-trace/src/plugins/ci_plugin.js +6 -1
- package/packages/dd-trace/src/plugins/index.js +1 -0
- package/packages/{datadog-plugin-jest/src/util.js → dd-trace/src/plugins/util/jest.js} +5 -65
- package/packages/dd-trace/src/plugins/util/test.js +93 -14
- package/packages/dd-trace/src/plugins/util/web.js +56 -2
- package/packages/dd-trace/src/profiling/profiler.js +1 -1
- package/packages/dd-trace/src/profiling/profilers/space.js +1 -3
- package/packages/dd-trace/src/profiling/profilers/wall.js +37 -90
- package/packages/dd-trace/src/profiling/webspan-utils.js +45 -0
- package/packages/dd-trace/src/proxy.js +38 -29
- package/packages/dd-trace/src/ritm.js +9 -2
- package/packages/dd-trace/src/serverless.js +37 -0
- package/packages/dd-trace/src/span_format.js +1 -0
- package/packages/dd-trace/src/span_stats.js +30 -3
- package/packages/dd-trace/src/storage-channels.js +86 -0
- package/packages/dd-trace/src/tracer.js +9 -2
- package/packages/dd-trace/src/tracer_metadata.js +14 -1
- package/packages/dd-trace/src/web-tags-cache.js +132 -0
- package/vendor/dist/@datadog/openfeature-node-server/LICENSE +201 -0
- package/vendor/dist/@datadog/openfeature-node-server/index.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/optional-peer-bundler.js +0 -65
- package/packages/datadog-webpack/src/optional-peer-loader.js +0 -17
- package/packages/dd-trace/src/feature-registry.js +0 -29
- package/packages/dd-trace/src/openfeature/register.js +0 -35
- package/packages/dd-trace/src/openfeature/require-provider.js +0 -18
|
@@ -8,6 +8,17 @@ const {
|
|
|
8
8
|
channel,
|
|
9
9
|
addHook,
|
|
10
10
|
} = require('./helpers/instrument')
|
|
11
|
+
const {
|
|
12
|
+
clearPoolWaitTime,
|
|
13
|
+
dispatchesAcquireSynchronously,
|
|
14
|
+
isPoolQueryAcquire,
|
|
15
|
+
runOutsidePoolQueryAcquire,
|
|
16
|
+
runPoolAcquireError,
|
|
17
|
+
runWithPoolWait,
|
|
18
|
+
takePoolWaitTime,
|
|
19
|
+
wrapPoolAcquireCarrier,
|
|
20
|
+
wrapPoolQueryMethod,
|
|
21
|
+
} = require('./helpers/pool-acquire')
|
|
11
22
|
|
|
12
23
|
const startCh = channel('apm:pg:query:start')
|
|
13
24
|
const finishCh = channel('apm:pg:query:finish')
|
|
@@ -21,20 +32,16 @@ const poolConnectFinishCh = channel('apm:pg:pool:connect:finish')
|
|
|
21
32
|
|
|
22
33
|
const poolAcquireStartCh = channel('apm:pg:pool:acquire:start')
|
|
23
34
|
const poolAcquireFinishCh = channel('apm:pg:pool:acquire:finish')
|
|
35
|
+
const poolAcquireChannels = {
|
|
36
|
+
connectionFinishCh: poolConnectFinishCh,
|
|
37
|
+
acquireStartCh: poolAcquireStartCh,
|
|
38
|
+
acquireFinishCh: poolAcquireFinishCh,
|
|
39
|
+
}
|
|
24
40
|
|
|
25
41
|
// Drivers like pg-promise reuse the same prepared-statement query object across executions; cache
|
|
26
42
|
// the un-injected `text` so the wrap doesn't capture a previous DBM injection as the new original.
|
|
27
43
|
const originalTextCache = new WeakMap()
|
|
28
44
|
|
|
29
|
-
// Pool.query dispatches its client query synchronously from the connect callback, including nested
|
|
30
|
-
// `_release` queue pulses, so the wait can cross that callback without retaining the client.
|
|
31
|
-
const poolWaitClients = []
|
|
32
|
-
const poolWaitTimes = []
|
|
33
|
-
|
|
34
|
-
// Pool.query reports its internal acquire on the query span; explicit connects get an acquire span.
|
|
35
|
-
// Pool.query calls connect synchronously, so a module flag reliably distinguishes the two.
|
|
36
|
-
let acquiringForPoolQuery = false
|
|
37
|
-
|
|
38
45
|
addHook({ name: 'pg', versions: ['>=8.0.3'], file: 'lib/native/client.js' }, Client => {
|
|
39
46
|
shimmer.wrap(Client.prototype, 'query', query => wrapQuery(query))
|
|
40
47
|
return Client
|
|
@@ -46,79 +53,118 @@ addHook({ name: 'pg', versions: ['>=8.0.3'], file: 'lib/client.js' }, Client =>
|
|
|
46
53
|
})
|
|
47
54
|
|
|
48
55
|
addHook({ name: 'pg', versions: ['>=8.0.3'] }, pg => {
|
|
56
|
+
const poolWaitTransfer = { deferred: false }
|
|
57
|
+
const deferredPoolAcquire = !dispatchesAcquireSynchronously(
|
|
58
|
+
pg.Pool.prototype.query,
|
|
59
|
+
Object.assign(Object.create(pg.Pool.prototype), { Promise }),
|
|
60
|
+
'connect',
|
|
61
|
+
['SELECT 1', () => {}]
|
|
62
|
+
)
|
|
63
|
+
|
|
49
64
|
// pg defers a busy pool's connect callback and runs it in the releasing query's async context;
|
|
50
65
|
// capture the caller's context and restore it around the callback so spans attach to the caller.
|
|
51
|
-
shimmer.wrap(pg.Pool.prototype, 'connect', connect =>
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
66
|
+
shimmer.wrap(pg.Pool.prototype, 'connect', connect => {
|
|
67
|
+
/**
|
|
68
|
+
* @param {Function|undefined} callback
|
|
69
|
+
* @returns {unknown}
|
|
70
|
+
*/
|
|
71
|
+
const wrappedConnect = function (callback) {
|
|
72
|
+
// Pool.query always supplies a callback, so a missing callback is an explicit acquire.
|
|
73
|
+
if (typeof callback !== 'function') {
|
|
74
|
+
if (!poolAcquireStartCh.hasSubscribers) {
|
|
75
|
+
return connect.apply(this, arguments)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const start = acquireStart(this)
|
|
79
|
+
const acquireCtx = { poolOptions: this.options }
|
|
80
|
+
poolAcquireStartCh.publish(acquireCtx)
|
|
81
|
+
|
|
82
|
+
return connectForAcquire(connect, this, arguments, acquireCtx, start).then(client => {
|
|
83
|
+
clearPoolWaitTime(client)
|
|
84
|
+
acquireCtx.params = client.connectionParameters
|
|
85
|
+
finishAcquire(acquireCtx, start)
|
|
86
|
+
return client
|
|
87
|
+
}, error => {
|
|
88
|
+
acquireCtx.error = error
|
|
89
|
+
finishAcquire(acquireCtx, start)
|
|
90
|
+
throw error
|
|
91
|
+
})
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (!poolConnectStartCh.hasSubscribers) {
|
|
55
95
|
return connect.apply(this, arguments)
|
|
56
96
|
}
|
|
57
97
|
|
|
98
|
+
const ctx = {}
|
|
99
|
+
const poolOptions = this.options
|
|
58
100
|
const start = acquireStart(this)
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
return connectForAcquire(connect, this, arguments, acquireCtx, start).then(client => {
|
|
63
|
-
acquireCtx.params = client.connectionParameters
|
|
64
|
-
finishAcquire(acquireCtx, start)
|
|
65
|
-
return client
|
|
66
|
-
}, error => {
|
|
67
|
-
acquireCtx.error = error
|
|
68
|
-
finishAcquire(acquireCtx, start)
|
|
69
|
-
throw error
|
|
70
|
-
})
|
|
71
|
-
}
|
|
101
|
+
const poolQueryAcquire = isPoolQueryAcquire()
|
|
102
|
+
let acquireCtx
|
|
72
103
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
const ctx = {}
|
|
78
|
-
const start = acquireStart(this)
|
|
79
|
-
let acquireCtx
|
|
80
|
-
|
|
81
|
-
if (acquiringForPoolQuery) {
|
|
82
|
-
arguments[0] = function (...args) {
|
|
83
|
-
const client = args[1]
|
|
84
|
-
if (client !== undefined) {
|
|
85
|
-
poolWaitClients.push(client)
|
|
86
|
-
poolWaitTimes.push(acquireWait(start))
|
|
87
|
-
}
|
|
88
|
-
try {
|
|
89
|
-
return poolConnectFinishCh.runStores(ctx, cb, this, ...args)
|
|
90
|
-
} finally {
|
|
104
|
+
if (poolQueryAcquire) {
|
|
105
|
+
arguments[0] = function (...args) {
|
|
106
|
+
const client = args[1]
|
|
91
107
|
if (client !== undefined) {
|
|
92
|
-
|
|
93
|
-
|
|
108
|
+
const waitTime = acquireWait(start)
|
|
109
|
+
return runWithPoolWait(
|
|
110
|
+
poolWaitTransfer,
|
|
111
|
+
client,
|
|
112
|
+
waitTime,
|
|
113
|
+
poolConnectFinishCh,
|
|
114
|
+
ctx,
|
|
115
|
+
callback,
|
|
116
|
+
this,
|
|
117
|
+
args
|
|
118
|
+
)
|
|
119
|
+
}
|
|
120
|
+
if (args[0] && poolAcquireStartCh.hasSubscribers) {
|
|
121
|
+
return runPoolAcquireError(
|
|
122
|
+
start,
|
|
123
|
+
args[0],
|
|
124
|
+
{ poolOptions },
|
|
125
|
+
poolAcquireChannels,
|
|
126
|
+
ctx,
|
|
127
|
+
callback,
|
|
128
|
+
this,
|
|
129
|
+
args
|
|
130
|
+
)
|
|
94
131
|
}
|
|
132
|
+
return poolConnectFinishCh.runStores(ctx, callback, this, ...args)
|
|
95
133
|
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
134
|
+
} else {
|
|
135
|
+
acquireCtx = { poolOptions: this.options }
|
|
136
|
+
poolAcquireStartCh.publish(acquireCtx)
|
|
137
|
+
|
|
138
|
+
arguments[0] = function (...args) {
|
|
139
|
+
const client = args[1]
|
|
140
|
+
acquireCtx.error = args[0]
|
|
141
|
+
// A failed acquire has no client, so keep the parameters `connectForAcquire` snapshotted.
|
|
142
|
+
if (client !== undefined) {
|
|
143
|
+
clearPoolWaitTime(client)
|
|
144
|
+
acquireCtx.params = client.connectionParameters
|
|
145
|
+
}
|
|
146
|
+
finishAcquire(acquireCtx, start)
|
|
147
|
+
return poolConnectFinishCh.runStores(ctx, callback, this, ...args)
|
|
107
148
|
}
|
|
108
|
-
finishAcquire(acquireCtx, start)
|
|
109
|
-
return poolConnectFinishCh.runStores(ctx, cb, this, ...args)
|
|
110
149
|
}
|
|
111
|
-
}
|
|
112
150
|
|
|
113
|
-
|
|
151
|
+
poolConnectStartCh.publish(ctx)
|
|
114
152
|
|
|
115
|
-
|
|
116
|
-
|
|
153
|
+
if (acquireCtx === undefined) return runOutsidePoolQueryAcquire(connect, this, arguments)
|
|
154
|
+
|
|
155
|
+
return connectForAcquire(connect, this, arguments, acquireCtx, start)
|
|
117
156
|
}
|
|
118
157
|
|
|
119
|
-
return
|
|
158
|
+
return wrapPoolAcquireCarrier(
|
|
159
|
+
wrappedConnect,
|
|
160
|
+
connect,
|
|
161
|
+
poolConnectStartCh,
|
|
162
|
+
deferredPoolAcquire
|
|
163
|
+
)
|
|
120
164
|
})
|
|
121
|
-
shimmer.wrap(pg.Pool.prototype, 'query', query => wrapPoolQuery(
|
|
165
|
+
shimmer.wrap(pg.Pool.prototype, 'query', query => wrapPoolQuery(
|
|
166
|
+
wrapPoolQueryMethod(query, poolConnectStartCh, deferredPoolAcquire)
|
|
167
|
+
))
|
|
122
168
|
return pg
|
|
123
169
|
})
|
|
124
170
|
|
|
@@ -153,14 +199,9 @@ function wrapQuery (query) {
|
|
|
153
199
|
stream,
|
|
154
200
|
}
|
|
155
201
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
ctx.poolWaitTime = poolWaitTimes[i]
|
|
160
|
-
poolWaitClients[i] = undefined
|
|
161
|
-
break
|
|
162
|
-
}
|
|
163
|
-
}
|
|
202
|
+
const waitTime = takePoolWaitTime(this)
|
|
203
|
+
if (waitTime !== undefined) {
|
|
204
|
+
ctx.poolWaitTime = waitTime
|
|
164
205
|
}
|
|
165
206
|
|
|
166
207
|
const finish = (error, res) => {
|
|
@@ -342,25 +383,10 @@ function finishAcquire (ctx, start) {
|
|
|
342
383
|
poolAcquireFinishCh.publish(ctx)
|
|
343
384
|
}
|
|
344
385
|
|
|
345
|
-
/**
|
|
346
|
-
* @param {Function} query
|
|
347
|
-
* @param {InstrumentedPool} pool
|
|
348
|
-
* @param {unknown[]} args
|
|
349
|
-
*/
|
|
350
|
-
function acquireForPoolQuery (query, pool, args) {
|
|
351
|
-
acquiringForPoolQuery = true
|
|
352
|
-
try {
|
|
353
|
-
return query.apply(pool, args)
|
|
354
|
-
} finally {
|
|
355
|
-
acquiringForPoolQuery = false
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
386
|
function wrapPoolQuery (query) {
|
|
359
387
|
return function (...args) {
|
|
360
388
|
if (!startPoolQueryCh.hasSubscribers) {
|
|
361
|
-
return
|
|
362
|
-
? acquireForPoolQuery(query, this, args)
|
|
363
|
-
: query.apply(this, args)
|
|
389
|
+
return query.apply(this, args)
|
|
364
390
|
}
|
|
365
391
|
|
|
366
392
|
const pgQuery = args[0] !== null && typeof args[0] === 'object' ? args[0] : { text: args[0] }
|
|
@@ -390,9 +416,7 @@ function wrapPoolQuery (query) {
|
|
|
390
416
|
})
|
|
391
417
|
}
|
|
392
418
|
|
|
393
|
-
const retval =
|
|
394
|
-
? acquireForPoolQuery(query, this, args)
|
|
395
|
-
: query.apply(this, args)
|
|
419
|
+
const retval = query.apply(this, args)
|
|
396
420
|
|
|
397
421
|
if (retval?.then) {
|
|
398
422
|
retval.then(() => {
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { channel } = require('dc-polyfill')
|
|
4
|
+
|
|
5
|
+
const reporterErrorCh = channel('ci:playwright:reporter:error')
|
|
6
|
+
const PLAYWRIGHT_REPORTER_ERROR_MESSAGE = 'Error in reporter'
|
|
7
|
+
const PLAYWRIGHT_REPORTER_ERROR_CALLER_RE =
|
|
8
|
+
/^\s*at wrapAsync .*?[\\/]playwright[\\/]lib[\\/]runner[\\/]index\.js:\d+:\d+\)?$/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Identifies the private Playwright 1.60-1.61 reporter error fallback without
|
|
12
|
+
* interpreting identical user console output as a framework error.
|
|
13
|
+
*
|
|
14
|
+
* @param {unknown} message - First console.error argument
|
|
15
|
+
* @returns {boolean}
|
|
16
|
+
*/
|
|
17
|
+
function isPlaywrightReporterError (message) {
|
|
18
|
+
if (message !== PLAYWRIGHT_REPORTER_ERROR_MESSAGE) return false
|
|
19
|
+
|
|
20
|
+
const originalPrepareStackTrace = Error.prepareStackTrace
|
|
21
|
+
try {
|
|
22
|
+
Error.prepareStackTrace = (_, callSites) => callSites
|
|
23
|
+
const stack = new Error('Playwright reporter error provenance').stack
|
|
24
|
+
return PLAYWRIGHT_REPORTER_ERROR_CALLER_RE.test(`at ${stack?.[2]?.toString() || ''}`)
|
|
25
|
+
} finally {
|
|
26
|
+
Error.prepareStackTrace = originalPrepareStackTrace
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
class DatadogPlaywrightReporter {
|
|
31
|
+
/**
|
|
32
|
+
* Restores console error after Playwright completes the reporter lifecycle.
|
|
33
|
+
*
|
|
34
|
+
* @returns {void}
|
|
35
|
+
*/
|
|
36
|
+
static restoreConsoleError () {
|
|
37
|
+
// eslint-disable-next-line no-console
|
|
38
|
+
if (console.error === DatadogPlaywrightReporter.consoleError) {
|
|
39
|
+
try {
|
|
40
|
+
// eslint-disable-next-line no-console
|
|
41
|
+
console.error = DatadogPlaywrightReporter.originalConsoleError
|
|
42
|
+
} catch {}
|
|
43
|
+
}
|
|
44
|
+
DatadogPlaywrightReporter.consoleError = undefined
|
|
45
|
+
DatadogPlaywrightReporter.originalConsoleError = undefined
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Marks the beginning of reporter finalization so later reporter errors can be identified.
|
|
50
|
+
*
|
|
51
|
+
* @returns {void}
|
|
52
|
+
*/
|
|
53
|
+
onEnd () {
|
|
54
|
+
this.isFinalizing = true
|
|
55
|
+
// Playwright 1.60 and 1.61 only expose reporter errors through this exact console call.
|
|
56
|
+
// eslint-disable-next-line no-console
|
|
57
|
+
const originalConsoleError = console.error
|
|
58
|
+
const reporter = this
|
|
59
|
+
const consoleError = function (message, error) {
|
|
60
|
+
if (isPlaywrightReporterError(message)) {
|
|
61
|
+
reporter.onError(error)
|
|
62
|
+
}
|
|
63
|
+
return originalConsoleError.apply(this, arguments)
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
// eslint-disable-next-line no-console
|
|
67
|
+
console.error = consoleError
|
|
68
|
+
} catch {
|
|
69
|
+
return
|
|
70
|
+
}
|
|
71
|
+
// An accessor may ignore the assignment without throwing.
|
|
72
|
+
// eslint-disable-next-line no-console
|
|
73
|
+
if (console.error !== consoleError) return
|
|
74
|
+
|
|
75
|
+
DatadogPlaywrightReporter.originalConsoleError = originalConsoleError
|
|
76
|
+
DatadogPlaywrightReporter.consoleError = consoleError
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Reports errors emitted by Playwright while later reporters are finalizing.
|
|
81
|
+
*
|
|
82
|
+
* @param {unknown} error
|
|
83
|
+
* @returns {void}
|
|
84
|
+
*/
|
|
85
|
+
onError (error) {
|
|
86
|
+
if (this.isFinalizing) reporterErrorCh.publish(error)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Keeps the internal reporter from affecting Playwright's output reporter selection.
|
|
91
|
+
*
|
|
92
|
+
* @returns {boolean}
|
|
93
|
+
*/
|
|
94
|
+
printsToStdio () {
|
|
95
|
+
return false
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
module.exports = DatadogPlaywrightReporter
|
|
@@ -45,6 +45,7 @@ const testSkipCh = channel('ci:playwright:test:skip')
|
|
|
45
45
|
const testSessionStartCh = channel('ci:playwright:session:start')
|
|
46
46
|
const testSessionConfigurationCh = channel('ci:playwright:session:configuration')
|
|
47
47
|
const testSessionFinishCh = channel('ci:playwright:session:finish')
|
|
48
|
+
const reporterErrorCh = channel('ci:playwright:reporter:error')
|
|
48
49
|
|
|
49
50
|
const libraryConfigurationCh = channel('ci:playwright:library-configuration')
|
|
50
51
|
const knownTestsCh = channel('ci:playwright:known-tests')
|
|
@@ -81,6 +82,8 @@ const isFailureScreenshotUploadEnabled =
|
|
|
81
82
|
getValueFromEnvSources('DD_TEST_FAILURE_SCREENSHOTS_ENABLED') === true
|
|
82
83
|
|
|
83
84
|
let applyRepeatEachIndex = null
|
|
85
|
+
let reporterError
|
|
86
|
+
let hasReporterError = false
|
|
84
87
|
|
|
85
88
|
let startedSuites = []
|
|
86
89
|
|
|
@@ -134,8 +137,10 @@ const DD_PROPERTIES_REQUEST = 'ddPropertiesRequest'
|
|
|
134
137
|
const DD_PROPERTIES_RESPONSE = 'ddProperties'
|
|
135
138
|
const kDdPlaywrightDisabledTestIds = Symbol('ddPlaywrightDisabledTestIds')
|
|
136
139
|
const kDdPlaywrightFailureScreenshots = Symbol('ddPlaywrightFailureScreenshots')
|
|
140
|
+
const kDdPlaywrightReporterConfigured = Symbol('ddPlaywrightReporterConfigured')
|
|
137
141
|
const kDdPlaywrightWorkerHostInstrumented = Symbol('ddPlaywrightWorkerHostInstrumented')
|
|
138
142
|
const kDdPlaywrightWorkerInstrumented = Symbol('ddPlaywrightWorkerInstrumented')
|
|
143
|
+
const instrumentedPlaywrightReporters = new WeakSet()
|
|
139
144
|
const PLAYWRIGHT_FAILURE_SCREENSHOT_PATH_RE = /(?:^|[\\/])test-failed-\d+\.png$/
|
|
140
145
|
const automaticFailureScreenshotPaths = new Set()
|
|
141
146
|
|
|
@@ -1252,6 +1257,17 @@ function dispatcherHookNew (dispatcherExport, runWrapper) {
|
|
|
1252
1257
|
function runAllTestsWrapper (runAllTests, playwrightVersion) {
|
|
1253
1258
|
// Config parameter is only available from >=1.55.0
|
|
1254
1259
|
return async function (config) {
|
|
1260
|
+
reporterError = undefined
|
|
1261
|
+
hasReporterError = false
|
|
1262
|
+
let restoreReporterConsoleError
|
|
1263
|
+
if (satisfies(playwrightVersion, '>=1.60.0') && config?.config) {
|
|
1264
|
+
const DatadogPlaywrightReporter = require('./playwright-reporter')
|
|
1265
|
+
restoreReporterConsoleError = DatadogPlaywrightReporter.restoreConsoleError
|
|
1266
|
+
if (!config.config[kDdPlaywrightReporterConfigured]) {
|
|
1267
|
+
Object.defineProperty(config.config, kDdPlaywrightReporterConfigured, { value: true })
|
|
1268
|
+
config.config.reporter.unshift([require.resolve('./playwright-reporter')])
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1255
1271
|
rootDir = getRootDir(this, config)
|
|
1256
1272
|
const projects = getProjectsFromRunner(this, config)
|
|
1257
1273
|
const isFailureScreenshotEnabled = isFailureScreenshotCaptureEnabled(projects)
|
|
@@ -1367,7 +1383,27 @@ function runAllTestsWrapper (runAllTests, playwrightVersion) {
|
|
|
1367
1383
|
}
|
|
1368
1384
|
}
|
|
1369
1385
|
|
|
1370
|
-
let runAllTestsReturn
|
|
1386
|
+
let runAllTestsReturn
|
|
1387
|
+
try {
|
|
1388
|
+
runAllTestsReturn = await runAllTests.apply(this, arguments)
|
|
1389
|
+
} catch (error) {
|
|
1390
|
+
try {
|
|
1391
|
+
await getChannelPromise(testSessionFinishCh, {
|
|
1392
|
+
status: 'fail',
|
|
1393
|
+
error: hasReporterError ? reporterError : error,
|
|
1394
|
+
isEarlyFlakeDetectionEnabled,
|
|
1395
|
+
isEarlyFlakeDetectionFaulty,
|
|
1396
|
+
isTestManagementTestsEnabled,
|
|
1397
|
+
})
|
|
1398
|
+
} catch (finalizationError) {
|
|
1399
|
+
log.error('Playwright test session finalization error: %s', finalizationError)
|
|
1400
|
+
}
|
|
1401
|
+
reporterError = undefined
|
|
1402
|
+
hasReporterError = false
|
|
1403
|
+
throw error
|
|
1404
|
+
} finally {
|
|
1405
|
+
restoreReporterConsoleError?.()
|
|
1406
|
+
}
|
|
1371
1407
|
|
|
1372
1408
|
// Tests that have only skipped tests may reach this point
|
|
1373
1409
|
// Skipped tests may or may not go through `testBegin` or `testEnd`
|
|
@@ -1422,12 +1458,21 @@ function runAllTestsWrapper (runAllTests, playwrightVersion) {
|
|
|
1422
1458
|
logTestOptimizationSummary({ attemptToFixExecutions, newTestsWithDynamicNames })
|
|
1423
1459
|
loggedAttemptToFixTests.clear()
|
|
1424
1460
|
|
|
1461
|
+
const finalizationError = reporterError
|
|
1462
|
+
const finalStatus = hasReporterError
|
|
1463
|
+
? 'fail'
|
|
1464
|
+
: (preventedToFail ? 'pass' : STATUS_TO_TEST_STATUS[sessionStatus])
|
|
1425
1465
|
await getChannelPromise(testSessionFinishCh, {
|
|
1426
|
-
status:
|
|
1466
|
+
status: finalStatus,
|
|
1467
|
+
error: finalizationError,
|
|
1427
1468
|
isEarlyFlakeDetectionEnabled,
|
|
1428
1469
|
isEarlyFlakeDetectionFaulty,
|
|
1429
1470
|
isTestManagementTestsEnabled,
|
|
1430
1471
|
})
|
|
1472
|
+
if (hasReporterError) {
|
|
1473
|
+
if (typeof runAllTestsReturn === 'string') runAllTestsReturn = 'failed'
|
|
1474
|
+
else runAllTestsReturn.status = 'failed'
|
|
1475
|
+
}
|
|
1431
1476
|
|
|
1432
1477
|
startedSuites = []
|
|
1433
1478
|
remainingTestsByFile = {}
|
|
@@ -1444,6 +1489,8 @@ function runAllTestsWrapper (runAllTests, playwrightVersion) {
|
|
|
1444
1489
|
ddPropertiesByTestId.clear()
|
|
1445
1490
|
ddPropertiesRequestsByTestId.clear()
|
|
1446
1491
|
disabledTestIds.clear()
|
|
1492
|
+
reporterError = undefined
|
|
1493
|
+
hasReporterError = false
|
|
1447
1494
|
|
|
1448
1495
|
// TODO: we can trick playwright into thinking the session passed by returning
|
|
1449
1496
|
// 'passed' here. We might be able to use this for both EFD and Test Management tests.
|
|
@@ -1451,6 +1498,68 @@ function runAllTestsWrapper (runAllTests, playwrightVersion) {
|
|
|
1451
1498
|
}
|
|
1452
1499
|
}
|
|
1453
1500
|
|
|
1501
|
+
/**
|
|
1502
|
+
* Records errors thrown or rejected by Playwright reporters before Playwright converts them into run status.
|
|
1503
|
+
*
|
|
1504
|
+
* @param {object} reportersPackage
|
|
1505
|
+
* @returns {object}
|
|
1506
|
+
*/
|
|
1507
|
+
function reportersHook (reportersPackage) {
|
|
1508
|
+
return shimmer.wrap(reportersPackage, 'createReporters', createReporters => async function () {
|
|
1509
|
+
const reporters = await createReporters.apply(this, arguments)
|
|
1510
|
+
for (const reporter of reporters) {
|
|
1511
|
+
if (instrumentedPlaywrightReporters.has(reporter)) continue
|
|
1512
|
+
|
|
1513
|
+
const onEnd = reporter.onEnd
|
|
1514
|
+
const onExit = reporter.onExit
|
|
1515
|
+
try {
|
|
1516
|
+
if (typeof onEnd === 'function') {
|
|
1517
|
+
reporter.onEnd = async function () {
|
|
1518
|
+
try {
|
|
1519
|
+
return await onEnd.apply(this, arguments)
|
|
1520
|
+
} catch (error) {
|
|
1521
|
+
recordReporterError(error)
|
|
1522
|
+
throw error
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1526
|
+
if (typeof onExit === 'function') {
|
|
1527
|
+
reporter.onExit = async function () {
|
|
1528
|
+
try {
|
|
1529
|
+
return await onExit.apply(this, arguments)
|
|
1530
|
+
} catch (error) {
|
|
1531
|
+
recordReporterError(error)
|
|
1532
|
+
throw error
|
|
1533
|
+
}
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
} catch {
|
|
1537
|
+
continue
|
|
1538
|
+
}
|
|
1539
|
+
if (reporter.onEnd !== onEnd || reporter.onExit !== onExit) instrumentedPlaywrightReporters.add(reporter)
|
|
1540
|
+
}
|
|
1541
|
+
return reporters
|
|
1542
|
+
}, { replaceGetter: true })
|
|
1543
|
+
}
|
|
1544
|
+
|
|
1545
|
+
/**
|
|
1546
|
+
* Records errors from the reporter multiplexer used by Playwright before 1.38.
|
|
1547
|
+
*
|
|
1548
|
+
* @param {object} reportersPackage
|
|
1549
|
+
* @returns {object}
|
|
1550
|
+
*/
|
|
1551
|
+
function reporterMultiplexerHook (reportersPackage) {
|
|
1552
|
+
shimmer.wrap(reportersPackage.Multiplexer.prototype, 'onEnd', onEnd => async function () {
|
|
1553
|
+
try {
|
|
1554
|
+
return await onEnd.apply(this, arguments)
|
|
1555
|
+
} catch (error) {
|
|
1556
|
+
recordReporterError(error)
|
|
1557
|
+
throw error
|
|
1558
|
+
}
|
|
1559
|
+
})
|
|
1560
|
+
return reportersPackage
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1454
1563
|
function runnerHook (runnerExport, playwrightVersion) {
|
|
1455
1564
|
shimmer.wrap(
|
|
1456
1565
|
runnerExport.Runner.prototype,
|
|
@@ -1550,6 +1659,32 @@ pageGotoCh.subscribe({
|
|
|
1550
1659
|
},
|
|
1551
1660
|
})
|
|
1552
1661
|
|
|
1662
|
+
reporterErrorCh.subscribe((error) => {
|
|
1663
|
+
recordReporterError(error)
|
|
1664
|
+
})
|
|
1665
|
+
|
|
1666
|
+
/**
|
|
1667
|
+
* Records a reporter failure even when the reporter throws a falsy value.
|
|
1668
|
+
*
|
|
1669
|
+
* @param {unknown} error
|
|
1670
|
+
* @returns {void}
|
|
1671
|
+
*/
|
|
1672
|
+
function recordReporterError (error) {
|
|
1673
|
+
if (hasReporterError) return
|
|
1674
|
+
|
|
1675
|
+
let normalizedError
|
|
1676
|
+
try {
|
|
1677
|
+
const errorObject = error && typeof error === 'object' ? error : undefined
|
|
1678
|
+
normalizedError = new Error(errorObject?.message || errorObject?.value || String(error))
|
|
1679
|
+
normalizedError.name = errorObject?.name || normalizedError.name
|
|
1680
|
+
normalizedError.stack = errorObject?.stack || normalizedError.stack
|
|
1681
|
+
} catch {
|
|
1682
|
+
normalizedError = new Error('Playwright reporter failed')
|
|
1683
|
+
}
|
|
1684
|
+
reporterError = normalizedError
|
|
1685
|
+
hasReporterError = true
|
|
1686
|
+
}
|
|
1687
|
+
|
|
1553
1688
|
/**
|
|
1554
1689
|
* Records a path created by Playwright's automatic screenshot recorder.
|
|
1555
1690
|
*
|
|
@@ -1597,6 +1732,12 @@ if (DD_MAJOR < 6) { // <1.38.0 is only supported up to version 5
|
|
|
1597
1732
|
file: 'lib/runner/runner.js',
|
|
1598
1733
|
versions: ['>=1.31.0 <1.38.0'],
|
|
1599
1734
|
}, runnerHook)
|
|
1735
|
+
|
|
1736
|
+
addHook({
|
|
1737
|
+
name: '@playwright/test',
|
|
1738
|
+
file: 'lib/reporters/multiplexer.js',
|
|
1739
|
+
versions: ['>=1.18.0 <1.38.0'],
|
|
1740
|
+
}, reporterMultiplexerHook)
|
|
1600
1741
|
}
|
|
1601
1742
|
|
|
1602
1743
|
addHook({
|
|
@@ -1617,6 +1758,12 @@ addHook({
|
|
|
1617
1758
|
versions: ['>=1.38.0 <1.60.0'],
|
|
1618
1759
|
}, runnerHook)
|
|
1619
1760
|
|
|
1761
|
+
addHook({
|
|
1762
|
+
name: 'playwright',
|
|
1763
|
+
file: 'lib/runner/reporters.js',
|
|
1764
|
+
versions: ['>=1.38.0 <1.60.0'],
|
|
1765
|
+
}, reportersHook)
|
|
1766
|
+
|
|
1620
1767
|
addHook({
|
|
1621
1768
|
name: 'playwright',
|
|
1622
1769
|
file: 'lib/runner/testRunner.js',
|
|
@@ -596,6 +596,7 @@ const visitedParams = new WeakSet()
|
|
|
596
596
|
function wrapHandleRequest (original) {
|
|
597
597
|
return function wrappedHandleRequest (...args) {
|
|
598
598
|
const req = args[0]
|
|
599
|
+
// eslint-disable-next-line no-restricted-syntax -- arbitrary param names; publishing {} sets a WAF address
|
|
599
600
|
if (routerParamStartCh.hasSubscribers && !visitedParams.has(req.params) && Object.keys(req.params).length) {
|
|
600
601
|
visitedParams.add(req.params)
|
|
601
602
|
|
|
@@ -635,6 +636,7 @@ function wrapParam (original) {
|
|
|
635
636
|
args[1] = shimmer.wrapFunction(args[1], (originalFn) => {
|
|
636
637
|
return function wrappedFn (...fnArgs) {
|
|
637
638
|
const req = fnArgs[0]
|
|
639
|
+
// eslint-disable-next-line no-restricted-syntax -- arbitrary param names; publishing {} sets a WAF address
|
|
638
640
|
if (routerParamStartCh.hasSubscribers && Object.keys(req.params).length && !visitedParams.has(req.params)) {
|
|
639
641
|
visitedParams.add(req.params)
|
|
640
642
|
|