dd-trace 6.10.0 → 6.12.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 (173) hide show
  1. package/LICENSE-3rdparty.csv +5 -0
  2. package/README.md +0 -17
  3. package/index.d.ts +128 -6
  4. package/initialize.mjs +28 -17
  5. package/openfeature.js +2 -2
  6. package/package.json +27 -23
  7. package/packages/datadog-esbuild/index.js +0 -34
  8. package/packages/datadog-instrumentations/src/anthropic.js +210 -15
  9. package/packages/datadog-instrumentations/src/aws-sdk.js +9 -1
  10. package/packages/datadog-instrumentations/src/browser-bunyan.js +11 -0
  11. package/packages/datadog-instrumentations/src/bunyan.js +3 -16
  12. package/packages/datadog-instrumentations/src/cucumber.js +30 -15
  13. package/packages/datadog-instrumentations/src/cypress-config.js +182 -16
  14. package/packages/datadog-instrumentations/src/cypress-legacy-finalizers.js +30 -0
  15. package/packages/datadog-instrumentations/src/cypress.js +2 -0
  16. package/packages/datadog-instrumentations/src/fastify.js +2 -0
  17. package/packages/datadog-instrumentations/src/helpers/bunyan.js +22 -0
  18. package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -1
  19. package/packages/datadog-instrumentations/src/helpers/pool-acquire.js +9 -4
  20. package/packages/datadog-instrumentations/src/helpers/register.js +10 -8
  21. package/packages/datadog-instrumentations/src/jest.js +25 -17
  22. package/packages/datadog-instrumentations/src/mariadb.js +278 -21
  23. package/packages/datadog-instrumentations/src/mocha/main.js +539 -55
  24. package/packages/datadog-instrumentations/src/mocha/utils.js +135 -19
  25. package/packages/datadog-instrumentations/src/playwright-reporter.js +247 -0
  26. package/packages/datadog-instrumentations/src/playwright.js +182 -35
  27. package/packages/datadog-instrumentations/src/router.js +2 -0
  28. package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +6 -8
  29. package/packages/datadog-instrumentations/src/vitest-main.js +11 -3
  30. package/packages/datadog-plugin-aws-sdk/src/base.js +1 -0
  31. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +163 -44
  32. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +2 -8
  33. package/packages/datadog-plugin-azure-functions/src/index.js +1 -1
  34. package/packages/datadog-plugin-browser-bunyan/src/index.js +9 -0
  35. package/packages/datadog-plugin-bunyan/src/index.js +5 -8
  36. package/packages/datadog-plugin-cucumber/src/index.js +11 -0
  37. package/packages/datadog-plugin-cypress/src/after-run.js +5 -1
  38. package/packages/datadog-plugin-cypress/src/after-spec.js +5 -1
  39. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +81 -29
  40. package/packages/datadog-plugin-cypress/src/finalization.js +76 -0
  41. package/packages/datadog-plugin-cypress/src/index.js +12 -6
  42. package/packages/datadog-plugin-cypress/src/plugin.js +16 -3
  43. package/packages/datadog-plugin-dd-trace-api/src/index.js +4 -0
  44. package/packages/datadog-plugin-electron/src/index.js +2 -0
  45. package/packages/datadog-plugin-fs/src/index.js +1 -1
  46. package/packages/datadog-plugin-jest/src/index.js +6 -0
  47. package/packages/datadog-plugin-mocha/src/index.js +56 -1
  48. package/packages/datadog-plugin-nats/src/index.js +1 -1
  49. package/packages/datadog-plugin-openai/src/tracing.js +41 -30
  50. package/packages/datadog-plugin-openai-agents/src/integration.js +1 -0
  51. package/packages/datadog-plugin-playwright/src/index.js +46 -13
  52. package/packages/datadog-plugin-vitest/src/index.js +6 -0
  53. package/packages/datadog-webpack/index.js +0 -11
  54. package/packages/dd-trace/index.js +0 -1
  55. package/packages/dd-trace/src/agent/info.js +6 -5
  56. package/packages/dd-trace/src/aiguard/client.js +100 -1
  57. package/packages/dd-trace/src/aiguard/errors.js +41 -0
  58. package/packages/dd-trace/src/aiguard/evaluation.js +357 -0
  59. package/packages/dd-trace/src/aiguard/integrations/anthropic.js +70 -0
  60. package/packages/dd-trace/src/aiguard/integrations/index.js +4 -0
  61. package/packages/dd-trace/src/aiguard/messages/anthropic.js +423 -0
  62. package/packages/dd-trace/src/aiguard/messages/openai.js +1 -24
  63. package/packages/dd-trace/src/aiguard/messages/utils.js +28 -0
  64. package/packages/dd-trace/src/aiguard/messages/vercel-ai.js +1 -11
  65. package/packages/dd-trace/src/aiguard/sdk.js +22 -278
  66. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +9 -12
  67. package/packages/dd-trace/src/appsec/reporter.js +2 -0
  68. package/packages/dd-trace/src/appsec/telemetry/index.js +13 -0
  69. package/packages/dd-trace/src/appsec/telemetry/rasp.js +16 -0
  70. package/packages/dd-trace/src/appsec/telemetry/waf.js +24 -0
  71. package/packages/dd-trace/src/carrier.js +107 -48
  72. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +1 -0
  73. package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +5 -5
  74. package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +29 -3
  75. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +27 -9
  76. package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +21 -5
  77. package/packages/dd-trace/src/ci-visibility/exporters/agentless/request-tracker.js +164 -0
  78. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +26 -8
  79. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +365 -32
  80. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +6 -4
  81. package/packages/dd-trace/src/ci-visibility/exporters/request.js +201 -0
  82. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +5 -3
  83. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +9 -5
  84. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +7 -4
  85. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +4 -2
  86. package/packages/dd-trace/src/ci-visibility/requests/rate-limit.js +39 -0
  87. package/packages/dd-trace/src/ci-visibility/requests/request.js +3 -6
  88. package/packages/dd-trace/src/ci-visibility/requests/upload-coverage-report.js +4 -2
  89. package/packages/dd-trace/src/ci-visibility/requests/upload-test-screenshot.js +10 -4
  90. package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +5 -5
  91. package/packages/dd-trace/src/config/generated-config-types.d.ts +4 -0
  92. package/packages/dd-trace/src/config/index.js +13 -2
  93. package/packages/dd-trace/src/config/major-overrides.js +7 -0
  94. package/packages/dd-trace/src/config/supported-configurations.json +14 -0
  95. package/packages/dd-trace/src/datastreams/index.js +2 -0
  96. package/packages/dd-trace/src/datastreams/manager.js +9 -2
  97. package/packages/dd-trace/src/datastreams/processor.js +15 -13
  98. package/packages/dd-trace/src/datastreams/size.js +5 -0
  99. package/packages/dd-trace/src/debugger/constants.js +1 -0
  100. package/packages/dd-trace/src/debugger/devtools_client/condition.js +1 -1
  101. package/packages/dd-trace/src/debugger/devtools_client/index.js +5 -11
  102. package/packages/dd-trace/src/debugger/index.js +4 -2
  103. package/packages/dd-trace/src/debugger/inspect-segment.js +154 -0
  104. package/packages/dd-trace/src/evp_proxy/constants.js +8 -0
  105. package/packages/dd-trace/src/evp_proxy/direct.js +64 -0
  106. package/packages/dd-trace/src/evp_proxy/discovery.js +133 -0
  107. package/packages/dd-trace/src/evp_proxy/path.js +22 -0
  108. package/packages/dd-trace/src/exporters/agent/writer.js +49 -9
  109. package/packages/dd-trace/src/exporters/common/buffering-exporter.js +6 -4
  110. package/packages/dd-trace/src/exporters/common/request.js +5 -2
  111. package/packages/dd-trace/src/exporters/common/writer.js +11 -6
  112. package/packages/dd-trace/src/llmobs/experiments/client.js +167 -5
  113. package/packages/dd-trace/src/llmobs/experiments/dataset.js +484 -92
  114. package/packages/dd-trace/src/llmobs/experiments/experiment.js +302 -29
  115. package/packages/dd-trace/src/llmobs/experiments/index.js +75 -64
  116. package/packages/dd-trace/src/llmobs/experiments/noop.js +135 -7
  117. package/packages/dd-trace/src/llmobs/experiments/result.js +1 -0
  118. package/packages/dd-trace/src/llmobs/experiments/util.js +101 -9
  119. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +12 -3
  120. package/packages/dd-trace/src/llmobs/plugins/base.js +4 -2
  121. package/packages/dd-trace/src/noop/proxy.js +3 -4
  122. package/packages/dd-trace/src/openfeature/constants/constants.js +0 -18
  123. package/packages/dd-trace/src/openfeature/flagging_provider.js +18 -2
  124. package/packages/dd-trace/src/openfeature/index.js +7 -4
  125. package/packages/dd-trace/src/openfeature/remote_config.js +1 -1
  126. package/packages/dd-trace/src/openfeature/writers/base.js +153 -11
  127. package/packages/dd-trace/src/openfeature/writers/exposures.js +62 -14
  128. package/packages/dd-trace/src/openfeature/writers/util.js +97 -15
  129. package/packages/dd-trace/src/opentelemetry/context_manager.js +7 -7
  130. package/packages/dd-trace/src/opentelemetry/logs/batch_log_processor.js +2 -1
  131. package/packages/dd-trace/src/opentelemetry/logs/logger.js +67 -11
  132. package/packages/dd-trace/src/opentelemetry/logs/otlp_transformer.js +14 -3
  133. package/packages/dd-trace/src/opentelemetry/metrics/index.js +25 -12
  134. package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_exporter.js +2 -5
  135. package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_transformer.js +96 -43
  136. package/packages/dd-trace/src/opentracing/propagation/text_map.js +22 -13
  137. package/packages/dd-trace/src/opentracing/tracer.js +5 -2
  138. package/packages/dd-trace/src/otel-thread-ctx.js +387 -0
  139. package/packages/dd-trace/src/plugin_manager.js +3 -3
  140. package/packages/dd-trace/src/plugins/ci_plugin.js +6 -1
  141. package/packages/dd-trace/src/plugins/index.js +1 -0
  142. package/packages/dd-trace/src/plugins/util/jest.js +4 -3
  143. package/packages/dd-trace/src/plugins/util/test.js +9 -9
  144. package/packages/dd-trace/src/plugins/util/web.js +3 -0
  145. package/packages/dd-trace/src/profiling/profiler.js +1 -1
  146. package/packages/dd-trace/src/profiling/profilers/space.js +1 -3
  147. package/packages/dd-trace/src/profiling/profilers/wall.js +37 -90
  148. package/packages/dd-trace/src/profiling/webspan-utils.js +45 -0
  149. package/packages/dd-trace/src/proxy.js +38 -29
  150. package/packages/dd-trace/src/ritm.js +9 -2
  151. package/packages/dd-trace/src/serverless.js +37 -0
  152. package/packages/dd-trace/src/span_format.js +1 -0
  153. package/packages/dd-trace/src/span_stats.js +30 -3
  154. package/packages/dd-trace/src/storage-channels.js +86 -0
  155. package/packages/dd-trace/src/telemetry/metrics.js +62 -8
  156. package/packages/dd-trace/src/telemetry/send-data.js +1 -0
  157. package/packages/dd-trace/src/tracer.js +9 -2
  158. package/packages/dd-trace/src/tracer_metadata.js +14 -1
  159. package/packages/dd-trace/src/web-tags-cache.js +132 -0
  160. package/vendor/dist/@datadog/openfeature-node-server/LICENSE +201 -0
  161. package/vendor/dist/@datadog/openfeature-node-server/index.js +1 -0
  162. package/vendor/dist/@datadog/sketches-js/index.js +1 -1
  163. package/vendor/dist/https-proxy-agent/LICENSE +22 -0
  164. package/vendor/dist/https-proxy-agent/index.js +4 -0
  165. package/vendor/dist/protobufjs/index.js +1 -1
  166. package/vendor/dist/protobufjs/minimal/index.js +1 -1
  167. package/vendor/dist/proxy-from-env/LICENSE +20 -0
  168. package/vendor/dist/proxy-from-env/index.js +1 -0
  169. package/packages/datadog-instrumentations/src/helpers/optional-peer-bundler.js +0 -65
  170. package/packages/datadog-webpack/src/optional-peer-loader.js +0 -17
  171. package/packages/dd-trace/src/feature-registry.js +0 -29
  172. package/packages/dd-trace/src/openfeature/register.js +0 -35
  173. package/packages/dd-trace/src/openfeature/require-provider.js +0 -18
