dd-trace 5.41.0 → 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/fetch.js +1 -1
- 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/dogstatsd.js +137 -28
- 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/plugin_manager.js +0 -4
- package/packages/dd-trace/src/plugins/ci_plugin.js +38 -10
- package/packages/dd-trace/src/plugins/index.js +2 -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/runtime_metrics/runtime_metrics.js +15 -80
- 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) {
|
|
@@ -6,6 +6,7 @@ const dgram = require('dgram')
|
|
|
6
6
|
const isIP = require('net').isIP
|
|
7
7
|
const log = require('./log')
|
|
8
8
|
const { URL, format } = require('url')
|
|
9
|
+
const Histogram = require('./histogram')
|
|
9
10
|
|
|
10
11
|
const MAX_BUFFER_SIZE = 1024 // limit from the agent
|
|
11
12
|
|
|
@@ -193,6 +194,117 @@ class DogStatsDClient {
|
|
|
193
194
|
}
|
|
194
195
|
}
|
|
195
196
|
|
|
197
|
+
// TODO: Handle arrays of tags and tags translation.
|
|
198
|
+
class MetricsAggregationClient {
|
|
199
|
+
constructor (client) {
|
|
200
|
+
this._client = client
|
|
201
|
+
|
|
202
|
+
this.reset()
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
flush () {
|
|
206
|
+
this._captureCounters()
|
|
207
|
+
this._captureGauges()
|
|
208
|
+
this._captureHistograms()
|
|
209
|
+
|
|
210
|
+
this._client.flush()
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
reset () {
|
|
214
|
+
this._counters = {}
|
|
215
|
+
this._gauges = {}
|
|
216
|
+
this._histograms = {}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
distribution (name, value, tag) {
|
|
220
|
+
this._client.distribution(name, value, tag && [tag])
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
boolean (name, value, tag) {
|
|
224
|
+
this.gauge(name, value ? 1 : 0, tag)
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
histogram (name, value, tag) {
|
|
228
|
+
this._histograms[name] = this._histograms[name] || new Map()
|
|
229
|
+
|
|
230
|
+
if (!this._histograms[name].has(tag)) {
|
|
231
|
+
this._histograms[name].set(tag, new Histogram())
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
this._histograms[name].get(tag).record(value)
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
count (name, count, tag, monotonic = false) {
|
|
238
|
+
if (typeof tag === 'boolean') {
|
|
239
|
+
monotonic = tag
|
|
240
|
+
tag = undefined
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const map = monotonic ? this._counters : this._gauges
|
|
244
|
+
|
|
245
|
+
map[name] = map[name] || new Map()
|
|
246
|
+
|
|
247
|
+
const value = map[name].get(tag) || 0
|
|
248
|
+
|
|
249
|
+
map[name].set(tag, value + count)
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
gauge (name, value, tag) {
|
|
253
|
+
this._gauges[name] = this._gauges[name] || new Map()
|
|
254
|
+
this._gauges[name].set(tag, value)
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
increment (name, count = 1, tag, monotonic) {
|
|
258
|
+
this.count(name, count, tag, monotonic)
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
decrement (name, count = 1, tag) {
|
|
262
|
+
this.count(name, -count, tag)
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
_captureGauges () {
|
|
266
|
+
Object.keys(this._gauges).forEach(name => {
|
|
267
|
+
this._gauges[name].forEach((value, tag) => {
|
|
268
|
+
this._client.gauge(name, value, tag && [tag])
|
|
269
|
+
})
|
|
270
|
+
})
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
_captureCounters () {
|
|
274
|
+
Object.keys(this._counters).forEach(name => {
|
|
275
|
+
this._counters[name].forEach((value, tag) => {
|
|
276
|
+
this._client.increment(name, value, tag && [tag])
|
|
277
|
+
})
|
|
278
|
+
})
|
|
279
|
+
|
|
280
|
+
this._counters = {}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
_captureHistograms () {
|
|
284
|
+
Object.keys(this._histograms).forEach(name => {
|
|
285
|
+
this._histograms[name].forEach((stats, tag) => {
|
|
286
|
+
const tags = tag && [tag]
|
|
287
|
+
|
|
288
|
+
// Stats can contain garbage data when a value was never recorded.
|
|
289
|
+
if (stats.count === 0) {
|
|
290
|
+
stats = { max: 0, min: 0, sum: 0, avg: 0, median: 0, p95: 0, count: 0, reset: stats.reset }
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
this._client.gauge(`${name}.min`, stats.min, tags)
|
|
294
|
+
this._client.gauge(`${name}.max`, stats.max, tags)
|
|
295
|
+
this._client.increment(`${name}.sum`, stats.sum, tags)
|
|
296
|
+
this._client.increment(`${name}.total`, stats.sum, tags)
|
|
297
|
+
this._client.gauge(`${name}.avg`, stats.avg, tags)
|
|
298
|
+
this._client.increment(`${name}.count`, stats.count, tags)
|
|
299
|
+
this._client.gauge(`${name}.median`, stats.median, tags)
|
|
300
|
+
this._client.gauge(`${name}.95percentile`, stats.p95, tags)
|
|
301
|
+
|
|
302
|
+
stats.reset()
|
|
303
|
+
})
|
|
304
|
+
})
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
196
308
|
/**
|
|
197
309
|
* This is a simplified user-facing proxy to the underlying DogStatsDClient instance
|
|
198
310
|
*
|
|
@@ -201,7 +313,7 @@ class DogStatsDClient {
|
|
|
201
313
|
class CustomMetrics {
|
|
202
314
|
constructor (config) {
|
|
203
315
|
const clientConfig = DogStatsDClient.generateClientConfig(config)
|
|
204
|
-
this.
|
|
316
|
+
this._client = new MetricsAggregationClient(new DogStatsDClient(clientConfig))
|
|
205
317
|
|
|
206
318
|
const flush = this.flush.bind(this)
|
|
207
319
|
|
|
@@ -212,47 +324,43 @@ class CustomMetrics {
|
|
|
212
324
|
}
|
|
213
325
|
|
|
214
326
|
increment (stat, value = 1, tags) {
|
|
215
|
-
|
|
216
|
-
stat,
|
|
217
|
-
|
|
218
|
-
CustomMetrics.tagTranslator(tags)
|
|
219
|
-
)
|
|
327
|
+
for (const tag of this._normalizeTags(tags)) {
|
|
328
|
+
this._client.increment(stat, value, tag)
|
|
329
|
+
}
|
|
220
330
|
}
|
|
221
331
|
|
|
222
332
|
decrement (stat, value = 1, tags) {
|
|
223
|
-
|
|
224
|
-
stat,
|
|
225
|
-
|
|
226
|
-
CustomMetrics.tagTranslator(tags)
|
|
227
|
-
)
|
|
333
|
+
for (const tag of this._normalizeTags(tags)) {
|
|
334
|
+
this._client.decrement(stat, value, tag)
|
|
335
|
+
}
|
|
228
336
|
}
|
|
229
337
|
|
|
230
338
|
gauge (stat, value, tags) {
|
|
231
|
-
|
|
232
|
-
stat,
|
|
233
|
-
|
|
234
|
-
CustomMetrics.tagTranslator(tags)
|
|
235
|
-
)
|
|
339
|
+
for (const tag of this._normalizeTags(tags)) {
|
|
340
|
+
this._client.gauge(stat, value, tag)
|
|
341
|
+
}
|
|
236
342
|
}
|
|
237
343
|
|
|
238
344
|
distribution (stat, value, tags) {
|
|
239
|
-
|
|
240
|
-
stat,
|
|
241
|
-
|
|
242
|
-
CustomMetrics.tagTranslator(tags)
|
|
243
|
-
)
|
|
345
|
+
for (const tag of this._normalizeTags(tags)) {
|
|
346
|
+
this._client.distribution(stat, value, tag)
|
|
347
|
+
}
|
|
244
348
|
}
|
|
245
349
|
|
|
246
350
|
histogram (stat, value, tags) {
|
|
247
|
-
|
|
248
|
-
stat,
|
|
249
|
-
|
|
250
|
-
CustomMetrics.tagTranslator(tags)
|
|
251
|
-
)
|
|
351
|
+
for (const tag of this._normalizeTags(tags)) {
|
|
352
|
+
this._client.histogram(stat, value, tag)
|
|
353
|
+
}
|
|
252
354
|
}
|
|
253
355
|
|
|
254
356
|
flush () {
|
|
255
|
-
return this.
|
|
357
|
+
return this._client.flush()
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
_normalizeTags (tags) {
|
|
361
|
+
tags = CustomMetrics.tagTranslator(tags)
|
|
362
|
+
|
|
363
|
+
return tags.length === 0 ? [undefined] : tags
|
|
256
364
|
}
|
|
257
365
|
|
|
258
366
|
/**
|
|
@@ -274,5 +382,6 @@ class CustomMetrics {
|
|
|
274
382
|
|
|
275
383
|
module.exports = {
|
|
276
384
|
DogStatsDClient,
|
|
277
|
-
CustomMetrics
|
|
385
|
+
CustomMetrics,
|
|
386
|
+
MetricsAggregationClient
|
|
278
387
|
}
|
|
@@ -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)
|