dd-trace 6.0.0 → 6.1.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/LICENSE-3rdparty.csv +1 -2
- package/index.d.ts +21 -1
- package/package.json +32 -29
- package/packages/datadog-instrumentations/src/ai.js +45 -0
- package/packages/datadog-instrumentations/src/apollo-server.js +5 -13
- package/packages/datadog-instrumentations/src/child_process.js +3 -3
- package/packages/datadog-instrumentations/src/claude-agent-sdk.js +587 -0
- package/packages/datadog-instrumentations/src/cucumber.js +102 -43
- package/packages/datadog-instrumentations/src/cypress-config.js +11 -3
- package/packages/datadog-instrumentations/src/fastify.js +27 -8
- package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/instrument.js +7 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/ai.js +6 -6
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/claude-agent-sdk.js +17 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
- package/packages/datadog-instrumentations/src/jest.js +713 -63
- package/packages/datadog-instrumentations/src/mocha/main.js +24 -3
- package/packages/datadog-instrumentations/src/mocha/utils.js +128 -22
- package/packages/datadog-instrumentations/src/mocha/worker.js +13 -0
- package/packages/datadog-instrumentations/src/mongodb.js +74 -0
- package/packages/datadog-instrumentations/src/mongoose.js +4 -5
- package/packages/datadog-instrumentations/src/playwright.js +13 -9
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +4 -0
- package/packages/datadog-instrumentations/src/vitest-main.js +28 -1
- package/packages/datadog-instrumentations/src/vitest-util.js +5 -0
- package/packages/datadog-instrumentations/src/vitest-worker.js +104 -34
- package/packages/datadog-plugin-ai/src/index.js +1 -1
- package/packages/datadog-plugin-ai/src/tracing.js +66 -3
- package/packages/datadog-plugin-ai/src/utils.js +17 -4
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/context.js +1 -0
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/handler.js +1 -0
- package/packages/datadog-plugin-child_process/src/index.js +13 -2
- package/packages/datadog-plugin-claude-agent-sdk/src/index.js +31 -0
- package/packages/datadog-plugin-claude-agent-sdk/src/tracing.js +107 -0
- package/packages/datadog-plugin-claude-agent-sdk/src/util.js +15 -0
- package/packages/datadog-plugin-cucumber/src/index.js +14 -23
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +351 -11
- package/packages/datadog-plugin-cypress/src/index.js +47 -2
- package/packages/datadog-plugin-cypress/src/plugin.js +1 -0
- package/packages/datadog-plugin-graphql/src/execute.js +21 -10
- package/packages/datadog-plugin-graphql/src/index.js +17 -1
- package/packages/datadog-plugin-graphql/src/utils.js +9 -2
- package/packages/datadog-plugin-graphql/src/validate.js +1 -1
- package/packages/datadog-plugin-jest/src/index.js +30 -14
- package/packages/datadog-plugin-mocha/src/index.js +39 -14
- package/packages/datadog-plugin-mongodb-core/src/bulk-write.js +43 -0
- package/packages/datadog-plugin-mongodb-core/src/index.js +8 -443
- package/packages/datadog-plugin-mongodb-core/src/query.js +452 -0
- package/packages/datadog-plugin-playwright/src/index.js +3 -2
- package/packages/datadog-plugin-vitest/src/index.js +51 -9
- package/packages/dd-trace/src/aiguard/index.js +9 -14
- package/packages/dd-trace/src/aiguard/integrations/index.js +34 -0
- package/packages/dd-trace/src/aiguard/integrations/openai.js +47 -33
- package/packages/dd-trace/src/aiguard/integrations/vercel-ai.js +42 -28
- package/packages/dd-trace/src/appsec/graphql.js +9 -6
- package/packages/dd-trace/src/appsec/iast/analyzers/nosql-injection-mongodb-analyzer.js +3 -10
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +26 -1
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +115 -24
- package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +3 -0
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +3 -0
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +75 -7
- package/packages/dd-trace/src/ci-visibility/requests/upload-test-screenshot.js +156 -0
- package/packages/dd-trace/src/config/generated-config-types.d.ts +10 -0
- package/packages/dd-trace/src/config/supported-configurations.json +37 -0
- package/packages/dd-trace/src/crashtracking/crashtracker.js +2 -2
- package/packages/dd-trace/src/llmobs/plugins/ai/ddTelemetry.js +403 -0
- package/packages/dd-trace/src/llmobs/plugins/ai/index.js +8 -395
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +27 -0
- package/packages/dd-trace/src/llmobs/plugins/ai/vercelTelemetry.js +363 -0
- package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/index.js +270 -0
- package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/utils.js +10 -0
- package/packages/dd-trace/src/opentelemetry/span.js +5 -0
- package/packages/dd-trace/src/plugin_manager.js +16 -0
- package/packages/dd-trace/src/plugins/ci_plugin.js +147 -7
- package/packages/dd-trace/src/plugins/index.js +2 -0
- package/packages/dd-trace/src/plugins/util/test.js +4 -0
- package/packages/dd-trace/src/profiling/exporters/agent.js +28 -3
|
@@ -84,6 +84,7 @@ const numAttemptToCtx = new Map()
|
|
|
84
84
|
const newTestsByTestFullname = new Map()
|
|
85
85
|
const attemptToFixTestsByTestFullname = new Map()
|
|
86
86
|
const modifiedTestsByPickleId = new Map()
|
|
87
|
+
const runnerToRetryState = new WeakMap()
|
|
87
88
|
// Pickle IDs for tests that are genuinely new (not in known tests list).
|
|
88
89
|
const newTestPickleIds = new Set()
|
|
89
90
|
const attemptToFixExecutions = new Map()
|
|
@@ -662,18 +663,97 @@ function getFinalStatus ({
|
|
|
662
663
|
}
|
|
663
664
|
}
|
|
664
665
|
|
|
666
|
+
async function handleRetriedAttempt (runner, state) {
|
|
667
|
+
const { promises } = state
|
|
668
|
+
if (promises.hitBreakpointPromise) {
|
|
669
|
+
await promises.hitBreakpointPromise
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
const setProbePromise = publishRetriedAttempt(runner, state)
|
|
673
|
+
if (setProbePromise) {
|
|
674
|
+
await setProbePromise
|
|
675
|
+
promises.setProbePromise = undefined
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
startRetriedAttempt(state)
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
function handleRetriedAttemptFromEnvelope (runner, state) {
|
|
682
|
+
publishRetriedAttempt(runner, state)
|
|
683
|
+
startRetriedAttempt(state)
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
function publishRetriedAttempt (runner, state) {
|
|
687
|
+
const { promises } = state
|
|
688
|
+
let error
|
|
689
|
+
try {
|
|
690
|
+
const cucumberResult = runner.getWorstStepResult()
|
|
691
|
+
error = getErrorFromCucumberResult(cucumberResult)
|
|
692
|
+
} catch {
|
|
693
|
+
// ignore error
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
const currentAttempt = state.numAttempt
|
|
697
|
+
const nextAttempt = currentAttempt + 1
|
|
698
|
+
const failedAttemptCtx = numAttemptToCtx.get(currentAttempt)
|
|
699
|
+
const isFirstAttempt = currentAttempt === 0
|
|
700
|
+
const isAtrRetry = !isFirstAttempt && isFlakyTestRetriesEnabled
|
|
701
|
+
|
|
702
|
+
// ATR: record this attempt as failed so when run().finally runs (after retry) we have all statuses
|
|
703
|
+
if (isFlakyTestRetriesEnabled) {
|
|
704
|
+
const nameForKey = runner.pickle.name.replace(/\s*\(attempt \d+(?:, retried)?\)\s*$/, '')
|
|
705
|
+
const atrKey = `${runner.pickle.uri}:${nameForKey}`
|
|
706
|
+
if (atrStatusesByScenarioKey.has(atrKey)) {
|
|
707
|
+
atrStatusesByScenarioKey.get(atrKey).push('fail')
|
|
708
|
+
} else {
|
|
709
|
+
atrStatusesByScenarioKey.set(atrKey, ['fail'])
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
// the current span will be finished and a new one will be created
|
|
714
|
+
testRetryCh.publish({
|
|
715
|
+
isFirstAttempt,
|
|
716
|
+
error,
|
|
717
|
+
isAtrRetry,
|
|
718
|
+
promises,
|
|
719
|
+
canWaitForDi: state.testStartPayload.canWaitForDi,
|
|
720
|
+
...failedAttemptCtx.currentStore,
|
|
721
|
+
})
|
|
722
|
+
|
|
723
|
+
state.numAttempt = nextAttempt
|
|
724
|
+
return promises.setProbePromise
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
function startRetriedAttempt (state) {
|
|
728
|
+
const { promises, testStartPayload } = state
|
|
729
|
+
const newCtx = { ...testStartPayload, promises }
|
|
730
|
+
numAttemptToCtx.set(state.numAttempt, newCtx)
|
|
731
|
+
|
|
732
|
+
testStartCh.runStores(newCtx, () => {})
|
|
733
|
+
}
|
|
734
|
+
|
|
665
735
|
function wrapRun (pl, isLatestVersion, version) {
|
|
666
736
|
if (patched.has(pl)) return
|
|
667
737
|
|
|
668
738
|
patched.add(pl)
|
|
669
739
|
|
|
740
|
+
const canAwaitRetries = typeof pl.prototype.runAttempt === 'function'
|
|
741
|
+
if (canAwaitRetries) {
|
|
742
|
+
shimmer.wrap(pl.prototype, 'runAttempt', runAttempt => async function (...args) {
|
|
743
|
+
const willBeRetried = await runAttempt.apply(this, args)
|
|
744
|
+
const state = runnerToRetryState.get(this)
|
|
745
|
+
if (willBeRetried && state) {
|
|
746
|
+
await handleRetriedAttempt(this, state)
|
|
747
|
+
}
|
|
748
|
+
return willBeRetried
|
|
749
|
+
})
|
|
750
|
+
}
|
|
751
|
+
|
|
670
752
|
shimmer.wrap(pl.prototype, 'run', run => function (...args) {
|
|
671
753
|
if (!testFinishCh.hasSubscribers) {
|
|
672
754
|
return run.apply(this, args)
|
|
673
755
|
}
|
|
674
756
|
|
|
675
|
-
let numAttempt = 0
|
|
676
|
-
|
|
677
757
|
const testFileAbsolutePath = this.pickle.uri
|
|
678
758
|
const testSuitePath = getTestSuitePath(testFileAbsolutePath, process.cwd())
|
|
679
759
|
|
|
@@ -684,58 +764,34 @@ function wrapRun (pl, isLatestVersion, version) {
|
|
|
684
764
|
testFileAbsolutePath,
|
|
685
765
|
testSourceLine,
|
|
686
766
|
isParallel: !!getEnvironmentVariable('CUCUMBER_WORKER_ID'),
|
|
767
|
+
// Older Cucumber runners do not expose an awaited retry boundary. Failed Test Replay
|
|
768
|
+
// intentionally skips DI setup there instead of bringing back the synchronous wait.
|
|
769
|
+
canWaitForDi: canAwaitRetries,
|
|
687
770
|
}
|
|
688
771
|
const ctx = testStartPayload
|
|
689
|
-
|
|
772
|
+
const promises = {}
|
|
773
|
+
const state = { numAttempt: 0, promises, testStartPayload }
|
|
774
|
+
numAttemptToCtx.set(state.numAttempt, ctx)
|
|
775
|
+
runnerToRetryState.set(this, state)
|
|
690
776
|
if (isTestManagementTestsEnabled && getTestProperties(testSuitePath, this.pickle.name).attemptToFix) {
|
|
691
777
|
logAttemptToFixTestExecution(testSuitePath, this.pickle.name, loggedAttemptToFixTests)
|
|
692
778
|
}
|
|
693
779
|
testStartCh.runStores(ctx, () => {})
|
|
694
|
-
const promises = {}
|
|
695
780
|
try {
|
|
696
|
-
const onEnvelope =
|
|
781
|
+
const onEnvelope = (testCase) => {
|
|
782
|
+
if (canAwaitRetries) return
|
|
783
|
+
|
|
697
784
|
// Only supported from >=8.0.0
|
|
698
785
|
if (testCase?.testCaseFinished) {
|
|
699
786
|
const { testCaseFinished: { willBeRetried } } = testCase
|
|
700
787
|
if (willBeRetried) { // test case failed and will be retried
|
|
701
|
-
|
|
702
|
-
try {
|
|
703
|
-
const cucumberResult = this.getWorstStepResult()
|
|
704
|
-
error = getErrorFromCucumberResult(cucumberResult)
|
|
705
|
-
} catch {
|
|
706
|
-
// ignore error
|
|
707
|
-
}
|
|
708
|
-
|
|
709
|
-
const failedAttemptCtx = numAttemptToCtx.get(numAttempt)
|
|
710
|
-
const isFirstAttempt = numAttempt++ === 0
|
|
711
|
-
const isAtrRetry = !isFirstAttempt && isFlakyTestRetriesEnabled
|
|
712
|
-
|
|
713
|
-
// ATR: record this attempt as failed so when run().finally runs (after retry) we have all statuses
|
|
714
|
-
if (isFlakyTestRetriesEnabled) {
|
|
715
|
-
const nameForKey = this.pickle.name.replace(/\s*\(attempt \d+(?:, retried)?\)\s*$/, '')
|
|
716
|
-
const atrKey = `${this.pickle.uri}:${nameForKey}`
|
|
717
|
-
if (atrStatusesByScenarioKey.has(atrKey)) {
|
|
718
|
-
atrStatusesByScenarioKey.get(atrKey).push('fail')
|
|
719
|
-
} else {
|
|
720
|
-
atrStatusesByScenarioKey.set(atrKey, ['fail'])
|
|
721
|
-
}
|
|
722
|
-
}
|
|
723
|
-
|
|
724
|
-
if (promises.hitBreakpointPromise) {
|
|
725
|
-
await promises.hitBreakpointPromise
|
|
726
|
-
}
|
|
727
|
-
|
|
728
|
-
// the current span will be finished and a new one will be created
|
|
729
|
-
testRetryCh.publish({ isFirstAttempt, error, isAtrRetry, ...failedAttemptCtx.currentStore })
|
|
730
|
-
|
|
731
|
-
const newCtx = { ...testStartPayload, promises }
|
|
732
|
-
numAttemptToCtx.set(numAttempt, newCtx)
|
|
733
|
-
|
|
734
|
-
testStartCh.runStores(newCtx, () => {})
|
|
788
|
+
handleRetriedAttemptFromEnvelope(this, state)
|
|
735
789
|
}
|
|
736
790
|
}
|
|
737
791
|
}
|
|
738
|
-
|
|
792
|
+
if (!canAwaitRetries) {
|
|
793
|
+
this.eventBroadcaster.on('envelope', onEnvelope)
|
|
794
|
+
}
|
|
739
795
|
let promise
|
|
740
796
|
const executionStart = performance.now()
|
|
741
797
|
|
|
@@ -743,7 +799,10 @@ function wrapRun (pl, isLatestVersion, version) {
|
|
|
743
799
|
promise = run.apply(this, args)
|
|
744
800
|
})
|
|
745
801
|
promise.finally(async () => {
|
|
746
|
-
|
|
802
|
+
if (!canAwaitRetries) {
|
|
803
|
+
this.eventBroadcaster.removeListener('envelope', onEnvelope)
|
|
804
|
+
}
|
|
805
|
+
runnerToRetryState.delete(this)
|
|
747
806
|
const result = this.getWorstStepResult()
|
|
748
807
|
const { status, skipReason } = isLatestVersion
|
|
749
808
|
? getStatusFromResultLatest(result)
|
|
@@ -851,7 +910,7 @@ function wrapRun (pl, isLatestVersion, version) {
|
|
|
851
910
|
}
|
|
852
911
|
}
|
|
853
912
|
|
|
854
|
-
const attemptCtx = numAttemptToCtx.get(numAttempt)
|
|
913
|
+
const attemptCtx = numAttemptToCtx.get(state.numAttempt)
|
|
855
914
|
|
|
856
915
|
const error = getErrorFromCucumberResult(result)
|
|
857
916
|
|
|
@@ -899,7 +958,7 @@ function wrapRun (pl, isLatestVersion, version) {
|
|
|
899
958
|
error,
|
|
900
959
|
isNew,
|
|
901
960
|
isEfdRetry,
|
|
902
|
-
isFlakyRetry: numAttempt > 0,
|
|
961
|
+
isFlakyRetry: state.numAttempt > 0,
|
|
903
962
|
isAttemptToFix,
|
|
904
963
|
isAttemptToFixRetry,
|
|
905
964
|
hasFailedAllRetries,
|
|
@@ -113,9 +113,10 @@ function injectSupportFile (config) {
|
|
|
113
113
|
* @param {object} config Cypress resolved config object
|
|
114
114
|
* @param {Function[]} userAfterSpecHandlers user's after:spec handlers collected from wrappedOn
|
|
115
115
|
* @param {Function[]} userAfterRunHandlers user's after:run handlers collected from wrappedOn
|
|
116
|
+
* @param {Function[]} userAfterScreenshotHandlers user's after:screenshot handlers collected from wrappedOn
|
|
116
117
|
* @returns {object} the config object (possibly modified)
|
|
117
118
|
*/
|
|
118
|
-
function registerDdTraceHooks (on, config, userAfterSpecHandlers, userAfterRunHandlers) {
|
|
119
|
+
function registerDdTraceHooks (on, config, userAfterSpecHandlers, userAfterRunHandlers, userAfterScreenshotHandlers) {
|
|
119
120
|
const wrapperFile = injectSupportFile(config)
|
|
120
121
|
|
|
121
122
|
const cleanupWrapper = () => {
|
|
@@ -136,6 +137,7 @@ function registerDdTraceHooks (on, config, userAfterSpecHandlers, userAfterRunHa
|
|
|
136
137
|
|
|
137
138
|
const registerNoopHandlers = () => {
|
|
138
139
|
for (const h of userAfterSpecHandlers) on('after:spec', h)
|
|
140
|
+
for (const h of userAfterScreenshotHandlers) on('after:screenshot', h)
|
|
139
141
|
registerAfterRunWithCleanup()
|
|
140
142
|
on('task', noopTask)
|
|
141
143
|
}
|
|
@@ -153,6 +155,7 @@ function registerDdTraceHooks (on, config, userAfterSpecHandlers, userAfterRunHa
|
|
|
153
155
|
config,
|
|
154
156
|
userAfterSpecHandlers,
|
|
155
157
|
userAfterRunHandlers,
|
|
158
|
+
userAfterScreenshotHandlers,
|
|
156
159
|
cleanupWrapper,
|
|
157
160
|
registered: false,
|
|
158
161
|
configPromise: undefined,
|
|
@@ -176,12 +179,15 @@ function wrapSetupNodeEvents (originalSetupNodeEvents) {
|
|
|
176
179
|
return function ddSetupNodeEvents (on, config) {
|
|
177
180
|
const userAfterSpecHandlers = []
|
|
178
181
|
const userAfterRunHandlers = []
|
|
182
|
+
const userAfterScreenshotHandlers = []
|
|
179
183
|
|
|
180
184
|
const wrappedOn = (event, handler) => {
|
|
181
185
|
if (event === 'after:spec') {
|
|
182
186
|
userAfterSpecHandlers.push(handler)
|
|
183
187
|
} else if (event === 'after:run') {
|
|
184
188
|
userAfterRunHandlers.push(handler)
|
|
189
|
+
} else if (event === 'after:screenshot') {
|
|
190
|
+
userAfterScreenshotHandlers.push(handler)
|
|
185
191
|
} else {
|
|
186
192
|
on(event, handler)
|
|
187
193
|
}
|
|
@@ -197,7 +203,8 @@ function wrapSetupNodeEvents (originalSetupNodeEvents) {
|
|
|
197
203
|
on,
|
|
198
204
|
mergeReturnedConfig(config, result),
|
|
199
205
|
userAfterSpecHandlers,
|
|
200
|
-
userAfterRunHandlers
|
|
206
|
+
userAfterRunHandlers,
|
|
207
|
+
userAfterScreenshotHandlers
|
|
201
208
|
)
|
|
202
209
|
})
|
|
203
210
|
}
|
|
@@ -206,7 +213,8 @@ function wrapSetupNodeEvents (originalSetupNodeEvents) {
|
|
|
206
213
|
on,
|
|
207
214
|
mergeReturnedConfig(config, maybePromise),
|
|
208
215
|
userAfterSpecHandlers,
|
|
209
|
-
userAfterRunHandlers
|
|
216
|
+
userAfterRunHandlers,
|
|
217
|
+
userAfterScreenshotHandlers
|
|
210
218
|
)
|
|
211
219
|
}
|
|
212
220
|
}
|
|
@@ -22,6 +22,8 @@ const callbackFinishCh = channel('datadog:fastify:callback:execute')
|
|
|
22
22
|
const parsingContexts = new WeakMap()
|
|
23
23
|
const cookiesPublished = new WeakSet()
|
|
24
24
|
const bodyPublished = new WeakSet()
|
|
25
|
+
let lastPublishedError
|
|
26
|
+
let lastPublishedReq
|
|
25
27
|
|
|
26
28
|
function wrapFastify (fastify, hasParsingEvents) {
|
|
27
29
|
if (typeof fastify !== 'function') return fastify
|
|
@@ -110,16 +112,20 @@ function invokeHookWithContext (name, fn, thisArg, args) {
|
|
|
110
112
|
const promise = fn.apply(thisArg, args)
|
|
111
113
|
|
|
112
114
|
if (promise && typeof promise.catch === 'function') {
|
|
113
|
-
|
|
115
|
+
// Observe the rejection to publish, then hand back the original promise so
|
|
116
|
+
// the rejection keeps propagating untouched. Returning the handler's
|
|
117
|
+
// promise instead would resolve with `undefined` and swallow the rejection.
|
|
118
|
+
promise.catch(error => {
|
|
114
119
|
ctx.error = error
|
|
115
|
-
|
|
120
|
+
publishError(ctx)
|
|
116
121
|
})
|
|
117
122
|
}
|
|
118
123
|
|
|
119
124
|
return promise
|
|
120
125
|
} catch (error) {
|
|
121
126
|
ctx.error = error
|
|
122
|
-
|
|
127
|
+
publishError(ctx)
|
|
128
|
+
throw error
|
|
123
129
|
}
|
|
124
130
|
}
|
|
125
131
|
|
|
@@ -305,11 +311,24 @@ function getRouteConfig (request) {
|
|
|
305
311
|
}
|
|
306
312
|
|
|
307
313
|
function publishError (ctx) {
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
314
|
+
const error = ctx.error
|
|
315
|
+
if (!error) return
|
|
316
|
+
|
|
317
|
+
// avvio's boot loop (`_encapsulateThreeParam`) re-invokes the same encapsulated
|
|
318
|
+
// hook after it throws, re-throwing the same error object on every sequential
|
|
319
|
+
// re-drive (#9099), recursing the subscriber until boot overflows the stack.
|
|
320
|
+
// The subscribers tag once per request, so the guard collapses only a re-drive
|
|
321
|
+
// of the same error against the same request; a distinct request reusing a
|
|
322
|
+
// cached error object still publishes. Boot hooks carry no request, so their
|
|
323
|
+
// re-drives share the same `undefined` req and collapse after the first. The
|
|
324
|
+
// re-drive re-throws the one caught error on the trailing hop, so a compare
|
|
325
|
+
// against the previous publish bounds it without a per-error side table.
|
|
326
|
+
const req = ctx.req
|
|
327
|
+
if (error === lastPublishedError && req === lastPublishedReq) return
|
|
328
|
+
lastPublishedError = error
|
|
329
|
+
lastPublishedReq = req
|
|
330
|
+
|
|
331
|
+
publishErrorChannel(ctx)
|
|
313
332
|
}
|
|
314
333
|
|
|
315
334
|
function onRoute (routeOptions) {
|
|
@@ -15,6 +15,7 @@ module.exports = {
|
|
|
15
15
|
vm: () => require('../vm'),
|
|
16
16
|
zlib: () => require('../zlib'),
|
|
17
17
|
// Non Node.js modules
|
|
18
|
+
'@anthropic-ai/claude-agent-sdk': { esmFirst: true, fn: () => require('../claude-agent-sdk') },
|
|
18
19
|
'@anthropic-ai/sdk': { esmFirst: true, fn: () => require('../anthropic') },
|
|
19
20
|
'@apollo/server': () => require('../apollo-server'),
|
|
20
21
|
'@apollo/gateway': () => require('../apollo'),
|
|
@@ -51,6 +51,13 @@ exports.tracingChannel = function (name) {
|
|
|
51
51
|
* inside Express) still reaches its subscribers instead of being dropped, and
|
|
52
52
|
* the guard costs a closure read rather than a per-publish channel lookup.
|
|
53
53
|
*
|
|
54
|
+
* The flag bounds only synchronous re-entry. A sequential re-drive of the same
|
|
55
|
+
* error (fastify's avvio boot loop) runs after the publish returned and the
|
|
56
|
+
* `finally` cleared the flag, so the framework that produces that shape guards
|
|
57
|
+
* it at its own seam; the middleware frameworks that republish the same error
|
|
58
|
+
* once per unwound layer (koa, router, connect, restify, each tagging a
|
|
59
|
+
* distinct span) must keep publishing it.
|
|
60
|
+
*
|
|
54
61
|
* @param {Channel} errorChannel
|
|
55
62
|
*/
|
|
56
63
|
exports.createErrorPublisher = function createErrorPublisher (errorChannel) {
|
|
@@ -5,7 +5,7 @@ module.exports = [
|
|
|
5
5
|
{
|
|
6
6
|
module: {
|
|
7
7
|
name: 'ai',
|
|
8
|
-
versionRange: '>=4.0.0',
|
|
8
|
+
versionRange: '>=4.0.0 <7.0.0',
|
|
9
9
|
filePath: 'dist/index.js',
|
|
10
10
|
},
|
|
11
11
|
functionQuery: {
|
|
@@ -17,7 +17,7 @@ module.exports = [
|
|
|
17
17
|
{
|
|
18
18
|
module: {
|
|
19
19
|
name: 'ai',
|
|
20
|
-
versionRange: '>=4.0.0',
|
|
20
|
+
versionRange: '>=4.0.0 <7.0.0',
|
|
21
21
|
filePath: 'dist/index.mjs',
|
|
22
22
|
},
|
|
23
23
|
functionQuery: {
|
|
@@ -54,7 +54,7 @@ module.exports = [
|
|
|
54
54
|
{
|
|
55
55
|
module: {
|
|
56
56
|
name: 'ai',
|
|
57
|
-
versionRange: '>=6.0.0',
|
|
57
|
+
versionRange: '>=6.0.0 <7.0.0',
|
|
58
58
|
filePath: 'dist/index.js',
|
|
59
59
|
},
|
|
60
60
|
functionQuery: {
|
|
@@ -66,7 +66,7 @@ module.exports = [
|
|
|
66
66
|
{
|
|
67
67
|
module: {
|
|
68
68
|
name: 'ai',
|
|
69
|
-
versionRange: '>=6.0.0',
|
|
69
|
+
versionRange: '>=6.0.0 <7.0.0',
|
|
70
70
|
filePath: 'dist/index.mjs',
|
|
71
71
|
},
|
|
72
72
|
functionQuery: {
|
|
@@ -104,7 +104,7 @@ module.exports = [
|
|
|
104
104
|
{
|
|
105
105
|
module: {
|
|
106
106
|
name: 'ai',
|
|
107
|
-
versionRange: '>=4.0.0',
|
|
107
|
+
versionRange: '>=4.0.0 <7.0.0',
|
|
108
108
|
filePath: 'dist/index.js',
|
|
109
109
|
},
|
|
110
110
|
functionQuery: {
|
|
@@ -116,7 +116,7 @@ module.exports = [
|
|
|
116
116
|
{
|
|
117
117
|
module: {
|
|
118
118
|
name: 'ai',
|
|
119
|
-
versionRange: '>=4.0.0',
|
|
119
|
+
versionRange: '>=4.0.0 <7.0.0',
|
|
120
120
|
filePath: 'dist/index.mjs',
|
|
121
121
|
},
|
|
122
122
|
functionQuery: {
|
package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/claude-agent-sdk.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
module.exports = [
|
|
4
|
+
{
|
|
5
|
+
module: {
|
|
6
|
+
name: '@anthropic-ai/claude-agent-sdk',
|
|
7
|
+
versionRange: '>=0.2.113',
|
|
8
|
+
filePath: 'sdk.mjs',
|
|
9
|
+
},
|
|
10
|
+
functionQuery: {
|
|
11
|
+
functionName: 'query',
|
|
12
|
+
kind: 'Async',
|
|
13
|
+
isExportAlias: true,
|
|
14
|
+
},
|
|
15
|
+
channelName: 'query',
|
|
16
|
+
},
|
|
17
|
+
]
|