@@ -1,90 +1,18 @@
1
1
  'use strict'
2
2
 
3
- const rfdc = require('../../../../vendor/dist/rfdc')({ proto: false, circles: false })
4
- const { HTTP_CLIENT_IP, NETWORK_CLIENT_IP, HTTP_USERAGENT } = require('../../../../ext/tags')
5
- const { USER_ID, USER_SESSION_ID } = require('../appsec/addresses')
6
- const { getActiveRequest } = require('../appsec/store')
7
3
  const log = require('../log')
8
- const { extractIp } = require('../plugins/util/ip_extractor')
9
- const telemetryMetrics = require('../telemetry/metrics')
10
- const tracerVersion = require('../../../../package.json').version
11
- const { keepTrace } = require('../priority_sampler')
12
- const { AI_GUARD } = require('../standalone/product')
4
+ const AIGuardClient = require('./client')
5
+ const { createEvaluationOutcome, EvaluationReporter } = require('./evaluation')
6
+ const { AIGuardAbortError } = require('./errors')
13
7
  const NoopAIGuard = require('./noop')
14
- const executeRequest = require('./client')
15
8
  const TAGS = require('./tags')
16
9
 
17
- const aiguardMetrics = telemetryMetrics.manager.namespace('ai_guard')
18
-
19
- const ALLOW = 'ALLOW'
20
-
21
- // Tags from the service entry span that must be mirrored onto every AI Guard span
22
- // so anomaly detection pipelines can process each span independently.
23
- const SERVICE_ENTRY_TAG_MAPPINGS = [
24
- [HTTP_USERAGENT, TAGS.HTTP_USERAGENT_TAG_KEY],
25
- [HTTP_CLIENT_IP, TAGS.HTTP_CLIENT_IP_TAG_KEY],
26
- [NETWORK_CLIENT_IP, TAGS.NETWORK_CLIENT_IP_TAG_KEY],
27
- [USER_ID, TAGS.USR_ID_TAG_KEY],
28
- [USER_SESSION_ID, TAGS.USR_SESSION_ID_TAG_KEY],
29
- ]
30
-
31
- /**
32
- * Reports a telemetry error
33
- *
34
- * @param {string} errorType - The error type constant (client_error, bad_status, bad_response)
35
- * @param {{ source: string, integration: string }} telemetryTags - Source and integration tags
36
- */
37
- function reportTelemetryError (errorType, telemetryTags) {
38
- aiguardMetrics.count(TAGS.TELEMETRY_REQUESTS, { error: true, ...telemetryTags }).inc(1)
39
- aiguardMetrics.count(TAGS.TELEMETRY_ERROR, { type: errorType, ...telemetryTags }).inc(1)
40
- }
41
-
42
- class AIGuardAbortError extends Error {
43
- constructor (reason, tags, tagProbs, sds) {
44
- super(reason)
45
- this.name = 'AIGuardAbortError'
46
- this.reason = reason
47
- this.tags = tags
48
- this.tagProbabilities = tagProbs
49
- this.sds = sds || []
50
- }
51
- }
52
-
53
- class AIGuardClientError extends Error {
54
- constructor (message, opts = {}) {
55
- super(message)
56
- this.name = 'AIGuardClientError'
57
- if (opts.errors) {
58
- this.errors = opts.errors
59
- }
60
- if (opts.cause) {
61
- this.cause = opts.cause
62
- }
63
- }
64
- }
65
-
66
- /**
67
- * Resolves the AI Guard host for a given Datadog site. Sites with a single subdomain level
68
- * (e.g. `datadoghq.com`, `ddog-gov.com`) are served from the `app.` subdomain, while regional
69
- * sites (e.g. `us3.datadoghq.com`, `ap1.datadoghq.com`) are used as-is.
70
- *
71
- * @param {string} site - Datadog site (e.g. `datadoghq.com`, `us3.datadoghq.com`)
72
- * @returns {string} The host to use for the AI Guard endpoint
73
- */
74
- function aiGuardHost (site) {
75
- return site.split('.').length === 2 ? `app.${site}` : site
76
- }
77
-
78
10
  class AIGuard extends NoopAIGuard {
79
11
  #initialized
80
12
  #tracer
81
- #headers
82
- #evaluateUrl
83
- #timeout
84
- #maxMessagesLength
85
- #maxContentSize
13
+ #client
14
+ #reporter
86
15
  #meta
87
- #config
88
16
 
89
17
  /**
90
18
  * @param {import('../tracer')} tracer - Tracer instance
@@ -99,223 +27,39 @@ class AIGuard extends NoopAIGuard {
99
27
  return
100
28
  }
101
29
  this.#tracer = tracer
102
- this.#headers = {
103
- 'DD-API-KEY': config.DD_API_KEY,
104
- 'DD-APPLICATION-KEY': config.DD_APP_KEY,
105
- 'DD-AI-GUARD-VERSION': tracerVersion,
106
- 'DD-AI-GUARD-SOURCE': 'SDK',
107
- 'DD-AI-GUARD-LANGUAGE': 'nodejs',
108
- }
109
- const endpoint = config.experimental.aiguard.endpoint || `https://${aiGuardHost(config.site)}/api/v2/ai-guard`
110
- this.#evaluateUrl = `${endpoint}/evaluate`
111
- this.#timeout = config.experimental.aiguard.timeout
112
- this.#maxMessagesLength = config.experimental.aiguard.maxMessagesLength
113
- this.#maxContentSize = config.experimental.aiguard.maxContentSize
30
+ this.#client = new AIGuardClient(config)
31
+ this.#reporter = new EvaluationReporter(config)
114
32
  this.#meta = { service: config.service, env: config.env }
115
- this.#config = config
116
33
  this.#initialized = true
117
34
  }
118
35
 
119
- /**
120
- * Returns a safe copy of the messages to be serialized into the meta struct.
121
- *
122
- * - Clones each message so callers cannot mutate the data set in the meta struct.
123
- * - Truncates the list of messages and `content` fields emitting metrics accordingly.
124
- *
125
- * @param {import('../../../../index').aiguard.Message[]} messages
126
- * @param {{ source: string, integration: string }} telemetryTags
127
- */
128
- #buildMessagesForMetaStruct (messages, telemetryTags) {
129
- const size = Math.min(messages.length, this.#maxMessagesLength)
130
- if (messages.length > size) {
131
- aiguardMetrics.count(TAGS.TELEMETRY_TRUNCATED, { type: 'messages', ...telemetryTags }).inc(1)
132
- }
133
- const result = []
134
- let contentTruncated = false
135
- for (let i = messages.length - size; i < messages.length; i++) {
136
- const message = rfdc(messages[i])
137
- if (message.content?.length > this.#maxContentSize) {
138
- contentTruncated = true
139
- message.content = message.content.slice(0, this.#maxContentSize)
140
- }
141
- result.push(message)
142
- }
143
- if (contentTruncated) {
144
- aiguardMetrics.count(TAGS.TELEMETRY_TRUNCATED, { type: 'content', ...telemetryTags }).inc(1)
145
- }
146
- return result
147
- }
148
-
149
- #isToolCall (message) {
150
- return message.tool_calls || message.tool_call_id
151
- }
152
-
153
- #getToolName (message, history) {
154
- // 1. assistant message with tool calls
155
- if (message.tool_calls) {
156
- const names = message.tool_calls.map((tool) => tool.function.name)
157
- return names.length === 0 ? null : names.join(',')
158
- }
159
- // 2. assistant message with tool output (search the linked tool call in reverse order)
160
- const id = message.tool_call_id
161
- for (let i = history.length - 2; i >= 0; i--) {
162
- const item = history[i]
163
- if (item.tool_calls) {
164
- for (const toolCall of item.tool_calls) {
165
- if (toolCall.id === id) {
166
- return toolCall.function.name
167
- }
168
- }
169
- }
170
- }
171
- return null
172
- }
173
-
174
- #setRootSpanClientIpTags (rootSpan) {
175
- if (!rootSpan) return
176
-
177
- const currentTags = rootSpan.context().getTags()
178
- const needsHttpClientIp = !Object.hasOwn(currentTags, HTTP_CLIENT_IP)
179
- const needsNetworkClientIp = !Object.hasOwn(currentTags, NETWORK_CLIENT_IP)
180
-
181
- if (!needsHttpClientIp && !needsNetworkClientIp) return
182
-
183
- const req = getActiveRequest()
184
-
185
- if (!req) return
186
-
187
- const newTags = {}
188
-
189
- if (needsHttpClientIp) {
190
- const clientIp = extractIp(this.#config, req)
191
-
192
- if (clientIp) {
193
- newTags[HTTP_CLIENT_IP] = clientIp
194
- }
195
- }
196
-
197
- if (needsNetworkClientIp) {
198
- const networkClientIp = req.socket?.remoteAddress
199
-
200
- if (networkClientIp) {
201
- newTags[NETWORK_CLIENT_IP] = networkClientIp
202
- }
203
- }
204
-
205
- if (Object.keys(newTags).length > 0) {
206
- rootSpan.addTags(newTags)
207
- }
208
- }
209
-
210
- /**
211
- * Copies service entry span tags needed by anomaly detection to the AI Guard span.
212
- *
213
- * @param {import('../opentracing/span')} guardSpan
214
- * @param {import('../opentracing/span')} rootSpan
215
- */
216
- #copyServiceEntryTagsToGuardSpan (guardSpan, rootSpan) {
217
- const rootTags = rootSpan.context().getTags()
218
- for (const [sourceTag, destTag] of SERVICE_ENTRY_TAG_MAPPINGS) {
219
- const value = rootTags[sourceTag]
220
- if (value !== undefined && value !== null) {
221
- guardSpan.setTag(destTag, value)
222
- }
223
- }
224
- }
225
-
226
36
  evaluate (messages, opts) {
227
37
  if (!this.#initialized) {
228
38
  return super.evaluate(messages, opts)
229
39
  }
230
40
  const { block = true, source = TAGS.SOURCE_SDK, integration = TAGS.INTEGRATION_NONE, childOf } = opts ?? {}
231
- const telemetryTags = { source, integration }
232
41
  // Only pass `childOf` when truthy so `tracer.trace`'s default (`scope().active()`)
233
42
  // still applies for SDK callers that don't supply an explicit parent.
234
43
  const traceOpts = childOf ? { childOf } : {}
235
44
  return this.#tracer.trace(TAGS.RESOURCE, traceOpts, async (span) => {
236
- const last = messages.at(-1)
237
- const target = this.#isToolCall(last) ? 'tool' : 'prompt'
238
- span.setTag(TAGS.TARGET_TAG_KEY, target)
239
- if (target === 'tool') {
240
- const name = this.#getToolName(last, messages)
241
- if (name) {
242
- span.setTag(TAGS.TOOL_NAME_TAG_KEY, name)
243
- }
244
- }
245
- const metaStruct = {
246
- messages: this.#buildMessagesForMetaStruct(messages, telemetryTags),
247
- }
248
- span.meta_struct = {
249
- [TAGS.META_STRUCT_KEY]: metaStruct,
250
- }
251
- const rootSpan = span.context()?._trace?.started?.[0]
252
- if (rootSpan) {
253
- this.#setRootSpanClientIpTags(rootSpan)
254
- this.#copyServiceEntryTagsToGuardSpan(span, rootSpan)
255
- // keepTrace must be called before executeRequest so the sampling decision
256
- // is propagated correctly to outgoing HTTP client calls.
257
- keepTrace(rootSpan, AI_GUARD)
258
- rootSpan.setTag(TAGS.EVENT_TAG_KEY, 'true')
259
- }
260
- let response
45
+ const report = this.#reporter.start(span, messages, { source, integration })
46
+ let evaluation
261
47
  try {
262
- const payload = {
263
- data: {
264
- attributes: {
265
- messages,
266
- meta: this.#meta,
267
- },
268
- },
269
- }
270
- response = await executeRequest(
271
- payload,
272
- { url: this.#evaluateUrl, headers: this.#headers, timeout: this.#timeout })
273
- } catch (e) {
274
- reportTelemetryError(TAGS.ERROR_TYPE_CLIENT, telemetryTags)
275
- throw new AIGuardClientError(`Unexpected error calling AI Guard service: ${e.message}`, { cause: e })
276
- }
277
- if (response.status !== 200) {
278
- reportTelemetryError(TAGS.ERROR_TYPE_STATUS, telemetryTags)
279
- throw new AIGuardClientError(
280
- `AI Guard service call failed, status ${response.status}`,
281
- { errors: response.body?.errors })
48
+ evaluation = await this.#client.evaluate(messages, this.#meta)
49
+ } catch (error) {
50
+ this.#reporter.fail(report, error.telemetryType ?? TAGS.ERROR_TYPE_CLIENT)
51
+ throw error
282
52
  }
283
- const attr = response.body?.data?.attributes
284
- if (!attr?.action) {
285
- reportTelemetryError(TAGS.ERROR_TYPE_RESPONSE, telemetryTags)
286
- throw new AIGuardClientError(`AI Guard service returned unexpected response : ${response.body}`)
287
- }
288
- const action = attr.action
289
- const reason = attr.reason
290
- const tags = attr.tags ?? []
291
- if (tags.length > 0) {
292
- metaStruct.attack_categories = tags
293
- }
294
- const sdsFindings = attr.sds_findings ?? []
295
- if (sdsFindings.length > 0) {
296
- metaStruct.sds = sdsFindings
297
- }
298
- const tagProbabilities = attr.tag_probs ?? {}
299
- if (attr.tag_probs) {
300
- metaStruct.tag_probs = tagProbabilities
301
- }
302
- const blockingEnabled = attr.is_blocking_enabled ?? false
303
- const shouldBlock = block && blockingEnabled && action !== ALLOW
304
- aiguardMetrics.count(TAGS.TELEMETRY_REQUESTS, {
305
- action,
306
- error: false,
307
- block: shouldBlock,
308
- ...telemetryTags,
309
- }).inc(1)
310
- span.setTag(TAGS.ACTION_TAG_KEY, action)
311
- if (reason) {
312
- span.setTag(TAGS.REASON_TAG_KEY, reason)
313
- }
314
- if (shouldBlock) {
315
- span.setTag(TAGS.BLOCKED_TAG_KEY, 'true')
316
- throw new AIGuardAbortError(reason, tags, tagProbabilities, sdsFindings)
53
+
54
+ const outcome = createEvaluationOutcome(evaluation, block)
55
+ this.#reporter.finish(report, outcome)
56
+
57
+ if (outcome.shouldBlock) {
58
+ const { reason, tags, tagProbabilities, sds } = outcome.result
59
+ throw new AIGuardAbortError(reason, tags, tagProbabilities, sds)
317
60
  }
318
- return { action, reason, tags, tagProbabilities, sds: sdsFindings }
61
+
62
+ return outcome.result
319
63
  })
320
64
  }
321
65
  }
