dd-trace 5.98.0 → 5.99.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 +0 -1
- package/ext/tags.js +1 -0
- package/index.d.ts +9 -1
- package/package.json +48 -46
- package/packages/datadog-instrumentations/src/crypto.js +45 -0
- package/packages/datadog-instrumentations/src/cypress-config.js +122 -16
- package/packages/datadog-instrumentations/src/dns.js +24 -56
- package/packages/datadog-instrumentations/src/graphql.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +74 -0
- package/packages/datadog-instrumentations/src/helpers/check-require-cache.js +4 -1
- package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/compiler.js +10 -3
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/modelcontextprotocol-sdk.js +59 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +11 -2
- package/packages/datadog-instrumentations/src/modelcontextprotocol-sdk.js +7 -0
- package/packages/datadog-instrumentations/src/pino.js +4 -28
- package/packages/datadog-instrumentations/src/playwright-browser-scripts.js +27 -0
- package/packages/datadog-instrumentations/src/playwright.js +5 -17
- package/packages/datadog-instrumentations/src/stripe.js +38 -24
- package/packages/datadog-instrumentations/src/vitest.js +32 -4
- package/packages/datadog-instrumentations/src/zlib.js +29 -0
- package/packages/datadog-plugin-aws-sdk/src/base.js +1 -2
- package/packages/datadog-plugin-azure-event-hubs/src/producer.js +8 -15
- package/packages/datadog-plugin-azure-service-bus/src/producer.js +4 -9
- package/packages/datadog-plugin-cucumber/src/index.js +2 -2
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +5 -5
- package/packages/datadog-plugin-cypress/src/source-map-utils.js +48 -1
- package/packages/datadog-plugin-http/src/server.js +11 -11
- package/packages/datadog-plugin-jest/src/index.js +2 -2
- package/packages/datadog-plugin-mocha/src/index.js +1 -2
- package/packages/datadog-plugin-modelcontextprotocol-sdk/src/index.js +24 -0
- package/packages/datadog-plugin-modelcontextprotocol-sdk/src/tracing.js +55 -0
- package/packages/datadog-plugin-mongodb-core/src/index.js +1 -6
- package/packages/datadog-plugin-playwright/src/index.js +2 -3
- package/packages/datadog-plugin-vitest/src/index.js +14 -6
- package/packages/datadog-plugin-ws/src/close.js +2 -0
- package/packages/datadog-plugin-ws/src/producer.js +2 -0
- package/packages/datadog-plugin-ws/src/receiver.js +1 -0
- package/packages/dd-trace/src/aiguard/channels.js +8 -0
- package/packages/dd-trace/src/aiguard/index.js +7 -3
- package/packages/dd-trace/src/aiguard/sdk.js +44 -0
- package/packages/dd-trace/src/aiguard/tags.js +1 -0
- package/packages/dd-trace/src/appsec/graphql.js +6 -6
- package/packages/dd-trace/src/appsec/index.js +9 -11
- package/packages/dd-trace/src/appsec/rasp/command_injection.js +4 -5
- package/packages/dd-trace/src/appsec/rasp/lfi.js +8 -4
- package/packages/dd-trace/src/appsec/rasp/sql_injection.js +5 -10
- package/packages/dd-trace/src/appsec/rasp/ssrf.js +5 -6
- package/packages/dd-trace/src/appsec/recommended.json +2438 -13
- package/packages/dd-trace/src/appsec/reporter.js +6 -5
- package/packages/dd-trace/src/appsec/sdk/user_blocking.js +4 -8
- package/packages/dd-trace/src/appsec/store.js +50 -0
- package/packages/dd-trace/src/appsec/waf/index.js +3 -5
- package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +2 -2
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +2 -2
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +2 -2
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +2 -2
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +3 -4
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +2 -2
- package/packages/dd-trace/src/ci-visibility/log-submission/log-submission-plugin.js +4 -5
- package/packages/dd-trace/src/ci-visibility/requests/fs-cache.js +3 -4
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +6 -6
- package/packages/dd-trace/src/ci-visibility/requests/upload-coverage-report.js +2 -2
- package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +2 -2
- package/packages/dd-trace/src/config/config-types.d.ts +0 -4
- package/packages/dd-trace/src/config/defaults.js +10 -10
- package/packages/dd-trace/src/config/generated-config-types.d.ts +13 -12
- package/packages/dd-trace/src/config/index.js +25 -35
- package/packages/dd-trace/src/config/parsers.js +26 -9
- package/packages/dd-trace/src/config/supported-configurations.json +32 -36
- package/packages/dd-trace/src/debugger/config.js +2 -0
- package/packages/dd-trace/src/debugger/devtools_client/send.js +25 -5
- package/packages/dd-trace/src/encode/0.4.js +4 -5
- package/packages/dd-trace/src/exporters/agent/index.js +0 -1
- package/packages/dd-trace/src/exporters/agent/writer.js +1 -2
- package/packages/dd-trace/src/exporters/agentless/writer.js +3 -3
- package/packages/dd-trace/src/exporters/common/util.js +2 -2
- package/packages/dd-trace/src/id.js +2 -0
- package/packages/dd-trace/src/index.js +2 -5
- package/packages/dd-trace/src/lambda/handler.js +1 -3
- package/packages/dd-trace/src/llmobs/plugins/{anthropic.js → anthropic/index.js} +5 -63
- package/packages/dd-trace/src/llmobs/plugins/anthropic/util.js +106 -0
- package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/chain.js +3 -2
- package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/chat_model.js +3 -2
- package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/embedding.js +2 -1
- package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +0 -49
- package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/vectorstore.js +2 -1
- package/packages/dd-trace/src/llmobs/plugins/langchain/messages.js +76 -0
- package/packages/dd-trace/src/llmobs/plugins/langgraph/index.js +1 -26
- package/packages/dd-trace/src/llmobs/plugins/modelcontextprotocol-sdk/index.js +68 -0
- package/packages/dd-trace/src/llmobs/plugins/modelcontextprotocol-sdk/utils.js +57 -0
- package/packages/dd-trace/src/llmobs/sdk.js +2 -2
- package/packages/dd-trace/src/openfeature/eval-metrics-hook.js +103 -0
- package/packages/dd-trace/src/openfeature/flagging_provider.js +3 -0
- package/packages/dd-trace/src/opentelemetry/logs/index.js +1 -1
- package/packages/dd-trace/src/opentelemetry/logs/otlp_http_log_exporter.js +3 -2
- package/packages/dd-trace/src/opentelemetry/metrics/index.js +1 -1
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_http_metric_exporter.js +3 -2
- package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +19 -66
- package/packages/dd-trace/src/opentelemetry/trace/index.js +11 -16
- package/packages/dd-trace/src/opentelemetry/trace/otlp_http_trace_exporter.js +11 -3
- package/packages/dd-trace/src/opentelemetry/trace/otlp_transformer.js +51 -41
- package/packages/dd-trace/src/opentelemetry/tracer.js +9 -11
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +17 -10
- package/packages/dd-trace/src/opentracing/span.js +1 -1
- package/packages/dd-trace/src/opentracing/tracer.js +12 -5
- package/packages/dd-trace/src/plugins/index.js +1 -0
- package/packages/dd-trace/src/plugins/util/test.js +126 -5
- package/packages/dd-trace/src/plugins/util/url.js +2 -1
- package/packages/dd-trace/src/profiling/profilers/event_plugins/crypto.js +32 -0
- package/packages/dd-trace/src/profiling/profilers/event_plugins/zlib.js +19 -0
- package/packages/dd-trace/src/profiling/profilers/events.js +35 -0
- package/packages/dd-trace/src/proxy.js +2 -8
- package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +2 -2
- package/packages/dd-trace/src/service-naming/schemas/v0/web.js +4 -0
- package/packages/dd-trace/src/service-naming/schemas/v1/web.js +4 -0
- package/packages/dd-trace/src/span_processor.js +1 -2
- package/packages/dd-trace/src/tagger.js +2 -2
- package/packages/dd-trace/src/telemetry/send-data.js +5 -7
- package/packages/dd-trace/src/tracer.js +2 -2
- package/vendor/dist/ignore/LICENSE +0 -21
- package/vendor/dist/ignore/index.js +0 -1
|
@@ -6,7 +6,7 @@ const realSetTimeout = setTimeout
|
|
|
6
6
|
|
|
7
7
|
const CiPlugin = require('../../dd-trace/src/plugins/ci_plugin')
|
|
8
8
|
const { storage } = require('../../datadog-core')
|
|
9
|
-
const { getEnvironmentVariable
|
|
9
|
+
const { getEnvironmentVariable } = require('../../dd-trace/src/config/helper')
|
|
10
10
|
|
|
11
11
|
const {
|
|
12
12
|
addIntelligentTestRunnerSpanTags,
|
|
@@ -117,7 +117,7 @@ class CucumberPlugin extends CiPlugin {
|
|
|
117
117
|
finishAllTraceSpans(this.testSessionSpan)
|
|
118
118
|
this.telemetry.count(TELEMETRY_TEST_SESSION, {
|
|
119
119
|
provider: this.ciProviderName,
|
|
120
|
-
autoInjected: !!
|
|
120
|
+
autoInjected: !!this._tracerConfig.DD_CIVISIBILITY_AUTO_INSTRUMENTATION_PROVIDER,
|
|
121
121
|
})
|
|
122
122
|
|
|
123
123
|
this.libraryConfig = null
|
|
@@ -100,7 +100,7 @@ const {
|
|
|
100
100
|
} = require('../../dd-trace/src/plugins/util/env')
|
|
101
101
|
const { DD_MAJOR } = require('../../../version')
|
|
102
102
|
const {
|
|
103
|
-
|
|
103
|
+
resolveOriginalSourceFile,
|
|
104
104
|
resolveSourceLineForTest,
|
|
105
105
|
shouldTrustInvocationDetailsLine,
|
|
106
106
|
} = require('./source-map-utils')
|
|
@@ -518,8 +518,7 @@ class CypressPlugin {
|
|
|
518
518
|
this.ciVisEvent(TELEMETRY_EVENT_CREATED, 'suite')
|
|
519
519
|
|
|
520
520
|
if (testSuiteAbsolutePath) {
|
|
521
|
-
const
|
|
522
|
-
const resolvedSuiteAbsolutePath = resolvedSuitePosition ? resolvedSuitePosition.sourceFile : testSuiteAbsolutePath
|
|
521
|
+
const resolvedSuiteAbsolutePath = resolveOriginalSourceFile(testSuiteAbsolutePath) || testSuiteAbsolutePath
|
|
523
522
|
const testSourceFile = getTestSuitePath(resolvedSuiteAbsolutePath, this.repositoryRoot)
|
|
524
523
|
testSuiteSpanMetadata[TEST_SOURCE_FILE] = testSourceFile
|
|
525
524
|
testSuiteSpanMetadata[TEST_SOURCE_START] = 1
|
|
@@ -950,8 +949,9 @@ class CypressPlugin {
|
|
|
950
949
|
if (this.itrCorrelationId) {
|
|
951
950
|
finishedTest.testSpan.setTag(ITR_CORRELATION_ID, this.itrCorrelationId)
|
|
952
951
|
}
|
|
953
|
-
const
|
|
954
|
-
|
|
952
|
+
const resolvedSpecAbsolutePath = spec.absolute
|
|
953
|
+
? resolveOriginalSourceFile(spec.absolute) || spec.absolute
|
|
954
|
+
: spec.absolute
|
|
955
955
|
const testSourceFile = resolvedSpecAbsolutePath && this.repositoryRoot
|
|
956
956
|
? getTestSuitePath(resolvedSpecAbsolutePath, this.repositoryRoot)
|
|
957
957
|
: spec.relative
|
|
@@ -165,6 +165,48 @@ function resolveOriginalSourcePosition (absoluteFilePath, generatedLine) {
|
|
|
165
165
|
return null
|
|
166
166
|
}
|
|
167
167
|
|
|
168
|
+
/**
|
|
169
|
+
* Given a generated file's absolute path, returns the first original source file
|
|
170
|
+
* referenced by its source map. This is useful for file-level metadata when the
|
|
171
|
+
* first generated line has no source mapping, such as TypeScript-emitted prologue
|
|
172
|
+
* statements.
|
|
173
|
+
* @param {string} absoluteFilePath - Absolute path to the generated file
|
|
174
|
+
* @returns {string | null}
|
|
175
|
+
*/
|
|
176
|
+
function resolveOriginalSourceFile (absoluteFilePath) {
|
|
177
|
+
const sourceMap = getCachedSourceMap(absoluteFilePath)
|
|
178
|
+
if (!sourceMap) return null
|
|
179
|
+
const { mappings, sources, sourceRoot } = sourceMap
|
|
180
|
+
if (!mappings || !sources?.length) return null
|
|
181
|
+
|
|
182
|
+
const mapDir = path.dirname(absoluteFilePath)
|
|
183
|
+
const cursor = { pos: 0 }
|
|
184
|
+
let srcFile = 0
|
|
185
|
+
|
|
186
|
+
const lines = mappings.split(';')
|
|
187
|
+
for (const line of lines) {
|
|
188
|
+
if (!line) continue
|
|
189
|
+
cursor.pos = 0
|
|
190
|
+
while (cursor.pos < line.length) {
|
|
191
|
+
decodeVLQ(line, cursor) // genCol - not needed
|
|
192
|
+
if (cursor.pos < line.length && line[cursor.pos] !== ',') {
|
|
193
|
+
srcFile += decodeVLQ(line, cursor)
|
|
194
|
+
decodeVLQ(line, cursor) // srcLine - not needed
|
|
195
|
+
decodeVLQ(line, cursor) // srcCol - not needed
|
|
196
|
+
if (cursor.pos < line.length && line[cursor.pos] !== ',') {
|
|
197
|
+
decodeVLQ(line, cursor) // namesIndex - not needed
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const sourcePath = sources[srcFile]
|
|
201
|
+
if (!sourcePath) return null
|
|
202
|
+
return resolveSourcePath(mapDir, sourceRoot, sourcePath)
|
|
203
|
+
}
|
|
204
|
+
if (cursor.pos < line.length && line[cursor.pos] === ',') cursor.pos++
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return null
|
|
208
|
+
}
|
|
209
|
+
|
|
168
210
|
/**
|
|
169
211
|
* Convert a template literal body (the text between backticks, with `${…}` interpolations)
|
|
170
212
|
* into a regex that matches the runtime-evaluated string. Each `${…}` expression is replaced
|
|
@@ -294,4 +336,9 @@ function resolveSourceLineForTest (absoluteFilePath, testName, invocationStack)
|
|
|
294
336
|
return null
|
|
295
337
|
}
|
|
296
338
|
|
|
297
|
-
module.exports = {
|
|
339
|
+
module.exports = {
|
|
340
|
+
resolveOriginalSourceFile,
|
|
341
|
+
resolveOriginalSourcePosition,
|
|
342
|
+
resolveSourceLineForTest,
|
|
343
|
+
shouldTrustInvocationDetailsLine,
|
|
344
|
+
}
|
|
@@ -2,10 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
const ServerPlugin = require('../../dd-trace/src/plugins/server')
|
|
4
4
|
const { storage } = require('../../datadog-core')
|
|
5
|
+
const { withRequest } = require('../../dd-trace/src/appsec/store')
|
|
5
6
|
const web = require('../../dd-trace/src/plugins/util/web')
|
|
6
7
|
const { incomingHttpRequestStart, incomingHttpRequestEnd } = require('../../dd-trace/src/appsec/channels')
|
|
7
8
|
const { COMPONENT, SVC_SRC_KEY } = require('../../dd-trace/src/constants')
|
|
8
9
|
|
|
10
|
+
const legacyStorage = storage('legacy')
|
|
11
|
+
|
|
9
12
|
class HttpServerPlugin extends ServerPlugin {
|
|
10
13
|
static id = 'http'
|
|
11
14
|
|
|
@@ -17,7 +20,7 @@ class HttpServerPlugin extends ServerPlugin {
|
|
|
17
20
|
}
|
|
18
21
|
|
|
19
22
|
start ({ req, res, abortController }) {
|
|
20
|
-
let store =
|
|
23
|
+
let store = legacyStorage.getStore()
|
|
21
24
|
const { name: schemaServiceName, source: schemaServiceSource } = this.serviceName()
|
|
22
25
|
const service = this.config.service || schemaServiceName
|
|
23
26
|
const serviceSource = (this.config.service && service !== this.tracer._service)
|
|
@@ -40,16 +43,13 @@ class HttpServerPlugin extends ServerPlugin {
|
|
|
40
43
|
span._integrationName = this.constructor.id
|
|
41
44
|
|
|
42
45
|
const context = web.getContext(req)
|
|
46
|
+
context.parentStore = store
|
|
43
47
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
// may be scheduled after the synchronous `request` event returns (e.g.
|
|
50
|
-
// Fastify).
|
|
51
|
-
if (incomingHttpRequestStart.hasSubscribers) {
|
|
52
|
-
store = { ...store, req, res }
|
|
48
|
+
const appsecActive = incomingHttpRequestStart.hasSubscribers
|
|
49
|
+
if (appsecActive) {
|
|
50
|
+
// AppSec, IAST, and AI Guard need req on the store so downstream
|
|
51
|
+
// subscribers can access them from the async context.
|
|
52
|
+
store = withRequest(store, req)
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
this.enter(span, store)
|
|
@@ -59,7 +59,7 @@ class HttpServerPlugin extends ServerPlugin {
|
|
|
59
59
|
context.instrumented = true
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
if (
|
|
62
|
+
if (appsecActive) {
|
|
63
63
|
incomingHttpRequestStart.publish({ req, res, abortController }) // TODO: no need to make a new object here
|
|
64
64
|
}
|
|
65
65
|
}
|
|
@@ -5,7 +5,7 @@ const realSetTimeout = setTimeout
|
|
|
5
5
|
|
|
6
6
|
const CiPlugin = require('../../dd-trace/src/plugins/ci_plugin')
|
|
7
7
|
const { storage } = require('../../datadog-core')
|
|
8
|
-
const { getEnvironmentVariable
|
|
8
|
+
const { getEnvironmentVariable } = require('../../dd-trace/src/config/helper')
|
|
9
9
|
const { appClosing: appClosingTelemetry } = require('../../dd-trace/src/telemetry')
|
|
10
10
|
|
|
11
11
|
const {
|
|
@@ -166,7 +166,7 @@ class JestPlugin extends CiPlugin {
|
|
|
166
166
|
|
|
167
167
|
this.telemetry.count(TELEMETRY_TEST_SESSION, {
|
|
168
168
|
provider: this.ciProviderName,
|
|
169
|
-
autoInjected: !!
|
|
169
|
+
autoInjected: !!this._tracerConfig.DD_CIVISIBILITY_AUTO_INSTRUMENTATION_PROVIDER,
|
|
170
170
|
})
|
|
171
171
|
|
|
172
172
|
appClosingTelemetry()
|
|
@@ -5,7 +5,6 @@ const realDateNow = Date.now.bind(Date)
|
|
|
5
5
|
|
|
6
6
|
const CiPlugin = require('../../dd-trace/src/plugins/ci_plugin')
|
|
7
7
|
const { storage } = require('../../datadog-core')
|
|
8
|
-
const { getValueFromEnvSources } = require('../../dd-trace/src/config/helper')
|
|
9
8
|
|
|
10
9
|
const {
|
|
11
10
|
TEST_STATUS,
|
|
@@ -406,7 +405,7 @@ class MochaPlugin extends CiPlugin {
|
|
|
406
405
|
finishAllTraceSpans(this.testSessionSpan)
|
|
407
406
|
this.telemetry.count(TELEMETRY_TEST_SESSION, {
|
|
408
407
|
provider: this.ciProviderName,
|
|
409
|
-
autoInjected: !!
|
|
408
|
+
autoInjected: !!this._tracerConfig.DD_CIVISIBILITY_AUTO_INSTRUMENTATION_PROVIDER,
|
|
410
409
|
})
|
|
411
410
|
}
|
|
412
411
|
this.libraryConfig = null
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const CompositePlugin = require('../../dd-trace/src/plugins/composite')
|
|
4
|
+
const mcpLLMObsPlugins = require('../../dd-trace/src/llmobs/plugins/modelcontextprotocol-sdk')
|
|
5
|
+
const tracingPlugins = require('./tracing')
|
|
6
|
+
|
|
7
|
+
const plugins = {}
|
|
8
|
+
|
|
9
|
+
// CRITICAL: LLMObs plugins MUST come first
|
|
10
|
+
for (const Plugin of mcpLLMObsPlugins) {
|
|
11
|
+
plugins[Plugin.id] = Plugin
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Tracing plugins second
|
|
15
|
+
for (const Plugin of tracingPlugins) {
|
|
16
|
+
plugins[Plugin.id] = Plugin
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
class ModelcontextprotocolSdkPlugin extends CompositePlugin {
|
|
20
|
+
static id = 'modelcontextprotocol-sdk'
|
|
21
|
+
static plugins = plugins
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
module.exports = ModelcontextprotocolSdkPlugin
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const TracingPlugin = require('../../dd-trace/src/plugins/tracing')
|
|
4
|
+
|
|
5
|
+
class McpToolCallPlugin extends TracingPlugin {
|
|
6
|
+
static id = 'modelcontextprotocol_client'
|
|
7
|
+
static prefix = 'tracing:orchestrion:@modelcontextprotocol/sdk:Client_callTool'
|
|
8
|
+
|
|
9
|
+
bindStart (ctx) {
|
|
10
|
+
const params = ctx.arguments?.[0]
|
|
11
|
+
const toolName = params?.name
|
|
12
|
+
|
|
13
|
+
this.startSpan('mcp.client.tool.call', {
|
|
14
|
+
resource: toolName,
|
|
15
|
+
type: 'mcp',
|
|
16
|
+
kind: 'client',
|
|
17
|
+
}, ctx)
|
|
18
|
+
|
|
19
|
+
return ctx.currentStore
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
asyncEnd (ctx) {
|
|
23
|
+
const result = ctx.result
|
|
24
|
+
if (result?.isError) {
|
|
25
|
+
const span = ctx.currentStore?.span
|
|
26
|
+
const errorText = result.content?.find?.(c => c.type === 'text')?.text || 'Tool call returned isError: true'
|
|
27
|
+
span?.setTag('error', new Error(errorText))
|
|
28
|
+
}
|
|
29
|
+
super.finish(ctx)
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
class McpListToolsPlugin extends TracingPlugin {
|
|
34
|
+
static id = 'modelcontextprotocol_list_tools'
|
|
35
|
+
static prefix = 'tracing:orchestrion:@modelcontextprotocol/sdk:Client_listTools'
|
|
36
|
+
|
|
37
|
+
bindStart (ctx) {
|
|
38
|
+
this.startSpan('mcp.tools.list', {
|
|
39
|
+
resource: 'tools/list',
|
|
40
|
+
type: 'mcp',
|
|
41
|
+
kind: 'client',
|
|
42
|
+
}, ctx)
|
|
43
|
+
|
|
44
|
+
return ctx.currentStore
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
asyncEnd (ctx) {
|
|
48
|
+
super.finish(ctx)
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
module.exports = [
|
|
53
|
+
McpToolCallPlugin,
|
|
54
|
+
McpListToolsPlugin,
|
|
55
|
+
]
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { isTrue } = require('../../dd-trace/src/util')
|
|
4
3
|
const DatabasePlugin = require('../../dd-trace/src/plugins/database')
|
|
5
|
-
const { getValueFromEnvSources } = require('../../dd-trace/src/config/helper')
|
|
6
4
|
|
|
7
5
|
class MongodbCorePlugin extends DatabasePlugin {
|
|
8
6
|
static id = 'mongodb-core'
|
|
@@ -20,11 +18,8 @@ class MongodbCorePlugin extends DatabasePlugin {
|
|
|
20
18
|
configure (config) {
|
|
21
19
|
super.configure(config)
|
|
22
20
|
|
|
23
|
-
const heartbeatFromEnv = getValueFromEnvSources('DD_TRACE_MONGODB_HEARTBEAT_ENABLED')
|
|
24
|
-
|
|
25
21
|
this.config.heartbeatEnabled = config.heartbeatEnabled ??
|
|
26
|
-
|
|
27
|
-
true
|
|
22
|
+
this._tracerConfig.DD_TRACE_MONGODB_HEARTBEAT_ENABLED
|
|
28
23
|
}
|
|
29
24
|
|
|
30
25
|
bindStart (ctx) {
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
const { storage } = require('../../datadog-core')
|
|
4
4
|
const id = require('../../dd-trace/src/id')
|
|
5
5
|
const CiPlugin = require('../../dd-trace/src/plugins/ci_plugin')
|
|
6
|
-
const { getValueFromEnvSources } = require('../../dd-trace/src/config/helper')
|
|
7
6
|
|
|
8
7
|
const {
|
|
9
8
|
finishAllTraceSpans,
|
|
@@ -108,7 +107,7 @@ class PlaywrightPlugin extends CiPlugin {
|
|
|
108
107
|
finishAllTraceSpans(this.testSessionSpan)
|
|
109
108
|
this.telemetry.count(TELEMETRY_TEST_SESSION, {
|
|
110
109
|
provider: this.ciProviderName,
|
|
111
|
-
autoInjected: !!
|
|
110
|
+
autoInjected: !!this._tracerConfig.DD_CIVISIBILITY_AUTO_INSTRUMENTATION_PROVIDER,
|
|
112
111
|
})
|
|
113
112
|
appClosingTelemetry()
|
|
114
113
|
this.tracer._exporter.flush(onDone)
|
|
@@ -420,7 +419,7 @@ class PlaywrightPlugin extends CiPlugin {
|
|
|
420
419
|
span.finish()
|
|
421
420
|
|
|
422
421
|
finishAllTraceSpans(span)
|
|
423
|
-
if (
|
|
422
|
+
if (this._tracerConfig.DD_PLAYWRIGHT_WORKER) {
|
|
424
423
|
this.tracer._exporter.flush(onDone)
|
|
425
424
|
}
|
|
426
425
|
})
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
const CiPlugin = require('../../dd-trace/src/plugins/ci_plugin')
|
|
4
4
|
const { storage } = require('../../datadog-core')
|
|
5
|
-
const { getValueFromEnvSources } = require('../../dd-trace/src/config/helper')
|
|
6
5
|
|
|
7
6
|
const {
|
|
8
7
|
TEST_STATUS,
|
|
@@ -34,6 +33,7 @@ const {
|
|
|
34
33
|
isModifiedTest,
|
|
35
34
|
TEST_IS_MODIFIED,
|
|
36
35
|
TEST_HAS_DYNAMIC_NAME,
|
|
36
|
+
TEST_FINAL_STATUS,
|
|
37
37
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
38
38
|
const { COMPONENT } = require('../../dd-trace/src/constants')
|
|
39
39
|
const {
|
|
@@ -213,10 +213,13 @@ class VitestPlugin extends CiPlugin {
|
|
|
213
213
|
return ctx.currentStore
|
|
214
214
|
})
|
|
215
215
|
|
|
216
|
-
this.addSub('ci:vitest:test:pass', ({ span, task }) => {
|
|
216
|
+
this.addSub('ci:vitest:test:pass', ({ span, task, finalStatus }) => {
|
|
217
217
|
if (span) {
|
|
218
218
|
this.telemetry.ciVisEvent(TELEMETRY_EVENT_FINISHED, 'test', this.getTestTelemetryTags(span))
|
|
219
219
|
span.setTag(TEST_STATUS, 'pass')
|
|
220
|
+
if (finalStatus) {
|
|
221
|
+
span.setTag(TEST_FINAL_STATUS, finalStatus)
|
|
222
|
+
}
|
|
220
223
|
span.finish(this.taskToFinishTime.get(task))
|
|
221
224
|
finishAllTraceSpans(span)
|
|
222
225
|
}
|
|
@@ -230,6 +233,7 @@ class VitestPlugin extends CiPlugin {
|
|
|
230
233
|
promises,
|
|
231
234
|
hasFailedAllRetries,
|
|
232
235
|
attemptToFixFailed,
|
|
236
|
+
finalStatus,
|
|
233
237
|
}) => {
|
|
234
238
|
if (!span) {
|
|
235
239
|
return
|
|
@@ -255,6 +259,9 @@ class VitestPlugin extends CiPlugin {
|
|
|
255
259
|
if (attemptToFixFailed) {
|
|
256
260
|
span.setTag(TEST_MANAGEMENT_ATTEMPT_TO_FIX_PASSED, 'false')
|
|
257
261
|
}
|
|
262
|
+
if (finalStatus) {
|
|
263
|
+
span.setTag(TEST_FINAL_STATUS, finalStatus)
|
|
264
|
+
}
|
|
258
265
|
if (duration) {
|
|
259
266
|
span.finish(span._startTime + duration - MILLISECONDS_TO_SUBTRACT_FROM_FAILED_TEST_DURATION) // milliseconds
|
|
260
267
|
} else {
|
|
@@ -273,6 +280,7 @@ class VitestPlugin extends CiPlugin {
|
|
|
273
280
|
[TEST_SOURCE_FILE]: testSuite,
|
|
274
281
|
[TEST_SOURCE_START]: 1, // we can't get the proper start line in vitest
|
|
275
282
|
[TEST_STATUS]: 'skip',
|
|
283
|
+
[TEST_FINAL_STATUS]: 'skip',
|
|
276
284
|
...(isDisabled ? { [TEST_MANAGEMENT_IS_DISABLED]: 'true' } : {}),
|
|
277
285
|
...(isNew ? { [TEST_IS_NEW]: 'true' } : {}),
|
|
278
286
|
}
|
|
@@ -285,12 +293,12 @@ class VitestPlugin extends CiPlugin {
|
|
|
285
293
|
const { testSuiteAbsolutePath, frameworkVersion } = ctx
|
|
286
294
|
|
|
287
295
|
// TODO: Handle case where the command is not set
|
|
288
|
-
this.command =
|
|
296
|
+
this.command = this._tracerConfig.DD_CIVISIBILITY_TEST_COMMAND
|
|
289
297
|
this.frameworkVersion = frameworkVersion
|
|
290
298
|
const testSessionSpanContext = this.tracer.extract('text_map', {
|
|
291
299
|
// TODO: Handle case where the session ID or module ID is not set
|
|
292
|
-
'x-datadog-trace-id':
|
|
293
|
-
'x-datadog-parent-id':
|
|
300
|
+
'x-datadog-trace-id': this._tracerConfig.DD_CIVISIBILITY_TEST_SESSION_ID,
|
|
301
|
+
'x-datadog-parent-id': this._tracerConfig.DD_CIVISIBILITY_TEST_MODULE_ID,
|
|
294
302
|
})
|
|
295
303
|
|
|
296
304
|
const trimmedCommand = DD_MAJOR < 6 ? this.command : 'vitest run'
|
|
@@ -415,7 +423,7 @@ class VitestPlugin extends CiPlugin {
|
|
|
415
423
|
finishAllTraceSpans(this.testSessionSpan)
|
|
416
424
|
this.telemetry.count(TELEMETRY_TEST_SESSION, {
|
|
417
425
|
provider: this.ciProviderName,
|
|
418
|
-
autoInjected: !!
|
|
426
|
+
autoInjected: !!this._tracerConfig.DD_CIVISIBILITY_AUTO_INSTRUMENTATION_PROVIDER,
|
|
419
427
|
})
|
|
420
428
|
this.tracer._exporter.flush(onFinish)
|
|
421
429
|
})
|
|
@@ -57,11 +57,13 @@ class WSClosePlugin extends TracingPlugin {
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
bindAsyncStart (ctx) {
|
|
60
|
+
if (!ctx.span) return ctx.parentStore
|
|
60
61
|
if (!ctx.isPeerClose) ctx.span.finish()
|
|
61
62
|
return ctx.parentStore
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
asyncStart (ctx) {
|
|
66
|
+
if (!ctx.span) return
|
|
65
67
|
ctx.span.finish()
|
|
66
68
|
}
|
|
67
69
|
|
|
@@ -46,11 +46,13 @@ class WSProducerPlugin extends TracingPlugin {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
bindAsyncStart (ctx) {
|
|
49
|
+
if (!ctx.span) return ctx.parentStore
|
|
49
50
|
ctx.span.finish()
|
|
50
51
|
return ctx.parentStore
|
|
51
52
|
}
|
|
52
53
|
|
|
53
54
|
asyncStart (ctx) {
|
|
55
|
+
if (!ctx.span) return
|
|
54
56
|
ctx.span.finish()
|
|
55
57
|
}
|
|
56
58
|
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { channel } = require('dc-polyfill')
|
|
4
3
|
const log = require('../log')
|
|
4
|
+
const { incomingHttpRequestStart, aiguardChannel } = require('./channels')
|
|
5
5
|
const AIGuard = require('./sdk')
|
|
6
6
|
|
|
7
|
-
const aiguardChannel = channel('dd-trace:ai:aiguard')
|
|
8
|
-
|
|
9
7
|
let isEnabled = false
|
|
10
8
|
let aiguard
|
|
11
9
|
let block
|
|
12
10
|
|
|
11
|
+
function onIncomingHttpRequestStart () {
|
|
12
|
+
// No-op: subscribing ensures the HTTP plugin spreads req onto the store
|
|
13
|
+
}
|
|
14
|
+
|
|
13
15
|
function enable (tracer, config) {
|
|
14
16
|
if (isEnabled) return
|
|
15
17
|
|
|
@@ -17,6 +19,7 @@ function enable (tracer, config) {
|
|
|
17
19
|
aiguard = new AIGuard(tracer, config)
|
|
18
20
|
block = config.experimental?.aiguard?.block !== false
|
|
19
21
|
|
|
22
|
+
incomingHttpRequestStart.subscribe(onIncomingHttpRequestStart)
|
|
20
23
|
aiguardChannel.subscribe(onEvaluate)
|
|
21
24
|
|
|
22
25
|
isEnabled = true
|
|
@@ -29,6 +32,7 @@ function enable (tracer, config) {
|
|
|
29
32
|
function disable () {
|
|
30
33
|
if (!isEnabled) return
|
|
31
34
|
|
|
35
|
+
incomingHttpRequestStart.unsubscribe(onIncomingHttpRequestStart)
|
|
32
36
|
aiguardChannel.unsubscribe(onEvaluate)
|
|
33
37
|
|
|
34
38
|
aiguard = undefined
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const rfdc = require('../../../../vendor/dist/rfdc')({ proto: false, circles: false })
|
|
4
|
+
const { HTTP_CLIENT_IP, NETWORK_CLIENT_IP } = require('../../../../ext/tags')
|
|
5
|
+
const { getActiveRequest } = require('../appsec/store')
|
|
4
6
|
const log = require('../log')
|
|
7
|
+
const { extractIp } = require('../plugins/util/ip_extractor')
|
|
5
8
|
const telemetryMetrics = require('../telemetry/metrics')
|
|
6
9
|
const tracerVersion = require('../../../../package.json').version
|
|
7
10
|
const { keepTrace } = require('../priority_sampler')
|
|
@@ -13,6 +16,7 @@ const {
|
|
|
13
16
|
AI_GUARD_TARGET_TAG_KEY,
|
|
14
17
|
AI_GUARD_REASON_TAG_KEY,
|
|
15
18
|
AI_GUARD_ACTION_TAG_KEY,
|
|
19
|
+
AI_GUARD_EVENT_TAG_KEY,
|
|
16
20
|
AI_GUARD_BLOCKED_TAG_KEY,
|
|
17
21
|
AI_GUARD_META_STRUCT_KEY,
|
|
18
22
|
AI_GUARD_TOOL_NAME_TAG_KEY,
|
|
@@ -57,6 +61,7 @@ class AIGuard extends NoopAIGuard {
|
|
|
57
61
|
#maxMessagesLength
|
|
58
62
|
#maxContentSize
|
|
59
63
|
#meta
|
|
64
|
+
#config
|
|
60
65
|
|
|
61
66
|
/**
|
|
62
67
|
* @param {import('../tracer')} tracer - Tracer instance
|
|
@@ -84,6 +89,7 @@ class AIGuard extends NoopAIGuard {
|
|
|
84
89
|
this.#maxMessagesLength = config.experimental.aiguard.maxMessagesLength
|
|
85
90
|
this.#maxContentSize = config.experimental.aiguard.maxContentSize
|
|
86
91
|
this.#meta = { service: config.service, env: config.env }
|
|
92
|
+
this.#config = config
|
|
87
93
|
this.#initialized = true
|
|
88
94
|
}
|
|
89
95
|
|
|
@@ -139,6 +145,42 @@ class AIGuard extends NoopAIGuard {
|
|
|
139
145
|
return null
|
|
140
146
|
}
|
|
141
147
|
|
|
148
|
+
#setRootSpanClientIpTags (rootSpan) {
|
|
149
|
+
if (!rootSpan) return
|
|
150
|
+
|
|
151
|
+
const currentTags = rootSpan.context()._tags
|
|
152
|
+
const needsHttpClientIp = !Object.hasOwn(currentTags, HTTP_CLIENT_IP)
|
|
153
|
+
const needsNetworkClientIp = !Object.hasOwn(currentTags, NETWORK_CLIENT_IP)
|
|
154
|
+
|
|
155
|
+
if (!needsHttpClientIp && !needsNetworkClientIp) return
|
|
156
|
+
|
|
157
|
+
const req = getActiveRequest()
|
|
158
|
+
|
|
159
|
+
if (!req) return
|
|
160
|
+
|
|
161
|
+
const newTags = {}
|
|
162
|
+
|
|
163
|
+
if (needsHttpClientIp) {
|
|
164
|
+
const clientIp = extractIp(this.#config, req)
|
|
165
|
+
|
|
166
|
+
if (clientIp) {
|
|
167
|
+
newTags[HTTP_CLIENT_IP] = clientIp
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (needsNetworkClientIp) {
|
|
172
|
+
const networkClientIp = req.socket?.remoteAddress
|
|
173
|
+
|
|
174
|
+
if (networkClientIp) {
|
|
175
|
+
newTags[NETWORK_CLIENT_IP] = networkClientIp
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (Object.keys(newTags).length > 0) {
|
|
180
|
+
rootSpan.addTags(newTags)
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
142
184
|
evaluate (messages, opts) {
|
|
143
185
|
if (!this.#initialized) {
|
|
144
186
|
return super.evaluate(messages, opts)
|
|
@@ -162,9 +204,11 @@ class AIGuard extends NoopAIGuard {
|
|
|
162
204
|
}
|
|
163
205
|
const rootSpan = span.context()?._trace?.started?.[0]
|
|
164
206
|
if (rootSpan) {
|
|
207
|
+
this.#setRootSpanClientIpTags(rootSpan)
|
|
165
208
|
// keepTrace must be called before executeRequest so the sampling decision
|
|
166
209
|
// is propagated correctly to outgoing HTTP client calls.
|
|
167
210
|
keepTrace(rootSpan, AI_GUARD)
|
|
211
|
+
rootSpan.setTag(AI_GUARD_EVENT_TAG_KEY, 'true')
|
|
168
212
|
}
|
|
169
213
|
let response
|
|
170
214
|
try {
|
|
@@ -7,6 +7,7 @@ module.exports = {
|
|
|
7
7
|
AI_GUARD_ACTION_TAG_KEY: 'ai_guard.action',
|
|
8
8
|
AI_GUARD_REASON_TAG_KEY: 'ai_guard.reason',
|
|
9
9
|
AI_GUARD_BLOCKED_TAG_KEY: 'ai_guard.blocked',
|
|
10
|
+
AI_GUARD_EVENT_TAG_KEY: 'ai_guard.event',
|
|
10
11
|
AI_GUARD_META_STRUCT_KEY: 'ai_guard',
|
|
11
12
|
|
|
12
13
|
AI_GUARD_TELEMETRY_REQUESTS: 'ai_guard.requests',
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { storage } = require('../../../datadog-core')
|
|
4
3
|
const log = require('../log')
|
|
5
4
|
const web = require('../plugins/util/web')
|
|
5
|
+
const { getActiveRequest } = require('./store')
|
|
6
6
|
const {
|
|
7
7
|
addSpecificEndpoint,
|
|
8
8
|
specificBlockingTypes,
|
|
@@ -33,7 +33,7 @@ function disable () {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
function onGraphqlStartResolve ({ context, resolverInfo }) {
|
|
36
|
-
const req =
|
|
36
|
+
const req = getActiveRequest()
|
|
37
37
|
|
|
38
38
|
if (!req) return
|
|
39
39
|
|
|
@@ -52,7 +52,7 @@ function onGraphqlStartResolve ({ context, resolverInfo }) {
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
function enterInApolloMiddleware (data) {
|
|
55
|
-
const req = data?.req ||
|
|
55
|
+
const req = data?.req || getActiveRequest()
|
|
56
56
|
if (!req) return
|
|
57
57
|
|
|
58
58
|
graphqlRequestData.set(req, {
|
|
@@ -61,7 +61,7 @@ function enterInApolloMiddleware (data) {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
function enterInApolloServerCoreRequest () {
|
|
64
|
-
const req =
|
|
64
|
+
const req = getActiveRequest()
|
|
65
65
|
if (!req) return
|
|
66
66
|
|
|
67
67
|
graphqlRequestData.set(req, {
|
|
@@ -71,7 +71,7 @@ function enterInApolloServerCoreRequest () {
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
function enterInApolloRequest () {
|
|
74
|
-
const req =
|
|
74
|
+
const req = getActiveRequest()
|
|
75
75
|
|
|
76
76
|
const requestData = graphqlRequestData.get(req)
|
|
77
77
|
if (requestData) {
|
|
@@ -83,7 +83,7 @@ function enterInApolloRequest () {
|
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
function beforeWriteApolloGraphqlResponse ({ abortController, abortData }) {
|
|
86
|
-
const req =
|
|
86
|
+
const req = getActiveRequest()
|
|
87
87
|
if (!req) return
|
|
88
88
|
|
|
89
89
|
const requestData = graphqlRequestData.get(req)
|