dd-trace 5.110.0 → 5.112.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/README.md +13 -8
- package/ci/init.js +21 -2
- package/ci/vitest-no-worker-init-setup.mjs +430 -0
- package/ext/tags.js +2 -0
- package/index.d.ts +34 -1
- package/initialize.mjs +5 -6
- package/loader-hook.mjs +76 -55
- package/package.json +37 -34
- 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/fs.js +8 -6
- package/packages/datadog-instrumentations/src/graphql.js +26 -495
- 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/graphql.js +201 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +2 -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 +13 -2
- package/packages/datadog-instrumentations/src/playwright.js +13 -9
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +1297 -0
- package/packages/datadog-instrumentations/src/vitest-main.js +1594 -0
- package/packages/datadog-instrumentations/src/vitest-util.js +254 -0
- package/packages/datadog-instrumentations/src/vitest-worker.js +823 -0
- package/packages/datadog-instrumentations/src/vitest.js +11 -1855
- 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/client.js +2 -2
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/context.js +19 -10
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/handler.js +1 -0
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/util.js +47 -11
- 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 +15 -24
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +360 -14
- package/packages/datadog-plugin-cypress/src/index.js +47 -2
- package/packages/datadog-plugin-cypress/src/plugin.js +1 -0
- package/packages/datadog-plugin-cypress/src/support.js +45 -1
- package/packages/datadog-plugin-express/src/code_origin.js +1 -1
- package/packages/datadog-plugin-fastify/src/code_origin.js +1 -1
- package/packages/datadog-plugin-graphql/src/execute.js +639 -12
- package/packages/datadog-plugin-graphql/src/index.js +37 -9
- package/packages/datadog-plugin-graphql/src/parse.js +24 -4
- package/packages/datadog-plugin-graphql/src/utils.js +9 -2
- package/packages/datadog-plugin-graphql/src/validate.js +17 -6
- package/packages/datadog-plugin-http/src/index.js +6 -8
- package/packages/datadog-plugin-jest/src/index.js +31 -15
- package/packages/datadog-plugin-mocha/src/index.js +40 -15
- 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-openai/src/services.js +2 -2
- package/packages/datadog-plugin-playwright/src/index.js +4 -3
- package/packages/datadog-plugin-vitest/src/index.js +120 -72
- package/packages/datadog-shimmer/src/shimmer.js +37 -16
- 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/aiguard/sdk.js +2 -2
- package/packages/dd-trace/src/appsec/api_security/sampler.js +3 -3
- package/packages/dd-trace/src/appsec/channels.js +3 -1
- package/packages/dd-trace/src/appsec/downstream_requests.js +4 -4
- package/packages/dd-trace/src/appsec/graphql.js +14 -11
- package/packages/dd-trace/src/appsec/iast/analyzers/nosql-injection-mongodb-analyzer.js +23 -23
- package/packages/dd-trace/src/appsec/iast/security-controls/index.js +2 -2
- package/packages/dd-trace/src/appsec/iast/telemetry/index.js +2 -1
- package/packages/dd-trace/src/appsec/index.js +10 -1
- package/packages/dd-trace/src/appsec/lambda.js +135 -0
- package/packages/dd-trace/src/appsec/reporter.js +49 -10
- package/packages/dd-trace/src/appsec/telemetry/index.js +1 -1
- package/packages/dd-trace/src/appsec/waf/index.js +16 -4
- package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +4 -4
- 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/early-flake-detection/get-known-tests.js +21 -6
- package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +5 -2
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +1 -1
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +1 -1
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +6 -2
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +1 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +130 -20
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +2 -2
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +17 -0
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +47 -26
- package/packages/dd-trace/src/ci-visibility/log-submission/log-submission-plugin.js +2 -2
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +64 -53
- package/packages/dd-trace/src/ci-visibility/requests/upload-coverage-report.js +3 -3
- package/packages/dd-trace/src/ci-visibility/requests/upload-test-screenshot.js +156 -0
- package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +23 -5
- package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +128 -0
- package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache.js +287 -0
- package/packages/dd-trace/src/config/defaults.js +3 -2
- package/packages/dd-trace/src/config/generated-config-types.d.ts +71 -57
- package/packages/dd-trace/src/config/helper.js +1 -0
- package/packages/dd-trace/src/config/index.js +35 -22
- package/packages/dd-trace/src/config/major-overrides.js +4 -2
- package/packages/dd-trace/src/config/remote_config.js +1 -1
- package/packages/dd-trace/src/config/supported-configurations.json +127 -56
- package/packages/dd-trace/src/constants.js +7 -0
- package/packages/dd-trace/src/crashtracking/crashtracker.js +2 -2
- package/packages/dd-trace/src/datastreams/processor.js +11 -3
- package/packages/dd-trace/src/exporters/agent/index.js +1 -1
- package/packages/dd-trace/src/exporters/agentless/writer.js +4 -4
- package/packages/dd-trace/src/llmobs/index.js +1 -1
- 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/base.js +4 -4
- 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/llmobs/plugins/langgraph/index.js +1 -1
- package/packages/dd-trace/src/llmobs/sdk.js +3 -3
- package/packages/dd-trace/src/llmobs/span_processor.js +1 -1
- package/packages/dd-trace/src/llmobs/tagger.js +3 -3
- package/packages/dd-trace/src/llmobs/writers/base.js +1 -1
- package/packages/dd-trace/src/opentelemetry/metrics/index.js +54 -5
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_exporter.js +40 -0
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_transformer.js +169 -0
- package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +38 -39
- package/packages/dd-trace/src/opentelemetry/span.js +5 -0
- package/packages/dd-trace/src/opentelemetry/trace/index.js +4 -0
- package/packages/dd-trace/src/opentelemetry/tracer_provider.js +1 -1
- package/packages/dd-trace/src/opentracing/tracer.js +6 -1
- package/packages/dd-trace/src/plugin_manager.js +23 -7
- package/packages/dd-trace/src/plugins/ci_plugin.js +159 -10
- package/packages/dd-trace/src/plugins/index.js +2 -0
- package/packages/dd-trace/src/plugins/util/llm.js +6 -1
- package/packages/dd-trace/src/plugins/util/test.js +15 -9
- package/packages/dd-trace/src/profiling/exporter_cli.js +2 -2
- package/packages/dd-trace/src/profiling/exporters/agent.js +28 -3
- package/packages/dd-trace/src/profiling/exporters/event_serializer.js +3 -3
- package/packages/dd-trace/src/profiling/profilers/wall.js +1 -1
- package/packages/dd-trace/src/proxy.js +8 -8
- package/packages/dd-trace/src/span_processor.js +5 -6
- package/packages/dd-trace/src/span_stats.js +96 -78
- package/packages/dd-trace/src/startup-log.js +2 -1
- package/packages/dd-trace/src/telemetry/dependencies.js +1 -1
- package/packages/dd-trace/src/telemetry/endpoints.js +6 -4
- package/packages/dd-trace/src/telemetry/index.js +2 -2
- package/packages/dd-trace/src/telemetry/logs/index.js +1 -1
- package/packages/dd-trace/src/telemetry/send-data.js +8 -8
- package/packages/dd-trace/src/telemetry/session-propagation.js +1 -1
- package/packages/dd-trace/src/telemetry/telemetry.js +9 -9
- 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-plugin-graphql/src/resolve.js +0 -170
|
@@ -5,7 +5,7 @@ const VercelAILLMObsPlugin = require('../../dd-trace/src/llmobs/plugins/ai')
|
|
|
5
5
|
const VercelAITracingPlugin = require('./tracing')
|
|
6
6
|
|
|
7
7
|
class VercelAIPlugin extends CompositePlugin {
|
|
8
|
-
static
|
|
8
|
+
static id = 'ai'
|
|
9
9
|
static get plugins () {
|
|
10
10
|
return {
|
|
11
11
|
llmobs: VercelAILLMObsPlugin,
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const CompositePlugin = require('../../dd-trace/src/plugins/composite')
|
|
3
4
|
const TracingPlugin = require('../../dd-trace/src/plugins/tracing')
|
|
4
|
-
const { getModelProvider } = require('./utils')
|
|
5
|
+
const { getModelProvider, parseModelProvider } = require('./utils')
|
|
5
6
|
|
|
6
|
-
class
|
|
7
|
-
static id = '
|
|
7
|
+
class DdTelemetryPlugin extends TracingPlugin {
|
|
8
|
+
static id = 'ai_tracing_dd_telemetry'
|
|
8
9
|
static prefix = 'tracing:dd-trace:vercel-ai'
|
|
9
10
|
|
|
10
11
|
bindStart (ctx) {
|
|
@@ -30,4 +31,66 @@ class VercelAITracingPlugin extends TracingPlugin {
|
|
|
30
31
|
}
|
|
31
32
|
}
|
|
32
33
|
|
|
34
|
+
class VercelAiTelemetryPlugin extends TracingPlugin {
|
|
35
|
+
static id = 'ai_tracing_vercel_telemetry'
|
|
36
|
+
static prefix = 'tracing:ai:telemetry'
|
|
37
|
+
|
|
38
|
+
#streamedCalls = new Set()
|
|
39
|
+
|
|
40
|
+
constructor () {
|
|
41
|
+
super(...arguments)
|
|
42
|
+
|
|
43
|
+
this.addSub('dd-trace:vercel-ai:chunk', ({ ctx, chunk, done }) => {
|
|
44
|
+
ctx.streamConsumed = done
|
|
45
|
+
})
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
bindStart (ctx) {
|
|
49
|
+
const { type: name, event } = ctx
|
|
50
|
+
const model = event.modelId
|
|
51
|
+
const modelProvider = parseModelProvider(event.provider, model)
|
|
52
|
+
|
|
53
|
+
let isStream = this.#streamedCalls.has(event.callId)
|
|
54
|
+
if (name.includes('stream')) {
|
|
55
|
+
this.#streamedCalls.add(event.callId)
|
|
56
|
+
isStream = true
|
|
57
|
+
|
|
58
|
+
ctx.streamConsumed = false
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
ctx.isStream = isStream
|
|
62
|
+
|
|
63
|
+
this.startSpan(name, {
|
|
64
|
+
meta: {
|
|
65
|
+
'resource.name': event.functionId ?? name,
|
|
66
|
+
'ai.request.model': model,
|
|
67
|
+
'ai.request.model_provider': modelProvider,
|
|
68
|
+
},
|
|
69
|
+
}, ctx)
|
|
70
|
+
|
|
71
|
+
return ctx.currentStore
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
asyncEnd (ctx) {
|
|
75
|
+
// check if isStreamed and stream resolved
|
|
76
|
+
// this event will fire multiple times for the same channel
|
|
77
|
+
if (ctx.isStream && ctx.result?.stream && !ctx.streamConsumed) return
|
|
78
|
+
|
|
79
|
+
if (ctx.type?.includes('stream')) {
|
|
80
|
+
this.#streamedCalls.delete(ctx.event?.callId)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const span = ctx.currentStore?.span
|
|
84
|
+
span?.finish()
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
class VercelAITracingPlugin extends CompositePlugin {
|
|
89
|
+
static id = 'ai_tracing'
|
|
90
|
+
static plugins = {
|
|
91
|
+
dd: DdTelemetryPlugin,
|
|
92
|
+
ai: VercelAiTelemetryPlugin,
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
33
96
|
module.exports = VercelAITracingPlugin
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { parseModelId } = require('../../datadog-plugin-aws-sdk/src/services/bedrockruntime/utils')
|
|
3
|
+
const { parseModelId: parseBedrockModelId } = require('../../datadog-plugin-aws-sdk/src/services/bedrockruntime/utils')
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Get the model provider from the span tags or attributes.
|
|
@@ -11,12 +11,24 @@ const { parseModelId } = require('../../datadog-plugin-aws-sdk/src/services/bedr
|
|
|
11
11
|
*/
|
|
12
12
|
function getModelProvider (tags) {
|
|
13
13
|
const modelProviderTag = tags['ai.model.provider']
|
|
14
|
-
const
|
|
14
|
+
const modelId = tags['ai.model.id']
|
|
15
|
+
|
|
16
|
+
return parseModelProvider(modelProviderTag, modelId)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Parse the model provider from the raw provider string.
|
|
21
|
+
*
|
|
22
|
+
* @param {string} rawProvider
|
|
23
|
+
* @param {string} modelId
|
|
24
|
+
* @returns {string}
|
|
25
|
+
*/
|
|
26
|
+
function parseModelProvider (rawProvider, modelId) {
|
|
27
|
+
const providerParts = rawProvider?.split('.')
|
|
15
28
|
const provider = providerParts?.[0]
|
|
16
29
|
|
|
17
30
|
if (provider === 'amazon-bedrock') {
|
|
18
|
-
const
|
|
19
|
-
const model = modelId && parseModelId(modelId)
|
|
31
|
+
const model = modelId && parseBedrockModelId(modelId)
|
|
20
32
|
return model?.modelProvider ?? provider
|
|
21
33
|
}
|
|
22
34
|
|
|
@@ -25,4 +37,5 @@ function getModelProvider (tags) {
|
|
|
25
37
|
|
|
26
38
|
module.exports = {
|
|
27
39
|
getModelProvider,
|
|
40
|
+
parseModelProvider,
|
|
28
41
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const ClientPlugin = require('../../dd-trace/src/plugins/client')
|
|
4
|
-
const { addOpMeta, unwrapDurableError } = require('./util')
|
|
4
|
+
const { addOpMeta, getStepDataForNext, unwrapDurableError } = require('./util')
|
|
5
5
|
|
|
6
6
|
class AwsDurableExecutionSdkJsClientPlugin extends ClientPlugin {
|
|
7
7
|
static id = 'aws-durable-execution-sdk-js'
|
|
@@ -29,7 +29,7 @@ class AwsDurableExecutionSdkJsClientPlugin extends ClientPlugin {
|
|
|
29
29
|
if (operationName) {
|
|
30
30
|
meta['aws.durable.operation_name'] = operationName
|
|
31
31
|
}
|
|
32
|
-
addOpMeta(meta, ctx.self)
|
|
32
|
+
addOpMeta(meta, getStepDataForNext(ctx.self))
|
|
33
33
|
|
|
34
34
|
this.startSpan(this.operationName(), {
|
|
35
35
|
resource: operationName,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const { storage } = require('../../datadog-core')
|
|
4
4
|
const TracingPlugin = require('../../dd-trace/src/plugins/tracing')
|
|
5
|
-
const { addOpMeta, unwrapDurableError } = require('./util')
|
|
5
|
+
const { addOpMeta, getOperationAttempt, getStepDataForNext, unwrapDurableError } = require('./util')
|
|
6
6
|
|
|
7
7
|
// Span names whose direct children must keep the default resource.
|
|
8
8
|
// These can have very high cardinality which is undesireable in the resource.
|
|
@@ -41,12 +41,19 @@ class BaseContextPlugin extends TracingPlugin {
|
|
|
41
41
|
if (operationName) {
|
|
42
42
|
meta['aws.durable.operation_name'] = operationName
|
|
43
43
|
}
|
|
44
|
-
|
|
44
|
+
const stepInfo = getStepDataForNext(ctx.self)
|
|
45
|
+
addOpMeta(meta, stepInfo)
|
|
46
|
+
|
|
47
|
+
const metrics = this.constructor.retryable
|
|
48
|
+
? { 'aws.durable.operation_attempt': getOperationAttempt(stepInfo.stepData) }
|
|
49
|
+
: undefined
|
|
45
50
|
|
|
46
51
|
this.startSpan(spanName, {
|
|
47
52
|
resource,
|
|
53
|
+
type: this.constructor.type,
|
|
48
54
|
kind: this.constructor.kind,
|
|
49
55
|
meta,
|
|
56
|
+
metrics,
|
|
50
57
|
}, ctx)
|
|
51
58
|
|
|
52
59
|
return ctx.currentStore
|
|
@@ -71,11 +78,12 @@ class BaseContextPlugin extends TracingPlugin {
|
|
|
71
78
|
}
|
|
72
79
|
}
|
|
73
80
|
|
|
74
|
-
function makeContextPlugin (method, spanName) {
|
|
81
|
+
function makeContextPlugin (method, spanName, { retryable }) {
|
|
75
82
|
return class extends BaseContextPlugin {
|
|
76
83
|
static prefix = `tracing:orchestrion:@aws/durable-execution-sdk-js:DurableContextImpl_${method}`
|
|
77
84
|
static settleChannel = `apm:aws-durable-execution-sdk-js:${method}:settle`
|
|
78
85
|
static spanName = spanName
|
|
86
|
+
static retryable = retryable
|
|
79
87
|
}
|
|
80
88
|
}
|
|
81
89
|
|
|
@@ -83,6 +91,7 @@ class RunInChildContextPlugin extends BaseContextPlugin {
|
|
|
83
91
|
static prefix = 'tracing:orchestrion:@aws/durable-execution-sdk-js:DurableContextImpl_runInChildContext'
|
|
84
92
|
static settleChannel = 'apm:aws-durable-execution-sdk-js:runInChildContext:settle'
|
|
85
93
|
static spanName = 'aws.durable.child_context'
|
|
94
|
+
static retryable = false
|
|
86
95
|
|
|
87
96
|
bindStart (ctx) {
|
|
88
97
|
if (SUPPRESSED_CHILD_CONTEXT_SUBTYPES.has(getRunInChildContextSubType(ctx))) {
|
|
@@ -103,12 +112,12 @@ function getRunInChildContextSubType (ctx) {
|
|
|
103
112
|
}
|
|
104
113
|
|
|
105
114
|
module.exports = {
|
|
106
|
-
step: makeContextPlugin('step', 'aws.durable.step'),
|
|
107
|
-
wait: makeContextPlugin('wait', 'aws.durable.wait'),
|
|
108
|
-
waitForCondition: makeContextPlugin('waitForCondition', 'aws.durable.wait_for_condition'),
|
|
109
|
-
waitForCallback: makeContextPlugin('waitForCallback', 'aws.durable.wait_for_callback'),
|
|
110
|
-
createCallback: makeContextPlugin('createCallback', 'aws.durable.create_callback'),
|
|
111
|
-
map: makeContextPlugin('map', 'aws.durable.map'),
|
|
112
|
-
parallel: makeContextPlugin('parallel', 'aws.durable.parallel'),
|
|
115
|
+
step: makeContextPlugin('step', 'aws.durable.step', { retryable: true }),
|
|
116
|
+
wait: makeContextPlugin('wait', 'aws.durable.wait', { retryable: false }),
|
|
117
|
+
waitForCondition: makeContextPlugin('waitForCondition', 'aws.durable.wait_for_condition', { retryable: true }),
|
|
118
|
+
waitForCallback: makeContextPlugin('waitForCallback', 'aws.durable.wait_for_callback', { retryable: false }),
|
|
119
|
+
createCallback: makeContextPlugin('createCallback', 'aws.durable.create_callback', { retryable: false }),
|
|
120
|
+
map: makeContextPlugin('map', 'aws.durable.map', { retryable: false }),
|
|
121
|
+
parallel: makeContextPlugin('parallel', 'aws.durable.parallel', { retryable: false }),
|
|
113
122
|
runInChildContext: RunInChildContextPlugin,
|
|
114
123
|
}
|
|
@@ -2,27 +2,63 @@
|
|
|
2
2
|
|
|
3
3
|
const { createHash } = require('node:crypto')
|
|
4
4
|
|
|
5
|
+
// A checkpoint in one of these terminal states means the operation is served from the checkpoint
|
|
6
|
+
// on a replay rather than executed: the SDK reloads a SUCCEEDED result or re-raises a FAILED error
|
|
7
|
+
// without running the user function. Both also carry the 1-indexed attempt that reached the terminal
|
|
8
|
+
// state, so both need the same normalization to agree with the 0-indexed live run.
|
|
9
|
+
const REPLAYED_STATUSES = new Set(['SUCCEEDED', 'FAILED'])
|
|
10
|
+
|
|
5
11
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* be served from the SDK's checkpoint). `aws.durable.operation_id` — the 16-hex-char MD5 of
|
|
10
|
-
* the stepId, mirroring the SDK's internal calculation — is only added when a stepId exists.
|
|
11
|
-
* @param {Record<string, string>} meta - The span meta/tags object to populate.
|
|
12
|
+
* Resolves the SDK's next stepId and its checkpoint entry in a single pass, so one span start can
|
|
13
|
+
* feed both addOpMeta and getOperationAttempt without traversing the SDK internals twice. `stepData`
|
|
14
|
+
* is undefined when there is no next stepId, or no checkpoint entry exists for it yet.
|
|
12
15
|
* @param {object} [ctxImpl] - The DurableContextImpl about to run the op.
|
|
13
|
-
* @returns {
|
|
16
|
+
* @returns {{ stepId: string | undefined, stepData: object | undefined }}
|
|
14
17
|
*/
|
|
15
|
-
function
|
|
18
|
+
function getStepDataForNext (ctxImpl) {
|
|
16
19
|
const stepId = ctxImpl?.getNextStepId?.()
|
|
20
|
+
const stepData = stepId ? ctxImpl?._executionContext?.getStepData?.(stepId) : undefined
|
|
21
|
+
return { stepId, stepData }
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Populates the replay and operation_id tags from a pre-resolved step lookup (see
|
|
26
|
+
* getStepDataForNext). `aws.durable.replayed` is always set ('true' when the next stepId already
|
|
27
|
+
* has a terminal checkpoint entry — SUCCEEDED or FAILED — i.e. the op will be served from the SDK's
|
|
28
|
+
* checkpoint rather than executed). `aws.durable.operation_id` — the 16-hex-char MD5 of the stepId,
|
|
29
|
+
* mirroring the SDK's internal calculation — is only added when a stepId exists.
|
|
30
|
+
* @param {Record<string, string>} meta - The span meta/tags object to populate.
|
|
31
|
+
* @param {{ stepId?: string, stepData?: object }} stepInfo - Resolved next stepId and checkpoint entry.
|
|
32
|
+
* @returns {void}
|
|
33
|
+
*/
|
|
34
|
+
function addOpMeta (meta, { stepId, stepData }) {
|
|
17
35
|
if (!stepId) {
|
|
18
36
|
meta['aws.durable.replayed'] = 'false'
|
|
19
37
|
return
|
|
20
38
|
}
|
|
21
|
-
|
|
22
|
-
meta['aws.durable.replayed'] = String(stepData?.Status === 'SUCCEEDED')
|
|
39
|
+
meta['aws.durable.replayed'] = String(REPLAYED_STATUSES.has(stepData?.Status))
|
|
23
40
|
meta['aws.durable.operation_id'] = createHash('md5').update(stepId).digest('hex').slice(0, 16)
|
|
24
41
|
}
|
|
25
42
|
|
|
43
|
+
/**
|
|
44
|
+
* Returns the 0-indexed attempt number for the op (0 original, 1 first retry, …) from a pre-resolved
|
|
45
|
+
* checkpoint entry (see getStepDataForNext), defaulting to 0 before any checkpoint exists.
|
|
46
|
+
*
|
|
47
|
+
* StepDetails.Attempt is indexed differently depending on checkpoint status: on a pending/retry
|
|
48
|
+
* checkpoint it's the count of prior failed attempts (already 0-indexed), but on a terminal
|
|
49
|
+
* checkpoint read on replay (SUCCEEDED or FAILED) it's the 1-indexed attempt that reached that
|
|
50
|
+
* state. We subtract 1 in the terminal case so a replay agrees with the original run, flooring at
|
|
51
|
+
* 0 since the 1-indexing is observed server behavior, not an SDK guarantee.
|
|
52
|
+
*
|
|
53
|
+
* @param {object} [stepData] - The checkpoint entry for the next stepId.
|
|
54
|
+
* @returns {number}
|
|
55
|
+
*/
|
|
56
|
+
function getOperationAttempt (stepData) {
|
|
57
|
+
const attempt = stepData?.StepDetails?.Attempt
|
|
58
|
+
if (!Number.isFinite(attempt)) return 0
|
|
59
|
+
return REPLAYED_STATUSES.has(stepData.Status) ? Math.max(0, attempt - 1) : attempt
|
|
60
|
+
}
|
|
61
|
+
|
|
26
62
|
/**
|
|
27
63
|
* The SDK wraps user errors in typed classes (StepError, ChildContextError, etc.); we follow the
|
|
28
64
|
* `.cause` chain to recover the user's original Error. SDK wrappers expose a string `errorType`
|
|
@@ -40,4 +76,4 @@ function unwrapDurableError (ctx) {
|
|
|
40
76
|
return err
|
|
41
77
|
}
|
|
42
78
|
|
|
43
|
-
module.exports = { addOpMeta, unwrapDurableError }
|
|
79
|
+
module.exports = { addOpMeta, getOperationAttempt, getStepDataForNext, unwrapDurableError }
|
|
@@ -97,11 +97,22 @@ class ChildProcessPlugin extends TracingPlugin {
|
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
asyncEnd (ctx) {
|
|
100
|
-
const { result } = ctx
|
|
100
|
+
const { result, error } = ctx
|
|
101
|
+
let exitCode
|
|
102
|
+
|
|
103
|
+
if (result !== null && typeof result === 'object') {
|
|
104
|
+
// util.promisify(execFile) resolves with a { stdout, stderr } object on
|
|
105
|
+
// success, where the exit code is 0.
|
|
106
|
+
exitCode = result.status ?? 0
|
|
107
|
+
} else if (result === undefined && error !== undefined) {
|
|
108
|
+
exitCode = error.status ?? error.code ?? 0
|
|
109
|
+
} else {
|
|
110
|
+
exitCode = result
|
|
111
|
+
}
|
|
101
112
|
|
|
102
113
|
const span = ctx.currentStore?.span || this.activeSpan
|
|
103
114
|
|
|
104
|
-
span?.setTag('cmd.exit_code', `${
|
|
115
|
+
span?.setTag('cmd.exit_code', `${exitCode}`)
|
|
105
116
|
span?.finish()
|
|
106
117
|
|
|
107
118
|
return ctx.parentStore
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
require('../../datadog-instrumentations/src/claude-agent-sdk')
|
|
4
|
+
|
|
5
|
+
const CompositePlugin = require('../../dd-trace/src/plugins/composite')
|
|
6
|
+
const ClaudeAgentSdkLLMObsPlugins = require('../../dd-trace/src/llmobs/plugins/claude-agent-sdk')
|
|
7
|
+
const ClaudeAgentSdkTracingPlugins = require('./tracing')
|
|
8
|
+
|
|
9
|
+
class ClaudeAgentSdkPlugin extends CompositePlugin {
|
|
10
|
+
static id = 'claude-agent-sdk'
|
|
11
|
+
|
|
12
|
+
static get plugins () {
|
|
13
|
+
const plugins = {}
|
|
14
|
+
|
|
15
|
+
// LLM Obs plugins must be registered before tracing plugins so that
|
|
16
|
+
// annotations are added to the span before it finishes.
|
|
17
|
+
// The tracing plugin uses `bindStart` vs the LLM Obs plugin's `start`,
|
|
18
|
+
// so the span is created in the tracing plugin before the LLM Obs one runs.
|
|
19
|
+
for (const Plugin of ClaudeAgentSdkLLMObsPlugins) {
|
|
20
|
+
plugins[Plugin.id] = Plugin
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
for (const Plugin of ClaudeAgentSdkTracingPlugins) {
|
|
24
|
+
plugins[Plugin.id] = Plugin
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return plugins
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
module.exports = ClaudeAgentSdkPlugin
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { storage } = require('../../datadog-core')
|
|
4
|
+
const TracingPlugin = require('../../dd-trace/src/plugins/tracing')
|
|
5
|
+
const { splitModel } = require('./util')
|
|
6
|
+
|
|
7
|
+
class QueryTracingPlugin extends TracingPlugin {
|
|
8
|
+
static id = 'claude_agent_sdk_query'
|
|
9
|
+
static operation = 'turn'
|
|
10
|
+
static system = 'claude-agent-sdk'
|
|
11
|
+
static prefix = 'tracing:orchestrion:@anthropic-ai/claude-agent-sdk:query'
|
|
12
|
+
|
|
13
|
+
bindStart (ctx) {
|
|
14
|
+
this.startSpan('claude_agent_sdk.query', {
|
|
15
|
+
meta: { 'resource.name': 'claude_agent_sdk.query' },
|
|
16
|
+
startTime: ctx.startTime,
|
|
17
|
+
}, ctx)
|
|
18
|
+
ctx.runInContext = fn => storage('legacy').run(ctx.currentStore, fn)
|
|
19
|
+
return ctx.currentStore
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
asyncEnd (ctx) {
|
|
23
|
+
if (!ctx.streamResolved) return
|
|
24
|
+
|
|
25
|
+
ctx.currentStore?.span?.finish(ctx.finishTime)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
class StepTracingPlugin extends TracingPlugin {
|
|
30
|
+
static id = 'claude_agent_sdk_step'
|
|
31
|
+
static operation = 'step'
|
|
32
|
+
static system = 'claude-agent-sdk'
|
|
33
|
+
static prefix = 'tracing:apm:claude-agent-sdk:step'
|
|
34
|
+
|
|
35
|
+
bindStart (ctx) {
|
|
36
|
+
this.startSpan(`step-${ctx.stepIndex}`, {
|
|
37
|
+
meta: { 'resource.name': 'claude_agent_sdk.step' },
|
|
38
|
+
startTime: ctx.startTime,
|
|
39
|
+
}, ctx)
|
|
40
|
+
|
|
41
|
+
return ctx.currentStore
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
end (ctx) {
|
|
45
|
+
ctx.currentStore?.span?.finish(ctx.finishTime)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
class ToolTracingPlugin extends TracingPlugin {
|
|
50
|
+
static id = 'claude_agent_sdk_tool'
|
|
51
|
+
static operation = 'tool'
|
|
52
|
+
static system = 'claude-agent-sdk'
|
|
53
|
+
static prefix = 'tracing:apm:claude-agent-sdk:tool'
|
|
54
|
+
|
|
55
|
+
bindStart (ctx) {
|
|
56
|
+
const toolName = ctx.name || 'claude_agent_sdk.tool'
|
|
57
|
+
|
|
58
|
+
this.startSpan(toolName, {
|
|
59
|
+
meta: { 'resource.name': 'claude_agent_sdk.tool' },
|
|
60
|
+
startTime: ctx.startTime,
|
|
61
|
+
}, ctx)
|
|
62
|
+
|
|
63
|
+
return ctx.currentStore
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
end (ctx) {
|
|
67
|
+
const span = ctx.currentStore?.span
|
|
68
|
+
if (ctx.error) this.addError(ctx.error, span)
|
|
69
|
+
span?.finish(ctx.finishTime)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
class LlmTracingPlugin extends TracingPlugin {
|
|
74
|
+
static id = 'claude_agent_sdk_llm'
|
|
75
|
+
static operation = 'llm'
|
|
76
|
+
static system = 'claude-agent-sdk'
|
|
77
|
+
static prefix = 'tracing:apm:claude-agent-sdk:llm'
|
|
78
|
+
|
|
79
|
+
bindStart (ctx) {
|
|
80
|
+
const { model } = ctx
|
|
81
|
+
|
|
82
|
+
const { modelName, modelProvider } = splitModel(model)
|
|
83
|
+
const name = modelName || 'claude_agent_sdk.llm'
|
|
84
|
+
|
|
85
|
+
this.startSpan(name, {
|
|
86
|
+
meta: {
|
|
87
|
+
'resource.name': 'claude_agent_sdk.llm',
|
|
88
|
+
'claude-agent-sdk.request.model_name': modelName,
|
|
89
|
+
'claude-agent-sdk.request.model_provider': modelProvider,
|
|
90
|
+
},
|
|
91
|
+
startTime: ctx.startTime,
|
|
92
|
+
}, ctx)
|
|
93
|
+
|
|
94
|
+
return ctx.currentStore
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
end (ctx) {
|
|
98
|
+
ctx.currentStore?.span?.finish(ctx.finishTime)
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
module.exports = [
|
|
103
|
+
QueryTracingPlugin,
|
|
104
|
+
StepTracingPlugin,
|
|
105
|
+
ToolTracingPlugin,
|
|
106
|
+
LlmTracingPlugin,
|
|
107
|
+
]
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Parse a model ID string into the model name and provider for claude agent sdk provided model IDs
|
|
5
|
+
* @param {string} model model id
|
|
6
|
+
* @returns {{ modelName: string, modelProvider: string }}
|
|
7
|
+
*/
|
|
8
|
+
function splitModel (model) {
|
|
9
|
+
if (!model) return { modelName: undefined, modelProvider: 'anthropic' }
|
|
10
|
+
const idx = model.indexOf('/')
|
|
11
|
+
if (idx === -1) return { modelName: model, modelProvider: 'anthropic' }
|
|
12
|
+
return { modelName: model.slice(idx + 1), modelProvider: model.slice(0, idx) }
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
module.exports = { splitModel }
|
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
// Capture real timers at module load time, before any test can install fake timers.
|
|
4
|
-
const realDateNow = Date.now.bind(Date)
|
|
5
|
-
const realSetTimeout = setTimeout
|
|
6
|
-
|
|
7
3
|
const CiPlugin = require('../../dd-trace/src/plugins/ci_plugin')
|
|
8
4
|
const { storage } = require('../../datadog-core')
|
|
9
5
|
const { getEnvironmentVariable } = require('../../dd-trace/src/config/helper')
|
|
@@ -54,9 +50,6 @@ const {
|
|
|
54
50
|
TELEMETRY_TEST_SESSION,
|
|
55
51
|
} = require('../../dd-trace/src/ci-visibility/telemetry')
|
|
56
52
|
|
|
57
|
-
const BREAKPOINT_HIT_GRACE_PERIOD_MS = 200
|
|
58
|
-
const BREAKPOINT_SET_GRACE_PERIOD_MS = 400
|
|
59
|
-
|
|
60
53
|
const isCucumberWorker = !!getEnvironmentVariable('CUCUMBER_WORKER_ID')
|
|
61
54
|
|
|
62
55
|
class CucumberPlugin extends CiPlugin {
|
|
@@ -130,7 +123,7 @@ class CucumberPlugin extends CiPlugin {
|
|
|
130
123
|
finishAllTraceSpans(this.testSessionSpan)
|
|
131
124
|
this.telemetry.count(TELEMETRY_TEST_SESSION, {
|
|
132
125
|
provider: this.ciProviderName,
|
|
133
|
-
autoInjected: !!this._tracerConfig.DD_CIVISIBILITY_AUTO_INSTRUMENTATION_PROVIDER,
|
|
126
|
+
autoInjected: !!this._tracerConfig.testOptimization.DD_CIVISIBILITY_AUTO_INSTRUMENTATION_PROVIDER,
|
|
134
127
|
})
|
|
135
128
|
|
|
136
129
|
this.libraryConfig = null
|
|
@@ -248,17 +241,14 @@ class CucumberPlugin extends CiPlugin {
|
|
|
248
241
|
ctx.currentStore = { ...store, span }
|
|
249
242
|
|
|
250
243
|
this.activeTestSpan = span
|
|
251
|
-
// Time we give the breakpoint to be hit
|
|
252
244
|
if (promises && this.runningTestProbe) {
|
|
253
|
-
promises.hitBreakpointPromise =
|
|
254
|
-
realSetTimeout(resolve, BREAKPOINT_HIT_GRACE_PERIOD_MS)
|
|
255
|
-
})
|
|
245
|
+
promises.hitBreakpointPromise = this.waitForDiBreakpointHits()
|
|
256
246
|
}
|
|
257
247
|
|
|
258
248
|
return ctx.currentStore
|
|
259
249
|
})
|
|
260
250
|
|
|
261
|
-
this.addSub('ci:cucumber:test:retry', ({ span, isFirstAttempt, error, isAtrRetry }) => {
|
|
251
|
+
this.addSub('ci:cucumber:test:retry', ({ span, isFirstAttempt, error, isAtrRetry, promises, canWaitForDi }) => {
|
|
262
252
|
if (!isFirstAttempt) {
|
|
263
253
|
span.setTag(TEST_IS_RETRY, 'true')
|
|
264
254
|
if (isAtrRetry) {
|
|
@@ -268,18 +258,18 @@ class CucumberPlugin extends CiPlugin {
|
|
|
268
258
|
}
|
|
269
259
|
}
|
|
270
260
|
span.setTag('error', error)
|
|
271
|
-
if (
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
// However, Cucumber doesn't have a mechanism for waiting asyncrounously here, so for now, we'll have to
|
|
281
|
-
// fall back to a fixed syncronous delay.
|
|
261
|
+
if (canWaitForDi !== false && promises && this.di && error && this.libraryConfig?.isDiEnabled) {
|
|
262
|
+
if (isFirstAttempt) {
|
|
263
|
+
const probeInformation = this.addDiProbe(error)
|
|
264
|
+
if (probeInformation) {
|
|
265
|
+
const { file, line, stackIndex, setProbePromise } = probeInformation
|
|
266
|
+
this.runningTestProbe = { file, line }
|
|
267
|
+
this.testErrorStackIndex = stackIndex
|
|
268
|
+
this.prepareDiBreakpointHitWait()
|
|
269
|
+
promises.setProbePromise = this.waitForDiOperation(setProbePromise)
|
|
282
270
|
}
|
|
271
|
+
} else if (this.runningTestProbe) {
|
|
272
|
+
this.prepareDiBreakpointHitWait()
|
|
283
273
|
}
|
|
284
274
|
}
|
|
285
275
|
span.setTag(TEST_STATUS, 'fail')
|
|
@@ -410,6 +400,7 @@ class CucumberPlugin extends CiPlugin {
|
|
|
410
400
|
this.tracer._exporter.flush()
|
|
411
401
|
}
|
|
412
402
|
this.activeTestSpan = null
|
|
403
|
+
this.cancelDiBreakpointHitWait()
|
|
413
404
|
if (this.runningTestProbe) {
|
|
414
405
|
this.removeDiProbe(this.runningTestProbe)
|
|
415
406
|
this.runningTestProbe = null
|