dd-trace 6.7.0 → 6.9.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 +27 -25
- package/ci/init.js +6 -6
- package/ci/runbook.md +114 -20
- package/ci/test-optimization-validation/approval-artifacts.js +36 -3
- package/ci/test-optimization-validation/approval.js +78 -22
- package/ci/test-optimization-validation/blocker-category.js +24 -0
- package/ci/test-optimization-validation/ci-discovery.js +23 -17
- package/ci/test-optimization-validation/ci-package-scripts.js +34 -6
- package/ci/test-optimization-validation/ci-remediation.js +1 -1
- package/ci/test-optimization-validation/cli.js +280 -52
- package/ci/test-optimization-validation/command-blocker.js +159 -20
- package/ci/test-optimization-validation/command-output-policy.js +14 -8
- package/ci/test-optimization-validation/command-runner.js +9 -7
- package/ci/test-optimization-validation/environment.js +4 -2
- package/ci/test-optimization-validation/executable.js +15 -13
- package/ci/test-optimization-validation/execution-lock.js +70 -0
- package/ci/test-optimization-validation/framework-adapters/cucumber-validation.json +3 -0
- package/ci/test-optimization-validation/framework-adapters/cucumber.js +657 -5
- package/ci/test-optimization-validation/framework-adapters/playwright.js +5 -5
- package/ci/test-optimization-validation/framework-adapters/vitest.js +517 -0
- package/ci/test-optimization-validation/generated-files.js +47 -37
- package/ci/test-optimization-validation/generated-test-contract.js +9 -7
- package/ci/test-optimization-validation/generated-verifier.js +24 -17
- package/ci/test-optimization-validation/literal-glob.js +52 -0
- package/ci/test-optimization-validation/manifest-loader.js +3 -0
- package/ci/test-optimization-validation/manifest-scaffold.js +301 -52
- package/ci/test-optimization-validation/manifest-schema.js +80 -17
- package/ci/test-optimization-validation/offline-fixtures.js +13 -4
- package/ci/test-optimization-validation/offline-output.js +6 -6
- package/ci/test-optimization-validation/package-check.js +94 -0
- package/ci/test-optimization-validation/plan-writer.js +183 -10
- package/ci/test-optimization-validation/preflight-runner.js +110 -31
- package/ci/test-optimization-validation/project-build-artifact.js +31 -0
- package/ci/test-optimization-validation/redaction.js +18 -27
- package/ci/test-optimization-validation/report-writer.js +182 -48
- package/ci/test-optimization-validation/result-semantics.js +20 -3
- package/ci/test-optimization-validation/runner-command.js +41 -21
- package/ci/test-optimization-validation/runner-contract.js +79 -43
- package/ci/test-optimization-validation/safe-files.js +4 -4
- package/ci/test-optimization-validation/scenarios/basic-reporting.js +60 -6
- package/ci/test-optimization-validation/scenarios/ci-wiring.js +141 -35
- package/ci/test-optimization-validation/scenarios/helpers.js +30 -6
- package/ci/test-optimization-validation/scenarios/test-management.js +2 -2
- package/ci/test-optimization-validation/static-diagnosis.js +10 -3
- package/ci/test-optimization-validation/test-output.js +2 -1
- package/ci/test-optimization-validation/validation-blocker.js +21 -0
- package/ci/vitest-no-worker-init-setup.mjs +377 -84
- package/index.d.ts +175 -14
- package/init.js +1 -17
- package/initialize.mjs +11 -0
- package/loader-hook.mjs +6 -4
- package/package.json +12 -4
- package/packages/datadog-core/src/utils/src/kebabcase.js +8 -2
- package/packages/datadog-core/src/utils/src/parse-tags.js +0 -1
- package/packages/datadog-esbuild/index.js +4 -2
- package/packages/datadog-esbuild/src/utils.js +17 -2
- package/packages/datadog-instrumentations/src/ai.js +61 -34
- package/packages/datadog-instrumentations/src/bluebird.js +6 -6
- package/packages/datadog-instrumentations/src/claude-agent-sdk.js +85 -9
- package/packages/datadog-instrumentations/src/cucumber.js +131 -51
- package/packages/datadog-instrumentations/src/dns.js +21 -2
- package/packages/datadog-instrumentations/src/electron.js +1 -0
- package/packages/datadog-instrumentations/src/fastify.js +3 -1
- package/packages/datadog-instrumentations/src/grpc/client.js +4 -2
- package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +3 -1
- package/packages/datadog-instrumentations/src/helpers/extract-package-and-module-path.js +10 -0
- package/packages/datadog-instrumentations/src/helpers/hook.js +19 -2
- package/packages/datadog-instrumentations/src/helpers/hooks.js +4 -0
- package/packages/datadog-instrumentations/src/helpers/register.js +9 -3
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +34 -9
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +175 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/loader.mjs +20 -2
- package/packages/datadog-instrumentations/src/helpers/rewriter/targets.js +32 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +61 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +50 -18
- package/packages/datadog-instrumentations/src/helpers/router-helper.js +38 -7
- package/packages/datadog-instrumentations/src/helpers/shared-utils.js +39 -0
- package/packages/datadog-instrumentations/src/http/client.js +1 -3
- package/packages/datadog-instrumentations/src/jest/coverage-backfill.js +1 -1
- package/packages/datadog-instrumentations/src/jest.js +986 -246
- package/packages/datadog-instrumentations/src/mocha/common.js +1 -3
- package/packages/datadog-instrumentations/src/mocha/main.js +109 -51
- package/packages/datadog-instrumentations/src/mocha/utils.js +120 -32
- package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +44 -0
- package/packages/datadog-instrumentations/src/mocha/worker.js +441 -43
- package/packages/datadog-instrumentations/src/moleculer/client.js +1 -1
- package/packages/datadog-instrumentations/src/mysql.js +1 -1
- package/packages/datadog-instrumentations/src/next.js +155 -23
- package/packages/datadog-instrumentations/src/openai.js +14 -0
- package/packages/datadog-instrumentations/src/pg.js +180 -6
- package/packages/datadog-instrumentations/src/playwright.js +176 -81
- package/packages/datadog-instrumentations/src/promise-js.js +4 -4
- package/packages/datadog-instrumentations/src/promise.js +3 -3
- package/packages/datadog-instrumentations/src/rhea.js +1 -1
- package/packages/datadog-instrumentations/src/router.js +195 -19
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +567 -65
- package/packages/datadog-instrumentations/src/vitest-main.js +438 -54
- package/packages/datadog-instrumentations/src/vitest-util.js +42 -7
- package/packages/datadog-instrumentations/src/vitest-worker.js +234 -17
- package/packages/datadog-instrumentations/src/webdriverio.js +1090 -0
- package/packages/datadog-instrumentations/src/when.js +3 -3
- package/packages/datadog-instrumentations/src/ws.js +5 -1
- package/packages/datadog-plugin-aerospike/src/index.js +1 -3
- package/packages/datadog-plugin-amqplib/src/client.js +1 -1
- package/packages/datadog-plugin-amqplib/src/producer.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +59 -48
- package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +2 -2
- package/packages/datadog-plugin-aws-sdk/src/services/stepfunctions.js +2 -2
- package/packages/datadog-plugin-azure-event-hubs/src/producer.js +1 -3
- package/packages/datadog-plugin-azure-service-bus/src/producer.js +5 -3
- package/packages/datadog-plugin-bullmq/src/producer.js +3 -3
- package/packages/datadog-plugin-child_process/src/index.js +3 -3
- package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +6 -11
- package/packages/datadog-plugin-cucumber/src/index.js +5 -1
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +50 -46
- package/packages/datadog-plugin-cypress/src/source-map-utils.js +1 -1
- package/packages/datadog-plugin-cypress/src/support.js +7 -4
- package/packages/datadog-plugin-electron/src/net.js +10 -4
- package/packages/datadog-plugin-fastify/src/tracing.js +1 -1
- package/packages/datadog-plugin-fs/src/index.js +0 -4
- package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +14 -7
- package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +19 -10
- package/packages/datadog-plugin-graphql/src/execute.js +1 -0
- package/packages/datadog-plugin-graphql/src/tools/signature.js +1 -1
- package/packages/datadog-plugin-http/src/client.js +3 -2
- package/packages/datadog-plugin-http2/src/client.js +1 -1
- package/packages/datadog-plugin-jest/src/index.js +3 -21
- package/packages/datadog-plugin-jest/src/util.js +4 -1
- package/packages/datadog-plugin-kafkajs/src/producer.js +2 -1
- package/packages/datadog-plugin-langchain/src/tokens.js +2 -2
- package/packages/datadog-plugin-mocha/src/index.js +342 -6
- package/packages/datadog-plugin-next/src/index.js +57 -9
- package/packages/datadog-plugin-openai/src/tracing.js +4 -0
- package/packages/datadog-plugin-pg/src/index.js +65 -1
- package/packages/datadog-plugin-playwright/src/index.js +1 -1
- package/packages/datadog-plugin-prisma/src/index.js +5 -1
- package/packages/datadog-plugin-rhea/src/consumer.js +16 -13
- package/packages/datadog-plugin-rhea/src/producer.js +1 -1
- package/packages/datadog-plugin-undici/src/index.js +2 -1
- package/packages/datadog-plugin-vitest/src/index.js +179 -18
- package/packages/datadog-shimmer/src/shimmer.js +6 -2
- package/packages/datadog-webpack/index.js +2 -2
- package/packages/dd-trace/src/aiguard/sdk.js +3 -0
- package/packages/dd-trace/src/appsec/{blocking.js → blocking/index.js} +26 -6
- package/packages/dd-trace/src/appsec/downstream_requests.js +1 -1
- package/packages/dd-trace/src/appsec/handlers/auth.js +62 -0
- package/packages/dd-trace/src/appsec/handlers/http-request.js +215 -0
- package/packages/dd-trace/src/appsec/handlers/http-response.js +78 -0
- package/packages/dd-trace/src/appsec/handlers/http-shared.js +24 -0
- package/packages/dd-trace/src/appsec/handlers/payments.js +104 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-base-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-password-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/hsts-header-missing-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +1 -3
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +2 -2
- package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +2 -2
- package/packages/dd-trace/src/appsec/index.js +48 -476
- package/packages/dd-trace/src/appsec/sdk/track_event.js +10 -1
- package/packages/dd-trace/src/appsec/waf/waf_manager.js +1 -1
- package/packages/dd-trace/src/ci-visibility/coverage-report-discovery.js +46 -14
- package/packages/dd-trace/src/ci-visibility/efd-retry-policy.js +89 -0
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/sink.js +7 -6
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +29 -15
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +19 -1
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +25 -1
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/webdriverio.js +26 -0
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +9 -1
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +22 -7
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +9 -14
- package/packages/dd-trace/src/ci-visibility/requests/request.js +3 -3
- package/packages/dd-trace/src/ci-visibility/requests/upload-coverage-report.js +21 -5
- package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +2 -2
- package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache.js +5 -1
- package/packages/dd-trace/src/config/defaults.js +14 -6
- package/packages/dd-trace/src/config/generated-config-types.d.ts +4 -2
- package/packages/dd-trace/src/config/helper.js +2 -0
- package/packages/dd-trace/src/config/index.js +31 -5
- package/packages/dd-trace/src/config/parsers.js +19 -1
- package/packages/dd-trace/src/config/remote_config.js +1 -1
- package/packages/dd-trace/src/config/supported-configurations.json +13 -6
- package/packages/dd-trace/src/datastreams/encoding.js +3 -4
- package/packages/dd-trace/src/debugger/devtools_client/log.js +2 -1
- package/packages/dd-trace/src/debugger/devtools_client/probe_sampler.js +1 -4
- package/packages/dd-trace/src/debugger/devtools_client/send.js +1 -2
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +2 -2
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/redaction.js +16 -2
- package/packages/dd-trace/src/debugger/devtools_client/status.js +1 -1
- package/packages/dd-trace/src/encode/coverage-ci-visibility.js +0 -1
- package/packages/dd-trace/src/encode/tags-processors.js +2 -2
- package/packages/dd-trace/src/exporters/common/url.js +3 -5
- package/packages/dd-trace/src/exporters/electron/index.js +4 -1
- package/packages/dd-trace/src/external-logger/src/index.js +1 -2
- package/packages/dd-trace/src/flare/index.js +2 -2
- package/packages/dd-trace/src/guardrails/apply-pm2-env.js +16 -0
- package/packages/dd-trace/src/guardrails/log.js +1 -10
- package/packages/dd-trace/src/id.js +1 -1
- package/packages/dd-trace/src/llmobs/constants/tags.js +1 -1
- package/packages/dd-trace/src/llmobs/eval-metric.js +249 -0
- package/packages/dd-trace/src/llmobs/experiments/client.js +4 -2
- package/packages/dd-trace/src/llmobs/experiments/dataset.js +66 -14
- package/packages/dd-trace/src/llmobs/experiments/experiment.js +289 -95
- package/packages/dd-trace/src/llmobs/experiments/index.js +66 -19
- package/packages/dd-trace/src/llmobs/experiments/noop.js +95 -10
- package/packages/dd-trace/src/llmobs/experiments/result.js +13 -2
- package/packages/dd-trace/src/llmobs/experiments/util.js +220 -0
- package/packages/dd-trace/src/llmobs/noop.js +2 -0
- package/packages/dd-trace/src/llmobs/plugins/ai/ddTelemetry.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/anthropic/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +5 -5
- package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/genai/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +1 -1
- package/packages/dd-trace/src/llmobs/sdk.js +152 -78
- package/packages/dd-trace/src/llmobs/span_processor.js +9 -7
- package/packages/dd-trace/src/llmobs/tagger.js +1 -2
- package/packages/dd-trace/src/llmobs/telemetry.js +18 -0
- package/packages/dd-trace/src/llmobs/writers/base.js +3 -0
- package/packages/dd-trace/src/llmobs/writers/spans.js +12 -6
- package/packages/dd-trace/src/llmobs/writers/util.js +2 -0
- package/packages/dd-trace/src/log/channels.js +1 -9
- package/packages/dd-trace/src/log/levels.js +12 -0
- package/packages/dd-trace/src/noop/proxy.js +2 -2
- package/packages/dd-trace/src/openfeature/writers/exposures.js +1 -1
- package/packages/dd-trace/src/openfeature/writers/util.js +1 -1
- package/packages/dd-trace/src/opentelemetry/logs/batch_log_processor.js +1 -1
- package/packages/dd-trace/src/opentelemetry/metrics/meter.js +8 -4
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_transformer.js +1 -1
- package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +3 -2
- package/packages/dd-trace/src/opentelemetry/span.js +4 -0
- package/packages/dd-trace/src/opentracing/span.js +1 -1
- package/packages/dd-trace/src/opentracing/span_context.js +1 -1
- package/packages/dd-trace/src/plugins/ci_plugin.js +124 -23
- package/packages/dd-trace/src/plugins/index.js +2 -0
- package/packages/dd-trace/src/plugins/plugin.js +1 -1
- package/packages/dd-trace/src/plugins/tracing.js +1 -0
- package/packages/dd-trace/src/plugins/util/ci.js +13 -6
- package/packages/dd-trace/src/plugins/util/git.js +7 -5
- package/packages/dd-trace/src/plugins/util/http-otel-semantics.js +3 -3
- package/packages/dd-trace/src/plugins/util/ip_extractor.js +1 -1
- package/packages/dd-trace/src/plugins/util/llm.js +2 -2
- package/packages/dd-trace/src/plugins/util/stacktrace.js +3 -0
- package/packages/dd-trace/src/plugins/util/tags.js +2 -0
- package/packages/dd-trace/src/plugins/util/test.js +356 -86
- package/packages/dd-trace/src/plugins/util/url.js +5 -5
- package/packages/dd-trace/src/plugins/util/user-provided-git.js +1 -1
- package/packages/dd-trace/src/plugins/util/web.js +24 -2
- package/packages/dd-trace/src/priority_sampler.js +6 -3
- package/packages/dd-trace/src/profiler.js +1 -1
- package/packages/dd-trace/src/profiling/exporters/event_serializer.js +1 -1
- package/packages/dd-trace/src/profiling/profilers/events.js +2 -2
- package/packages/dd-trace/src/profiling/profilers/poisson.js +1 -1
- package/packages/dd-trace/src/profiling/profilers/shared.js +2 -2
- package/packages/dd-trace/src/proxy.js +1 -0
- package/packages/dd-trace/src/ritm.js +10 -20
- package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +4 -2
- package/packages/dd-trace/src/sampling_rule.js +4 -2
- package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +1 -1
- package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +1 -1
- package/packages/dd-trace/src/startup-log.js +3 -0
- package/packages/dd-trace/src/telemetry/logs/index.js +3 -0
- package/packages/dd-trace/src/telemetry/logs/log-collector.js +3 -1
- package/packages/dd-trace/src/telemetry/telemetry.js +1 -1
- package/packages/dd-trace/src/util.js +16 -0
- package/vendor/dist/@apm-js-collab/code-transformer/index.js +12 -12
- package/vendor/dist/pprof-format/index.js +1 -1
- package/vendor/dist/source-map/index.js +1 -1
- package/version.js +10 -8
- /package/packages/dd-trace/src/appsec/{blocked_templates.js → blocking/templates.js} +0 -0
|
@@ -15,6 +15,7 @@ const queryParsedChannel = channel('apm:next:query-parsed')
|
|
|
15
15
|
|
|
16
16
|
const requests = new WeakSet()
|
|
17
17
|
const nodeNextRequestsToNextRequests = new WeakMap()
|
|
18
|
+
const requestErrors = new WeakMap()
|
|
18
19
|
|
|
19
20
|
// Next.js <= 14.2.6
|
|
20
21
|
const MIDDLEWARE_HEADER = 'x-middleware-invoke'
|
|
@@ -213,10 +214,8 @@ function wrapServeStatic (serveStatic) {
|
|
|
213
214
|
}
|
|
214
215
|
|
|
215
216
|
function finish (ctx, result, err) {
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
errorChannel.publish(ctx)
|
|
219
|
-
}
|
|
217
|
+
publishError(ctx.req, ctx, err)
|
|
218
|
+
requestErrors.delete(ctx.req)
|
|
220
219
|
|
|
221
220
|
const maybeNextRequest = nodeNextRequestsToNextRequests.get(ctx.req)
|
|
222
221
|
if (maybeNextRequest) {
|
|
@@ -226,6 +225,27 @@ function finish (ctx, result, err) {
|
|
|
226
225
|
finishChannel.publish(ctx)
|
|
227
226
|
}
|
|
228
227
|
|
|
228
|
+
function publishError (req, ctx, error) {
|
|
229
|
+
if (!error) return
|
|
230
|
+
|
|
231
|
+
req = req.originalRequest || req
|
|
232
|
+
let errors = requestErrors.get(req)
|
|
233
|
+
if (errors?.has(error)) return
|
|
234
|
+
|
|
235
|
+
if (!errors) {
|
|
236
|
+
errors = new Set()
|
|
237
|
+
requestErrors.set(req, errors)
|
|
238
|
+
}
|
|
239
|
+
errors.add(error)
|
|
240
|
+
|
|
241
|
+
if (ctx) {
|
|
242
|
+
ctx.error = error
|
|
243
|
+
errorChannel.publish(ctx)
|
|
244
|
+
} else {
|
|
245
|
+
errorChannel.publish({ error })
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
229
249
|
// also wrapped in dist/server/future/route-handlers/app-route-route-handler.js
|
|
230
250
|
// in versions below 13.3.0 that support middleware,
|
|
231
251
|
// however, it is not provided as a class function or exported property
|
|
@@ -244,15 +264,11 @@ addHook({
|
|
|
244
264
|
return NextRequestAdapter
|
|
245
265
|
})
|
|
246
266
|
|
|
247
|
-
// From
|
|
248
|
-
//
|
|
249
|
-
//
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
// bundled. The bundler/experimental part of the name is matched with a pattern rather than
|
|
253
|
-
// enumerated, so a variant next adds later is picked up without a code change.
|
|
254
|
-
const patchedAppRouteModules = new WeakSet()
|
|
255
|
-
|
|
267
|
+
// From Next 15.4.1, route modules execute through precompiled runtime bundles that bypass the
|
|
268
|
+
// classic server hooks above. Match bundler and experimental filename variants without enumerating
|
|
269
|
+
// them so App Routes, Pages APIs, and App Pages reuse the existing Next request lifecycle.
|
|
270
|
+
const patchedRouteModules = new WeakSet()
|
|
271
|
+
const COMPILED_RUNTIME_PATH = 'dist/compiled/next-server/'
|
|
256
272
|
function wrapOnRequestError (onRequestError) {
|
|
257
273
|
return function (req, error) {
|
|
258
274
|
if (error) {
|
|
@@ -262,21 +278,137 @@ function wrapOnRequestError (onRequestError) {
|
|
|
262
278
|
}
|
|
263
279
|
}
|
|
264
280
|
|
|
265
|
-
function
|
|
266
|
-
const
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
281
|
+
function getRoutePage (routeModule, fallbackPage) {
|
|
282
|
+
const definition = routeModule?.definition
|
|
283
|
+
if (typeof definition?.pathname === 'string') {
|
|
284
|
+
return { page: definition.pathname, isFilesystemPath: false }
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if (typeof definition?.page === 'string') {
|
|
288
|
+
return { page: definition.page, isFilesystemPath: true }
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
return { page: fallbackPage, isFilesystemPath: false }
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function publishRoutePage (ctx, routeModule, fallbackPage, isAppPath) {
|
|
295
|
+
if (!ctx || !pageLoadChannel.hasSubscribers) return
|
|
296
|
+
|
|
297
|
+
const pageData = getRoutePage(routeModule, fallbackPage)
|
|
298
|
+
if (pageData.page) {
|
|
299
|
+
pageLoadChannel.publish(isAppPath ? { ...pageData, isAppPath: true } : pageData)
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
function wrapAppRouteHandle (handle) {
|
|
304
|
+
return function (req, context) {
|
|
305
|
+
if (!startChannel.hasSubscribers && !queryParsedChannel.hasSubscribers) {
|
|
306
|
+
return handle.apply(this, arguments)
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
const res = { statusCode: 500 }
|
|
310
|
+
nodeNextRequestsToNextRequests.set(req, req)
|
|
311
|
+
|
|
312
|
+
return instrument(req, res, ctx => {
|
|
313
|
+
publishRoutePage(ctx, this, undefined, true)
|
|
314
|
+
|
|
315
|
+
return handle.apply(this, arguments).then(response => {
|
|
316
|
+
if (ctx) ctx.res.statusCode = response?.status || 200
|
|
317
|
+
return response
|
|
318
|
+
})
|
|
319
|
+
})
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function instrumentRouteModule (RouteModule, method, wrapper, handleErrors) {
|
|
324
|
+
const proto = RouteModule?.prototype
|
|
325
|
+
if (!proto || patchedRouteModules.has(RouteModule)) return
|
|
326
|
+
|
|
327
|
+
patchedRouteModules.add(RouteModule)
|
|
328
|
+
if (typeof proto[method] === 'function') {
|
|
329
|
+
shimmer.wrap(proto, method, wrapper)
|
|
330
|
+
}
|
|
331
|
+
if (handleErrors && typeof proto.onRequestError === 'function') {
|
|
270
332
|
shimmer.wrap(proto, 'onRequestError', wrapOnRequestError)
|
|
271
333
|
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
function instrumentAppRouteRuntime (runtime) {
|
|
337
|
+
instrumentRouteModule(runtime.AppRouteRouteModule, 'handle', wrapAppRouteHandle, true)
|
|
272
338
|
return runtime
|
|
273
339
|
}
|
|
274
340
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
}
|
|
341
|
+
function wrapPagesApiRender (render) {
|
|
342
|
+
return function (req, res, context = {}) {
|
|
343
|
+
if (!startChannel.hasSubscribers && !queryParsedChannel.hasSubscribers) {
|
|
344
|
+
return render.apply(this, arguments)
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
return instrument(req, res, ctx => {
|
|
348
|
+
publishRoutePage(ctx, this, context.page, false)
|
|
349
|
+
|
|
350
|
+
const { onError } = context
|
|
351
|
+
return render.call(this, req, res, {
|
|
352
|
+
...context,
|
|
353
|
+
onError: function (error) {
|
|
354
|
+
publishError(req, ctx, error)
|
|
355
|
+
return onError?.apply(this, arguments)
|
|
356
|
+
},
|
|
357
|
+
})
|
|
358
|
+
})
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
function instrumentPagesApiRuntime (runtime) {
|
|
363
|
+
const PagesAPIRouteModule = runtime.PagesAPIRouteModule || runtime.default
|
|
364
|
+
instrumentRouteModule(PagesAPIRouteModule, 'render', wrapPagesApiRender, false)
|
|
365
|
+
return runtime
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
function wrapAppPageRender (render) {
|
|
369
|
+
return function (req, res, context = {}) {
|
|
370
|
+
if (!startChannel.hasSubscribers && !queryParsedChannel.hasSubscribers) {
|
|
371
|
+
return render.apply(this, arguments)
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
return instrument(req, res, ctx => {
|
|
375
|
+
publishRoutePage(ctx, this, context.page, true)
|
|
376
|
+
|
|
377
|
+
return render.apply(this, arguments).then(result => {
|
|
378
|
+
const statusCode = result?.metadata?.statusCode
|
|
379
|
+
if (ctx && typeof statusCode === 'number') {
|
|
380
|
+
ctx.res.statusCode = statusCode
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
return result
|
|
384
|
+
}, error => {
|
|
385
|
+
if (ctx && (typeof ctx.res.statusCode !== 'number' || ctx.res.statusCode < 400)) {
|
|
386
|
+
ctx.res.statusCode = 500
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
throw error
|
|
390
|
+
})
|
|
391
|
+
})
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
function instrumentAppPageRuntime (runtime) {
|
|
396
|
+
const AppPageRouteModule = runtime.AppPageRouteModule || runtime.default
|
|
397
|
+
instrumentRouteModule(AppPageRouteModule, 'render', wrapAppPageRender, true)
|
|
398
|
+
return runtime
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
for (const [runtime, instrumentRuntime] of [
|
|
402
|
+
['app-route', instrumentAppRouteRuntime],
|
|
403
|
+
['pages-api', instrumentPagesApiRuntime],
|
|
404
|
+
['app-page', instrumentAppPageRuntime],
|
|
405
|
+
]) {
|
|
406
|
+
addHook({
|
|
407
|
+
name: 'next',
|
|
408
|
+
versions: ['>=15.4.1'],
|
|
409
|
+
filePattern: String.raw`${COMPILED_RUNTIME_PATH}${runtime}[\w-]*\.runtime\.(?:dev|prod)\.js$`,
|
|
410
|
+
}, instrumentRuntime)
|
|
411
|
+
}
|
|
280
412
|
|
|
281
413
|
addHook({
|
|
282
414
|
name: 'next',
|
|
@@ -210,10 +210,24 @@ addHook({ name: 'openai', file: 'dist/api.js', versions: ['>=3.0.0 <4'] }, expor
|
|
|
210
210
|
return exports
|
|
211
211
|
})
|
|
212
212
|
|
|
213
|
+
/**
|
|
214
|
+
* @typedef {{
|
|
215
|
+
* methodName: string,
|
|
216
|
+
* args: unknown[],
|
|
217
|
+
* basePath?: string,
|
|
218
|
+
* result?: Record<string, unknown>,
|
|
219
|
+
* error?: unknown,
|
|
220
|
+
* }} OpenAiContext
|
|
221
|
+
*/
|
|
222
|
+
|
|
213
223
|
/**
|
|
214
224
|
* For streamed responses, we need to accumulate all of the content in
|
|
215
225
|
* the chunks, and let the combined content be the final response.
|
|
216
226
|
* This way, spans look the same as when not streamed.
|
|
227
|
+
*
|
|
228
|
+
* @param {{ headers: unknown, url: string }} response
|
|
229
|
+
* @param {{ method: string }} options
|
|
230
|
+
* @param {OpenAiContext} ctx
|
|
217
231
|
*/
|
|
218
232
|
function wrapStreamIterator (response, options, ctx) {
|
|
219
233
|
return function (itr) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { errorMonitor } = require('node:events')
|
|
4
|
+
const { performance } = require('node:perf_hooks')
|
|
4
5
|
|
|
5
6
|
const shimmer = require('../../datadog-shimmer')
|
|
6
7
|
const {
|
|
@@ -18,10 +19,22 @@ const finishPoolQueryCh = channel('datadog:pg:pool:query:finish')
|
|
|
18
19
|
const poolConnectStartCh = channel('apm:pg:pool:connect:start')
|
|
19
20
|
const poolConnectFinishCh = channel('apm:pg:pool:connect:finish')
|
|
20
21
|
|
|
22
|
+
const poolAcquireStartCh = channel('apm:pg:pool:acquire:start')
|
|
23
|
+
const poolAcquireFinishCh = channel('apm:pg:pool:acquire:finish')
|
|
24
|
+
|
|
21
25
|
// Drivers like pg-promise reuse the same prepared-statement query object across executions; cache
|
|
22
26
|
// the un-injected `text` so the wrap doesn't capture a previous DBM injection as the new original.
|
|
23
27
|
const originalTextCache = new WeakMap()
|
|
24
28
|
|
|
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
|
+
|
|
25
38
|
addHook({ name: 'pg', versions: ['>=8.0.3'], file: 'lib/native/client.js' }, Client => {
|
|
26
39
|
shimmer.wrap(Client.prototype, 'query', query => wrapQuery(query))
|
|
27
40
|
return Client
|
|
@@ -36,18 +49,74 @@ addHook({ name: 'pg', versions: ['>=8.0.3'] }, pg => {
|
|
|
36
49
|
// pg defers a busy pool's connect callback and runs it in the releasing query's async context;
|
|
37
50
|
// capture the caller's context and restore it around the callback so spans attach to the caller.
|
|
38
51
|
shimmer.wrap(pg.Pool.prototype, 'connect', connect => function (cb) {
|
|
39
|
-
|
|
52
|
+
// Pool.query always supplies a callback, so a missing callback is an explicit acquire.
|
|
53
|
+
if (typeof cb !== 'function') {
|
|
54
|
+
if (!poolAcquireStartCh.hasSubscribers) {
|
|
55
|
+
return connect.apply(this, arguments)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const start = acquireStart(this)
|
|
59
|
+
const acquireCtx = { poolOptions: this.options }
|
|
60
|
+
poolAcquireStartCh.publish(acquireCtx)
|
|
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
|
+
}
|
|
72
|
+
|
|
73
|
+
if (!poolConnectStartCh.hasSubscribers) {
|
|
40
74
|
return connect.apply(this, arguments)
|
|
41
75
|
}
|
|
42
76
|
|
|
43
77
|
const ctx = {}
|
|
44
|
-
|
|
45
|
-
|
|
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 {
|
|
91
|
+
if (client !== undefined) {
|
|
92
|
+
poolWaitClients.pop()
|
|
93
|
+
poolWaitTimes.pop()
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
} else {
|
|
98
|
+
acquireCtx = { poolOptions: this.options }
|
|
99
|
+
poolAcquireStartCh.publish(acquireCtx)
|
|
100
|
+
|
|
101
|
+
arguments[0] = function (...args) {
|
|
102
|
+
const client = args[1]
|
|
103
|
+
acquireCtx.error = args[0]
|
|
104
|
+
// A failed acquire has no client, so keep the parameters `connectForAcquire` snapshotted.
|
|
105
|
+
if (client !== undefined) {
|
|
106
|
+
acquireCtx.params = client.connectionParameters
|
|
107
|
+
}
|
|
108
|
+
finishAcquire(acquireCtx, start)
|
|
109
|
+
return poolConnectFinishCh.runStores(ctx, cb, this, ...args)
|
|
110
|
+
}
|
|
46
111
|
}
|
|
47
112
|
|
|
48
113
|
poolConnectStartCh.publish(ctx)
|
|
49
114
|
|
|
50
|
-
|
|
115
|
+
if (acquireCtx === undefined) {
|
|
116
|
+
return connect.apply(this, arguments)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return connectForAcquire(connect, this, arguments, acquireCtx, start)
|
|
51
120
|
})
|
|
52
121
|
shimmer.wrap(pg.Pool.prototype, 'query', query => wrapPoolQuery(query))
|
|
53
122
|
return pg
|
|
@@ -83,6 +152,17 @@ function wrapQuery (query) {
|
|
|
83
152
|
abortController,
|
|
84
153
|
stream,
|
|
85
154
|
}
|
|
155
|
+
|
|
156
|
+
if (poolWaitClients.length !== 0) {
|
|
157
|
+
for (let i = poolWaitClients.length - 1; i >= 0; i--) {
|
|
158
|
+
if (poolWaitClients[i] === this) {
|
|
159
|
+
ctx.poolWaitTime = poolWaitTimes[i]
|
|
160
|
+
poolWaitClients[i] = undefined
|
|
161
|
+
break
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
86
166
|
const finish = (error, res) => {
|
|
87
167
|
if (error) {
|
|
88
168
|
ctx.error = error
|
|
@@ -185,10 +265,102 @@ function wrapQuery (query) {
|
|
|
185
265
|
const finish = (ctx) => {
|
|
186
266
|
finishPoolQueryCh.publish(ctx)
|
|
187
267
|
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* @typedef {{ database?: string, user?: string, host?: string, port?: number }} PoolConnectionParameters
|
|
271
|
+
* @typedef {{ connectionParameters?: PoolConnectionParameters }} PoolClient
|
|
272
|
+
* @typedef {{
|
|
273
|
+
* options?: PoolConnectionParameters,
|
|
274
|
+
* idleCount: number,
|
|
275
|
+
* waitingCount: number,
|
|
276
|
+
* _clients?: PoolClient[]
|
|
277
|
+
* }} InstrumentedPool
|
|
278
|
+
* @typedef {{
|
|
279
|
+
* poolOptions?: PoolConnectionParameters,
|
|
280
|
+
* params?: PoolConnectionParameters,
|
|
281
|
+
* error?: unknown,
|
|
282
|
+
* poolWaitTime?: number
|
|
283
|
+
* }} AcquireContext
|
|
284
|
+
* @typedef {{ length: number, [index: number]: unknown } & Iterable<unknown>} ArgumentsLike
|
|
285
|
+
*/
|
|
286
|
+
|
|
287
|
+
// pg drains its pending queue FIFO on the next tick, so an idle client is only ours when it
|
|
288
|
+
// outnumbers the requests already queued ahead of us. That handoff is not a wait on the pool.
|
|
289
|
+
/**
|
|
290
|
+
* @param {InstrumentedPool} pool
|
|
291
|
+
*/
|
|
292
|
+
function acquireStart (pool) {
|
|
293
|
+
return pool.idleCount > pool.waitingCount ? undefined : performance.now()
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* @param {number | undefined} start
|
|
298
|
+
*/
|
|
299
|
+
function acquireWait (start) {
|
|
300
|
+
return start === undefined ? 0 : performance.now() - start
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* @param {InstrumentedPool} pool
|
|
305
|
+
*/
|
|
306
|
+
function latestPoolConnectionParameters (pool) {
|
|
307
|
+
// pg-pool removes a failed client before invoking the acquire callback, so snapshot it while
|
|
308
|
+
// connect is still pending.
|
|
309
|
+
const clients = pool._clients
|
|
310
|
+
return clients?.at(-1)?.connectionParameters
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* @param {Function} connect
|
|
315
|
+
* @param {InstrumentedPool} pool
|
|
316
|
+
* @param {ArgumentsLike} args
|
|
317
|
+
* @param {AcquireContext} acquireCtx
|
|
318
|
+
* @param {number | undefined} start
|
|
319
|
+
*/
|
|
320
|
+
function connectForAcquire (connect, pool, args, acquireCtx, start) {
|
|
321
|
+
let result
|
|
322
|
+
try {
|
|
323
|
+
result = connect.apply(pool, args)
|
|
324
|
+
} catch (error) {
|
|
325
|
+
// pg throws synchronously when it cannot even build a client, from a malformed connection
|
|
326
|
+
// string or a caller-supplied `Client` constructor, so the span needs finishing here.
|
|
327
|
+
acquireCtx.error = error
|
|
328
|
+
finishAcquire(acquireCtx, start)
|
|
329
|
+
throw error
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
acquireCtx.params = latestPoolConnectionParameters(pool)
|
|
333
|
+
return result
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* @param {AcquireContext} ctx
|
|
338
|
+
* @param {number | undefined} start
|
|
339
|
+
*/
|
|
340
|
+
function finishAcquire (ctx, start) {
|
|
341
|
+
ctx.poolWaitTime = acquireWait(start)
|
|
342
|
+
poolAcquireFinishCh.publish(ctx)
|
|
343
|
+
}
|
|
344
|
+
|
|
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
|
+
}
|
|
188
358
|
function wrapPoolQuery (query) {
|
|
189
359
|
return function (...args) {
|
|
190
360
|
if (!startPoolQueryCh.hasSubscribers) {
|
|
191
|
-
return
|
|
361
|
+
return poolConnectStartCh.hasSubscribers
|
|
362
|
+
? acquireForPoolQuery(query, this, args)
|
|
363
|
+
: query.apply(this, args)
|
|
192
364
|
}
|
|
193
365
|
|
|
194
366
|
const pgQuery = args[0] !== null && typeof args[0] === 'object' ? args[0] : { text: args[0] }
|
|
@@ -218,7 +390,9 @@ function wrapPoolQuery (query) {
|
|
|
218
390
|
})
|
|
219
391
|
}
|
|
220
392
|
|
|
221
|
-
const retval =
|
|
393
|
+
const retval = poolConnectStartCh.hasSubscribers
|
|
394
|
+
? acquireForPoolQuery(query, this, args)
|
|
395
|
+
: query.apply(this, args)
|
|
222
396
|
|
|
223
397
|
if (retval?.then) {
|
|
224
398
|
retval.then(() => {
|