dd-trace 5.86.0 → 5.88.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 +60 -32
- package/ext/exporters.d.ts +1 -0
- package/ext/exporters.js +1 -0
- package/index.d.ts +243 -7
- package/package.json +9 -6
- package/packages/datadog-instrumentations/src/ai.js +54 -90
- package/packages/datadog-instrumentations/src/cucumber.js +14 -0
- package/packages/datadog-instrumentations/src/helpers/hook.js +17 -11
- package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/compiler.js +55 -14
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +15 -13
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/ai.js +103 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/bullmq.js +108 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +2 -1
- package/packages/datadog-instrumentations/src/helpers/rewriter/transformer.js +21 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +138 -12
- package/packages/datadog-instrumentations/src/http/client.js +119 -1
- package/packages/datadog-instrumentations/src/jest.js +179 -15
- package/packages/datadog-instrumentations/src/kafkajs.js +20 -17
- package/packages/datadog-instrumentations/src/mocha/utils.js +6 -0
- package/packages/datadog-instrumentations/src/mysql2.js +131 -64
- package/packages/datadog-instrumentations/src/playwright.js +9 -1
- package/packages/datadog-instrumentations/src/stripe.js +92 -0
- package/packages/datadog-instrumentations/src/vitest.js +11 -0
- package/packages/datadog-plugin-amqplib/src/consumer.js +14 -10
- package/packages/datadog-plugin-amqplib/src/producer.js +23 -19
- package/packages/datadog-plugin-azure-functions/src/index.js +53 -37
- package/packages/datadog-plugin-bullmq/src/consumer.js +33 -11
- package/packages/datadog-plugin-bullmq/src/producer.js +60 -31
- package/packages/datadog-plugin-cucumber/src/index.js +9 -6
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +33 -0
- package/packages/datadog-plugin-cypress/src/support.js +48 -8
- package/packages/datadog-plugin-jest/src/index.js +12 -2
- package/packages/datadog-plugin-jest/src/util.js +2 -1
- package/packages/datadog-plugin-kafkajs/src/consumer.js +22 -12
- package/packages/datadog-plugin-kafkajs/src/producer.js +33 -22
- package/packages/datadog-plugin-mocha/src/index.js +9 -6
- package/packages/datadog-plugin-playwright/src/index.js +10 -6
- package/packages/datadog-plugin-vitest/src/index.js +13 -8
- package/packages/dd-trace/src/appsec/addresses.js +11 -0
- package/packages/dd-trace/src/appsec/channels.js +5 -1
- package/packages/dd-trace/src/appsec/downstream_requests.js +302 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/cookie-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/ssrf-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/unvalidated-redirect-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +4 -5
- package/packages/dd-trace/src/appsec/iast/path-line.js +36 -25
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/command-sensitive-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +3 -4
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +3 -2
- package/packages/dd-trace/src/appsec/index.js +103 -0
- package/packages/dd-trace/src/appsec/rasp/ssrf.js +66 -4
- package/packages/dd-trace/src/azure_metadata.js +0 -2
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +14 -1
- package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +1 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +2 -0
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +1 -1
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +4 -1
- package/packages/dd-trace/src/ci-visibility/requests/request.js +236 -0
- package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +1 -1
- package/packages/dd-trace/src/config/defaults.js +148 -195
- package/packages/dd-trace/src/config/helper.js +43 -1
- package/packages/dd-trace/src/config/index.js +42 -14
- package/packages/dd-trace/src/config/supported-configurations.json +4115 -510
- package/packages/dd-trace/src/constants.js +0 -2
- package/packages/dd-trace/src/crashtracking/crashtracker.js +10 -3
- package/packages/dd-trace/src/datastreams/pathway.js +22 -3
- package/packages/dd-trace/src/datastreams/processor.js +14 -1
- package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +47 -2
- package/packages/dd-trace/src/debugger/devtools_client/index.js +75 -23
- package/packages/dd-trace/src/debugger/devtools_client/remote_config.js +23 -1
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/collector.js +3 -3
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +168 -36
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/processor.js +18 -0
- package/packages/dd-trace/src/encode/agentless-json.js +141 -0
- package/packages/dd-trace/src/exporter.js +2 -0
- package/packages/dd-trace/src/exporters/agent/writer.js +22 -8
- package/packages/dd-trace/src/exporters/agentless/index.js +89 -0
- package/packages/dd-trace/src/exporters/agentless/writer.js +184 -0
- package/packages/dd-trace/src/exporters/common/agents.js +1 -1
- package/packages/dd-trace/src/exporters/common/request.js +4 -4
- package/packages/dd-trace/src/llmobs/constants/writers.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/ai/index.js +5 -3
- package/packages/dd-trace/src/llmobs/sdk.js +34 -5
- package/packages/dd-trace/src/opentelemetry/context_manager.js +19 -46
- package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +3 -4
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +3 -5
- package/packages/dd-trace/src/opentracing/span.js +6 -4
- package/packages/dd-trace/src/plugins/ci_plugin.js +57 -5
- package/packages/dd-trace/src/plugins/database.js +57 -45
- package/packages/dd-trace/src/plugins/outbound.js +27 -2
- package/packages/dd-trace/src/plugins/tracing.js +39 -4
- package/packages/dd-trace/src/plugins/util/inferred_proxy.js +7 -0
- package/packages/dd-trace/src/plugins/util/test.js +48 -0
- package/packages/dd-trace/src/plugins/util/web.js +8 -7
- package/packages/dd-trace/src/profiling/exporter_cli.js +1 -0
- package/packages/dd-trace/src/propagation-hash/index.js +145 -0
- package/packages/dd-trace/src/proxy.js +4 -0
- package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +1 -1
- package/packages/dd-trace/src/startup-log.js +3 -3
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/bullmq.json +0 -106
- package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secrets-rules.js +0 -741
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-regex.js +0 -11
- package/packages/dd-trace/src/plugins/util/serverless.js +0 -8
- package/packages/dd-trace/src/scope/noop/scope.js +0 -21
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const http = require('http')
|
|
4
|
+
const https = require('https')
|
|
5
|
+
const zlib = require('zlib')
|
|
6
|
+
|
|
7
|
+
const { storage } = require('../../../../datadog-core')
|
|
8
|
+
const log = require('../../log')
|
|
9
|
+
const { httpAgent, httpsAgent } = require('../../exporters/common/agents')
|
|
10
|
+
const { urlToHttpOptions } = require('../../exporters/common/url-to-http-options-polyfill')
|
|
11
|
+
|
|
12
|
+
const RATE_LIMIT_MAX_WAIT_MS = 30_000
|
|
13
|
+
const RETRY_BASE_MS = 5000
|
|
14
|
+
const RETRY_JITTER_MS = 2500
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Calculates retry delay with jitter to prevent thundering herd.
|
|
18
|
+
* Delay is RETRY_BASE_MS + random(0, RETRY_JITTER_MS) (e.g. 5–7.5 seconds).
|
|
19
|
+
*
|
|
20
|
+
* @returns {number} Delay in milliseconds
|
|
21
|
+
*/
|
|
22
|
+
function getRetryDelay () {
|
|
23
|
+
return RETRY_BASE_MS + (Math.random() * RETRY_JITTER_MS)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Determines if a network error is retriable (transient failures only).
|
|
28
|
+
* ECONNREFUSED is retried because it can be transient (service starting up,
|
|
29
|
+
* restarts, rolling deploys, k8s pod/readiness transitions). ENOTFOUND is
|
|
30
|
+
* excluded as it indicates DNS failure or wrong host and is usually not transient.
|
|
31
|
+
*
|
|
32
|
+
* @param {Error} err - The error to check
|
|
33
|
+
* @returns {boolean}
|
|
34
|
+
*/
|
|
35
|
+
function isRetriableNetworkError (err) {
|
|
36
|
+
if (!err.code) return false
|
|
37
|
+
return err.code === 'ECONNREFUSED' ||
|
|
38
|
+
err.code === 'ECONNRESET' ||
|
|
39
|
+
err.code === 'ETIMEDOUT' ||
|
|
40
|
+
err.code === 'EPIPE'
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function parseUrl (urlObjOrString) {
|
|
44
|
+
if (urlObjOrString !== null && typeof urlObjOrString === 'object') {
|
|
45
|
+
return urlToHttpOptions(urlObjOrString)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const url = urlToHttpOptions(new URL(urlObjOrString))
|
|
49
|
+
|
|
50
|
+
if (url.protocol === 'unix:' && url.hostname === '.') {
|
|
51
|
+
const udsPath = urlObjOrString.slice(5)
|
|
52
|
+
url.path = udsPath
|
|
53
|
+
url.pathname = udsPath
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return url
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Simplified HTTP request for test optimization (library config). Uses common HTTP agents.
|
|
61
|
+
* Retries: 429 (with X-ratelimit-reset, max 30s wait),
|
|
62
|
+
* >=500 and transient network errors (5–7.5s delay with jitter). Max one retry.
|
|
63
|
+
* Destroys connections on errors to prevent reuse of bad connections. Preserves
|
|
64
|
+
* original status code across retries for telemetry.
|
|
65
|
+
*
|
|
66
|
+
* @param {string} data - Request body (e.g. JSON string)
|
|
67
|
+
* @param {object} options - { url, path?, method?, headers?, timeout? } (may be mutated)
|
|
68
|
+
* @param {Function} callback - (err, res, statusCode) => void
|
|
69
|
+
*/
|
|
70
|
+
function request (data, options, callback) {
|
|
71
|
+
const headers = options.headers ? { ...options.headers } : {}
|
|
72
|
+
headers['Content-Length'] = Buffer.byteLength(data, 'utf8')
|
|
73
|
+
|
|
74
|
+
const opts = { ...options, method: 'POST', headers }
|
|
75
|
+
|
|
76
|
+
if (opts.url) {
|
|
77
|
+
const url = parseUrl(opts.url)
|
|
78
|
+
if (url.protocol === 'unix:') {
|
|
79
|
+
opts.socketPath = url.pathname
|
|
80
|
+
} else {
|
|
81
|
+
opts.path = opts.path ?? url.path
|
|
82
|
+
opts.protocol = url.protocol
|
|
83
|
+
opts.hostname = url.hostname
|
|
84
|
+
opts.port = url.port
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const timeout = opts.timeout || 2000
|
|
89
|
+
const isSecure = opts.protocol === 'https:'
|
|
90
|
+
const client = isSecure ? https : http
|
|
91
|
+
|
|
92
|
+
if (!opts.socketPath) {
|
|
93
|
+
opts.agent = isSecure ? httpsAgent : httpAgent
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
let hasRetried = false
|
|
97
|
+
let firstStatusCode = null
|
|
98
|
+
|
|
99
|
+
const makeRequest = () => {
|
|
100
|
+
storage('legacy').run({ noop: true }, () => {
|
|
101
|
+
const req = client.request(opts, (res) => {
|
|
102
|
+
// Capture non-2xx status code as soon as we see it so telemetry preserves it if the retry
|
|
103
|
+
// fails with a network error (no HTTP response) before 'end' fires
|
|
104
|
+
if (res.statusCode >= 400 && firstStatusCode === null) {
|
|
105
|
+
firstStatusCode = res.statusCode
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const chunks = []
|
|
109
|
+
|
|
110
|
+
res.setTimeout(timeout)
|
|
111
|
+
|
|
112
|
+
res.on('data', chunk => {
|
|
113
|
+
chunks.push(chunk)
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
res.once('end', () => {
|
|
117
|
+
const buffer = Buffer.concat(chunks)
|
|
118
|
+
|
|
119
|
+
if (res.statusCode >= 200 && res.statusCode <= 299) {
|
|
120
|
+
const isGzip = res.headers['content-encoding'] === 'gzip'
|
|
121
|
+
if (isGzip) {
|
|
122
|
+
zlib.gunzip(buffer, (err, result) => {
|
|
123
|
+
if (err) {
|
|
124
|
+
log.error('Could not gunzip response: %s', err.message)
|
|
125
|
+
callback(null, '', res.statusCode)
|
|
126
|
+
} else {
|
|
127
|
+
callback(null, result.toString(), res.statusCode)
|
|
128
|
+
}
|
|
129
|
+
})
|
|
130
|
+
} else {
|
|
131
|
+
callback(null, buffer.toString(), res.statusCode)
|
|
132
|
+
}
|
|
133
|
+
return
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (res.statusCode === 429 && !hasRetried) {
|
|
137
|
+
const resetHeader = res.headers['x-ratelimit-reset']
|
|
138
|
+
const resetTs = (resetHeader === null || resetHeader === undefined)
|
|
139
|
+
? Number.NaN
|
|
140
|
+
: Number.parseInt(resetHeader, 10)
|
|
141
|
+
const waitMs = Number.isFinite(resetTs) ? Math.max(0, resetTs * 1000 - Date.now()) : Number.NaN
|
|
142
|
+
|
|
143
|
+
if (Number.isFinite(waitMs) && waitMs <= RATE_LIMIT_MAX_WAIT_MS) {
|
|
144
|
+
hasRetried = true
|
|
145
|
+
setTimeout(makeRequest, waitMs)
|
|
146
|
+
return
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (!Number.isFinite(waitMs) || waitMs > RATE_LIMIT_MAX_WAIT_MS) {
|
|
150
|
+
log.debug('Rate limited (429): drop payload (wait %sms > %sms or invalid header)',
|
|
151
|
+
Number.isFinite(waitMs) ? waitMs : 'N/A', RATE_LIMIT_MAX_WAIT_MS)
|
|
152
|
+
}
|
|
153
|
+
} else if (res.statusCode >= 500 && !hasRetried) {
|
|
154
|
+
try {
|
|
155
|
+
if (req.socket) req.socket.destroy()
|
|
156
|
+
} catch {
|
|
157
|
+
// ignore
|
|
158
|
+
}
|
|
159
|
+
hasRetried = true
|
|
160
|
+
setTimeout(makeRequest, getRetryDelay())
|
|
161
|
+
return
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const error = buildError(res, buffer, opts)
|
|
165
|
+
// Use original status code if this is a failed retry
|
|
166
|
+
callback(error, null, firstStatusCode === null ? res.statusCode : firstStatusCode)
|
|
167
|
+
})
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
req.once('error', err => {
|
|
171
|
+
try {
|
|
172
|
+
if (req.socket) req.socket.destroy()
|
|
173
|
+
} catch {
|
|
174
|
+
// ignore
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Retry on retriable network errors
|
|
178
|
+
if (!hasRetried && isRetriableNetworkError(err)) {
|
|
179
|
+
hasRetried = true
|
|
180
|
+
setTimeout(makeRequest, getRetryDelay())
|
|
181
|
+
return
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Pass original status code (if any) for accurate telemetry
|
|
185
|
+
callback(err, null, firstStatusCode)
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
req.setTimeout(timeout, () => {
|
|
189
|
+
try {
|
|
190
|
+
if (typeof req.abort === 'function') {
|
|
191
|
+
req.abort()
|
|
192
|
+
} else {
|
|
193
|
+
req.destroy()
|
|
194
|
+
}
|
|
195
|
+
} catch {
|
|
196
|
+
// ignore
|
|
197
|
+
}
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
req.write(data, 'utf8')
|
|
201
|
+
req.end()
|
|
202
|
+
})
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
makeRequest()
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* @param {object} res - IncomingMessage
|
|
210
|
+
* @param {Buffer} buffer - Response body
|
|
211
|
+
* @param {object} options - Request options
|
|
212
|
+
* @returns {Error}
|
|
213
|
+
*/
|
|
214
|
+
function buildError (res, buffer, options) {
|
|
215
|
+
let errorMessage = ''
|
|
216
|
+
try {
|
|
217
|
+
const fullUrl = new URL(
|
|
218
|
+
options.path,
|
|
219
|
+
options.url || options.hostname || `http://localhost:${options.port}`
|
|
220
|
+
).href
|
|
221
|
+
errorMessage = `Error from ${fullUrl}: ${res.statusCode} ${http.STATUS_CODES[res.statusCode]}.`
|
|
222
|
+
} catch {
|
|
223
|
+
// ignore
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const responseData = buffer.toString()
|
|
227
|
+
if (responseData) {
|
|
228
|
+
errorMessage += ` Response from the endpoint: "${responseData}"`
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const error = new log.NoTransmitError(errorMessage)
|
|
232
|
+
error.status = res.statusCode
|
|
233
|
+
return error
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
module.exports = request
|
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const pkg = require('../pkg')
|
|
4
|
-
const {
|
|
4
|
+
const { isFalse, isTrue } = require('../util')
|
|
5
5
|
const { getEnvironmentVariable: getEnv } = require('./helper')
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const defaultWafObfuscatorKeyRegex = String.raw`(?i)pass|pw(?:or)?d|secret|(?:api|private|public|access)[_-]?key|token|consumer[_-]?(?:id|key|secret)|sign(?:ed|ature)|bearer|authorization|jsessionid|phpsessid|asp\.net[_-]sessionid|sid|jwt`
|
|
11
|
-
// eslint-disable-next-line @stylistic/max-len
|
|
12
|
-
const defaultWafObfuscatorValueRegex = String.raw`(?i)(?:p(?:ass)?w(?:or)?d|pass(?:[_-]?phrase)?|secret(?:[_-]?key)?|(?:(?:api|private|public|access)[_-]?)key(?:[_-]?id)?|(?:(?:auth|access|id|refresh)[_-]?)?token|consumer[_-]?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?|jsessionid|phpsessid|asp\.net(?:[_-]|-)sessionid|sid|jwt)(?:\s*=([^;&]+)|"\s*:\s*("[^"]+"|\d+))|bearer\s+([a-z0-9\._\-]+)|token\s*:\s*([a-z0-9]{13})|gh[opsu]_([0-9a-zA-Z]{36})|ey[I-L][\w=-]+\.(ey[I-L][\w=-]+(?:\.[\w.+\/=-]+)?)|[\-]{5}BEGIN[a-z\s]+PRIVATE\sKEY[\-]{5}([^\-]+)[\-]{5}END[a-z\s]+PRIVATE\sKEY|ssh-rsa\s*([a-z0-9\/\.+]{100,})`
|
|
7
|
+
const {
|
|
8
|
+
supportedConfigurations,
|
|
9
|
+
} = /** @type {import('./helper').SupportedConfigurationsJson} */ (require('./supported-configurations.json'))
|
|
13
10
|
|
|
14
11
|
const service = getEnv('AWS_LAMBDA_FUNCTION_NAME') ||
|
|
15
12
|
getEnv('FUNCTION_NAME') || // Google Cloud Function Name set by deprecated runtimes
|
|
@@ -18,204 +15,160 @@ const service = getEnv('AWS_LAMBDA_FUNCTION_NAME') ||
|
|
|
18
15
|
pkg.name ||
|
|
19
16
|
'node'
|
|
20
17
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
18
|
+
/**
|
|
19
|
+
* @param {string|null} raw
|
|
20
|
+
* @param {string} type
|
|
21
|
+
* @returns {string|number|boolean|Record<string, string>|unknown[]|undefined}
|
|
22
|
+
*/
|
|
23
|
+
function parseDefaultByType (raw, type) {
|
|
24
|
+
if (raw === null) {
|
|
25
|
+
return
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
switch (type) {
|
|
29
|
+
case 'boolean':
|
|
30
|
+
if (isTrue(raw)) return true
|
|
31
|
+
if (isFalse(raw)) return false
|
|
32
|
+
// TODO: What should we do with these?
|
|
33
|
+
return
|
|
34
|
+
case 'int':
|
|
35
|
+
case 'decimal': {
|
|
36
|
+
return Number(raw)
|
|
37
|
+
}
|
|
38
|
+
case 'array': {
|
|
39
|
+
if (!raw || raw.length === 0) return []
|
|
40
|
+
// TODO: Make the parsing a helper that is reused.
|
|
41
|
+
return raw.split(',').map(item => {
|
|
42
|
+
const colonIndex = item.indexOf(':')
|
|
43
|
+
if (colonIndex === -1) {
|
|
44
|
+
return item.trim()
|
|
45
|
+
}
|
|
46
|
+
const key = item.slice(0, colonIndex).trim()
|
|
47
|
+
const value = item.slice(colonIndex + 1).trim()
|
|
48
|
+
return `${key}:${value}`
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
case 'map': {
|
|
52
|
+
if (!raw || raw.length === 0) return {}
|
|
53
|
+
// TODO: Make the parsing a helper that is reused.
|
|
54
|
+
/** @type {Record<string, string>} */
|
|
55
|
+
const entries = {}
|
|
56
|
+
for (const item of raw.split(',')) {
|
|
57
|
+
const colonIndex = item.indexOf(':')
|
|
58
|
+
if (colonIndex === -1) {
|
|
59
|
+
const key = item.trim()
|
|
60
|
+
if (key.length > 0) {
|
|
61
|
+
entries[key] = ''
|
|
62
|
+
}
|
|
63
|
+
continue
|
|
64
|
+
}
|
|
65
|
+
const key = item.slice(0, colonIndex).trim()
|
|
66
|
+
const value = item.slice(colonIndex + 1).trim()
|
|
67
|
+
if (key.length > 0) {
|
|
68
|
+
entries[key] = value
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return entries
|
|
72
|
+
}
|
|
73
|
+
default:
|
|
74
|
+
return raw
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** @type {Record<string, unknown>} */
|
|
79
|
+
const metadataDefaults = {}
|
|
80
|
+
for (const entries of Object.values(supportedConfigurations)) {
|
|
81
|
+
for (const entry of entries) {
|
|
82
|
+
// TODO: Replace $dynamic with method names that would be called and that
|
|
83
|
+
// are also called when the user passes through the value. That way the
|
|
84
|
+
// handling is unified and methods can be declared as default.
|
|
85
|
+
// The name of that method should be expressive for users.
|
|
86
|
+
// TODO: Add handling for all environment variable names. They should not
|
|
87
|
+
// need a configuration name for being listed with their default.
|
|
88
|
+
if (!Array.isArray(entry.configurationNames)) {
|
|
89
|
+
continue
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const parsedValue = parseDefaultByType(entry.default, entry.type)
|
|
93
|
+
for (const configurationName of entry.configurationNames) {
|
|
94
|
+
metadataDefaults[configurationName] = entry.default === null ? undefined : parsedValue
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Defaults required by JS config merge/applyCalculated that are not represented in supported-configurations.
|
|
100
|
+
const defaultsWithoutSupportedConfigurationEntry = {
|
|
101
|
+
'cloudPayloadTagging.rules': [],
|
|
55
102
|
'cloudPayloadTagging.requestsEnabled': false,
|
|
56
103
|
'cloudPayloadTagging.responsesEnabled': false,
|
|
57
|
-
'cloudPayloadTagging.maxDepth': 10,
|
|
58
|
-
'cloudPayloadTagging.rules': [],
|
|
59
|
-
'crashtracking.enabled': true,
|
|
60
|
-
'codeOriginForSpans.enabled': true,
|
|
61
|
-
'codeOriginForSpans.experimental.exit_spans.enabled': false,
|
|
62
|
-
dbmPropagationMode: 'disabled',
|
|
63
|
-
'dogstatsd.hostname': '127.0.0.1',
|
|
64
|
-
'dogstatsd.port': '8125',
|
|
65
|
-
dsmEnabled: false,
|
|
66
|
-
'dynamicInstrumentation.captureTimeoutMs': 15,
|
|
67
|
-
'dynamicInstrumentation.enabled': false,
|
|
68
|
-
'dynamicInstrumentation.probeFile': undefined,
|
|
69
|
-
'dynamicInstrumentation.redactedIdentifiers': [],
|
|
70
|
-
'dynamicInstrumentation.redactionExcludedIdentifiers': [],
|
|
71
|
-
'dynamicInstrumentation.uploadIntervalSeconds': 1,
|
|
72
|
-
env: undefined,
|
|
73
|
-
'experimental.aiguard.enabled': false,
|
|
74
|
-
'experimental.aiguard.endpoint': undefined,
|
|
75
|
-
'experimental.aiguard.maxMessagesLength': 16,
|
|
76
|
-
'experimental.aiguard.maxContentSize': 512 * 1024,
|
|
77
|
-
'experimental.aiguard.timeout': 10_000, // ms
|
|
78
|
-
'experimental.enableGetRumData': false,
|
|
79
|
-
'experimental.exporter': undefined,
|
|
80
|
-
'experimental.flaggingProvider.enabled': false,
|
|
81
|
-
'experimental.flaggingProvider.initializationTimeoutMs': 30_000,
|
|
82
|
-
flushInterval: 2000,
|
|
83
|
-
flushMinSpans: 1000,
|
|
84
|
-
gitMetadataEnabled: true,
|
|
85
|
-
graphqlErrorExtensions: [],
|
|
86
|
-
'grpc.client.error.statuses': GRPC_CLIENT_ERROR_STATUSES,
|
|
87
|
-
'grpc.server.error.statuses': GRPC_SERVER_ERROR_STATUSES,
|
|
88
|
-
headerTags: [],
|
|
89
|
-
'heapSnapshot.count': 0,
|
|
90
|
-
'heapSnapshot.destination': '',
|
|
91
|
-
'heapSnapshot.interval': 3600,
|
|
92
|
-
hostname: '127.0.0.1',
|
|
93
|
-
'iast.dbRowsToTaint': 1,
|
|
94
|
-
'iast.deduplicationEnabled': true,
|
|
95
|
-
'iast.enabled': false,
|
|
96
|
-
'iast.maxConcurrentRequests': 2,
|
|
97
|
-
'iast.maxContextOperations': 2,
|
|
98
|
-
'iast.redactionEnabled': true,
|
|
99
|
-
'iast.redactionNamePattern': null,
|
|
100
|
-
'iast.redactionValuePattern': null,
|
|
101
|
-
'iast.requestSampling': 30,
|
|
102
|
-
'iast.securityControlsConfiguration': null,
|
|
103
|
-
'iast.telemetryVerbosity': 'INFORMATION',
|
|
104
|
-
'iast.stackTrace.enabled': true,
|
|
105
|
-
injectionEnabled: [],
|
|
106
|
-
'installSignature.id': null,
|
|
107
|
-
'installSignature.time': null,
|
|
108
|
-
'installSignature.type': null,
|
|
109
|
-
instrumentationSource: 'manual',
|
|
110
|
-
injectForce: null,
|
|
111
104
|
isAzureFunction: false,
|
|
112
105
|
isCiVisibility: false,
|
|
113
|
-
isEarlyFlakeDetectionEnabled: false,
|
|
114
|
-
isFlakyTestRetriesEnabled: false,
|
|
115
|
-
flakyTestRetriesCount: 5,
|
|
116
106
|
isGCPFunction: false,
|
|
117
|
-
|
|
107
|
+
instrumentationSource: 'manual',
|
|
108
|
+
isServiceUserProvided: false,
|
|
109
|
+
lookup: undefined,
|
|
110
|
+
plugins: true,
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// These values are documented in supported-configurations as CI Visibility
|
|
114
|
+
// defaults. Keep startup baseline false and let #applyCalculated() switch them
|
|
115
|
+
// when CI Visibility is active.
|
|
116
|
+
// TODO: These entries should be removed. They are off by default
|
|
117
|
+
// because they rely on other configs.
|
|
118
|
+
const defaultsWithConditionalRuntimeBehavior = {
|
|
118
119
|
isGitUploadEnabled: false,
|
|
120
|
+
isImpactedTestsEnabled: false,
|
|
119
121
|
isIntelligentTestRunnerEnabled: false,
|
|
120
122
|
isManualApiEnabled: false,
|
|
121
|
-
'langchain.spanCharLimit': 128,
|
|
122
|
-
'langchain.spanPromptCompletionSampleRate': 1,
|
|
123
|
-
'llmobs.agentlessEnabled': undefined,
|
|
124
|
-
'llmobs.enabled': false,
|
|
125
|
-
'llmobs.mlApp': undefined,
|
|
126
|
-
ciVisibilityTestSessionName: '',
|
|
127
|
-
ciVisAgentlessLogSubmissionEnabled: false,
|
|
128
|
-
legacyBaggageEnabled: true,
|
|
129
|
-
isTestDynamicInstrumentationEnabled: false,
|
|
130
|
-
isServiceUserProvided: false,
|
|
131
|
-
testManagementAttemptToFixRetries: 20,
|
|
132
123
|
isTestManagementEnabled: false,
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
otelLogsEnabled: false,
|
|
136
|
-
otelUrl: undefined,
|
|
137
|
-
otelLogsUrl: undefined, // Will be computed using agent host
|
|
138
|
-
otelHeaders: undefined,
|
|
139
|
-
otelLogsHeaders: '',
|
|
140
|
-
otelProtocol: 'http/protobuf',
|
|
141
|
-
otelLogsProtocol: 'http/protobuf',
|
|
142
|
-
otelLogsTimeout: 10_000,
|
|
143
|
-
otelTimeout: 10_000,
|
|
144
|
-
otelBatchTimeout: 5000,
|
|
145
|
-
otelMaxExportBatchSize: 512,
|
|
146
|
-
otelMaxQueueSize: 2048,
|
|
147
|
-
otelMetricsEnabled: false,
|
|
148
|
-
otelMetricsUrl: undefined, // Will be computed using agent host
|
|
149
|
-
otelMetricsHeaders: '',
|
|
150
|
-
otelMetricsProtocol: 'http/protobuf',
|
|
151
|
-
otelMetricsTimeout: 10_000,
|
|
152
|
-
otelMetricsExportTimeout: 7500,
|
|
153
|
-
otelMetricsExportInterval: 10_000,
|
|
154
|
-
otelMetricsTemporalityPreference: 'DELTA', // DELTA, CUMULATIVE, or LOWMEMORY
|
|
155
|
-
lookup: undefined,
|
|
156
|
-
inferredProxyServicesEnabled: false,
|
|
157
|
-
memcachedCommandEnabled: false,
|
|
158
|
-
middlewareTracingEnabled: true,
|
|
159
|
-
openAiLogsEnabled: false,
|
|
160
|
-
'openai.spanCharLimit': 128,
|
|
161
|
-
peerServiceMapping: {},
|
|
162
|
-
plugins: true,
|
|
124
|
+
// TODO: These are not conditional, they would just be of type number.
|
|
125
|
+
'dogstatsd.port': '8125',
|
|
163
126
|
port: '8126',
|
|
164
|
-
|
|
165
|
-
'
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
127
|
+
// Override due to expecting numbers, not strings. TODO: Replace later.
|
|
128
|
+
'grpc.client.error.statuses': [
|
|
129
|
+
1,
|
|
130
|
+
2,
|
|
131
|
+
3,
|
|
132
|
+
4,
|
|
133
|
+
5,
|
|
134
|
+
6,
|
|
135
|
+
7,
|
|
136
|
+
8,
|
|
137
|
+
9,
|
|
138
|
+
10,
|
|
139
|
+
11,
|
|
140
|
+
12,
|
|
141
|
+
13,
|
|
142
|
+
14,
|
|
143
|
+
15,
|
|
144
|
+
16,
|
|
145
|
+
],
|
|
146
|
+
'grpc.server.error.statuses': [
|
|
147
|
+
2,
|
|
148
|
+
3,
|
|
149
|
+
4,
|
|
150
|
+
5,
|
|
151
|
+
6,
|
|
152
|
+
7,
|
|
153
|
+
8,
|
|
154
|
+
9,
|
|
155
|
+
10,
|
|
156
|
+
11,
|
|
157
|
+
12,
|
|
158
|
+
13,
|
|
159
|
+
14,
|
|
160
|
+
15,
|
|
161
|
+
16,
|
|
162
|
+
],
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/** @type {Record<string, unknown>} */
|
|
166
|
+
const defaults = {
|
|
167
|
+
...defaultsWithoutSupportedConfigurationEntry,
|
|
168
|
+
...metadataDefaults,
|
|
169
|
+
...defaultsWithConditionalRuntimeBehavior,
|
|
184
170
|
service,
|
|
185
|
-
serviceMapping: {},
|
|
186
|
-
site: 'datadoghq.com',
|
|
187
|
-
spanAttributeSchema: 'v0',
|
|
188
|
-
spanComputePeerService: false,
|
|
189
|
-
spanLeakDebug: 0,
|
|
190
|
-
spanRemoveIntegrationFromService: false,
|
|
191
|
-
startupLogs: false,
|
|
192
|
-
'stats.enabled': false,
|
|
193
|
-
tags: {},
|
|
194
|
-
tagsHeaderMaxLength: 512,
|
|
195
|
-
'telemetry.debug': false,
|
|
196
|
-
'telemetry.dependencyCollection': true,
|
|
197
|
-
'telemetry.enabled': true,
|
|
198
|
-
'telemetry.heartbeatInterval': 60_000,
|
|
199
|
-
'telemetry.logCollection': true,
|
|
200
|
-
'telemetry.metrics': true,
|
|
201
|
-
traceEnabled: true,
|
|
202
|
-
traceId128BitGenerationEnabled: true,
|
|
203
|
-
traceId128BitLoggingEnabled: true,
|
|
204
|
-
tracePropagationExtractFirst: false,
|
|
205
|
-
tracePropagationBehaviorExtract: 'continue',
|
|
206
|
-
'tracePropagationStyle.inject': ['datadog', 'tracecontext', 'baggage'],
|
|
207
|
-
'tracePropagationStyle.extract': ['datadog', 'tracecontext', 'baggage'],
|
|
208
|
-
'tracePropagationStyle.otelPropagators': false,
|
|
209
|
-
traceWebsocketMessagesEnabled: true,
|
|
210
|
-
traceWebsocketMessagesInheritSampling: true,
|
|
211
|
-
traceWebsocketMessagesSeparateTraces: true,
|
|
212
|
-
tracing: true,
|
|
213
|
-
url: undefined,
|
|
214
171
|
version: pkg.version,
|
|
215
|
-
instrumentation_config_id: undefined,
|
|
216
|
-
'vertexai.spanCharLimit': 128,
|
|
217
|
-
'vertexai.spanPromptCompletionSampleRate': 1,
|
|
218
|
-
'trace.aws.addSpanPointers': true,
|
|
219
|
-
'trace.dynamoDb.tablePrimaryKeys': undefined,
|
|
220
|
-
'trace.nativeSpanEvents': false,
|
|
221
172
|
}
|
|
173
|
+
|
|
174
|
+
module.exports = defaults
|
|
@@ -2,8 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
/* eslint-disable eslint-rules/eslint-process-env */
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* @typedef {object} SupportedConfigurationEntry
|
|
7
|
+
* @property {string} implementation
|
|
8
|
+
* @property {string} type
|
|
9
|
+
* @property {string|number|boolean|null|object|unknown[]} default
|
|
10
|
+
* @property {string[]} [aliases]
|
|
11
|
+
* @property {string[]} [configurationNames]
|
|
12
|
+
* @property {string|boolean} [deprecated]
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @typedef {object} SupportedConfigurationsJson
|
|
17
|
+
* @property {Record<`DD_${string}` | `OTEL_${string}`, SupportedConfigurationEntry[]>} supportedConfigurations
|
|
18
|
+
*/
|
|
19
|
+
|
|
5
20
|
const { deprecate } = require('util')
|
|
6
|
-
const {
|
|
21
|
+
const {
|
|
22
|
+
supportedConfigurations,
|
|
23
|
+
} = /** @type {SupportedConfigurationsJson} */ (require('./supported-configurations.json'))
|
|
7
24
|
|
|
8
25
|
/**
|
|
9
26
|
* Types for environment variable handling.
|
|
@@ -12,6 +29,31 @@ const { supportedConfigurations, aliases, deprecations } = require('./supported-
|
|
|
12
29
|
* @typedef {Partial<typeof process.env> & Partial<Record<SupportedEnvKey, string|undefined>>} TracerEnv
|
|
13
30
|
*/
|
|
14
31
|
|
|
32
|
+
// Backwards-compatible views for old helper logic:
|
|
33
|
+
// - `aliases`: Record<canonicalEnvVar, string[]>
|
|
34
|
+
// - `deprecations`: Record<deprecatedEnvVar, string> (message suffix)
|
|
35
|
+
const aliases = {}
|
|
36
|
+
const deprecations = {}
|
|
37
|
+
|
|
38
|
+
for (const [canonical, configuration] of Object.entries(supportedConfigurations)) {
|
|
39
|
+
for (const implementation of configuration) {
|
|
40
|
+
if (implementation.deprecated) {
|
|
41
|
+
deprecations[canonical] = implementation.deprecated
|
|
42
|
+
// Deprecated entries with an alias may not be listed in the supported configurations map
|
|
43
|
+
if (implementation.aliases) {
|
|
44
|
+
delete supportedConfigurations[canonical]
|
|
45
|
+
continue
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (Array.isArray(implementation.aliases)) {
|
|
49
|
+
for (const alias of implementation.aliases) {
|
|
50
|
+
aliases[canonical] ??= new Set()
|
|
51
|
+
aliases[canonical].add(alias)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
15
57
|
const aliasToCanonical = {}
|
|
16
58
|
for (const canonical of Object.keys(aliases)) {
|
|
17
59
|
for (const alias of aliases[canonical]) {
|