@@ -97,15 +97,14 @@ function getPrepareStackTraceAccessor () {
97
97
 
98
98
  function getCompileMethodFn (compileMethod) {
99
99
  let delegate = function (content, filename) {
100
+ if (isDdTrace(filename) || !isPrivateModule(filename) || !config.iast?.enabled) {
101
+ return compileMethod.apply(this, [content, filename])
102
+ }
103
+
104
+ // TODO when we have CJS support for orchestrion and taint-tracking, add
105
+ // them here as appropriate
106
+ let rewrittenContent
100
107
  try {
101
- if (isDdTrace(filename)) {
102
- return compileMethod.apply(this, [content, filename])
103
- }
104
- if (!isPrivateModule(filename) || !config.iast?.enabled) {
105
- return compileMethod.apply(this, [content, filename])
106
- }
107
- // TODO when we have CJS support for orchestrion and taint-tracking, add
108
- // them here as appropriate
109
108
  const rewritten = rewriter.rewrite(content, filename, ['iast'])
110
109
 
111
110
  incrementTelemetryIfNeeded(rewritten.metrics)
@@ -114,13 +113,11 @@ function getCompileMethodFn (compileMethod) {
114
113
  hardcodedSecretCh.publish(rewritten.literalsResult)
115
114
  }
116
115
 
117
- if (rewritten?.content) {
118
- return compileMethod.apply(this, [rewritten.content, filename])
119
- }
116
+ rewrittenContent = rewritten?.content
120
117
  } catch (e) {
121
118
  log.error('Error rewriting file %s', filename, e)
122
119
  }
123
- return compileMethod.apply(this, [content, filename])
120
+ return compileMethod.apply(this, [rewrittenContent || content, filename])
124
121
  }
125
122
 
126
123
  const shim = function (...args) {
@@ -15,6 +15,7 @@ const {
15
15
  incrementWafUpdatesMetric,
16
16
  incrementWafConfigErrorsMetric,
17
17
  incrementWafRequestsMetric,
18
+ incrementRequestDurationMetrics,
18
19
  updateWafRequestsMetricTags,
19
20
  updateRaspRequestsMetricTags,
20
21
  updateRaspRuleSkippedMetricTags,
@@ -608,6 +609,7 @@ function finishRequest (req, res, storedResponseHeaders, requestBody, rootSpan)
608
609
 
609
610
  if (!req) return
610
611
 
612
+ incrementRequestDurationMetrics(req)
611
613
  incrementWafRequestsMetric(req)
612
614
 
613
615
  const tags = rootSpan.context().getTags()
@@ -12,6 +12,7 @@ const {
12
12
  trackRaspMetrics,
13
13
  trackRaspRuleMatch,
14
14
  trackRaspRuleSkipped,
15
+ incrementRaspDurationMetrics,
15
16
  } = require('./rasp')
16
17
  const {
17
18
  addWafRequestMetrics,
@@ -20,6 +21,7 @@ const {
20
21
  incrementWafUpdates,
21
22
  incrementWafConfigErrors,
22
23
  incrementWafRequests,
24
+ incrementWafDurationMetrics,
23
25
  } = require('./waf')
24
26
 
25
27
  const metricsStoreMap = new WeakMap()
@@ -142,6 +144,16 @@ function incrementWafRequestsMetric (req) {
142
144
  metricsStoreMap.delete(req)
143
145
  }
144
146
 
147
+ function incrementRequestDurationMetrics (req) {
148
+ if (!req || !enabled) return
149
+
150
+ const store = getStore(req)
151
+ const requestMetrics = store[DD_TELEMETRY_REQUEST_METRICS]
152
+
153
+ incrementWafDurationMetrics(requestMetrics)
154
+ incrementRaspDurationMetrics(requestMetrics)
155
+ }
156
+
145
157
  function incrementMissingUserLoginMetric (framework, eventType) {
146
158
  if (!enabled) return
147
159
 
@@ -199,6 +211,7 @@ module.exports = {
199
211
  incrementWafUpdatesMetric,
200
212
  incrementWafConfigErrorsMetric,
201
213
  incrementWafRequestsMetric,
214
+ incrementRequestDurationMetrics,
202
215
  incrementMissingUserLoginMetric,
203
216
  incrementMissingUserIdMetric,
204
217
  incrementSdkEventMetric,
@@ -77,6 +77,21 @@ function trackRaspRuleMatch (store, raspRule, blockTriggered, blocked) {
77
77
  appsecMetrics.count('rasp.rule.match', tags).inc(1)
78
78
  }
79
79
 
80
+ function incrementRaspDurationMetrics (requestMetrics) {
81
+ const { raspDuration, raspDurationExt, wafVersion, rulesVersion } = requestMetrics
82
+ if (!raspDuration && !raspDurationExt) return
83
+
84
+ const versionsTags = getVersionsTags(wafVersion, rulesVersion)
85
+
86
+ if (raspDuration) {
87
+ appsecMetrics.distribution('rasp.duration', versionsTags).track(raspDuration)
88
+ }
89
+
90
+ if (raspDurationExt) {
91
+ appsecMetrics.distribution('rasp.duration_ext', versionsTags).track(raspDurationExt)
92
+ }
93
+ }
94
+
80
95
  function trackRaspRuleSkipped (raspRule, reason) {
81
96
  const tags = { reason, rule_type: raspRule.type }
82
97
 
@@ -100,4 +115,5 @@ module.exports = {
100
115
  trackRaspMetrics,
101
116
  trackRaspRuleMatch,
102
117
  trackRaspRuleSkipped,
118
+ incrementRaspDurationMetrics,
103
119
  }
@@ -34,6 +34,14 @@ function addWafRequestMetrics (store, { duration, durationExt, wafTimeout, error
34
34
  function trackWafMetrics (store, metrics) {
35
35
  const versionsTags = getVersionsTags(metrics.wafVersion, metrics.rulesVersion)
36
36
 
37
+ const requestMetrics = store[DD_TELEMETRY_REQUEST_METRICS]
38
+ if (metrics.wafVersion) {
39
+ requestMetrics.wafVersion = metrics.wafVersion
40
+ }
41
+ if (metrics.rulesVersion) {
42
+ requestMetrics.rulesVersion = metrics.rulesVersion
43
+ }
44
+
37
45
  const metricTags = getOrCreateMetricTags(store, versionsTags)
38
46
 
39
47
  if (metrics.blockFailed) {
@@ -118,6 +126,21 @@ function incrementWafRequests (store) {
118
126
  }
119
127
  }
120
128
 
129
+ function incrementWafDurationMetrics (requestMetrics) {
130
+ const { duration, durationExt, wafVersion, rulesVersion } = requestMetrics
131
+ if (!duration && !durationExt) return
132
+
133
+ const versionsTags = getVersionsTags(wafVersion, rulesVersion)
134
+
135
+ if (duration) {
136
+ appsecMetrics.distribution('waf.duration', versionsTags).track(duration)
137
+ }
138
+
139
+ if (durationExt) {
140
+ appsecMetrics.distribution('waf.duration_ext', versionsTags).track(durationExt)
141
+ }
142
+ }
143
+
121
144
  function incrementTruncatedMetrics (metrics, truncationReason) {
122
145
  const truncationTags = { truncation_reason: truncationReason }
123
146
  appsecMetrics.count('waf.input_truncated', truncationTags).inc(1)
@@ -140,4 +163,5 @@ module.exports = {
140
163
  incrementWafUpdates,
141
164
  incrementWafConfigErrors,
142
165
  incrementWafRequests,
166
+ incrementWafDurationMetrics,
143
167
  }