dd-trace 5.41.1 → 5.42.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE-3rdparty.csv +1 -0
- package/index.d.ts +8 -1
- package/package.json +6 -3
- package/packages/datadog-esbuild/index.js +3 -1
- package/packages/datadog-instrumentations/src/cucumber.js +37 -29
- package/packages/datadog-instrumentations/src/google-cloud-vertexai.js +102 -0
- package/packages/datadog-instrumentations/src/{check_require_cache.js → helpers/check-require-cache.js} +2 -2
- package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -2
- package/packages/datadog-instrumentations/src/helpers/register.js +4 -1
- package/packages/datadog-instrumentations/src/jest.js +72 -49
- package/packages/datadog-instrumentations/src/langchain.js +29 -10
- package/packages/datadog-instrumentations/src/mocha/main.js +53 -34
- package/packages/datadog-instrumentations/src/mocha/utils.js +34 -24
- package/packages/datadog-instrumentations/src/mocha/worker.js +7 -8
- package/packages/datadog-instrumentations/src/openai.js +1 -1
- package/packages/datadog-instrumentations/src/playwright.js +37 -30
- package/packages/datadog-instrumentations/src/vitest.js +64 -29
- package/packages/datadog-plugin-cucumber/src/index.js +13 -4
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +41 -35
- package/packages/datadog-plugin-cypress/src/plugin.js +10 -0
- package/packages/datadog-plugin-google-cloud-vertexai/src/index.js +195 -0
- package/packages/datadog-plugin-jest/src/index.js +18 -6
- package/packages/datadog-plugin-langchain/src/handlers/embedding.js +4 -1
- package/packages/datadog-plugin-mocha/src/index.js +13 -4
- package/packages/datadog-plugin-playwright/src/index.js +19 -5
- package/packages/datadog-plugin-vitest/src/index.js +41 -17
- package/packages/dd-trace/src/appsec/api_security_sampler.js +7 -3
- package/packages/dd-trace/src/appsec/blocking.js +23 -16
- package/packages/dd-trace/src/appsec/graphql.js +13 -6
- package/packages/dd-trace/src/appsec/rasp/utils.js +0 -1
- package/packages/dd-trace/src/appsec/reporter.js +35 -0
- package/packages/dd-trace/src/appsec/sdk/user_blocking.js +1 -3
- package/packages/dd-trace/src/appsec/telemetry/index.js +5 -1
- package/packages/dd-trace/src/appsec/telemetry/rasp.js +16 -1
- package/packages/dd-trace/src/appsec/telemetry/waf.js +16 -1
- package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +43 -13
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +2 -2
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +15 -14
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +1 -2
- package/packages/dd-trace/src/ci-visibility/telemetry.js +2 -1
- package/packages/dd-trace/src/ci-visibility/{quarantined-tests/get-quarantined-tests.js → test-management/get-test-management-tests.js} +5 -5
- package/packages/dd-trace/src/config.js +11 -1
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +9 -2
- package/packages/dd-trace/src/lambda/runtime/patch.js +5 -3
- package/packages/dd-trace/src/lambda/runtime/ritm.js +13 -18
- package/packages/dd-trace/src/llmobs/plugins/openai.js +27 -2
- package/packages/dd-trace/src/opentracing/span.js +3 -0
- package/packages/dd-trace/src/plugins/ci_plugin.js +38 -10
- package/packages/dd-trace/src/plugins/index.js +1 -0
- package/packages/dd-trace/src/plugins/util/git.js +7 -3
- package/packages/dd-trace/src/plugins/util/test.js +10 -0
- package/packages/dd-trace/src/plugins/util/web.js +5 -2
- package/packages/dd-trace/src/priority_sampler.js +116 -15
- package/packages/dd-trace/src/sampler.js +9 -0
- package/packages/dd-trace/src/standalone/product.js +6 -2
- package/packages/dd-trace/src/startup-log.js +2 -1
- package/packages/dd-trace/src/telemetry/metrics.js +0 -8
- package/packages/dd-trace/src/tracer.js +1 -1
- /package/packages/datadog-instrumentations/src/{utils/src → helpers}/extract-package-and-module-path.js +0 -0
|
@@ -103,16 +103,34 @@ function reportWafInit (wafVersion, rulesVersion, diagnosticsRules = {}) {
|
|
|
103
103
|
function reportMetrics (metrics, raspRule) {
|
|
104
104
|
const store = storage('legacy').getStore()
|
|
105
105
|
const rootSpan = store?.req && web.root(store.req)
|
|
106
|
+
|
|
106
107
|
if (!rootSpan) return
|
|
107
108
|
|
|
108
109
|
if (metrics.rulesVersion) {
|
|
109
110
|
rootSpan.setTag('_dd.appsec.event_rules.version', metrics.rulesVersion)
|
|
110
111
|
}
|
|
112
|
+
|
|
111
113
|
if (raspRule) {
|
|
112
114
|
updateRaspRequestsMetricTags(metrics, store.req, raspRule)
|
|
113
115
|
} else {
|
|
114
116
|
updateWafRequestsMetricTags(metrics, store.req)
|
|
115
117
|
}
|
|
118
|
+
|
|
119
|
+
reportTruncationMetrics(rootSpan, metrics)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function reportTruncationMetrics (rootSpan, metrics) {
|
|
123
|
+
if (metrics.maxTruncatedString) {
|
|
124
|
+
rootSpan.setTag('_dd.appsec.truncated.string_length', metrics.maxTruncatedString)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (metrics.maxTruncatedContainerSize) {
|
|
128
|
+
rootSpan.setTag('_dd.appsec.truncated.container_size', metrics.maxTruncatedContainerSize)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (metrics.maxTruncatedContainerDepth) {
|
|
132
|
+
rootSpan.setTag('_dd.appsec.truncated.container_depth', metrics.maxTruncatedContainerDepth)
|
|
133
|
+
}
|
|
116
134
|
}
|
|
117
135
|
|
|
118
136
|
function reportAttack (attackData) {
|
|
@@ -189,6 +207,7 @@ function finishRequest (req, res) {
|
|
|
189
207
|
}
|
|
190
208
|
|
|
191
209
|
const metrics = getRequestMetrics(req)
|
|
210
|
+
|
|
192
211
|
if (metrics?.duration) {
|
|
193
212
|
rootSpan.setTag('_dd.appsec.waf.duration', metrics.duration)
|
|
194
213
|
}
|
|
@@ -197,6 +216,14 @@ function finishRequest (req, res) {
|
|
|
197
216
|
rootSpan.setTag('_dd.appsec.waf.duration_ext', metrics.durationExt)
|
|
198
217
|
}
|
|
199
218
|
|
|
219
|
+
if (metrics?.wafErrorCode) {
|
|
220
|
+
rootSpan.setTag('_dd.appsec.waf.error', metrics.wafErrorCode)
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (metrics?.wafTimeouts) {
|
|
224
|
+
rootSpan.setTag('_dd.appsec.waf.timeouts', metrics.wafTimeouts)
|
|
225
|
+
}
|
|
226
|
+
|
|
200
227
|
if (metrics?.raspDuration) {
|
|
201
228
|
rootSpan.setTag('_dd.appsec.rasp.duration', metrics.raspDuration)
|
|
202
229
|
}
|
|
@@ -205,6 +232,14 @@ function finishRequest (req, res) {
|
|
|
205
232
|
rootSpan.setTag('_dd.appsec.rasp.duration_ext', metrics.raspDurationExt)
|
|
206
233
|
}
|
|
207
234
|
|
|
235
|
+
if (metrics?.raspErrorCode) {
|
|
236
|
+
rootSpan.setTag('_dd.appsec.rasp.error', metrics.raspErrorCode)
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (metrics?.raspTimeouts) {
|
|
240
|
+
rootSpan.setTag('_dd.appsec.rasp.timeout', metrics.raspTimeouts)
|
|
241
|
+
}
|
|
242
|
+
|
|
208
243
|
if (metrics?.raspEvalCount) {
|
|
209
244
|
rootSpan.setTag('_dd.appsec.rasp.rule.eval', metrics.raspEvalCount)
|
|
210
245
|
}
|
|
@@ -5,10 +5,25 @@ const { DD_TELEMETRY_REQUEST_METRICS } = require('./common')
|
|
|
5
5
|
|
|
6
6
|
const appsecMetrics = telemetryMetrics.manager.namespace('appsec')
|
|
7
7
|
|
|
8
|
-
function addRaspRequestMetrics (store, { duration, durationExt }) {
|
|
8
|
+
function addRaspRequestMetrics (store, { duration, durationExt, wafTimeout, errorCode }) {
|
|
9
9
|
store[DD_TELEMETRY_REQUEST_METRICS].raspDuration += duration || 0
|
|
10
10
|
store[DD_TELEMETRY_REQUEST_METRICS].raspDurationExt += durationExt || 0
|
|
11
11
|
store[DD_TELEMETRY_REQUEST_METRICS].raspEvalCount++
|
|
12
|
+
|
|
13
|
+
if (wafTimeout) {
|
|
14
|
+
store[DD_TELEMETRY_REQUEST_METRICS].raspTimeouts++
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (errorCode) {
|
|
18
|
+
if (store[DD_TELEMETRY_REQUEST_METRICS].raspErrorCode) {
|
|
19
|
+
store[DD_TELEMETRY_REQUEST_METRICS].raspErrorCode = Math.max(
|
|
20
|
+
errorCode,
|
|
21
|
+
store[DD_TELEMETRY_REQUEST_METRICS].raspErrorCode
|
|
22
|
+
)
|
|
23
|
+
} else {
|
|
24
|
+
store[DD_TELEMETRY_REQUEST_METRICS].raspErrorCode = errorCode
|
|
25
|
+
}
|
|
26
|
+
}
|
|
12
27
|
}
|
|
13
28
|
|
|
14
29
|
function trackRaspMetrics (metrics, raspRule) {
|
|
@@ -7,9 +7,24 @@ const appsecMetrics = telemetryMetrics.manager.namespace('appsec')
|
|
|
7
7
|
|
|
8
8
|
const DD_TELEMETRY_WAF_RESULT_TAGS = Symbol('_dd.appsec.telemetry.waf.result.tags')
|
|
9
9
|
|
|
10
|
-
function addWafRequestMetrics (store, { duration, durationExt }) {
|
|
10
|
+
function addWafRequestMetrics (store, { duration, durationExt, wafTimeout, errorCode }) {
|
|
11
11
|
store[DD_TELEMETRY_REQUEST_METRICS].duration += duration || 0
|
|
12
12
|
store[DD_TELEMETRY_REQUEST_METRICS].durationExt += durationExt || 0
|
|
13
|
+
|
|
14
|
+
if (wafTimeout) {
|
|
15
|
+
store[DD_TELEMETRY_REQUEST_METRICS].wafTimeouts++
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (errorCode) {
|
|
19
|
+
if (store[DD_TELEMETRY_REQUEST_METRICS].wafErrorCode) {
|
|
20
|
+
store[DD_TELEMETRY_REQUEST_METRICS].wafErrorCode = Math.max(
|
|
21
|
+
errorCode,
|
|
22
|
+
store[DD_TELEMETRY_REQUEST_METRICS].wafErrorCode
|
|
23
|
+
)
|
|
24
|
+
} else {
|
|
25
|
+
store[DD_TELEMETRY_REQUEST_METRICS].wafErrorCode = errorCode
|
|
26
|
+
}
|
|
27
|
+
}
|
|
13
28
|
}
|
|
14
29
|
|
|
15
30
|
function trackWafDurations ({ duration, durationExt }, versionsTags) {
|
|
@@ -17,8 +17,8 @@ class WAFContextWrapper {
|
|
|
17
17
|
this.wafTimeout = wafTimeout
|
|
18
18
|
this.wafVersion = wafVersion
|
|
19
19
|
this.rulesVersion = rulesVersion
|
|
20
|
-
this.addressesToSkip = new Set()
|
|
21
20
|
this.knownAddresses = knownAddresses
|
|
21
|
+
this.addressesToSkip = new Set()
|
|
22
22
|
this.cachedUserIdActions = new Map()
|
|
23
23
|
}
|
|
24
24
|
|
|
@@ -77,6 +77,20 @@ class WAFContextWrapper {
|
|
|
77
77
|
|
|
78
78
|
if (!payloadHasData) return
|
|
79
79
|
|
|
80
|
+
const metrics = {
|
|
81
|
+
rulesVersion: this.rulesVersion,
|
|
82
|
+
wafVersion: this.wafVersion,
|
|
83
|
+
wafTimeout: false,
|
|
84
|
+
duration: 0,
|
|
85
|
+
durationExt: 0,
|
|
86
|
+
blockTriggered: false,
|
|
87
|
+
ruleTriggered: false,
|
|
88
|
+
errorCode: null,
|
|
89
|
+
maxTruncatedString: null,
|
|
90
|
+
maxTruncatedContainerSize: null,
|
|
91
|
+
maxTruncatedContainerDepth: null
|
|
92
|
+
}
|
|
93
|
+
|
|
80
94
|
try {
|
|
81
95
|
const start = process.hrtime.bigint()
|
|
82
96
|
|
|
@@ -84,6 +98,23 @@ class WAFContextWrapper {
|
|
|
84
98
|
|
|
85
99
|
const end = process.hrtime.bigint()
|
|
86
100
|
|
|
101
|
+
metrics.durationExt = parseInt(end - start) / 1e3
|
|
102
|
+
|
|
103
|
+
if (typeof result.errorCode === 'number' && result.errorCode < 0) {
|
|
104
|
+
const error = new Error('WAF code error')
|
|
105
|
+
error.errorCode = result.errorCode
|
|
106
|
+
|
|
107
|
+
throw error
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (result.metrics) {
|
|
111
|
+
const { maxTruncatedString, maxTruncatedContainerSize, maxTruncatedContainerDepth } = result.metrics
|
|
112
|
+
|
|
113
|
+
if (maxTruncatedString) metrics.maxTruncatedString = maxTruncatedString
|
|
114
|
+
if (maxTruncatedContainerSize) metrics.maxTruncatedContainerSize = maxTruncatedContainerSize
|
|
115
|
+
if (maxTruncatedContainerDepth) metrics.maxTruncatedContainerDepth = maxTruncatedContainerDepth
|
|
116
|
+
}
|
|
117
|
+
|
|
87
118
|
this.addressesToSkip = newAddressesToSkip
|
|
88
119
|
|
|
89
120
|
const ruleTriggered = !!result.events?.length
|
|
@@ -96,15 +127,10 @@ class WAFContextWrapper {
|
|
|
96
127
|
this.setUserIdCache(userId, result)
|
|
97
128
|
}
|
|
98
129
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
ruleTriggered,
|
|
104
|
-
blockTriggered,
|
|
105
|
-
wafVersion: this.wafVersion,
|
|
106
|
-
wafTimeout: result.timeout
|
|
107
|
-
}, raspRule)
|
|
130
|
+
metrics.duration = result.totalRuntime / 1e3
|
|
131
|
+
metrics.blockTriggered = blockTriggered
|
|
132
|
+
metrics.ruleTriggered = ruleTriggered
|
|
133
|
+
metrics.wafTimeout = result.timeout
|
|
108
134
|
|
|
109
135
|
if (ruleTriggered) {
|
|
110
136
|
Reporter.reportAttack(JSON.stringify(result.events))
|
|
@@ -112,13 +138,17 @@ class WAFContextWrapper {
|
|
|
112
138
|
|
|
113
139
|
Reporter.reportDerivatives(result.derivatives)
|
|
114
140
|
|
|
141
|
+
return result.actions
|
|
142
|
+
} catch (err) {
|
|
143
|
+
log.error('[ASM] Error while running the AppSec WAF', err)
|
|
144
|
+
|
|
145
|
+
metrics.errorCode = err.errorCode ?? -127
|
|
146
|
+
} finally {
|
|
115
147
|
if (wafRunFinished.hasSubscribers) {
|
|
116
148
|
wafRunFinished.publish({ payload })
|
|
117
149
|
}
|
|
118
150
|
|
|
119
|
-
|
|
120
|
-
} catch (err) {
|
|
121
|
-
log.error('[ASM] Error while running the AppSec WAF', err)
|
|
151
|
+
Reporter.reportMetrics(metrics, raspRule)
|
|
122
152
|
}
|
|
123
153
|
}
|
|
124
154
|
|
|
@@ -6,7 +6,8 @@ const { sendGitMetadata: sendGitMetadataRequest } = require('./git/git_metadata'
|
|
|
6
6
|
const { getLibraryConfiguration: getLibraryConfigurationRequest } = require('../requests/get-library-configuration')
|
|
7
7
|
const { getSkippableSuites: getSkippableSuitesRequest } = require('../intelligent-test-runner/get-skippable-suites')
|
|
8
8
|
const { getKnownTests: getKnownTestsRequest } = require('../early-flake-detection/get-known-tests')
|
|
9
|
-
const {
|
|
9
|
+
const { getTestManagementTests: getTestManagementTestsRequest } =
|
|
10
|
+
require('../test-management/get-test-management-tests')
|
|
10
11
|
const log = require('../../log')
|
|
11
12
|
const AgentInfoExporter = require('../../exporters/common/agent-info-exporter')
|
|
12
13
|
const { GIT_REPOSITORY_URL, GIT_COMMIT_SHA } = require('../../plugins/util/tags')
|
|
@@ -93,11 +94,11 @@ class CiVisibilityExporter extends AgentInfoExporter {
|
|
|
93
94
|
)
|
|
94
95
|
}
|
|
95
96
|
|
|
96
|
-
|
|
97
|
+
shouldRequestTestManagementTests () {
|
|
97
98
|
return !!(
|
|
98
99
|
this._canUseCiVisProtocol &&
|
|
99
100
|
this._config.isTestManagementEnabled &&
|
|
100
|
-
this._libraryConfig?.
|
|
101
|
+
this._libraryConfig?.isTestManagementEnabled
|
|
101
102
|
)
|
|
102
103
|
}
|
|
103
104
|
|
|
@@ -147,11 +148,11 @@ class CiVisibilityExporter extends AgentInfoExporter {
|
|
|
147
148
|
getKnownTestsRequest(this.getRequestConfiguration(testConfiguration), callback)
|
|
148
149
|
}
|
|
149
150
|
|
|
150
|
-
|
|
151
|
-
if (!this.
|
|
151
|
+
getTestManagementTests (testConfiguration, callback) {
|
|
152
|
+
if (!this.shouldRequestTestManagementTests()) {
|
|
152
153
|
return callback(null)
|
|
153
154
|
}
|
|
154
|
-
|
|
155
|
+
getTestManagementTestsRequest(this.getRequestConfiguration(testConfiguration), callback)
|
|
155
156
|
}
|
|
156
157
|
|
|
157
158
|
/**
|
|
@@ -214,7 +215,7 @@ class CiVisibilityExporter extends AgentInfoExporter {
|
|
|
214
215
|
isFlakyTestRetriesEnabled,
|
|
215
216
|
isDiEnabled,
|
|
216
217
|
isKnownTestsEnabled,
|
|
217
|
-
|
|
218
|
+
isTestManagementEnabled
|
|
218
219
|
} = remoteConfiguration
|
|
219
220
|
return {
|
|
220
221
|
isCodeCoverageEnabled,
|
|
@@ -228,7 +229,7 @@ class CiVisibilityExporter extends AgentInfoExporter {
|
|
|
228
229
|
flakyTestRetriesCount: this._config.flakyTestRetriesCount,
|
|
229
230
|
isDiEnabled: isDiEnabled && this._config.isTestDynamicInstrumentationEnabled,
|
|
230
231
|
isKnownTestsEnabled,
|
|
231
|
-
|
|
232
|
+
isTestManagementEnabled: isTestManagementEnabled && this._config.isTestManagementEnabled
|
|
232
233
|
}
|
|
233
234
|
}
|
|
234
235
|
|
|
@@ -374,14 +375,14 @@ class CiVisibilityExporter extends AgentInfoExporter {
|
|
|
374
375
|
return this._url
|
|
375
376
|
}
|
|
376
377
|
|
|
377
|
-
// By the time
|
|
378
|
-
|
|
379
|
-
if (this._writer?.
|
|
380
|
-
this._writer.
|
|
378
|
+
// By the time addMetadataTags is called, the agent info request might not have finished
|
|
379
|
+
addMetadataTags (tags) {
|
|
380
|
+
if (this._writer?.addMetadataTags) {
|
|
381
|
+
this._writer.addMetadataTags(tags)
|
|
381
382
|
} else {
|
|
382
383
|
this._canUseCiVisProtocolPromise.then(() => {
|
|
383
|
-
if (this._writer?.
|
|
384
|
-
this._writer.
|
|
384
|
+
if (this._writer?.addMetadataTags) {
|
|
385
|
+
this._writer.addMetadataTags(tags)
|
|
385
386
|
}
|
|
386
387
|
})
|
|
387
388
|
}
|
|
@@ -113,8 +113,7 @@ function getLibraryConfiguration ({
|
|
|
113
113
|
isFlakyTestRetriesEnabled,
|
|
114
114
|
isDiEnabled: isDiEnabled && isFlakyTestRetriesEnabled,
|
|
115
115
|
isKnownTestsEnabled,
|
|
116
|
-
|
|
117
|
-
isQuarantinedTestsEnabled: (testManagementConfig?.enabled ?? false)
|
|
116
|
+
isTestManagementEnabled: (testManagementConfig?.enabled ?? false)
|
|
118
117
|
}
|
|
119
118
|
|
|
120
119
|
log.debug(() => `Remote settings: ${JSON.stringify(settings)}`)
|
|
@@ -13,7 +13,8 @@ const formattedTags = {
|
|
|
13
13
|
isUnsupportedCIProvider: 'is_unsupported_ci',
|
|
14
14
|
isNew: 'is_new',
|
|
15
15
|
isRum: 'is_rum',
|
|
16
|
-
browserDriver: 'browser_driver'
|
|
16
|
+
browserDriver: 'browser_driver',
|
|
17
|
+
autoInjected: 'auto_injected'
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
// Transform tags dictionary to array of strings.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const request = require('../../exporters/common/request')
|
|
2
2
|
const id = require('../../id')
|
|
3
3
|
|
|
4
|
-
function
|
|
4
|
+
function getTestManagementTests ({
|
|
5
5
|
url,
|
|
6
6
|
isEvpProxy,
|
|
7
7
|
evpProxyPrefix,
|
|
@@ -28,7 +28,7 @@ function getQuarantinedTests ({
|
|
|
28
28
|
} else {
|
|
29
29
|
const apiKey = process.env.DATADOG_API_KEY || process.env.DD_API_KEY
|
|
30
30
|
if (!apiKey) {
|
|
31
|
-
return done(new Error('
|
|
31
|
+
return done(new Error('Test management tests were not fetched because Datadog API key is not defined.'))
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
options.headers['dd-api-key'] = apiKey
|
|
@@ -49,9 +49,9 @@ function getQuarantinedTests ({
|
|
|
49
49
|
done(err)
|
|
50
50
|
} else {
|
|
51
51
|
try {
|
|
52
|
-
const { data: { attributes: { modules:
|
|
52
|
+
const { data: { attributes: { modules: testManagementTests } } } = JSON.parse(res)
|
|
53
53
|
|
|
54
|
-
done(null,
|
|
54
|
+
done(null, testManagementTests)
|
|
55
55
|
} catch (err) {
|
|
56
56
|
done(err)
|
|
57
57
|
}
|
|
@@ -59,4 +59,4 @@ function getQuarantinedTests ({
|
|
|
59
59
|
})
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
module.exports = {
|
|
62
|
+
module.exports = { getTestManagementTests }
|
|
@@ -591,8 +591,10 @@ class Config {
|
|
|
591
591
|
this._setValue(defaults, 'url', undefined)
|
|
592
592
|
this._setValue(defaults, 'version', pkg.version)
|
|
593
593
|
this._setValue(defaults, 'instrumentation_config_id', undefined)
|
|
594
|
+
this._setValue(defaults, 'aws.dynamoDb.tablePrimaryKeys', undefined)
|
|
595
|
+
this._setValue(defaults, 'vertexai.spanCharLimit', 128)
|
|
596
|
+
this._setValue(defaults, 'vertexai.spanPromptCompletionSampleRate', 1.0)
|
|
594
597
|
this._setValue(defaults, 'trace.aws.addSpanPointers', true)
|
|
595
|
-
this._setValue(defaults, 'trace.dynamoDb.tablePrimaryKeys', undefined)
|
|
596
598
|
}
|
|
597
599
|
|
|
598
600
|
_applyLocalStableConfig () {
|
|
@@ -760,6 +762,8 @@ class Config {
|
|
|
760
762
|
DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH,
|
|
761
763
|
DD_TRACING_ENABLED,
|
|
762
764
|
DD_VERSION,
|
|
765
|
+
DD_VERTEXAI_SPAN_PROMPT_COMPLETION_SAMPLE_RATE,
|
|
766
|
+
DD_VERTEXAI_SPAN_CHAR_LIMIT,
|
|
763
767
|
DD_TRACE_INFERRED_PROXY_SERVICES_ENABLED,
|
|
764
768
|
OTEL_METRICS_EXPORTER,
|
|
765
769
|
OTEL_PROPAGATORS,
|
|
@@ -973,6 +977,12 @@ class Config {
|
|
|
973
977
|
this._setBoolean(env, 'trace.aws.addSpanPointers', DD_TRACE_AWS_ADD_SPAN_POINTERS)
|
|
974
978
|
this._setString(env, 'trace.dynamoDb.tablePrimaryKeys', DD_TRACE_DYNAMODB_TABLE_PRIMARY_KEYS)
|
|
975
979
|
this._setArray(env, 'graphqlErrorExtensions', DD_TRACE_GRAPHQL_ERROR_EXTENSIONS)
|
|
980
|
+
this._setValue(
|
|
981
|
+
env,
|
|
982
|
+
'vertexai.spanPromptCompletionSampleRate',
|
|
983
|
+
maybeFloat(DD_VERTEXAI_SPAN_PROMPT_COMPLETION_SAMPLE_RATE)
|
|
984
|
+
)
|
|
985
|
+
this._setValue(env, 'vertexai.spanCharLimit', maybeInt(DD_VERTEXAI_SPAN_CHAR_LIMIT))
|
|
976
986
|
}
|
|
977
987
|
|
|
978
988
|
_applyOptions (options) {
|
|
@@ -48,8 +48,15 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
|
|
|
48
48
|
this.reset()
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
addMetadataTags (tags) {
|
|
52
|
+
ALLOWED_CONTENT_TYPES.forEach(type => {
|
|
53
|
+
if (tags[type]) {
|
|
54
|
+
this.metadataTags[type] = {
|
|
55
|
+
...this.metadataTags[type],
|
|
56
|
+
...tags[type]
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
})
|
|
53
60
|
}
|
|
54
61
|
|
|
55
62
|
_encodeTestSuite (bytes, content) {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const path = require('path')
|
|
4
4
|
|
|
5
|
-
const { _extractModuleNameAndHandlerPath, _extractModuleRootAndHandler,
|
|
5
|
+
const { _extractModuleNameAndHandlerPath, _extractModuleRootAndHandler, _getLambdaFilePaths } = require('./ritm')
|
|
6
6
|
const { datadog } = require('../handler')
|
|
7
7
|
const { addHook } = require('../../../../datadog-instrumentations/src/helpers/instrument')
|
|
8
8
|
const shimmer = require('../../../../datadog-shimmer')
|
|
@@ -65,9 +65,11 @@ if (originalLambdaHandler !== undefined) {
|
|
|
65
65
|
const [_module, handlerPath] = _extractModuleNameAndHandlerPath(moduleAndHandler)
|
|
66
66
|
|
|
67
67
|
const lambdaStylePath = path.resolve(lambdaTaskRoot, moduleRoot, _module)
|
|
68
|
-
const
|
|
68
|
+
const lambdaFilePaths = _getLambdaFilePaths(lambdaStylePath)
|
|
69
69
|
|
|
70
|
-
|
|
70
|
+
for (const lambdaFilePath of lambdaFilePaths) {
|
|
71
|
+
addHook({ name: lambdaFilePath }, patchLambdaModule(handlerPath))
|
|
72
|
+
}
|
|
71
73
|
} else {
|
|
72
74
|
// Instrumentation is done manually.
|
|
73
75
|
addHook({ name: 'datadog-lambda-js' }, patchDatadogLambdaModule)
|
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
*/
|
|
8
8
|
'use strict'
|
|
9
9
|
|
|
10
|
-
const fs = require('fs')
|
|
11
10
|
const path = require('path')
|
|
12
11
|
|
|
13
12
|
const log = require('../../log')
|
|
@@ -60,23 +59,18 @@ function _extractModuleNameAndHandlerPath (handler) {
|
|
|
60
59
|
}
|
|
61
60
|
|
|
62
61
|
/**
|
|
63
|
-
* Returns
|
|
64
|
-
* when required.
|
|
62
|
+
* Returns all possible paths of the files to be patched when required.
|
|
65
63
|
*
|
|
66
64
|
* @param {*} lambdaStylePath the path comprised of the `LAMBDA_TASK_ROOT`,
|
|
67
65
|
* the root of the module of the Lambda handler, and the module name.
|
|
68
|
-
* @returns the lambdaStylePath with
|
|
66
|
+
* @returns the lambdaStylePath with appropiate extensions for the hook.
|
|
69
67
|
*/
|
|
70
|
-
function
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
} else if (fs.existsSync(lambdaStylePath + '.cjs')) {
|
|
77
|
-
lambdaFilePath += '.cjs'
|
|
78
|
-
}
|
|
79
|
-
return lambdaFilePath
|
|
68
|
+
function _getLambdaFilePaths (lambdaStylePath) {
|
|
69
|
+
return [
|
|
70
|
+
`${lambdaStylePath}.js`,
|
|
71
|
+
`${lambdaStylePath}.mjs`,
|
|
72
|
+
`${lambdaStylePath}.cjs`
|
|
73
|
+
]
|
|
80
74
|
}
|
|
81
75
|
|
|
82
76
|
/**
|
|
@@ -92,12 +86,13 @@ const registerLambdaHook = () => {
|
|
|
92
86
|
const [_module] = _extractModuleNameAndHandlerPath(moduleAndHandler)
|
|
93
87
|
|
|
94
88
|
const lambdaStylePath = path.resolve(lambdaTaskRoot, moduleRoot, _module)
|
|
95
|
-
const
|
|
89
|
+
const lambdaFilePaths = _getLambdaFilePaths(lambdaStylePath)
|
|
96
90
|
|
|
97
|
-
|
|
91
|
+
// TODO: Redo this like any other instrumentation.
|
|
92
|
+
Hook(lambdaFilePaths, (moduleExports, name) => {
|
|
98
93
|
require('./patch')
|
|
99
94
|
|
|
100
|
-
for (const { hook } of instrumentations[
|
|
95
|
+
for (const { hook } of instrumentations[name]) {
|
|
101
96
|
try {
|
|
102
97
|
moduleExports = hook(moduleExports)
|
|
103
98
|
} catch (e) {
|
|
@@ -133,6 +128,6 @@ const registerLambdaHook = () => {
|
|
|
133
128
|
module.exports = {
|
|
134
129
|
_extractModuleRootAndHandler,
|
|
135
130
|
_extractModuleNameAndHandlerPath,
|
|
136
|
-
|
|
131
|
+
_getLambdaFilePaths,
|
|
137
132
|
registerLambdaHook
|
|
138
133
|
}
|
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
const LLMObsPlugin = require('./base')
|
|
4
4
|
|
|
5
|
+
function isIterable (obj) {
|
|
6
|
+
if (obj == null) {
|
|
7
|
+
return false
|
|
8
|
+
}
|
|
9
|
+
return typeof obj[Symbol.iterator] === 'function'
|
|
10
|
+
}
|
|
11
|
+
|
|
5
12
|
class OpenAiLLMObsPlugin extends LLMObsPlugin {
|
|
6
13
|
static get id () { return 'openai' }
|
|
7
14
|
static get prefix () {
|
|
@@ -16,10 +23,13 @@ class OpenAiLLMObsPlugin extends LLMObsPlugin {
|
|
|
16
23
|
const inputs = ctx.args[0] // completion, chat completion, and embeddings take one argument
|
|
17
24
|
const operation = getOperation(methodName)
|
|
18
25
|
const kind = operation === 'embedding' ? 'embedding' : 'llm'
|
|
19
|
-
|
|
26
|
+
|
|
27
|
+
const { modelProvider, client } = this._getModelProviderAndClient(ctx.basePath)
|
|
28
|
+
|
|
29
|
+
const name = `${client}.${methodName}`
|
|
20
30
|
|
|
21
31
|
return {
|
|
22
|
-
modelProvider
|
|
32
|
+
modelProvider,
|
|
23
33
|
modelName: inputs.model,
|
|
24
34
|
kind,
|
|
25
35
|
name
|
|
@@ -52,6 +62,16 @@ class OpenAiLLMObsPlugin extends LLMObsPlugin {
|
|
|
52
62
|
}
|
|
53
63
|
}
|
|
54
64
|
|
|
65
|
+
_getModelProviderAndClient (baseUrl = '') {
|
|
66
|
+
if (baseUrl.includes('azure')) {
|
|
67
|
+
return { modelProvider: 'azure_openai', client: 'AzureOpenAI' }
|
|
68
|
+
} else if (baseUrl.includes('deepseek')) {
|
|
69
|
+
return { modelProvider: 'deepseek', client: 'DeepSeek' }
|
|
70
|
+
} else {
|
|
71
|
+
return { modelProvider: 'openai', client: 'OpenAI' }
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
55
75
|
_extractMetrics (response) {
|
|
56
76
|
const metrics = {}
|
|
57
77
|
const tokenUsage = response.usage
|
|
@@ -122,6 +142,11 @@ class OpenAiLLMObsPlugin extends LLMObsPlugin {
|
|
|
122
142
|
|
|
123
143
|
const outputMessages = []
|
|
124
144
|
const { choices } = response
|
|
145
|
+
if (!isIterable(choices)) {
|
|
146
|
+
this._tagger.tagLLMIO(span, messages, [{ content: '' }])
|
|
147
|
+
return
|
|
148
|
+
}
|
|
149
|
+
|
|
125
150
|
for (const choice of choices) {
|
|
126
151
|
const message = choice.message || choice.delta
|
|
127
152
|
const content = message.content || ''
|