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,11 +8,6 @@ const { pathToFileURL, fileURLToPath } = require('node:url')
|
|
|
8
8
|
const instrumentations = require('../datadog-instrumentations/src/helpers/instrumentations')
|
|
9
9
|
const extractPackageAndModulePath = require('../datadog-instrumentations/src/helpers/extract-package-and-module-path')
|
|
10
10
|
const hooks = require('../datadog-instrumentations/src/helpers/hooks')
|
|
11
|
-
const {
|
|
12
|
-
OPTIONAL_PEER_FILTER,
|
|
13
|
-
matchesOptionalPeerFile,
|
|
14
|
-
rewriteOptionalPeerLoads,
|
|
15
|
-
} = require('../datadog-instrumentations/src/helpers/optional-peer-bundler')
|
|
16
11
|
const { processModule, isESMFile } = require('./src/utils')
|
|
17
12
|
const log = require('./src/log')
|
|
18
13
|
|
|
@@ -133,19 +128,6 @@ module.exports.setup = function (build) {
|
|
|
133
128
|
${build.initialOptions.banner.js}`
|
|
134
129
|
}
|
|
135
130
|
|
|
136
|
-
// Keep the build from failing on the optional `@openfeature/core` peer of
|
|
137
|
-
// `@openfeature/server-sdk` when it is not installed (#8635). esbuild follows the chain
|
|
138
|
-
// whenever `@openfeature/server-sdk` is reachable -- the app importing it directly, or the
|
|
139
|
-
// bundled provider when the optional peer is present -- so mark `@openfeature/core` external
|
|
140
|
-
// when it is absent rather than erroring at bundle time.
|
|
141
|
-
try {
|
|
142
|
-
// eslint-disable-next-line n/no-unpublished-require
|
|
143
|
-
require.resolve('@openfeature/core')
|
|
144
|
-
} catch {
|
|
145
|
-
build.initialOptions.external ??= []
|
|
146
|
-
build.initialOptions.external.push('@openfeature/core')
|
|
147
|
-
}
|
|
148
|
-
|
|
149
131
|
const esmBuild = isESMBuild(build)
|
|
150
132
|
if (
|
|
151
133
|
esmBuild &&
|
|
@@ -182,22 +164,6 @@ ${build.initialOptions.banner.js}`
|
|
|
182
164
|
log.warn('No git metadata available - skipping injection')
|
|
183
165
|
}
|
|
184
166
|
|
|
185
|
-
// Rewrite optional-peer loads so installed peers get bundled and survive the bundle being
|
|
186
|
-
// relocated without them on disk (#8980). Registered before the generic onLoad so it wins for
|
|
187
|
-
// these files. Absent peers stay opaque, so a build that does not opt into the feature does not
|
|
188
|
-
// follow their dependency chain (#8635).
|
|
189
|
-
build.onLoad({ filter: OPTIONAL_PEER_FILTER }, args => {
|
|
190
|
-
const normalizedPath = args.path.replaceAll('\\', '/')
|
|
191
|
-
if (!matchesOptionalPeerFile(normalizedPath)) return
|
|
192
|
-
|
|
193
|
-
log.debug('INLINE: optional-peer loader applied to %s', normalizedPath)
|
|
194
|
-
return {
|
|
195
|
-
contents: rewriteOptionalPeerLoads(fs.readFileSync(args.path, 'utf8'), path.dirname(args.path)),
|
|
196
|
-
loader: 'js',
|
|
197
|
-
resolveDir: path.dirname(args.path),
|
|
198
|
-
}
|
|
199
|
-
})
|
|
200
|
-
|
|
201
167
|
// first time is intercepted, proxy should be created, next time the original should be loaded
|
|
202
168
|
const interceptedESMModules = new Set()
|
|
203
169
|
|
|
@@ -6,6 +6,144 @@ const { addHook } = require('./helpers/instrument')
|
|
|
6
6
|
|
|
7
7
|
const anthropicTracingChannel = tracingChannel('apm:anthropic:request')
|
|
8
8
|
const onStreamedChunkCh = channel('apm:anthropic:request:chunk')
|
|
9
|
+
const messagesBeforeChannel = channel('dd-trace:anthropic:messages:before')
|
|
10
|
+
const messagesAfterChannel = channel('dd-trace:anthropic:messages:after')
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Publishes a provider-native lifecycle payload to a cancelable lifecycle channel.
|
|
14
|
+
*
|
|
15
|
+
* Subscribers push async work into `pending` synchronously during publication and
|
|
16
|
+
* abort `abortController` with an error before the pushed promise resolves to block.
|
|
17
|
+
*
|
|
18
|
+
* @param {object} channel
|
|
19
|
+
* @param {object} payload
|
|
20
|
+
* @returns {Promise<void>}
|
|
21
|
+
*/
|
|
22
|
+
function publishLifecycle (channel, payload) {
|
|
23
|
+
const abortController = new AbortController()
|
|
24
|
+
const ctx = { ...payload, abortController, pending: [] }
|
|
25
|
+
|
|
26
|
+
channel.publish(ctx)
|
|
27
|
+
|
|
28
|
+
return Promise.all(ctx.pending).then(() => {
|
|
29
|
+
if (abortController.signal.aborted) {
|
|
30
|
+
throw abortController.signal.reason
|
|
31
|
+
}
|
|
32
|
+
})
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @template T
|
|
37
|
+
* @param {Promise<T>} promise
|
|
38
|
+
* @param {Promise<void>|undefined} verdict
|
|
39
|
+
* @returns {Promise<T>}
|
|
40
|
+
*/
|
|
41
|
+
function waitForVerdict (promise, verdict) {
|
|
42
|
+
if (!verdict) return promise
|
|
43
|
+
|
|
44
|
+
// The lifecycle verdict takes precedence over an earlier SDK rejection.
|
|
45
|
+
promise.catch(() => {})
|
|
46
|
+
return verdict.then(() => promise)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @param {Array<unknown>} args
|
|
51
|
+
* @returns {Array<unknown>|undefined}
|
|
52
|
+
*/
|
|
53
|
+
function snapshotLifecycleArgs (args) {
|
|
54
|
+
const options = args[0]
|
|
55
|
+
if (!options || typeof options !== 'object') return
|
|
56
|
+
|
|
57
|
+
const input = { messages: options.messages }
|
|
58
|
+
if (options.system !== undefined) input.system = options.system
|
|
59
|
+
|
|
60
|
+
// Snapshot via JSON so AI Guard evaluates exactly what the SDK serializes and sends, immune to
|
|
61
|
+
// later caller mutation. If it can't serialize (e.g. circular), the SDK's own serialization would
|
|
62
|
+
// fail too, so skipping evaluation is safe — nothing reaches the model.
|
|
63
|
+
try {
|
|
64
|
+
const snapshot = [...args]
|
|
65
|
+
// eslint-disable-next-line unicorn/prefer-structured-clone
|
|
66
|
+
snapshot[0] = { ...options, ...JSON.parse(JSON.stringify(input)) }
|
|
67
|
+
return snapshot
|
|
68
|
+
} catch {
|
|
69
|
+
// Unserializable input — leave AI Guard inactive for this call (the SDK send would fail too).
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Finishes after output evaluation so a block propagates to the caller and span.
|
|
75
|
+
*
|
|
76
|
+
* @param {object} ctx
|
|
77
|
+
* @param {object} result
|
|
78
|
+
* @param {(body: object) => Promise<void>|undefined} getVerdict
|
|
79
|
+
* @param {object|string} [returnedResult]
|
|
80
|
+
* @returns {object|string|Promise<object|string>}
|
|
81
|
+
*/
|
|
82
|
+
function finishResult (ctx, result, getVerdict, returnedResult = result) {
|
|
83
|
+
const verdict = getVerdict(result)
|
|
84
|
+
if (!verdict) {
|
|
85
|
+
finish(ctx, result)
|
|
86
|
+
return returnedResult
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return verdict.then(() => {
|
|
90
|
+
finish(ctx, result)
|
|
91
|
+
return returnedResult
|
|
92
|
+
})
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* @param {object} ctx
|
|
97
|
+
* @param {Error} error
|
|
98
|
+
* @throws {Error} Always rethrows the supplied error.
|
|
99
|
+
*/
|
|
100
|
+
function finishAndThrow (ctx, error) {
|
|
101
|
+
finish(ctx, null, error)
|
|
102
|
+
throw error
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* @param {object} response
|
|
107
|
+
* @param {'json'|'text'} method
|
|
108
|
+
* @param {object} ctx
|
|
109
|
+
* @param {(body: object) => Promise<void>|undefined} getVerdict
|
|
110
|
+
*/
|
|
111
|
+
function wrapResponseReader (response, method, ctx, getVerdict) {
|
|
112
|
+
if (typeof response[method] !== 'function') return
|
|
113
|
+
|
|
114
|
+
shimmer.wrap(response, method, original => function (...args) {
|
|
115
|
+
return original.apply(this, args)
|
|
116
|
+
.then(body => {
|
|
117
|
+
if (method === 'json') return finishResult(ctx, body, getVerdict)
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
return finishResult(ctx, JSON.parse(body), getVerdict, body)
|
|
121
|
+
} catch {
|
|
122
|
+
finish(ctx)
|
|
123
|
+
return body
|
|
124
|
+
}
|
|
125
|
+
})
|
|
126
|
+
.catch(error => finishAndThrow(ctx, error))
|
|
127
|
+
})
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* @param {object} response
|
|
132
|
+
* @param {object} ctx
|
|
133
|
+
* @param {(body: object) => Promise<void>|undefined} getVerdict
|
|
134
|
+
*/
|
|
135
|
+
function wrapRawResponse (response, ctx, getVerdict) {
|
|
136
|
+
wrapResponseReader(response, 'json', ctx, getVerdict)
|
|
137
|
+
wrapResponseReader(response, 'text', ctx, getVerdict)
|
|
138
|
+
|
|
139
|
+
if (typeof response.clone !== 'function') return
|
|
140
|
+
|
|
141
|
+
shimmer.wrap(response, 'clone', clone => function (...args) {
|
|
142
|
+
const clonedResponse = clone.apply(this, args)
|
|
143
|
+
wrapRawResponse(clonedResponse, ctx, getVerdict)
|
|
144
|
+
return clonedResponse
|
|
145
|
+
})
|
|
146
|
+
}
|
|
9
147
|
|
|
10
148
|
function wrapStreamIterator (iterator, ctx) {
|
|
11
149
|
return function (...args) {
|
|
@@ -34,40 +172,94 @@ function wrapStreamIterator (iterator, ctx) {
|
|
|
34
172
|
|
|
35
173
|
function wrapCreate (create) {
|
|
36
174
|
return function (...args) {
|
|
37
|
-
|
|
175
|
+
const options = args[0]
|
|
176
|
+
const stream = options?.stream
|
|
177
|
+
|
|
178
|
+
// Streaming is out of scope for lifecycle evaluation.
|
|
179
|
+
const lifecycleArgs = !stream &&
|
|
180
|
+
(messagesBeforeChannel.hasSubscribers || messagesAfterChannel.hasSubscribers)
|
|
181
|
+
? snapshotLifecycleArgs(args)
|
|
182
|
+
: undefined
|
|
183
|
+
|
|
184
|
+
if (!anthropicTracingChannel.start.hasSubscribers && !lifecycleArgs) {
|
|
38
185
|
return create.apply(this, args)
|
|
39
186
|
}
|
|
40
187
|
|
|
41
|
-
const
|
|
42
|
-
const stream = options.stream
|
|
43
|
-
|
|
44
|
-
const ctx = { options, resource: 'create', baseUrl: this._client?.baseURL }
|
|
188
|
+
const ctx = { options: lifecycleArgs?.[0] ?? options, resource: 'create', baseUrl: this._client?.baseURL }
|
|
45
189
|
|
|
46
190
|
return anthropicTracingChannel.start.runStores(ctx, () => {
|
|
191
|
+
const parentSpan = lifecycleArgs ? ctx.currentStore?.span : undefined
|
|
192
|
+
|
|
47
193
|
let apiPromise
|
|
48
194
|
try {
|
|
49
|
-
|
|
195
|
+
// Anthropic starts the request eagerly; the input verdict only gates result delivery.
|
|
196
|
+
apiPromise = create.apply(this, lifecycleArgs ?? args)
|
|
50
197
|
} catch (error) {
|
|
51
198
|
finish(ctx, null, error)
|
|
52
199
|
throw error
|
|
53
200
|
}
|
|
54
201
|
|
|
55
|
-
|
|
56
|
-
|
|
202
|
+
let beforeVerdict
|
|
203
|
+
let afterVerdict
|
|
204
|
+
let parseResult
|
|
205
|
+
let wrappedResponse
|
|
206
|
+
|
|
207
|
+
function getBeforeVerdict () {
|
|
208
|
+
if (!lifecycleArgs || beforeVerdict) return beforeVerdict
|
|
209
|
+
if (!messagesBeforeChannel.hasSubscribers) return
|
|
210
|
+
|
|
211
|
+
beforeVerdict = publishLifecycle(messagesBeforeChannel, { args: lifecycleArgs, parentSpan })
|
|
212
|
+
return beforeVerdict
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* @param {object|string} body
|
|
217
|
+
*/
|
|
218
|
+
function getAfterVerdict (body) {
|
|
219
|
+
if (!lifecycleArgs || afterVerdict) return afterVerdict
|
|
220
|
+
if (!messagesAfterChannel.hasSubscribers) return
|
|
221
|
+
|
|
222
|
+
afterVerdict = publishLifecycle(messagesAfterChannel, { args: lifecycleArgs, body, parentSpan })
|
|
223
|
+
return afterVerdict
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
shimmer.wrap(apiPromise, 'parse', parse => function (...parseArgs) {
|
|
227
|
+
if (parseResult) return parseResult
|
|
228
|
+
|
|
229
|
+
const parsed = parse.apply(this, parseArgs)
|
|
230
|
+
parseResult = waitForVerdict(parsed, getBeforeVerdict())
|
|
57
231
|
.then(response => {
|
|
58
232
|
if (stream) {
|
|
59
233
|
shimmer.wrap(response, Symbol.asyncIterator, iterator => wrapStreamIterator(iterator, ctx))
|
|
60
|
-
|
|
61
|
-
finish(ctx, response, null)
|
|
234
|
+
return response
|
|
62
235
|
}
|
|
63
|
-
|
|
64
|
-
return response
|
|
65
|
-
}).catch(error => {
|
|
66
|
-
finish(ctx, null, error)
|
|
67
|
-
throw error
|
|
236
|
+
return finishResult(ctx, response, getAfterVerdict)
|
|
68
237
|
})
|
|
238
|
+
.catch(error => finishAndThrow(ctx, error))
|
|
239
|
+
|
|
240
|
+
return parseResult
|
|
69
241
|
})
|
|
70
242
|
|
|
243
|
+
if (typeof apiPromise.asResponse === 'function') {
|
|
244
|
+
shimmer.wrap(apiPromise, 'asResponse', origAsResponse => function (...asResponseArgs) {
|
|
245
|
+
return waitForVerdict(origAsResponse.apply(this, asResponseArgs), getBeforeVerdict())
|
|
246
|
+
.then(response => {
|
|
247
|
+
// Wrap the raw response's json()/text()/clone() readers to evaluate output on read,
|
|
248
|
+
// but only while someone still consumes the result and not twice for the same response.
|
|
249
|
+
const outputObserved = anthropicTracingChannel.start.hasSubscribers ||
|
|
250
|
+
afterVerdict || messagesAfterChannel.hasSubscribers
|
|
251
|
+
if (!stream && outputObserved && wrappedResponse !== response) {
|
|
252
|
+
wrappedResponse = response
|
|
253
|
+
wrapRawResponse(response, ctx, getAfterVerdict)
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if (afterVerdict) return afterVerdict.then(() => response)
|
|
257
|
+
return response
|
|
258
|
+
})
|
|
259
|
+
.catch(error => finishAndThrow(ctx, error))
|
|
260
|
+
})
|
|
261
|
+
}
|
|
262
|
+
|
|
71
263
|
anthropicTracingChannel.end.publish(ctx)
|
|
72
264
|
|
|
73
265
|
return apiPromise
|
|
@@ -76,6 +268,8 @@ function wrapCreate (create) {
|
|
|
76
268
|
}
|
|
77
269
|
|
|
78
270
|
function finish (ctx, result, error) {
|
|
271
|
+
if (ctx.finished) return
|
|
272
|
+
|
|
79
273
|
if (error) {
|
|
80
274
|
ctx.error = error
|
|
81
275
|
anthropicTracingChannel.error.publish(ctx)
|
|
@@ -83,6 +277,7 @@ function finish (ctx, result, error) {
|
|
|
83
277
|
|
|
84
278
|
// streamed responses are handled and set separately
|
|
85
279
|
ctx.result ??= result
|
|
280
|
+
ctx.finished = true
|
|
86
281
|
|
|
87
282
|
anthropicTracingChannel.asyncEnd.publish(ctx)
|
|
88
283
|
}
|
|
@@ -25,6 +25,13 @@ const KNOWN_CHANNEL_SUFFIXES = new Set([
|
|
|
25
25
|
'bedrockruntime',
|
|
26
26
|
])
|
|
27
27
|
|
|
28
|
+
// Older SDK clients report EventBridge under its CloudWatch Events name or its `events` endpoint
|
|
29
|
+
// prefix; both share the EventBridge channels.
|
|
30
|
+
const CHANNEL_SUFFIX_ALIASES = new Map([
|
|
31
|
+
['cloudwatchevents', 'eventbridge'],
|
|
32
|
+
['events', 'eventbridge'],
|
|
33
|
+
])
|
|
34
|
+
|
|
28
35
|
/**
|
|
29
36
|
* @typedef {object} ChannelBag
|
|
30
37
|
* @property {ReturnType<typeof channel>} start
|
|
@@ -314,7 +321,8 @@ function addResponse (ctx, error, result) {
|
|
|
314
321
|
function getChannelSuffix (name) {
|
|
315
322
|
// some resource identifiers have spaces between ex: bedrock runtime
|
|
316
323
|
name = String(name).replaceAll(' ', '')
|
|
317
|
-
|
|
324
|
+
if (KNOWN_CHANNEL_SUFFIXES.has(name)) return name
|
|
325
|
+
return CHANNEL_SUFFIX_ALIASES.get(name) ?? 'default'
|
|
318
326
|
}
|
|
319
327
|
|
|
320
328
|
addHook({ name: '@smithy/smithy-client', versions: ['>=1.0.3'] }, smithy => {
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const wrapLogger = require('./helpers/bunyan')
|
|
4
|
+
const { addHook } = require('./helpers/instrument')
|
|
5
|
+
|
|
6
|
+
addHook({ name: 'browser-bunyan', versions: ['>=1'] }, browserBunyan => {
|
|
7
|
+
// Published versions generate `_emit` through different bundle shapes,
|
|
8
|
+
// so Orchestrion has no stable function to match.
|
|
9
|
+
wrapLogger(browserBunyan.Logger, 'browser-bunyan')
|
|
10
|
+
return browserBunyan
|
|
11
|
+
})
|
|
@@ -1,22 +1,9 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const {
|
|
5
|
-
channel,
|
|
6
|
-
addHook,
|
|
7
|
-
} = require('./helpers/instrument')
|
|
3
|
+
const wrapLogger = require('./helpers/bunyan')
|
|
4
|
+
const { addHook } = require('./helpers/instrument')
|
|
8
5
|
|
|
9
6
|
addHook({ name: 'bunyan', versions: ['>=1'] }, Logger => {
|
|
10
|
-
|
|
11
|
-
shimmer.wrap(Logger.prototype, '_emit', emit => {
|
|
12
|
-
return function wrappedEmit (rec) {
|
|
13
|
-
if (logCh.hasSubscribers) {
|
|
14
|
-
const payload = { message: rec }
|
|
15
|
-
logCh.publish(payload)
|
|
16
|
-
arguments[0] = payload.message
|
|
17
|
-
}
|
|
18
|
-
return emit.apply(this, arguments)
|
|
19
|
-
}
|
|
20
|
-
})
|
|
7
|
+
wrapLogger(Logger, 'bunyan')
|
|
21
8
|
return Logger
|
|
22
9
|
})
|
|
@@ -29,6 +29,17 @@ const channels = {
|
|
|
29
29
|
|
|
30
30
|
const disabledHeaderWeakSet = new WeakSet()
|
|
31
31
|
|
|
32
|
+
const EMPTY_CARRIER = Object.create(null)
|
|
33
|
+
/** @type {string[]} */
|
|
34
|
+
const NO_MERGEABLE_KEYS = []
|
|
35
|
+
|
|
36
|
+
/** @typedef {string | Buffer} NativeHeaderValue */
|
|
37
|
+
/** @typedef {Array<Record<string, NativeHeaderValue>>} NativeHeaders */
|
|
38
|
+
/** @typedef {Record<string, NativeHeaderValue | NativeHeaderValue[]>} NativeHeaderCarrier */
|
|
39
|
+
|
|
40
|
+
/** @type {NativeHeaders} */
|
|
41
|
+
const EMPTY_NATIVE_HEADERS = []
|
|
42
|
+
|
|
32
43
|
// we need to store the offset per partition per topic for the consumer to track offsets for DSM
|
|
33
44
|
const latestConsumerOffsets = new Map()
|
|
34
45
|
|
|
@@ -60,17 +71,47 @@ function instrumentBaseModule (module) {
|
|
|
60
71
|
}
|
|
61
72
|
|
|
62
73
|
const brokers = this.globalConfig?.['bootstrap.servers']
|
|
74
|
+
const nativeHeaders = Array.isArray(headers) ? headers : EMPTY_NATIVE_HEADERS
|
|
75
|
+
|
|
76
|
+
let carrier
|
|
77
|
+
let forwardCallerHeaders = false
|
|
78
|
+
let applicationValues = EMPTY_CARRIER
|
|
79
|
+
let headerKeys = NO_MERGEABLE_KEYS
|
|
80
|
+
if (nativeHeaders.length !== 0) {
|
|
81
|
+
// `__proto__` is a legal Kafka header key and propagation never
|
|
82
|
+
// writes it, so only the seeded carrier needs a null prototype.
|
|
83
|
+
const candidateCarrier = Object.create(null)
|
|
84
|
+
const candidateValues = Object.create(null)
|
|
85
|
+
const candidateKeys = seedNativeHeaderCarrier(nativeHeaders, candidateCarrier, candidateValues)
|
|
86
|
+
if (candidateKeys === undefined) {
|
|
87
|
+
forwardCallerHeaders = true
|
|
88
|
+
} else if (candidateKeys.length !== 0) {
|
|
89
|
+
carrier = candidateCarrier
|
|
90
|
+
applicationValues = candidateValues
|
|
91
|
+
headerKeys = candidateKeys
|
|
92
|
+
}
|
|
93
|
+
}
|
|
63
94
|
|
|
64
95
|
const ctx = {
|
|
65
96
|
topic,
|
|
66
|
-
messages: [{
|
|
97
|
+
messages: [{
|
|
98
|
+
key,
|
|
99
|
+
value: message,
|
|
100
|
+
headers: carrier,
|
|
101
|
+
}],
|
|
67
102
|
bootstrapServers: brokers,
|
|
68
103
|
}
|
|
69
104
|
|
|
70
105
|
return channels.producerStart.runStores(ctx, () => {
|
|
71
106
|
try {
|
|
72
|
-
const
|
|
73
|
-
|
|
107
|
+
const producedHeaders = forwardCallerHeaders
|
|
108
|
+
? nativeHeaders
|
|
109
|
+
: mergeNativeHeaders(
|
|
110
|
+
nativeHeaders, headerKeys, applicationValues, ctx.messages[0].headers ?? EMPTY_CARRIER
|
|
111
|
+
)
|
|
112
|
+
const result = produce.apply(this, [
|
|
113
|
+
topic, partition, message, key, timestamp, opaque, producedHeaders,
|
|
114
|
+
])
|
|
74
115
|
|
|
75
116
|
ctx.result = result
|
|
76
117
|
channels.producerCommit.publish(ctx)
|
|
@@ -432,7 +473,71 @@ function getLatestOffsets () {
|
|
|
432
473
|
return [...latestConsumerOffsets.values()]
|
|
433
474
|
}
|
|
434
475
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
476
|
+
/**
|
|
477
|
+
* `Producer::NodeProduce` reads the first *enumerable* own key of each entry and
|
|
478
|
+
* validates the value itself. A `null` or `undefined` entry aborts the process
|
|
479
|
+
* there, so those are the only entries we refuse to hand back to it.
|
|
480
|
+
*
|
|
481
|
+
* @param {NativeHeaders} headers Caller-owned.
|
|
482
|
+
* @param {NativeHeaderCarrier} carrier
|
|
483
|
+
* @param {NativeHeaderCarrier} applicationValues
|
|
484
|
+
* @returns {string[] | undefined} `undefined` when the binding has to reject the
|
|
485
|
+
* array itself; empty when it cannot consume the array at all.
|
|
486
|
+
* @see https://github.com/confluentinc/confluent-kafka-javascript/blob/v1.9.1/src/producer.cc
|
|
487
|
+
*/
|
|
488
|
+
function seedNativeHeaderCarrier (headers, carrier, applicationValues) {
|
|
489
|
+
const keys = new Array(headers.length)
|
|
490
|
+
for (let i = 0; i < headers.length; i++) {
|
|
491
|
+
const header = headers[i]
|
|
492
|
+
if (header === null || header === undefined) return NO_MERGEABLE_KEYS
|
|
493
|
+
|
|
494
|
+
const key = Object.keys(header)[0]
|
|
495
|
+
if (key === undefined) return
|
|
496
|
+
|
|
497
|
+
keys[i] = key
|
|
498
|
+
const value = header[key]
|
|
499
|
+
if (typeof value !== 'string' && !Buffer.isBuffer(value)) return
|
|
500
|
+
|
|
501
|
+
if (i === 0) {
|
|
502
|
+
carrier[key] = value
|
|
503
|
+
applicationValues[key] = value
|
|
504
|
+
continue
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
const previousValue = carrier[key]
|
|
508
|
+
if (previousValue === undefined) {
|
|
509
|
+
carrier[key] = value
|
|
510
|
+
} else if (Array.isArray(previousValue)) {
|
|
511
|
+
previousValue.push(value)
|
|
512
|
+
} else {
|
|
513
|
+
carrier[key] = [previousValue, value]
|
|
514
|
+
}
|
|
515
|
+
applicationValues[key] = carrier[key]
|
|
516
|
+
}
|
|
517
|
+
return keys
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* @param {NativeHeaders} headers Caller-owned; surviving entries are forwarded
|
|
522
|
+
* by reference, never copied or mutated.
|
|
523
|
+
* @param {string[]} headerKeys Parallel to `headers`.
|
|
524
|
+
* @param {NativeHeaderCarrier} applicationValues Carrier contents before
|
|
525
|
+
* propagation ran.
|
|
526
|
+
* @param {NativeHeaderCarrier} carrier
|
|
527
|
+
*/
|
|
528
|
+
function mergeNativeHeaders (headers, headerKeys, applicationValues, carrier) {
|
|
529
|
+
const merged = []
|
|
530
|
+
for (let i = 0; i < headerKeys.length; i++) {
|
|
531
|
+
const key = headerKeys[i]
|
|
532
|
+
if (carrier[key] === applicationValues[key]) {
|
|
533
|
+
merged.push(headers[i])
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
for (const key of Object.keys(carrier)) {
|
|
538
|
+
if (carrier[key] !== applicationValues[key]) {
|
|
539
|
+
merged.push({ [key]: carrier[key] })
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
return merged
|
|
438
543
|
}
|
|
@@ -116,7 +116,7 @@ let pickleByFile = {}
|
|
|
116
116
|
const pickleResultByFile = {}
|
|
117
117
|
|
|
118
118
|
let skippableSuites = []
|
|
119
|
-
let skippableSuitesCoverage
|
|
119
|
+
let skippableSuitesCoverage
|
|
120
120
|
let skippedSuitesCoverage = {}
|
|
121
121
|
let itrCorrelationId = ''
|
|
122
122
|
let isForcedToRun = false
|
|
@@ -153,12 +153,6 @@ function isValidKnownTests (receivedKnownTests) {
|
|
|
153
153
|
return !!receivedKnownTests.cucumber
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
-
function hasSkippableSuitesCoverage () {
|
|
157
|
-
return skippableSuitesCoverage &&
|
|
158
|
-
typeof skippableSuitesCoverage === 'object' &&
|
|
159
|
-
Object.keys(skippableSuitesCoverage).length > 0
|
|
160
|
-
}
|
|
161
|
-
|
|
162
156
|
function isTiaCoverageBackfillEnabled () {
|
|
163
157
|
return isItrEnabled && isCoverageReportUploadEnabled
|
|
164
158
|
}
|
|
@@ -172,7 +166,7 @@ function shouldReportCodeCoverageLinesPct (hasBackfilledCoverage) {
|
|
|
172
166
|
}
|
|
173
167
|
|
|
174
168
|
function getSkippedSuitesCoverageForRun () {
|
|
175
|
-
return isSuitesSkipped && isTiaCoverageBackfillEnabled() &&
|
|
169
|
+
return isSuitesSkipped && isTiaCoverageBackfillEnabled() && skippableSuitesCoverage !== undefined
|
|
176
170
|
? skippableSuitesCoverage
|
|
177
171
|
: {}
|
|
178
172
|
}
|
|
@@ -188,7 +182,7 @@ function getCucumberTestSessionCoverageFiles () {
|
|
|
188
182
|
|
|
189
183
|
function resetSuiteSkippingRunState () {
|
|
190
184
|
skippableSuites = []
|
|
191
|
-
skippableSuitesCoverage =
|
|
185
|
+
skippableSuitesCoverage = undefined
|
|
192
186
|
skippedSuitesCoverage = {}
|
|
193
187
|
skippedSuites = []
|
|
194
188
|
isSuitesSkipped = false
|
|
@@ -1143,7 +1137,7 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
|
|
|
1143
1137
|
|
|
1144
1138
|
errorSkippableRequest = skippableResponse.err
|
|
1145
1139
|
skippableSuites = skippableResponse.skippableSuites ?? []
|
|
1146
|
-
skippableSuitesCoverage = skippableResponse.skippableSuitesCoverage
|
|
1140
|
+
skippableSuitesCoverage = skippableResponse.skippableSuitesCoverage
|
|
1147
1141
|
|
|
1148
1142
|
if (!errorSkippableRequest) {
|
|
1149
1143
|
const filteredPickles = isCoordinator
|
|
@@ -1222,7 +1216,28 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
|
|
|
1222
1216
|
itrSkippedSuitesCh.publish({ skippedSuites, frameworkVersion })
|
|
1223
1217
|
}
|
|
1224
1218
|
|
|
1225
|
-
|
|
1219
|
+
let result
|
|
1220
|
+
try {
|
|
1221
|
+
result = await start.apply(this, arguments)
|
|
1222
|
+
} catch (error) {
|
|
1223
|
+
try {
|
|
1224
|
+
await getChannelPromise(sessionFinishCh, {
|
|
1225
|
+
status: 'fail',
|
|
1226
|
+
error,
|
|
1227
|
+
isSuitesSkipped,
|
|
1228
|
+
numSkippedSuites: skippedSuites.length,
|
|
1229
|
+
hasUnskippableSuites: isUnskippable,
|
|
1230
|
+
hasForcedToRunSuites: isForcedToRun,
|
|
1231
|
+
isEarlyFlakeDetectionEnabled,
|
|
1232
|
+
isEarlyFlakeDetectionFaulty,
|
|
1233
|
+
isTestManagementTestsEnabled,
|
|
1234
|
+
isParallel,
|
|
1235
|
+
})
|
|
1236
|
+
} catch (finalizationError) {
|
|
1237
|
+
log.error('Cucumber test session finalization error: %s', finalizationError)
|
|
1238
|
+
}
|
|
1239
|
+
throw error
|
|
1240
|
+
}
|
|
1226
1241
|
const success = satisfies(frameworkVersion, '>=13.1.0') ? result.success : result
|
|
1227
1242
|
|
|
1228
1243
|
let untestedCoverage
|