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.
Files changed (123) hide show
  1. package/LICENSE-3rdparty.csv +0 -1
  2. package/ext/tags.js +1 -0
  3. package/index.d.ts +9 -1
  4. package/package.json +48 -46
  5. package/packages/datadog-instrumentations/src/crypto.js +45 -0
  6. package/packages/datadog-instrumentations/src/cypress-config.js +122 -16
  7. package/packages/datadog-instrumentations/src/dns.js +24 -56
  8. package/packages/datadog-instrumentations/src/graphql.js +1 -1
  9. package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +74 -0
  10. package/packages/datadog-instrumentations/src/helpers/check-require-cache.js +4 -1
  11. package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
  12. package/packages/datadog-instrumentations/src/helpers/rewriter/compiler.js +10 -3
  13. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
  14. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/modelcontextprotocol-sdk.js +59 -0
  15. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +11 -2
  16. package/packages/datadog-instrumentations/src/modelcontextprotocol-sdk.js +7 -0
  17. package/packages/datadog-instrumentations/src/pino.js +4 -28
  18. package/packages/datadog-instrumentations/src/playwright-browser-scripts.js +27 -0
  19. package/packages/datadog-instrumentations/src/playwright.js +5 -17
  20. package/packages/datadog-instrumentations/src/stripe.js +38 -24
  21. package/packages/datadog-instrumentations/src/vitest.js +32 -4
  22. package/packages/datadog-instrumentations/src/zlib.js +29 -0
  23. package/packages/datadog-plugin-aws-sdk/src/base.js +1 -2
  24. package/packages/datadog-plugin-azure-event-hubs/src/producer.js +8 -15
  25. package/packages/datadog-plugin-azure-service-bus/src/producer.js +4 -9
  26. package/packages/datadog-plugin-cucumber/src/index.js +2 -2
  27. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +5 -5
  28. package/packages/datadog-plugin-cypress/src/source-map-utils.js +48 -1
  29. package/packages/datadog-plugin-http/src/server.js +11 -11
  30. package/packages/datadog-plugin-jest/src/index.js +2 -2
  31. package/packages/datadog-plugin-mocha/src/index.js +1 -2
  32. package/packages/datadog-plugin-modelcontextprotocol-sdk/src/index.js +24 -0
  33. package/packages/datadog-plugin-modelcontextprotocol-sdk/src/tracing.js +55 -0
  34. package/packages/datadog-plugin-mongodb-core/src/index.js +1 -6
  35. package/packages/datadog-plugin-playwright/src/index.js +2 -3
  36. package/packages/datadog-plugin-vitest/src/index.js +14 -6
  37. package/packages/datadog-plugin-ws/src/close.js +2 -0
  38. package/packages/datadog-plugin-ws/src/producer.js +2 -0
  39. package/packages/datadog-plugin-ws/src/receiver.js +1 -0
  40. package/packages/dd-trace/src/aiguard/channels.js +8 -0
  41. package/packages/dd-trace/src/aiguard/index.js +7 -3
  42. package/packages/dd-trace/src/aiguard/sdk.js +44 -0
  43. package/packages/dd-trace/src/aiguard/tags.js +1 -0
  44. package/packages/dd-trace/src/appsec/graphql.js +6 -6
  45. package/packages/dd-trace/src/appsec/index.js +9 -11
  46. package/packages/dd-trace/src/appsec/rasp/command_injection.js +4 -5
  47. package/packages/dd-trace/src/appsec/rasp/lfi.js +8 -4
  48. package/packages/dd-trace/src/appsec/rasp/sql_injection.js +5 -10
  49. package/packages/dd-trace/src/appsec/rasp/ssrf.js +5 -6
  50. package/packages/dd-trace/src/appsec/recommended.json +2438 -13
  51. package/packages/dd-trace/src/appsec/reporter.js +6 -5
  52. package/packages/dd-trace/src/appsec/sdk/user_blocking.js +4 -8
  53. package/packages/dd-trace/src/appsec/store.js +50 -0
  54. package/packages/dd-trace/src/appsec/waf/index.js +3 -5
  55. package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +2 -2
  56. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +2 -2
  57. package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +2 -2
  58. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +2 -2
  59. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +3 -4
  60. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +2 -2
  61. package/packages/dd-trace/src/ci-visibility/log-submission/log-submission-plugin.js +4 -5
  62. package/packages/dd-trace/src/ci-visibility/requests/fs-cache.js +3 -4
  63. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +6 -6
  64. package/packages/dd-trace/src/ci-visibility/requests/upload-coverage-report.js +2 -2
  65. package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +2 -2
  66. package/packages/dd-trace/src/config/config-types.d.ts +0 -4
  67. package/packages/dd-trace/src/config/defaults.js +10 -10
  68. package/packages/dd-trace/src/config/generated-config-types.d.ts +13 -12
  69. package/packages/dd-trace/src/config/index.js +25 -35
  70. package/packages/dd-trace/src/config/parsers.js +26 -9
  71. package/packages/dd-trace/src/config/supported-configurations.json +32 -36
  72. package/packages/dd-trace/src/debugger/config.js +2 -0
  73. package/packages/dd-trace/src/debugger/devtools_client/send.js +25 -5
  74. package/packages/dd-trace/src/encode/0.4.js +4 -5
  75. package/packages/dd-trace/src/exporters/agent/index.js +0 -1
  76. package/packages/dd-trace/src/exporters/agent/writer.js +1 -2
  77. package/packages/dd-trace/src/exporters/agentless/writer.js +3 -3
  78. package/packages/dd-trace/src/exporters/common/util.js +2 -2
  79. package/packages/dd-trace/src/id.js +2 -0
  80. package/packages/dd-trace/src/index.js +2 -5
  81. package/packages/dd-trace/src/lambda/handler.js +1 -3
  82. package/packages/dd-trace/src/llmobs/plugins/{anthropic.js → anthropic/index.js} +5 -63
  83. package/packages/dd-trace/src/llmobs/plugins/anthropic/util.js +106 -0
  84. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/chain.js +3 -2
  85. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/chat_model.js +3 -2
  86. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/embedding.js +2 -1
  87. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +0 -49
  88. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/vectorstore.js +2 -1
  89. package/packages/dd-trace/src/llmobs/plugins/langchain/messages.js +76 -0
  90. package/packages/dd-trace/src/llmobs/plugins/langgraph/index.js +1 -26
  91. package/packages/dd-trace/src/llmobs/plugins/modelcontextprotocol-sdk/index.js +68 -0
  92. package/packages/dd-trace/src/llmobs/plugins/modelcontextprotocol-sdk/utils.js +57 -0
  93. package/packages/dd-trace/src/llmobs/sdk.js +2 -2
  94. package/packages/dd-trace/src/openfeature/eval-metrics-hook.js +103 -0
  95. package/packages/dd-trace/src/openfeature/flagging_provider.js +3 -0
  96. package/packages/dd-trace/src/opentelemetry/logs/index.js +1 -1
  97. package/packages/dd-trace/src/opentelemetry/logs/otlp_http_log_exporter.js +3 -2
  98. package/packages/dd-trace/src/opentelemetry/metrics/index.js +1 -1
  99. package/packages/dd-trace/src/opentelemetry/metrics/otlp_http_metric_exporter.js +3 -2
  100. package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +19 -66
  101. package/packages/dd-trace/src/opentelemetry/trace/index.js +11 -16
  102. package/packages/dd-trace/src/opentelemetry/trace/otlp_http_trace_exporter.js +11 -3
  103. package/packages/dd-trace/src/opentelemetry/trace/otlp_transformer.js +51 -41
  104. package/packages/dd-trace/src/opentelemetry/tracer.js +9 -11
  105. package/packages/dd-trace/src/opentracing/propagation/text_map.js +17 -10
  106. package/packages/dd-trace/src/opentracing/span.js +1 -1
  107. package/packages/dd-trace/src/opentracing/tracer.js +12 -5
  108. package/packages/dd-trace/src/plugins/index.js +1 -0
  109. package/packages/dd-trace/src/plugins/util/test.js +126 -5
  110. package/packages/dd-trace/src/plugins/util/url.js +2 -1
  111. package/packages/dd-trace/src/profiling/profilers/event_plugins/crypto.js +32 -0
  112. package/packages/dd-trace/src/profiling/profilers/event_plugins/zlib.js +19 -0
  113. package/packages/dd-trace/src/profiling/profilers/events.js +35 -0
  114. package/packages/dd-trace/src/proxy.js +2 -8
  115. package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +2 -2
  116. package/packages/dd-trace/src/service-naming/schemas/v0/web.js +4 -0
  117. package/packages/dd-trace/src/service-naming/schemas/v1/web.js +4 -0
  118. package/packages/dd-trace/src/span_processor.js +1 -2
  119. package/packages/dd-trace/src/tagger.js +2 -2
  120. package/packages/dd-trace/src/telemetry/send-data.js +5 -7
  121. package/packages/dd-trace/src/tracer.js +2 -2
  122. package/vendor/dist/ignore/LICENSE +0 -21
  123. 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, getValueFromEnvSources } = require('../../dd-trace/src/config/helper')
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: !!getValueFromEnvSources('DD_CIVISIBILITY_AUTO_INSTRUMENTATION_PROVIDER'),
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
- resolveOriginalSourcePosition,
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 resolvedSuitePosition = resolveOriginalSourcePosition(testSuiteAbsolutePath, 1)
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 resolvedSpecPosition = spec.absolute ? resolveOriginalSourcePosition(spec.absolute, 1) : null
954
- const resolvedSpecAbsolutePath = resolvedSpecPosition ? resolvedSpecPosition.sourceFile : spec.absolute
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 = { resolveOriginalSourcePosition, resolveSourceLineForTest, shouldTrustInvocationDetailsLine }
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 = storage('legacy').getStore()
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
- if (context) {
45
- context.parentStore = store
46
- }
47
-
48
- // Only AppSec needs the request scope to be active for any async work that
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 (incomingHttpRequestStart.hasSubscribers) {
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, getValueFromEnvSources } = require('../../dd-trace/src/config/helper')
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: !!getValueFromEnvSources('DD_CIVISIBILITY_AUTO_INSTRUMENTATION_PROVIDER'),
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: !!getValueFromEnvSources('DD_CIVISIBILITY_AUTO_INSTRUMENTATION_PROVIDER'),
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
- (heartbeatFromEnv && isTrue(heartbeatFromEnv)) ??
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: !!getValueFromEnvSources('DD_CIVISIBILITY_AUTO_INSTRUMENTATION_PROVIDER'),
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 (getValueFromEnvSources('DD_PLAYWRIGHT_WORKER')) {
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 = getValueFromEnvSources('DD_CIVISIBILITY_TEST_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': getValueFromEnvSources('DD_CIVISIBILITY_TEST_SESSION_ID'),
293
- 'x-datadog-parent-id': getValueFromEnvSources('DD_CIVISIBILITY_TEST_MODULE_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: !!getValueFromEnvSources('DD_CIVISIBILITY_AUTO_INSTRUMENTATION_PROVIDER'),
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
 
@@ -62,6 +62,7 @@ class WSReceiverPlugin extends TracingPlugin {
62
62
  }
63
63
 
64
64
  asyncStart (ctx) {
65
+ if (!ctx.span) return
65
66
  ctx.span.finish()
66
67
  }
67
68
 
@@ -0,0 +1,8 @@
1
+ 'use strict'
2
+
3
+ const dc = require('dc-polyfill')
4
+
5
+ module.exports = {
6
+ aiguardChannel: dc.channel('dd-trace:ai:aiguard'),
7
+ incomingHttpRequestStart: dc.channel('dd-trace:incomingHttpRequestStart'),
8
+ }
@@ -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 = storage('legacy').getStore()?.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 || storage('legacy').getStore()?.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 = storage('legacy').getStore()?.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 = storage('legacy').getStore()?.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 = storage('legacy').getStore()?.req
86
+ const req = getActiveRequest()
87
87
  if (!req) return
88
88
 
89
89
  const requestData = graphqlRequestData.get(req)