dd-trace 5.114.0 → 5.116.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.electron.md +7 -0
- package/README.md +17 -0
- package/ci/diagnose.js +2100 -0
- package/ci/init.js +23 -2
- package/ci/runbook.md +198 -0
- package/ci/test-optimization-validation/approval-artifacts.js +143 -0
- package/ci/test-optimization-validation/approval.js +299 -0
- package/ci/test-optimization-validation/artifact-id.js +20 -0
- package/ci/test-optimization-validation/bounded-json.js +121 -0
- package/ci/test-optimization-validation/ci-command-candidate.js +83 -0
- package/ci/test-optimization-validation/ci-discovery.js +181 -0
- package/ci/test-optimization-validation/ci-remediation.js +210 -0
- package/ci/test-optimization-validation/cli.js +903 -0
- package/ci/test-optimization-validation/command-blocker.js +81 -0
- package/ci/test-optimization-validation/command-output-policy.js +206 -0
- package/ci/test-optimization-validation/command-runner.js +707 -0
- package/ci/test-optimization-validation/command-suitability.js +471 -0
- package/ci/test-optimization-validation/executable-approval.js +48 -0
- package/ci/test-optimization-validation/executable.js +480 -0
- package/ci/test-optimization-validation/generated-file-policy.js +63 -0
- package/ci/test-optimization-validation/generated-files.js +351 -0
- package/ci/test-optimization-validation/generated-verifier.js +196 -0
- package/ci/test-optimization-validation/init-probe-preload.js +163 -0
- package/ci/test-optimization-validation/init-probe.js +246 -0
- package/ci/test-optimization-validation/late-initialization.js +63 -0
- package/ci/test-optimization-validation/local-command.js +163 -0
- package/ci/test-optimization-validation/manifest-loader.js +133 -0
- package/ci/test-optimization-validation/manifest-scaffold.js +738 -0
- package/ci/test-optimization-validation/manifest-schema.js +862 -0
- package/ci/test-optimization-validation/offline-fixtures.js +327 -0
- package/ci/test-optimization-validation/offline-output.js +406 -0
- package/ci/test-optimization-validation/payload-normalizer.js +72 -0
- package/ci/test-optimization-validation/plan-writer.js +1120 -0
- package/ci/test-optimization-validation/preflight-runner.js +114 -0
- package/ci/test-optimization-validation/redaction.js +331 -0
- package/ci/test-optimization-validation/report-writer.js +1508 -0
- package/ci/test-optimization-validation/safe-files.js +203 -0
- package/ci/test-optimization-validation/scenarios/auto-test-retries.js +159 -0
- package/ci/test-optimization-validation/scenarios/basic-reporting.js +657 -0
- package/ci/test-optimization-validation/scenarios/ci-wiring.js +780 -0
- package/ci/test-optimization-validation/scenarios/early-flake-detection.js +141 -0
- package/ci/test-optimization-validation/scenarios/helpers.js +539 -0
- package/ci/test-optimization-validation/scenarios/test-management.js +218 -0
- package/ci/test-optimization-validation/setup-runner.js +97 -0
- package/ci/test-optimization-validation/static-diagnosis.js +159 -0
- package/ci/test-optimization-validation/test-output.js +129 -0
- package/ci/test-optimization-validation-manifest.schema.json +1 -0
- package/ci/validate-test-optimization.js +3 -0
- package/ext/exporters.js +1 -0
- package/index.d.ts +121 -8
- package/index.electron.js +3 -0
- package/init.js +18 -0
- package/initialize.mjs +1 -1
- package/loader-hook.mjs +28 -18
- package/openfeature.d.ts +1 -0
- package/openfeature.js +4 -0
- package/package.json +15 -8
- package/packages/datadog-instrumentations/src/ai.js +37 -26
- package/packages/datadog-instrumentations/src/child_process.js +1 -1
- package/packages/datadog-instrumentations/src/claude-agent-sdk.js +1 -1
- package/packages/datadog-instrumentations/src/cucumber-worker-threads.js +9 -3
- package/packages/datadog-instrumentations/src/cucumber.js +24 -10
- package/packages/datadog-instrumentations/src/cypress-config.js +398 -52
- package/packages/datadog-instrumentations/src/express.js +20 -2
- package/packages/datadog-instrumentations/src/fastify.js +7 -11
- package/packages/datadog-instrumentations/src/grpc/server.js +18 -0
- package/packages/datadog-instrumentations/src/helpers/hook.js +27 -6
- package/packages/datadog-instrumentations/src/helpers/optional-peer-bundler.js +8 -8
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +28 -2
- package/packages/datadog-instrumentations/src/helpers/router-helper.js +8 -8
- package/packages/datadog-instrumentations/src/http2/server.js +143 -17
- package/packages/datadog-instrumentations/src/jest.js +36 -4
- package/packages/datadog-instrumentations/src/mariadb.js +1 -1
- package/packages/datadog-instrumentations/src/mocha/main.js +0 -2
- package/packages/datadog-instrumentations/src/mocha/utils.js +0 -4
- package/packages/datadog-instrumentations/src/mongodb.js +3 -3
- package/packages/datadog-instrumentations/src/mongoose.js +3 -3
- package/packages/datadog-instrumentations/src/mquery.js +2 -2
- package/packages/datadog-instrumentations/src/mysql.js +1 -1
- package/packages/datadog-instrumentations/src/next.js +24 -0
- package/packages/datadog-instrumentations/src/nyc.js +0 -2
- package/packages/datadog-instrumentations/src/oracledb.js +2 -2
- package/packages/datadog-instrumentations/src/pg.js +2 -2
- package/packages/datadog-instrumentations/src/playwright.js +159 -22
- package/packages/datadog-instrumentations/src/process.js +3 -0
- package/packages/datadog-instrumentations/src/router.js +191 -106
- package/packages/datadog-instrumentations/src/selenium.js +52 -26
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +2 -2
- package/packages/datadog-instrumentations/src/vitest-main.js +0 -2
- package/packages/datadog-instrumentations/src/ws.js +2 -1
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/context.js +2 -2
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/util.js +2 -1
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +41 -16
- package/packages/datadog-plugin-aws-sdk/src/services/sns.js +21 -21
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +14 -8
- package/packages/datadog-plugin-aws-sdk/src/util.js +2 -24
- package/packages/datadog-plugin-cucumber/src/index.js +1 -1
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +24 -62
- package/packages/datadog-plugin-cypress/src/index.js +6 -1
- package/packages/datadog-plugin-cypress/src/support.js +92 -26
- package/packages/datadog-plugin-electron/src/ipc.js +1 -1
- package/packages/datadog-plugin-graphql/src/execute.js +177 -59
- package/packages/datadog-plugin-graphql/src/parse.js +22 -1
- package/packages/datadog-plugin-graphql/src/request.js +32 -1
- package/packages/datadog-plugin-graphql/src/utils.js +42 -0
- package/packages/datadog-plugin-graphql/src/validate.js +15 -3
- package/packages/datadog-plugin-http2/src/client.js +1 -1
- package/packages/datadog-plugin-http2/src/server.js +38 -6
- package/packages/datadog-plugin-jest/src/util.js +21 -6
- package/packages/datadog-plugin-langchain/src/handlers/embedding.js +2 -1
- package/packages/datadog-plugin-langchain/src/handlers/language_models.js +2 -1
- package/packages/datadog-plugin-langchain/src/tokens.js +2 -2
- package/packages/datadog-plugin-playwright/src/index.js +177 -64
- package/packages/datadog-plugin-router/src/index.js +11 -2
- package/packages/datadog-plugin-selenium/src/index.js +5 -36
- package/packages/datadog-plugin-vitest/src/index.js +4 -2
- package/packages/datadog-plugin-ws/src/close.js +2 -1
- package/packages/datadog-plugin-ws/src/producer.js +2 -1
- package/packages/datadog-plugin-ws/src/receiver.js +2 -1
- package/packages/datadog-plugin-ws/src/server.js +2 -1
- package/packages/dd-trace/index.electron.js +3 -0
- package/packages/dd-trace/index.js +2 -37
- package/packages/dd-trace/src/aiguard/sdk.js +1 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +2 -2
- package/packages/dd-trace/src/appsec/iast/telemetry/span-tags.js +3 -1
- package/packages/dd-trace/src/azure_metadata.js +2 -1
- package/packages/dd-trace/src/bootstrap.js +39 -0
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +93 -28
- package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +1 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/index.js +160 -0
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/msgpack-to-json.js +288 -0
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/payload-projection.js +84 -0
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/sink.js +369 -0
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/writer.js +60 -0
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +55 -5
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +22 -6
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +5 -0
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +62 -7
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +9 -2
- package/packages/dd-trace/src/ci-visibility/requests/upload-coverage-report.js +6 -2
- package/packages/dd-trace/src/ci-visibility/rum.js +7 -0
- package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +4 -0
- package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +1 -1
- package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +137 -9
- package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache.js +173 -9
- package/packages/dd-trace/src/ci-visibility/test-screenshot.js +90 -0
- package/packages/dd-trace/src/config/generated-config-types.d.ts +20 -0
- package/packages/dd-trace/src/config/helper.js +1 -0
- package/packages/dd-trace/src/config/index.js +10 -0
- package/packages/dd-trace/src/config/supported-configurations.json +83 -0
- package/packages/dd-trace/src/constants.js +7 -0
- package/packages/dd-trace/src/datastreams/pathway.js +6 -4
- package/packages/dd-trace/src/exporter.js +2 -0
- package/packages/dd-trace/src/exporters/common/client-library-headers.js +21 -0
- package/packages/dd-trace/src/exporters/common/request.js +59 -30
- package/packages/dd-trace/src/exporters/common/url.js +15 -1
- package/packages/dd-trace/src/feature-registry.js +29 -0
- package/packages/dd-trace/src/llmobs/constants/tags.js +1 -0
- package/packages/dd-trace/src/llmobs/experiments/client.js +113 -0
- package/packages/dd-trace/src/llmobs/experiments/dataset.js +154 -0
- package/packages/dd-trace/src/llmobs/experiments/experiment.js +283 -0
- package/packages/dd-trace/src/llmobs/experiments/index.js +152 -0
- package/packages/dd-trace/src/llmobs/experiments/noop.js +30 -0
- package/packages/dd-trace/src/llmobs/experiments/result.js +34 -0
- package/packages/dd-trace/src/llmobs/index.js +10 -2
- package/packages/dd-trace/src/llmobs/noop.js +6 -0
- package/packages/dd-trace/src/llmobs/plugins/ai/vercelTelemetry.js +20 -3
- package/packages/dd-trace/src/llmobs/plugins/anthropic/index.js +2 -2
- package/packages/dd-trace/src/llmobs/plugins/langgraph/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/openai/constants.js +8 -0
- package/packages/dd-trace/src/llmobs/plugins/openai/index.js +48 -14
- package/packages/dd-trace/src/llmobs/plugins/openai/utils.js +43 -0
- package/packages/dd-trace/src/llmobs/sdk.js +17 -0
- package/packages/dd-trace/src/llmobs/tagger.js +79 -7
- package/packages/dd-trace/src/llmobs/telemetry.js +2 -1
- package/packages/dd-trace/src/llmobs/util.js +32 -0
- package/packages/dd-trace/src/noop/proxy.js +5 -4
- package/packages/dd-trace/src/openfeature/agentless_configuration_source.js +322 -0
- package/packages/dd-trace/src/openfeature/configuration_source.js +90 -0
- package/packages/dd-trace/src/openfeature/flagging_provider.js +14 -23
- package/packages/dd-trace/src/openfeature/index.js +0 -2
- package/packages/dd-trace/src/openfeature/noop.js +1 -28
- package/packages/dd-trace/src/openfeature/register.js +35 -0
- package/packages/dd-trace/src/openfeature/remote_config.js +15 -18
- package/packages/dd-trace/src/openfeature/require-provider.js +18 -0
- package/packages/dd-trace/src/opentelemetry/span-ending-hook.js +10 -0
- package/packages/dd-trace/src/opentelemetry/span.js +5 -0
- package/packages/dd-trace/src/opentracing/propagation/log.js +11 -2
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +80 -14
- package/packages/dd-trace/src/opentracing/propagation/text_map_dsm.js +10 -1
- package/packages/dd-trace/src/opentracing/tracer.js +7 -1
- package/packages/dd-trace/src/plugins/ci_plugin.js +20 -6
- package/packages/dd-trace/src/plugins/util/git.js +3 -2
- package/packages/dd-trace/src/plugins/util/inferred_proxy.js +29 -5
- package/packages/dd-trace/src/plugins/util/test.js +65 -8
- package/packages/dd-trace/src/plugins/util/web.js +12 -0
- package/packages/dd-trace/src/proxy.js +99 -10
- package/packages/dd-trace/src/span_processor.js +5 -0
- package/packages/dd-trace/src/standalone/index.js +0 -36
- package/packages/dd-trace/src/telemetry/send-data.js +2 -2
- package/packages/dd-trace/src/util.js +26 -0
- package/vendor/dist/@apm-js-collab/code-transformer/index.js +1 -1
- package/vendor/dist/@datadog/sketches-js/index.js +1 -1
- package/vendor/dist/protobufjs/index.js +1 -1
- package/vendor/dist/protobufjs/minimal/index.js +1 -1
- package/vendor/dist/shell-quote/index.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/require-optional-peer.js +0 -17
|
@@ -8,7 +8,8 @@ const { getCompileToRegexp } = require('./path-to-regexp')
|
|
|
8
8
|
const {
|
|
9
9
|
getRouterMountPaths,
|
|
10
10
|
joinPath,
|
|
11
|
-
|
|
11
|
+
setLayerMeta,
|
|
12
|
+
getLayerMeta,
|
|
12
13
|
isAppMounted,
|
|
13
14
|
setRouterMountPath,
|
|
14
15
|
extractMountPaths,
|
|
@@ -25,137 +26,219 @@ function isFastSlash (layer, matchers) {
|
|
|
25
26
|
return layer.regexp?.fast_slash ?? matchers.hasSlashPath
|
|
26
27
|
}
|
|
27
28
|
|
|
28
|
-
// TODO: Move this function to a shared file between Express and Router
|
|
29
29
|
/**
|
|
30
|
+
* Cache the per-layer dispatch metadata in a side table instead of replacing
|
|
31
|
+
* `layer.handle`. Phase-sorting hosts (loopback's `_findLayerByHandler`) map a
|
|
32
|
+
* layer back to the user handler by scanning the handle, so the handle has to
|
|
33
|
+
* stay the user's function.
|
|
34
|
+
*
|
|
35
|
+
* @param {{ handle: Function, name?: string, path?: string,
|
|
36
|
+
* regexp?: { fast_star?: boolean, fast_slash?: boolean } }} layer
|
|
37
|
+
* @param {Array<{ path?: string, regex?: RegExp }> & { hasStarPath?: boolean, hasSlashPath?: boolean }} matchers
|
|
38
|
+
*/
|
|
39
|
+
function annotateLayer (layer, matchers) {
|
|
40
|
+
const handle = layer.handle
|
|
41
|
+
const name = handle._name || layer.name || handle.name
|
|
42
|
+
|
|
43
|
+
let captureRoute
|
|
44
|
+
let needMultiMatch = false
|
|
45
|
+
if (matchers.length !== 0 && !isFastStar(layer, matchers) && !isFastSlash(layer, matchers)) {
|
|
46
|
+
if (matchers.length === 1) {
|
|
47
|
+
captureRoute = matchers[0].path
|
|
48
|
+
} else {
|
|
49
|
+
needMultiMatch = true
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
setLayerMeta(layer, { name, captureRoute, needMultiMatch, matchers })
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Resolve the route for a dispatched layer. Single-pattern layers carry a
|
|
58
|
+
* constant route; only multi-pattern stacks need the per-request `layer.path`
|
|
59
|
+
* match the host already computed.
|
|
60
|
+
*
|
|
61
|
+
* @param {{ captureRoute?: string, needMultiMatch: boolean,
|
|
62
|
+
* matchers: Array<{ path?: string, regex?: RegExp }> }} meta
|
|
63
|
+
* @param {{ path?: string }} layer
|
|
64
|
+
* @returns {string | undefined}
|
|
65
|
+
*/
|
|
66
|
+
function resolveLayerRoute (meta, layer) {
|
|
67
|
+
if (!meta.needMultiMatch) return meta.captureRoute
|
|
68
|
+
|
|
69
|
+
for (const matcher of meta.matchers) {
|
|
70
|
+
if (matcher.regex?.test(layer.path)) return matcher.path
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Build the request/error dispatch wrappers for one host (`express` / `router`).
|
|
76
|
+
* They wrap the layer's prototype dispatch and read the side-table metadata, so
|
|
77
|
+
* `layer.handle` is never replaced. The arity guard mirrors the host's own
|
|
78
|
+
* (`handle_request` skips 4-arg handlers, `handle_error` skips the rest), so a
|
|
79
|
+
* span is published only for the layer the host actually runs.
|
|
80
|
+
*
|
|
30
81
|
* @param {string} name Channel namespace (`apm:<name>:middleware:*`).
|
|
31
|
-
* @param {((pattern: string | RegExp) => RegExp | undefined) | undefined} compile
|
|
32
|
-
* Host-resolved path-to-regexp compile adapter, or undefined when the host
|
|
33
|
-
* instance ships no path-to-regexp. Captured here so each express/router
|
|
34
|
-
* instance keeps the dialect it actually loaded.
|
|
35
82
|
*/
|
|
36
|
-
function
|
|
83
|
+
function createLayerDispatchWrappers (name) {
|
|
37
84
|
const enterChannel = channel(`apm:${name}:middleware:enter`)
|
|
38
85
|
const exitChannel = channel(`apm:${name}:middleware:exit`)
|
|
39
86
|
const finishChannel = channel(`apm:${name}:middleware:finish`)
|
|
40
87
|
const errorChannel = channel(`apm:${name}:middleware:error`)
|
|
41
88
|
const nextChannel = channel(`apm:${name}:middleware:next`)
|
|
42
|
-
const
|
|
89
|
+
const repeatChannel = channel(`apm:${name}:middleware:repeat`)
|
|
43
90
|
// Bound per name so express and a bare router keep independent guards.
|
|
44
91
|
const publishError = createErrorPublisher(errorChannel)
|
|
45
92
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
//
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
93
|
+
/**
|
|
94
|
+
* @param {import('node:http').IncomingMessage} req
|
|
95
|
+
* @param {string | undefined} layerName
|
|
96
|
+
* @param {(error?: unknown) => void} originalNext
|
|
97
|
+
*/
|
|
98
|
+
function wrapNext (req, layerName, originalNext) {
|
|
99
|
+
// Per layer dispatch, N per request. Named `next`/arity-1 mirrors the
|
|
100
|
+
// router continuation so wrapCallback skips its name/length rewrite.
|
|
101
|
+
let calls = 0
|
|
102
|
+
return shimmer.wrapCallback(originalNext, original => function next (error) {
|
|
103
|
+
// A handler that calls `next()` and then rejects (`next(); await bg()`)
|
|
104
|
+
// makes the host call this continuation twice. Publish once so the second
|
|
105
|
+
// pass cannot tag the already-finished span's parent with a late error.
|
|
106
|
+
calls++
|
|
107
|
+
if (calls === 1) {
|
|
108
|
+
if (error && error !== 'route' && error !== 'router') {
|
|
109
|
+
publishError({ req, error })
|
|
110
|
+
}
|
|
64
111
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
// Workaround for loopback's phase-based middleware sorting. Its
|
|
75
|
-
// `_findLayerByHandler` maps a layer back to the user handler by scanning
|
|
76
|
-
// the layer handle's enumerable properties for the original function.
|
|
77
|
-
// Replacing `layer.handle` with this wrapper hides that handler, so without
|
|
78
|
-
// the back-reference loopback cannot tag the layer with its phase and
|
|
79
|
-
// `app.middleware(phase, ...)` handlers run in insertion order instead of
|
|
80
|
-
// phase order. The property name is part of that contract; keep it stable.
|
|
81
|
-
wrapped._datadog_orig = original
|
|
112
|
+
nextChannel.publish({ req })
|
|
113
|
+
finishChannel.publish({ req })
|
|
114
|
+
} else if (calls === 2) {
|
|
115
|
+
// Surface the repeat as a diagnostic on the still-live request span. The
|
|
116
|
+
// host cannot tell a legitimate `next(); await bg()` from a buggy double
|
|
117
|
+
// `next()`, so this only records that it happened, not that it is wrong.
|
|
118
|
+
repeatChannel.publish({ req, name: layerName, error })
|
|
119
|
+
}
|
|
82
120
|
|
|
83
|
-
|
|
121
|
+
original.apply(this, arguments)
|
|
122
|
+
})
|
|
84
123
|
}
|
|
85
124
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
125
|
+
// Every host dispatch turns a synchronous throw into `next(error)`, and the
|
|
126
|
+
// hosts that await the handler (router >=2, express 5, express 4 +
|
|
127
|
+
// express-async-errors) do the same for a rejected promise. Passing
|
|
128
|
+
// `wrappedNext` through captures both without a tracer-side try/catch; only
|
|
129
|
+
// `exit` needs the `finally`. express 4's native dispatch converts only the
|
|
130
|
+
// synchronous throw — exactly what the pre-refactor handle wrap caught.
|
|
131
|
+
function wrapLayerRequest (originalRequest) {
|
|
132
|
+
return function (req, res, next) {
|
|
133
|
+
if (!enterChannel.hasSubscribers) return originalRequest.call(this, req, res, next)
|
|
91
134
|
|
|
92
|
-
|
|
93
|
-
if (
|
|
94
|
-
for (const matcher of matchers) {
|
|
95
|
-
if (matcher.regex?.test(layer.path)) {
|
|
96
|
-
route = matcher.path
|
|
97
|
-
break
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
135
|
+
const meta = getLayerMeta(this)
|
|
136
|
+
if (meta === undefined || this.handle.length > 3) return originalRequest.call(this, req, res, next)
|
|
101
137
|
|
|
102
|
-
|
|
138
|
+
const wrappedNext = typeof next === 'function' ? wrapNext(req, meta.name, next) : next
|
|
139
|
+
enterChannel.publish({ name: meta.name, req, route: resolveLayerRoute(meta, this), layer: this })
|
|
103
140
|
|
|
104
141
|
try {
|
|
105
|
-
return
|
|
106
|
-
} catch (error) {
|
|
107
|
-
publishError({ req, error })
|
|
108
|
-
nextChannel.publish({ req })
|
|
109
|
-
finishChannel.publish({ req })
|
|
110
|
-
|
|
111
|
-
throw error
|
|
142
|
+
return originalRequest.call(this, req, res, wrappedNext)
|
|
112
143
|
} finally {
|
|
113
144
|
exitChannel.publish({ req })
|
|
114
145
|
}
|
|
115
146
|
}
|
|
116
147
|
}
|
|
117
148
|
|
|
118
|
-
function
|
|
119
|
-
return
|
|
120
|
-
if (!enterChannel.hasSubscribers) return
|
|
149
|
+
function wrapLayerError (originalError) {
|
|
150
|
+
return function (error, req, res, next) {
|
|
151
|
+
if (!enterChannel.hasSubscribers) return originalError.call(this, error, req, res, next)
|
|
121
152
|
|
|
122
|
-
const
|
|
153
|
+
const meta = getLayerMeta(this)
|
|
154
|
+
if (meta === undefined || this.handle.length !== 4) return originalError.call(this, error, req, res, next)
|
|
123
155
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}
|
|
156
|
+
const wrappedNext = typeof next === 'function' ? wrapNext(req, meta.name, next) : next
|
|
157
|
+
enterChannel.publish({ name: meta.name, req, route: resolveLayerRoute(meta, this), layer: this })
|
|
158
|
+
|
|
159
|
+
try {
|
|
160
|
+
return originalError.call(this, error, req, res, wrappedNext)
|
|
161
|
+
} finally {
|
|
162
|
+
exitChannel.publish({ req })
|
|
132
163
|
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
133
166
|
|
|
134
|
-
|
|
167
|
+
// express <4.6.0 has no `Layer` prototype dispatch: the router invokes
|
|
168
|
+
// `layer.handle` directly and routes errors by its arity. There the handle is
|
|
169
|
+
// replaced in place, with the arity preserved so the host still routes
|
|
170
|
+
// correctly. Newer express, express 5, and the router package keep `handle`
|
|
171
|
+
// pristine and are traced through the prototype wraps above.
|
|
172
|
+
function wrapLegacyHandle (layer, original) {
|
|
173
|
+
// `annotateLayer` always runs first in `wrapStack`, so the captured meta is
|
|
174
|
+
// never undefined here (unlike the prototype wraps, where `this` can be any
|
|
175
|
+
// layer the host dispatches).
|
|
176
|
+
const meta = getLayerMeta(layer)
|
|
177
|
+
const wrapped = shimmer.wrapFunction(original, inner => function (...args) {
|
|
178
|
+
if (!enterChannel.hasSubscribers) return inner.apply(this, args)
|
|
179
|
+
|
|
180
|
+
const isErrorHandler = original.length === 4
|
|
181
|
+
const req = args[isErrorHandler ? 1 : 0]
|
|
182
|
+
const nextIndex = isErrorHandler ? 3 : 2
|
|
183
|
+
if (typeof args[nextIndex] === 'function') args[nextIndex] = wrapNext(req, meta.name, args[nextIndex])
|
|
184
|
+
|
|
185
|
+
enterChannel.publish({ name: meta.name, req, route: resolveLayerRoute(meta, layer), layer })
|
|
135
186
|
|
|
136
187
|
try {
|
|
137
|
-
return
|
|
138
|
-
} catch (
|
|
139
|
-
|
|
188
|
+
return inner.apply(this, args)
|
|
189
|
+
} catch (error) {
|
|
190
|
+
// Unlike the prototype hosts, this router catches a synchronous throw
|
|
191
|
+
// outside the layer and calls its own `next(error)`, never `wrappedNext`.
|
|
192
|
+
// Mirror `wrapNext` here so the throwing layer still tags its error and
|
|
193
|
+
// finishes, rather than lingering on the stack until request finish.
|
|
194
|
+
publishError({ req, error })
|
|
140
195
|
nextChannel.publish({ req })
|
|
141
196
|
finishChannel.publish({ req })
|
|
142
197
|
|
|
143
|
-
throw
|
|
198
|
+
throw error
|
|
144
199
|
} finally {
|
|
145
200
|
exitChannel.publish({ req })
|
|
146
201
|
}
|
|
147
|
-
}
|
|
202
|
+
})
|
|
203
|
+
Object.defineProperty(wrapped, 'length', { value: original.length, configurable: true })
|
|
204
|
+
return wrapped
|
|
148
205
|
}
|
|
149
206
|
|
|
207
|
+
return { wrapLayerRequest, wrapLayerError, wrapLegacyHandle }
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* @param {{ handle_request?: unknown, handleRequest?: unknown }} layer
|
|
212
|
+
*/
|
|
213
|
+
function hasLayerDispatch (layer) {
|
|
214
|
+
return typeof layer.handle_request === 'function' || typeof layer.handleRequest === 'function'
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// TODO: Move this function to a shared file between Express and Router
|
|
218
|
+
/**
|
|
219
|
+
* @param {string} name Channel namespace (`apm:<name>:middleware:*`).
|
|
220
|
+
* @param {((pattern: string | RegExp) => RegExp | undefined) | undefined} compile
|
|
221
|
+
* Host-resolved path-to-regexp compile adapter, or undefined when the host
|
|
222
|
+
* instance ships no path-to-regexp. Captured here so each express/router
|
|
223
|
+
* instance keeps the dialect it actually loaded.
|
|
224
|
+
* @param {((layer: object, original: Function) => Function) | undefined} [wrapLegacyHandle]
|
|
225
|
+
* Fallback that replaces `layer.handle` for hosts without a `Layer` prototype
|
|
226
|
+
* dispatch (express <4.6.0). Omitted for hosts that always ship one.
|
|
227
|
+
*/
|
|
228
|
+
function createWrapRouterMethod (name, compile, wrapLegacyHandle) {
|
|
229
|
+
const routeAddedChannel = channel(`apm:${name}:route:added`)
|
|
230
|
+
|
|
150
231
|
function wrapStack (layers, matchers) {
|
|
151
232
|
for (const layer of layers) {
|
|
152
|
-
|
|
153
|
-
layer.__handle = wrapLayerHandle(layer, layer.__handle, matchers)
|
|
154
|
-
} else {
|
|
155
|
-
layer.handle = wrapLayerHandle(layer, layer.handle, matchers)
|
|
156
|
-
}
|
|
233
|
+
annotateLayer(layer, matchers)
|
|
157
234
|
|
|
158
|
-
|
|
235
|
+
if (wrapLegacyHandle !== undefined && !hasLayerDispatch(layer)) {
|
|
236
|
+
if (layer.__handle) { // express-async-errors
|
|
237
|
+
layer.__handle = wrapLegacyHandle(layer, layer.__handle)
|
|
238
|
+
} else {
|
|
239
|
+
layer.handle = wrapLegacyHandle(layer, layer.handle)
|
|
240
|
+
}
|
|
241
|
+
}
|
|
159
242
|
|
|
160
243
|
if (layer.route) {
|
|
161
244
|
for (const method of METHODS) {
|
|
@@ -169,21 +252,6 @@ function createWrapRouterMethod (name, compile) {
|
|
|
169
252
|
}
|
|
170
253
|
}
|
|
171
254
|
|
|
172
|
-
function wrapNext (req, originalNext) {
|
|
173
|
-
// Per layer dispatch, N per request. Named `next`/arity-1 mirrors the
|
|
174
|
-
// router continuation so wrapCallback skips its name/length rewrite.
|
|
175
|
-
return shimmer.wrapCallback(originalNext, original => function next (error) {
|
|
176
|
-
if (error && error !== 'route' && error !== 'router') {
|
|
177
|
-
publishError({ req, error })
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
nextChannel.publish({ req })
|
|
181
|
-
finishChannel.publish({ req })
|
|
182
|
-
|
|
183
|
-
original.apply(this, arguments)
|
|
184
|
-
})
|
|
185
|
-
}
|
|
186
|
-
|
|
187
255
|
function extractMatchers (fn) {
|
|
188
256
|
const arg = Array.isArray(fn) ? fn.flat(Infinity) : [fn]
|
|
189
257
|
|
|
@@ -304,6 +372,15 @@ addHook({ name: 'router', versions: ['>=1 <2'] }, Router => {
|
|
|
304
372
|
return Router
|
|
305
373
|
})
|
|
306
374
|
|
|
375
|
+
addHook({ name: 'router', file: 'lib/layer.js', versions: ['>=1 <2'] }, Layer => {
|
|
376
|
+
const { wrapLayerRequest, wrapLayerError } = createLayerDispatchWrappers('router')
|
|
377
|
+
|
|
378
|
+
shimmer.wrap(Layer.prototype, 'handle_request', wrapLayerRequest)
|
|
379
|
+
shimmer.wrap(Layer.prototype, 'handle_error', wrapLayerError)
|
|
380
|
+
|
|
381
|
+
return Layer
|
|
382
|
+
})
|
|
383
|
+
|
|
307
384
|
const queryParserReadCh = channel('datadog:query:read:finish')
|
|
308
385
|
|
|
309
386
|
addHook({ name: 'router', versions: ['>=2'] }, Router => {
|
|
@@ -365,6 +442,14 @@ function wrapHandleRequest (original) {
|
|
|
365
442
|
addHook({
|
|
366
443
|
name: 'router', file: 'lib/layer.js', versions: ['>=2'],
|
|
367
444
|
}, Layer => {
|
|
445
|
+
const { wrapLayerRequest, wrapLayerError } = createLayerDispatchWrappers('router')
|
|
446
|
+
|
|
447
|
+
// `handleRequest` carries two concerns: the middleware dispatch span and the
|
|
448
|
+
// param-start publish (`wrapHandleRequest`). Wrap the dispatch first so it
|
|
449
|
+
// sits inner and param-start still fires before `middleware:enter`, matching
|
|
450
|
+
// the order from when the handle itself was wrapped.
|
|
451
|
+
shimmer.wrap(Layer.prototype, 'handleRequest', wrapLayerRequest)
|
|
452
|
+
shimmer.wrap(Layer.prototype, 'handleError', wrapLayerError)
|
|
368
453
|
shimmer.wrap(Layer.prototype, 'handleRequest', wrapHandleRequest)
|
|
369
454
|
return Layer
|
|
370
455
|
})
|
|
@@ -404,4 +489,4 @@ addHook({
|
|
|
404
489
|
return router
|
|
405
490
|
})
|
|
406
491
|
|
|
407
|
-
module.exports = { createWrapRouterMethod }
|
|
492
|
+
module.exports = { createWrapRouterMethod, createLayerDispatchWrappers }
|
|
@@ -5,6 +5,10 @@ const realSetTimeout = setTimeout
|
|
|
5
5
|
|
|
6
6
|
const shimmer = require('../../datadog-shimmer')
|
|
7
7
|
const { getValueFromEnvSources } = require('../../dd-trace/src/config/helper')
|
|
8
|
+
const {
|
|
9
|
+
RUM_TEST_EXECUTION_ID_COOKIE_NAME: DD_CIVISIBILITY_TEST_EXECUTION_ID_COOKIE_NAME,
|
|
10
|
+
} = require('../../dd-trace/src/ci-visibility/rum')
|
|
11
|
+
const log = require('../../dd-trace/src/log')
|
|
8
12
|
const { addHook, channel } = require('./helpers/instrument')
|
|
9
13
|
|
|
10
14
|
const ciSeleniumDriverGetStartCh = channel('ci:selenium:driver:get')
|
|
@@ -20,7 +24,6 @@ if (window.DD_RUM && window.DD_RUM.stopSession) {
|
|
|
20
24
|
const IS_RUM_ACTIVE_SCRIPT = 'return !!window.DD_RUM'
|
|
21
25
|
|
|
22
26
|
const DD_CIVISIBILITY_RUM_FLUSH_WAIT_MILLIS = getValueFromEnvSources('DD_CIVISIBILITY_RUM_FLUSH_WAIT_MILLIS')
|
|
23
|
-
const DD_CIVISIBILITY_TEST_EXECUTION_ID_COOKIE_NAME = 'datadog-ci-visibility-test-execution-id'
|
|
24
27
|
|
|
25
28
|
// TODO: can we increase the supported version range?
|
|
26
29
|
addHook({
|
|
@@ -32,28 +35,47 @@ addHook({
|
|
|
32
35
|
if (!ciSeleniumDriverGetStartCh.hasSubscribers) {
|
|
33
36
|
return get.apply(this, arguments)
|
|
34
37
|
}
|
|
35
|
-
let traceId
|
|
36
|
-
const setTraceId = (inputTraceId) => {
|
|
37
|
-
traceId = inputTraceId
|
|
38
|
-
}
|
|
39
38
|
const getResult = await get.apply(this, arguments)
|
|
40
39
|
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
let isRumActive
|
|
41
|
+
try {
|
|
42
|
+
isRumActive = await this.executeScript(IS_RUM_ACTIVE_SCRIPT)
|
|
43
|
+
} catch (error) {
|
|
44
|
+
log.error('Selenium RUM detection error', error)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
let browserName
|
|
48
|
+
let browserVersion
|
|
49
|
+
try {
|
|
50
|
+
const capabilities = await this.getCapabilities()
|
|
51
|
+
browserName = capabilities.getBrowserName()
|
|
52
|
+
browserVersion = capabilities.getBrowserVersion()
|
|
53
|
+
} catch (error) {
|
|
54
|
+
log.error('Selenium browser metadata error', error)
|
|
55
|
+
}
|
|
43
56
|
|
|
44
|
-
|
|
45
|
-
setTraceId,
|
|
57
|
+
const context = {
|
|
46
58
|
seleniumVersion,
|
|
47
|
-
browserName
|
|
48
|
-
browserVersion
|
|
59
|
+
browserName,
|
|
60
|
+
browserVersion,
|
|
49
61
|
isRumActive,
|
|
50
|
-
|
|
62
|
+
testExecutionId: undefined,
|
|
63
|
+
}
|
|
64
|
+
try {
|
|
65
|
+
ciSeleniumDriverGetStartCh.publish(context)
|
|
66
|
+
} catch (error) {
|
|
67
|
+
log.error('Selenium RUM correlation channel error', error)
|
|
68
|
+
}
|
|
51
69
|
|
|
52
|
-
if (
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
70
|
+
if (context.testExecutionId && isRumActive) {
|
|
71
|
+
try {
|
|
72
|
+
await this.manage().addCookie({
|
|
73
|
+
name: DD_CIVISIBILITY_TEST_EXECUTION_ID_COOKIE_NAME,
|
|
74
|
+
value: context.testExecutionId,
|
|
75
|
+
})
|
|
76
|
+
} catch (error) {
|
|
77
|
+
log.error('Selenium RUM correlation cookie error', error)
|
|
78
|
+
}
|
|
57
79
|
}
|
|
58
80
|
|
|
59
81
|
return getResult
|
|
@@ -63,16 +85,20 @@ addHook({
|
|
|
63
85
|
if (!ciSeleniumDriverGetStartCh.hasSubscribers) {
|
|
64
86
|
return quit.apply(this, arguments)
|
|
65
87
|
}
|
|
66
|
-
|
|
88
|
+
try {
|
|
89
|
+
const isRumActive = await this.executeScript(RUM_STOP_SESSION_SCRIPT)
|
|
67
90
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
91
|
+
if (isRumActive) {
|
|
92
|
+
// We'll have time for RUM to flush the events (there's no callback to know when it's done)
|
|
93
|
+
await new Promise(resolve => {
|
|
94
|
+
realSetTimeout(() => {
|
|
95
|
+
resolve()
|
|
96
|
+
}, DD_CIVISIBILITY_RUM_FLUSH_WAIT_MILLIS)
|
|
97
|
+
})
|
|
98
|
+
await this.manage().deleteCookie(DD_CIVISIBILITY_TEST_EXECUTION_ID_COOKIE_NAME)
|
|
99
|
+
}
|
|
100
|
+
} catch (error) {
|
|
101
|
+
log.error('Selenium RUM cleanup error', error)
|
|
76
102
|
}
|
|
77
103
|
|
|
78
104
|
return quit.apply(this, arguments)
|
|
@@ -784,7 +784,7 @@ function getRepeatedTestReport (task, testName, testSuiteAbsolutePath, testPrope
|
|
|
784
784
|
|
|
785
785
|
return {
|
|
786
786
|
errors,
|
|
787
|
-
finalAttempt: attempts
|
|
787
|
+
finalAttempt: attempts.at(-1),
|
|
788
788
|
nonFinalAttempts: attempts.slice(0, -1),
|
|
789
789
|
state,
|
|
790
790
|
status,
|
|
@@ -880,7 +880,7 @@ function reportFinalTestAttempt (testReport) {
|
|
|
880
880
|
const finalAttempt = testReport.finalAttempt
|
|
881
881
|
|
|
882
882
|
if (status === 'fail') {
|
|
883
|
-
const error = errors
|
|
883
|
+
const error = errors.at(-1) || errors[0]
|
|
884
884
|
reportTestAttempt(testReport, finalAttempt || {
|
|
885
885
|
error,
|
|
886
886
|
finalStatus,
|
|
@@ -1343,10 +1343,8 @@ function wrapTinyPoolRun (TinyPool) {
|
|
|
1343
1343
|
|
|
1344
1344
|
shimmer.wrap(TinyPool.prototype, 'run', run => async function () {
|
|
1345
1345
|
// We have to do this before and after because the threads list gets recycled, that is, the processes are re-created
|
|
1346
|
-
// eslint-disable-next-line unicorn/no-array-for-each
|
|
1347
1346
|
this.threads.forEach(threadHandler)
|
|
1348
1347
|
const runResult = await run.apply(this, arguments)
|
|
1349
|
-
// eslint-disable-next-line unicorn/no-array-for-each
|
|
1350
1348
|
this.threads.forEach(threadHandler)
|
|
1351
1349
|
return runResult
|
|
1352
1350
|
})
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
const { tracingChannel } = /** @type {import('node:diagnostics_channel')} */ (require('dc-polyfill'))
|
|
4
4
|
|
|
5
5
|
const shimmer = require('../../datadog-shimmer')
|
|
6
|
+
const { getSegment } = require('../../dd-trace/src/util')
|
|
6
7
|
const {
|
|
7
8
|
addHook,
|
|
8
9
|
channel,
|
|
@@ -106,7 +107,7 @@ function createWrapEmit (emit) {
|
|
|
106
107
|
}
|
|
107
108
|
|
|
108
109
|
const ctx = { req }
|
|
109
|
-
ctx.req.resStatus = headers[0]
|
|
110
|
+
ctx.req.resStatus = getSegment(headers[0], ' ', 1)
|
|
110
111
|
|
|
111
112
|
emitCh.runStores(ctx, () => {
|
|
112
113
|
try {
|
|
@@ -94,7 +94,7 @@ class RunInChildContextPlugin extends BaseContextPlugin {
|
|
|
94
94
|
static retryable = false
|
|
95
95
|
|
|
96
96
|
bindStart (ctx) {
|
|
97
|
-
if (SUPPRESSED_CHILD_CONTEXT_SUBTYPES.has(
|
|
97
|
+
if (SUPPRESSED_CHILD_CONTEXT_SUBTYPES.has(getRunInChildContextSubtype(ctx))) {
|
|
98
98
|
// Pass the active store through unchanged so any nested spans
|
|
99
99
|
// remain parented to the surrounding map/parallel span
|
|
100
100
|
ctx.suppressed = true
|
|
@@ -105,7 +105,7 @@ class RunInChildContextPlugin extends BaseContextPlugin {
|
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
// runInChildContext has two overloads: `(name, fn, options)` and `(fn, options)`.
|
|
108
|
-
function
|
|
108
|
+
function getRunInChildContextSubtype (ctx) {
|
|
109
109
|
const args = ctx.arguments || []
|
|
110
110
|
const opts = typeof args[0] === 'function' ? args[1] : args[2]
|
|
111
111
|
return opts?.subType
|
|
@@ -16,7 +16,8 @@ const REPLAYED_STATUSES = new Set(['SUCCEEDED', 'FAILED'])
|
|
|
16
16
|
* @returns {{ stepId: string | undefined, stepData: object | undefined }}
|
|
17
17
|
*/
|
|
18
18
|
function getStepDataForNext (ctxImpl) {
|
|
19
|
-
|
|
19
|
+
// @aws/durable-execution-sdk-js@2.2.0 renames .getNextStepId() to .peekStepId()
|
|
20
|
+
const stepId = ctxImpl?.peekStepId?.() ?? ctxImpl?.getNextStepId?.()
|
|
20
21
|
const stepData = stepId ? ctxImpl?._executionContext?.getStepData?.(stepId) : undefined
|
|
21
22
|
return { stepId, stepData }
|
|
22
23
|
}
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
const { DsmPathwayCodec, getSizeOrZero } = require('../../../dd-trace/src/datastreams')
|
|
3
3
|
const log = require('../../../dd-trace/src/log')
|
|
4
4
|
const BaseAwsSdkPlugin = require('../base')
|
|
5
|
-
const { isEmpty } = require('../util')
|
|
6
5
|
|
|
7
6
|
function recordDataAsString (data) {
|
|
8
7
|
return Buffer.isBuffer(data) ? data.toString('utf8') : Buffer.from(data).toString('utf8')
|
|
@@ -13,6 +12,16 @@ function recordDataAsString (data) {
|
|
|
13
12
|
// delete on consume, so their working set is ~the active shard count.
|
|
14
13
|
const MAX_TRACKED_SHARD_ITERATORS = 1000
|
|
15
14
|
|
|
15
|
+
// The default Kinesis record limit is 1 MiB. Streams configured for larger records
|
|
16
|
+
// conservatively skip propagation above this point because the request does not expose that limit.
|
|
17
|
+
const KINESIS_DEFAULT_MAX_RECORD_BYTES = 1_048_576
|
|
18
|
+
|
|
19
|
+
// The DSM pathway field (`dd-pathway-ctx-base64`) always serializes to a fixed 55 bytes: a
|
|
20
|
+
// 21-char key, a 28-char base64 value, and 6 bytes of JSON framing. Mirrors PATHWAY_HEADER_BYTES
|
|
21
|
+
// in dd-trace/src/datastreams/processor.js. Reserved in the size gate so setDSMCheckpoint never
|
|
22
|
+
// runs for a record that would ship over the cap once the pathway context is attached.
|
|
23
|
+
const DSM_PATHWAY_FIELD_BYTES = 55
|
|
24
|
+
|
|
16
25
|
class Kinesis extends BaseAwsSdkPlugin {
|
|
17
26
|
static id = 'kinesis'
|
|
18
27
|
static peerServicePrecursors = ['streamname']
|
|
@@ -237,6 +246,12 @@ class Kinesis extends BaseAwsSdkPlugin {
|
|
|
237
246
|
}
|
|
238
247
|
}
|
|
239
248
|
|
|
249
|
+
/**
|
|
250
|
+
* @param {import('../../../dd-trace/src/opentracing/span') | null} span
|
|
251
|
+
* @param {{ Data: Buffer|string|Uint8Array, PartitionKey?: string } | undefined} params
|
|
252
|
+
* @param {string} stream
|
|
253
|
+
* @param {boolean} injectTraceContext
|
|
254
|
+
*/
|
|
240
255
|
injectToMessage (span, params, stream, injectTraceContext) {
|
|
241
256
|
if (!params) {
|
|
242
257
|
return
|
|
@@ -251,30 +266,40 @@ class Kinesis extends BaseAwsSdkPlugin {
|
|
|
251
266
|
}
|
|
252
267
|
}
|
|
253
268
|
|
|
254
|
-
|
|
269
|
+
let ddInfo
|
|
255
270
|
// For now we only inject to the first message; batches may change later.
|
|
256
271
|
if (injectTraceContext) {
|
|
257
|
-
this.tracer.inject(span, 'text_map'
|
|
272
|
+
ddInfo = this.tracer.inject(span, 'text_map')
|
|
258
273
|
}
|
|
259
274
|
|
|
260
|
-
|
|
261
|
-
|
|
275
|
+
const dsmEnabled = this.config.dsmEnabled
|
|
276
|
+
if (!ddInfo && !dsmEnabled) return
|
|
277
|
+
|
|
278
|
+
parsedData._datadog = ddInfo ?? {}
|
|
279
|
+
// Gate before setDSMCheckpoint: a record we can't ship must not record a checkpoint.
|
|
280
|
+
// Reserve the pathway field that DSM appends after the gate.
|
|
281
|
+
let serialized = JSON.stringify(parsedData)
|
|
282
|
+
const reservedBytes = dsmEnabled ? DSM_PATHWAY_FIELD_BYTES : 0
|
|
283
|
+
const partitionKeyBytes = Buffer.byteLength(params.PartitionKey ?? '', 'utf8')
|
|
284
|
+
if (
|
|
285
|
+
Buffer.byteLength(serialized, 'utf8') + partitionKeyBytes + reservedBytes >
|
|
286
|
+
KINESIS_DEFAULT_MAX_RECORD_BYTES
|
|
287
|
+
) {
|
|
288
|
+
log.info('Payload size too large to pass context')
|
|
289
|
+
return
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if (dsmEnabled) {
|
|
262
293
|
const dataStreamsContext = this.setDSMCheckpoint(span, params, stream)
|
|
263
|
-
|
|
264
|
-
|
|
294
|
+
ddInfo = DsmPathwayCodec.encode(dataStreamsContext, ddInfo) ?? ddInfo
|
|
295
|
+
if (ddInfo) {
|
|
296
|
+
parsedData._datadog = ddInfo
|
|
297
|
+
serialized = JSON.stringify(parsedData)
|
|
265
298
|
}
|
|
266
299
|
}
|
|
267
300
|
|
|
268
|
-
if (
|
|
301
|
+
if (!ddInfo) return
|
|
269
302
|
|
|
270
|
-
parsedData._datadog = ddInfo
|
|
271
|
-
const serialized = JSON.stringify(parsedData)
|
|
272
|
-
const byteSize = Buffer.byteLength(serialized, 'utf8')
|
|
273
|
-
// Kinesis max payload size is 1 MiB; bail if our context push tipped us over.
|
|
274
|
-
if (byteSize >= 1_048_576) {
|
|
275
|
-
log.info('Payload size too large to pass context')
|
|
276
|
-
return
|
|
277
|
-
}
|
|
278
303
|
params.Data = Buffer.from(serialized, 'utf8')
|
|
279
304
|
}
|
|
280
305
|
|