dd-trace 5.108.0 → 5.110.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/ci/init.js +4 -3
- package/index.d.ts +88 -25
- package/loader-hook.mjs +88 -2
- package/package.json +19 -14
- package/packages/datadog-esbuild/index.js +26 -0
- package/packages/datadog-esbuild/src/utils.js +46 -3
- package/packages/datadog-instrumentations/src/ai.js +43 -48
- package/packages/datadog-instrumentations/src/aws-durable-execution-sdk-js-context-methods.js +18 -0
- package/packages/datadog-instrumentations/src/aws-durable-execution-sdk-js.js +111 -0
- package/packages/datadog-instrumentations/src/aws-sdk.js +3 -1
- package/packages/datadog-instrumentations/src/connect.js +4 -3
- package/packages/datadog-instrumentations/src/electron.js +1 -1
- package/packages/datadog-instrumentations/src/fastify.js +4 -12
- package/packages/datadog-instrumentations/src/graphql.js +17 -6
- package/packages/datadog-instrumentations/src/helpers/check-require-cache.js +81 -8
- package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/instrument.js +27 -2
- package/packages/datadog-instrumentations/src/helpers/optional-peer-bundler.js +65 -0
- package/packages/datadog-instrumentations/src/helpers/register.js +6 -4
- package/packages/datadog-instrumentations/src/helpers/require-optional-peer.js +17 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/aws-durable-execution-sdk-js.js +31 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/loader.mjs +18 -2
- package/packages/datadog-instrumentations/src/http/client.js +12 -2
- package/packages/datadog-instrumentations/src/ioredis.js +0 -1
- package/packages/datadog-instrumentations/src/iovalkey.js +1 -2
- package/packages/datadog-instrumentations/src/koa.js +3 -2
- package/packages/datadog-instrumentations/src/mariadb.js +4 -2
- package/packages/datadog-instrumentations/src/mocha/main.js +3 -3
- package/packages/datadog-instrumentations/src/next.js +44 -10
- package/packages/datadog-instrumentations/src/openai.js +77 -18
- package/packages/datadog-instrumentations/src/otel-sdk-trace.js +7 -6
- package/packages/datadog-instrumentations/src/playwright.js +1 -1
- package/packages/datadog-instrumentations/src/redis.js +0 -1
- package/packages/datadog-instrumentations/src/restify.js +4 -3
- package/packages/datadog-instrumentations/src/router.js +18 -5
- package/packages/datadog-instrumentations/src/selenium.js +1 -2
- package/packages/datadog-instrumentations/src/tedious.js +28 -0
- package/packages/datadog-instrumentations/src/vitest.js +323 -7
- package/packages/datadog-plugin-avsc/src/schema_iterator.js +2 -2
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/checkpoint.js +31 -0
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/client.js +55 -0
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/context.js +114 -0
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/handler.js +128 -0
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/index.js +19 -0
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/trace-checkpoint.js +224 -0
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/util.js +43 -0
- package/packages/datadog-plugin-aws-sdk/src/base.js +14 -16
- package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +43 -6
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +100 -37
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +108 -99
- package/packages/datadog-plugin-bullmq/src/filter.js +35 -0
- package/packages/datadog-plugin-bullmq/src/producer.js +84 -4
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +9 -1
- package/packages/datadog-plugin-fs/src/index.js +1 -0
- package/packages/datadog-plugin-http/src/client.js +8 -3
- package/packages/datadog-plugin-http2/src/client.js +5 -2
- package/packages/datadog-plugin-mysql/src/index.js +7 -2
- package/packages/datadog-plugin-protobufjs/src/schema_iterator.js +2 -2
- package/packages/datadog-plugin-redis/src/index.js +1 -2
- package/packages/datadog-plugin-undici/src/index.js +5 -2
- package/packages/datadog-plugin-vitest/src/index.js +11 -2
- package/packages/datadog-webpack/index.js +17 -1
- package/packages/datadog-webpack/src/optional-peer-loader.js +17 -0
- package/packages/dd-trace/src/aiguard/channels.js +0 -1
- package/packages/dd-trace/src/aiguard/index.js +11 -49
- package/packages/dd-trace/src/aiguard/integrations/evaluate.js +46 -0
- package/packages/dd-trace/src/aiguard/integrations/openai.js +66 -0
- package/packages/dd-trace/src/aiguard/integrations/vercel-ai.js +78 -0
- package/packages/{datadog-instrumentations/src/helpers/ai-messages.js → dd-trace/src/aiguard/messages/openai.js} +85 -193
- package/packages/dd-trace/src/aiguard/messages/vercel-ai.js +185 -0
- package/packages/dd-trace/src/aiguard/sdk.js +13 -1
- package/packages/dd-trace/src/appsec/api_security/index.js +55 -0
- package/packages/dd-trace/src/appsec/api_security/sampler.js +147 -0
- package/packages/dd-trace/src/appsec/channels.js +1 -0
- package/packages/dd-trace/src/appsec/downstream_requests.js +111 -58
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/ldap-sensitive-analyzer.js +54 -12
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/url-sensitive-analyzer.js +5 -1
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +29 -4
- package/packages/dd-trace/src/appsec/index.js +10 -6
- package/packages/dd-trace/src/appsec/rasp/ssrf.js +19 -11
- package/packages/dd-trace/src/appsec/reporter.js +1 -0
- package/packages/dd-trace/src/appsec/telemetry/api_security.js +34 -0
- package/packages/dd-trace/src/appsec/telemetry/index.js +26 -0
- package/packages/dd-trace/src/ci-visibility/requests/request.js +1 -17
- package/packages/dd-trace/src/config/defaults.js +22 -3
- package/packages/dd-trace/src/config/generated-config-types.d.ts +538 -1
- package/packages/dd-trace/src/config/helper.js +133 -33
- package/packages/dd-trace/src/config/index.js +4 -1
- package/packages/dd-trace/src/config/parsers.js +19 -1
- package/packages/dd-trace/src/config/supported-configurations.json +45 -5
- package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +49 -35
- package/packages/dd-trace/src/debugger/devtools_client/index.js +31 -66
- package/packages/dd-trace/src/debugger/devtools_client/probe_sampler.js +83 -0
- package/packages/dd-trace/src/debugger/devtools_client/state.js +1 -0
- package/packages/dd-trace/src/debugger/index.js +5 -0
- package/packages/dd-trace/src/debugger/probe_sampler.js +112 -0
- package/packages/dd-trace/src/debugger/probe_sampler_constants.js +19 -0
- package/packages/dd-trace/src/dogstatsd.js +15 -8
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +77 -26
- package/packages/dd-trace/src/exporters/agentless/index.js +7 -5
- package/packages/dd-trace/src/exporters/agentless/intake.js +43 -0
- package/packages/dd-trace/src/exporters/agentless/writer.js +5 -4
- package/packages/dd-trace/src/exporters/common/request.js +1 -20
- package/packages/dd-trace/src/exporters/common/url.js +34 -0
- package/packages/dd-trace/src/exporters/span-stats/writer.js +1 -3
- package/packages/dd-trace/src/guardrails/index.js +8 -5
- package/packages/dd-trace/src/index.js +6 -4
- package/packages/dd-trace/src/llmobs/constants/tags.js +6 -0
- package/packages/dd-trace/src/llmobs/index.js +16 -5
- package/packages/dd-trace/src/llmobs/plugins/genai/util.js +3 -3
- package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +5 -1
- package/packages/dd-trace/src/llmobs/sdk.js +5 -3
- package/packages/dd-trace/src/llmobs/span_processor.js +4 -0
- package/packages/dd-trace/src/llmobs/tagger.js +55 -0
- package/packages/dd-trace/src/llmobs/telemetry.js +1 -0
- package/packages/dd-trace/src/log/index.js +18 -20
- package/packages/dd-trace/src/openfeature/flagging_provider.js +3 -1
- package/packages/dd-trace/src/opentelemetry/bridge-span-base.js +5 -4
- package/packages/dd-trace/src/opentelemetry/metrics/instruments.js +2 -1
- package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +4 -3
- package/packages/dd-trace/src/opentelemetry/metrics/time.js +19 -0
- package/packages/dd-trace/src/opentelemetry/otlp/common.proto +2 -2
- package/packages/dd-trace/src/opentelemetry/otlp/logs.proto +1 -1
- package/packages/dd-trace/src/opentelemetry/otlp/logs_service.proto +1 -1
- package/packages/dd-trace/src/opentelemetry/otlp/metrics.proto +1 -1
- package/packages/dd-trace/src/opentelemetry/otlp/metrics_service.proto +1 -1
- package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +11 -4
- package/packages/dd-trace/src/opentelemetry/span-helpers.js +29 -13
- package/packages/dd-trace/src/opentelemetry/span.js +14 -3
- package/packages/dd-trace/src/opentelemetry/span_context.js +1 -0
- package/packages/dd-trace/src/opentelemetry/trace/index.js +2 -1
- package/packages/dd-trace/src/opentelemetry/trace/otlp_http_trace_exporter.js +3 -2
- package/packages/dd-trace/src/opentelemetry/trace/otlp_transformer.js +26 -13
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +3 -3
- package/packages/dd-trace/src/opentracing/span_context.js +17 -0
- package/packages/dd-trace/src/plugin_manager.js +7 -1
- package/packages/dd-trace/src/plugins/ci_plugin.js +36 -3
- package/packages/dd-trace/src/plugins/index.js +3 -0
- package/packages/dd-trace/src/plugins/util/http-otel-semantics.js +276 -0
- package/packages/dd-trace/src/plugins/util/test.js +80 -0
- package/packages/dd-trace/src/plugins/util/url.js +68 -1
- package/packages/dd-trace/src/plugins/util/web.js +19 -36
- package/packages/dd-trace/src/priority_sampler.js +1 -13
- package/packages/dd-trace/src/profiling/config.js +129 -198
- package/packages/dd-trace/src/profiling/constants.js +4 -7
- package/packages/dd-trace/src/profiling/exporter_cli.js +10 -10
- package/packages/dd-trace/src/profiling/exporters/agent.js +23 -16
- package/packages/dd-trace/src/profiling/exporters/event_serializer.js +45 -14
- package/packages/dd-trace/src/profiling/exporters/file.js +16 -5
- package/packages/dd-trace/src/profiling/oom.js +71 -0
- package/packages/dd-trace/src/profiling/profiler.js +35 -23
- package/packages/dd-trace/src/profiling/profilers/events.js +14 -7
- package/packages/dd-trace/src/profiling/profilers/space.js +27 -18
- package/packages/dd-trace/src/profiling/profilers/wall.js +35 -25
- package/packages/dd-trace/src/ritm.js +4 -2
- package/packages/dd-trace/src/serverless.js +1 -2
- package/packages/dd-trace/src/service-naming/schemas/util.js +36 -5
- package/packages/dd-trace/src/service-naming/schemas/v0/serverless.js +12 -0
- package/packages/dd-trace/src/service-naming/schemas/v1/serverless.js +12 -0
- package/packages/dd-trace/src/service-naming/schemas/v1/web.js +5 -3
- package/packages/dd-trace/src/span_format.js +2 -1
- package/packages/dd-trace/src/span_processor.js +6 -0
- package/packages/dd-trace/src/telemetry/send-data.js +12 -10
- package/packages/dd-trace/src/tracer.js +15 -1
- package/packages/dd-trace/src/util.js +14 -0
- package/register.js +58 -1
- package/vendor/dist/@apm-js-collab/code-transformer/index.js +1 -1
- package/vendor/dist/@datadog/sketches-js/index.js +1 -1
- package/vendor/dist/pprof-format/index.js +1 -1
- package/vendor/dist/protobufjs/index.js +1 -1
- package/vendor/dist/protobufjs/minimal/index.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/openai-ai-guard.js +0 -284
- package/packages/dd-trace/src/appsec/api_security_sampler.js +0 -117
|
@@ -149,7 +149,140 @@ function validateAccess (name) {
|
|
|
149
149
|
}
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
+
let configurationsTable
|
|
153
|
+
let configDefaults
|
|
154
|
+
|
|
155
|
+
// Lazy require to keep the `config -> helper` import direction acyclic: helper
|
|
156
|
+
// must not pull `config/defaults` at module load. `config/defaults` defers its
|
|
157
|
+
// own instrumented `dns` require until after it exports, so by the time any
|
|
158
|
+
// caller resolves a value the table is fully populated.
|
|
159
|
+
function loadConfigurationsTable () {
|
|
160
|
+
if (configurationsTable === undefined) {
|
|
161
|
+
const defaultsModule = require('./defaults')
|
|
162
|
+
configurationsTable = defaultsModule.configurationsTable
|
|
163
|
+
configDefaults = defaultsModule.defaults
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Parses and transforms a raw environment value with the same parser and
|
|
169
|
+
* transformer Config applies when it reads environment sources, so callers
|
|
170
|
+
* receive the typed value instead of the raw string.
|
|
171
|
+
*
|
|
172
|
+
* @param {string} name Canonical or alias environment variable name.
|
|
173
|
+
* @param {string} value Raw value read from an environment source.
|
|
174
|
+
* @param {'env_var'|'fleet_stable_config'|'local_stable_config'} source Source the value was read from.
|
|
175
|
+
* @returns {string | number | boolean | object | undefined}
|
|
176
|
+
*/
|
|
177
|
+
function parseConfigurationValue (name, value, source) {
|
|
178
|
+
loadConfigurationsTable()
|
|
179
|
+
const canonical = aliasToCanonical[name] ?? name
|
|
180
|
+
const entry = configurationsTable[canonical]
|
|
181
|
+
const parsed = entry.parser(value, canonical, source)
|
|
182
|
+
return parsed !== undefined && entry.transformer ? entry.transformer(parsed, canonical, source) : parsed
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Returns the registered default for a configuration — the same value Config
|
|
187
|
+
* resolves when no environment source sets it.
|
|
188
|
+
*
|
|
189
|
+
* @param {string} name Canonical or alias environment variable name.
|
|
190
|
+
* @returns {string | number | boolean | object | undefined}
|
|
191
|
+
*/
|
|
192
|
+
function getRegisteredDefault (name) {
|
|
193
|
+
loadConfigurationsTable()
|
|
194
|
+
const canonical = aliasToCanonical[name] ?? name
|
|
195
|
+
const entry = configurationsTable[canonical]
|
|
196
|
+
return configDefaults[entry.property ?? canonical]
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/** @typedef {import('./generated-config-types').GeneratedEnvVarConfig} GeneratedEnvVarConfig */
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Returns the value stored at the given name, assumed to be in environment variable format,
|
|
203
|
+
* from the supported env sources (process.env, local stable config, fleet stable config).
|
|
204
|
+
* Falls back to aliases if the canonical name is not set.
|
|
205
|
+
*
|
|
206
|
+
* The raw value is parsed and transformed exactly as Config does when it reads environment
|
|
207
|
+
* sources, so the returned value is typed (boolean, number, array, map, ...) rather than the
|
|
208
|
+
* raw string. A literal supported name resolves to its specific configured type.
|
|
209
|
+
*
|
|
210
|
+
* When the name is not set in any source, the registered default is returned, so callers can
|
|
211
|
+
* use the value directly. Callers that must distinguish an explicitly configured value from the
|
|
212
|
+
* default (e.g. an OTel fallback that only applies when the option is unset) pass `skipDefault`
|
|
213
|
+
* to receive `undefined` for an unset value instead. All sources (process.env, local and fleet
|
|
214
|
+
* stable config) are read in both modes.
|
|
215
|
+
*
|
|
216
|
+
* @template {keyof GeneratedEnvVarConfig} TName
|
|
217
|
+
* @overload
|
|
218
|
+
* @param {TName} name Environment variable name
|
|
219
|
+
* @returns {GeneratedEnvVarConfig[TName]}
|
|
220
|
+
*/
|
|
221
|
+
/**
|
|
222
|
+
* @template {keyof GeneratedEnvVarConfig} TName
|
|
223
|
+
* @overload
|
|
224
|
+
* @param {TName} name Environment variable name
|
|
225
|
+
* @param {boolean} skipDefault Return `undefined` instead of the registered default when unset.
|
|
226
|
+
* @returns {GeneratedEnvVarConfig[TName] | undefined}
|
|
227
|
+
*/
|
|
228
|
+
/**
|
|
229
|
+
* @overload
|
|
230
|
+
* @param {string} name Environment variable name
|
|
231
|
+
* @param {boolean} [skipDefault] Return `undefined` instead of the registered default when unset.
|
|
232
|
+
* @returns {string | number | boolean | object | undefined}
|
|
233
|
+
*/
|
|
234
|
+
/**
|
|
235
|
+
* @param {string} name
|
|
236
|
+
* @param {boolean} [skipDefault]
|
|
237
|
+
* @throws {Error} if the configuration is not supported
|
|
238
|
+
*/
|
|
239
|
+
function getValueFromEnvSources (name, skipDefault) {
|
|
240
|
+
validateAccess(name)
|
|
241
|
+
|
|
242
|
+
if (!stableConfigLoaded) {
|
|
243
|
+
loadStableConfig()
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Sources are read in priority order (fleet > env > local). A value the parser
|
|
247
|
+
// or transformer rejects resolves to `undefined` and is ignored, falling
|
|
248
|
+
// through to the next source and finally the registered default — mirroring
|
|
249
|
+
// how Config applies env sources (`setAndTrack` skips such values). This keeps
|
|
250
|
+
// a malformed higher-priority value (e.g. a fleet-stable `DD_TRACE_DEBUG=maybe`)
|
|
251
|
+
// from masking a valid `DD_TRACE_DEBUG=true`.
|
|
252
|
+
if (fleetStableConfig !== undefined) {
|
|
253
|
+
const fromFleet = getValueFromSource(name, fleetStableConfig)
|
|
254
|
+
if (fromFleet !== undefined) {
|
|
255
|
+
const parsed = parseConfigurationValue(name, fromFleet, 'fleet_stable_config')
|
|
256
|
+
if (parsed !== undefined) {
|
|
257
|
+
return parsed
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const fromEnv = getValueFromSource(name, process.env)
|
|
263
|
+
if (fromEnv !== undefined) {
|
|
264
|
+
const parsed = parseConfigurationValue(name, fromEnv, 'env_var')
|
|
265
|
+
if (parsed !== undefined) {
|
|
266
|
+
return parsed
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if (localStableConfig !== undefined) {
|
|
271
|
+
const fromLocal = getValueFromSource(name, localStableConfig)
|
|
272
|
+
if (fromLocal !== undefined) {
|
|
273
|
+
const parsed = parseConfigurationValue(name, fromLocal, 'local_stable_config')
|
|
274
|
+
if (parsed !== undefined) {
|
|
275
|
+
return parsed
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
return skipDefault ? undefined : getRegisteredDefault(name)
|
|
281
|
+
}
|
|
282
|
+
|
|
152
283
|
module.exports = {
|
|
284
|
+
getValueFromEnvSources,
|
|
285
|
+
|
|
153
286
|
/**
|
|
154
287
|
* Expose raw stable config maps and warnings for consumers that need
|
|
155
288
|
* per-source access (e.g. telemetry in Config).
|
|
@@ -209,39 +342,6 @@ module.exports = {
|
|
|
209
342
|
return getValueFromSource(name, process.env)
|
|
210
343
|
},
|
|
211
344
|
|
|
212
|
-
/**
|
|
213
|
-
* Returns the value stored at the given name, assumed to be in environment variable format,
|
|
214
|
-
* from the supported env sources (process.env, local stable config, fleet stable config).
|
|
215
|
-
* Falls back to aliases if the canonical name is not set.
|
|
216
|
-
*
|
|
217
|
-
* @param {string} name Environment variable name
|
|
218
|
-
* @returns {string|undefined}
|
|
219
|
-
* @throws {Error} if the configuration is not supported
|
|
220
|
-
*/
|
|
221
|
-
getValueFromEnvSources (name) {
|
|
222
|
-
validateAccess(name)
|
|
223
|
-
|
|
224
|
-
if (!stableConfigLoaded) {
|
|
225
|
-
loadStableConfig()
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
if (fleetStableConfig !== undefined) {
|
|
229
|
-
const fromFleet = getValueFromSource(name, fleetStableConfig)
|
|
230
|
-
if (fromFleet !== undefined) {
|
|
231
|
-
return fromFleet
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
const fromEnv = getValueFromSource(name, process.env)
|
|
236
|
-
if (fromEnv !== undefined) {
|
|
237
|
-
return fromEnv
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
if (localStableConfig !== undefined) {
|
|
241
|
-
return getValueFromSource(name, localStableConfig)
|
|
242
|
-
}
|
|
243
|
-
},
|
|
244
|
-
|
|
245
345
|
/**
|
|
246
346
|
* Returns the actual environment variable name used for a supported configuration
|
|
247
347
|
* from a specific environment-based source.
|
|
@@ -7,7 +7,7 @@ const { URL, format } = require('node:url')
|
|
|
7
7
|
const rfdc = require('../../../../vendor/dist/rfdc')({ proto: false, circles: false })
|
|
8
8
|
const uuid = require('../../../../vendor/dist/crypto-randomuuid') // we need to keep the old uuid dep because of cypress
|
|
9
9
|
const set = require('../../../datadog-core/src/utils/src/set')
|
|
10
|
-
const { DD_MAJOR } = require('../../../../version')
|
|
10
|
+
const { DD_MAJOR, NODE_MAJOR } = require('../../../../version')
|
|
11
11
|
const log = require('../log')
|
|
12
12
|
const pkg = require('../pkg')
|
|
13
13
|
const { isTrue } = require('../util')
|
|
@@ -361,6 +361,9 @@ class Config extends ConfigBase {
|
|
|
361
361
|
if (this.telemetry.heartbeatInterval) {
|
|
362
362
|
setAndTrack(this, 'telemetry.heartbeatInterval', Math.floor(this.telemetry.heartbeatInterval * 1000))
|
|
363
363
|
}
|
|
364
|
+
|
|
365
|
+
// Allocation profiling needs a sampling hook only available on Node.js 26+.
|
|
366
|
+
setAndTrack(this, 'DD_PROFILING_ALLOCATION_ENABLED', NODE_MAJOR >= 26 && this.DD_PROFILING_ALLOCATION_ENABLED)
|
|
364
367
|
if (this.telemetry.extendedHeartbeatInterval) {
|
|
365
368
|
setAndTrack(this, 'telemetry.extendedHeartbeatInterval',
|
|
366
369
|
Math.floor(this.telemetry.extendedHeartbeatInterval * 1000))
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const fs = require('fs')
|
|
4
4
|
|
|
5
|
-
const { DD_MAJOR } = require('../../../../version')
|
|
5
|
+
const { DD_MAJOR, NODE_MAJOR } = require('../../../../version')
|
|
6
6
|
const tagger = require('../tagger')
|
|
7
7
|
|
|
8
8
|
let warnInvalidValue
|
|
@@ -100,6 +100,24 @@ const transformers = {
|
|
|
100
100
|
}
|
|
101
101
|
return configValue
|
|
102
102
|
},
|
|
103
|
+
/**
|
|
104
|
+
* Parses DD_PROFILING_DEBUG_UPLOAD_COMPRESSION ('on' | 'off' | 'gzip[-1..9]' | 'zstd[-1..22]')
|
|
105
|
+
* into the codec and level the profiler uploads with. The value's shape is already range-checked
|
|
106
|
+
* by the `allowed` pattern, so no validation is needed here.
|
|
107
|
+
*
|
|
108
|
+
* @param {string} value
|
|
109
|
+
* @returns {{ method: string, level: number | undefined }}
|
|
110
|
+
*/
|
|
111
|
+
normalizeProfilingUploadCompression (value) {
|
|
112
|
+
let [method, level] = value.toLowerCase().split('-')
|
|
113
|
+
// Default "on" to zstd on Node.js 24+ and gzip earlier. zstd ships everywhere via a Rust
|
|
114
|
+
// compressor, but 24+ has a built-in that runs on libuv worker threads just as gzip does, so it
|
|
115
|
+
// is the least disruptive default.
|
|
116
|
+
if (method === 'on') {
|
|
117
|
+
method = NODE_MAJOR >= 24 ? 'zstd' : 'gzip'
|
|
118
|
+
}
|
|
119
|
+
return { method, level: level ? Number.parseInt(level, 10) : undefined }
|
|
120
|
+
},
|
|
103
121
|
sampleRate (value, optionName, source) {
|
|
104
122
|
const number = Number(value)
|
|
105
123
|
if (Number.isNaN(number) || value === null) {
|
|
@@ -167,6 +167,14 @@
|
|
|
167
167
|
"default": "1"
|
|
168
168
|
}
|
|
169
169
|
],
|
|
170
|
+
"DD_API_SECURITY_MAX_DOWNSTREAM_BODY_BYTES": [
|
|
171
|
+
{
|
|
172
|
+
"implementation": "A",
|
|
173
|
+
"type": "int",
|
|
174
|
+
"internalPropertyName": "appsec.apiSecurity.maxDownstreamBodyBytes",
|
|
175
|
+
"default": "10485760"
|
|
176
|
+
}
|
|
177
|
+
],
|
|
170
178
|
"DD_API_SECURITY_SAMPLE_DELAY": [
|
|
171
179
|
{
|
|
172
180
|
"implementation": "A",
|
|
@@ -1230,6 +1238,16 @@
|
|
|
1230
1238
|
"default": null
|
|
1231
1239
|
}
|
|
1232
1240
|
],
|
|
1241
|
+
"DD_LLMOBS_SAMPLE_RATE": [
|
|
1242
|
+
{
|
|
1243
|
+
"implementation": "A",
|
|
1244
|
+
"type": "decimal",
|
|
1245
|
+
"configurationNames": [
|
|
1246
|
+
"llmobs.sampleRate"
|
|
1247
|
+
],
|
|
1248
|
+
"default": "1.0"
|
|
1249
|
+
}
|
|
1250
|
+
],
|
|
1233
1251
|
"DD_LOGS_INJECTION": [
|
|
1234
1252
|
{
|
|
1235
1253
|
"implementation": "B",
|
|
@@ -1247,6 +1265,20 @@
|
|
|
1247
1265
|
"default": "false"
|
|
1248
1266
|
}
|
|
1249
1267
|
],
|
|
1268
|
+
"DD_TRACE_AWS_DURABLE_EXECUTION_SDK_JS_ENABLED": [
|
|
1269
|
+
{
|
|
1270
|
+
"implementation": "A",
|
|
1271
|
+
"type": "boolean",
|
|
1272
|
+
"default": "true"
|
|
1273
|
+
}
|
|
1274
|
+
],
|
|
1275
|
+
"DD_DURABLE_CROSS_INVOCATION_TRACING_ENABLED": [
|
|
1276
|
+
{
|
|
1277
|
+
"implementation": "A",
|
|
1278
|
+
"type": "boolean",
|
|
1279
|
+
"default": "true"
|
|
1280
|
+
}
|
|
1281
|
+
],
|
|
1250
1282
|
"DD_TRACE_LOG_LEVEL": [
|
|
1251
1283
|
{
|
|
1252
1284
|
"implementation": "C",
|
|
@@ -1376,8 +1408,8 @@
|
|
|
1376
1408
|
"implementation": "B",
|
|
1377
1409
|
"type": "string",
|
|
1378
1410
|
"default": "on",
|
|
1379
|
-
"allowed": "on|off|(
|
|
1380
|
-
"transform": "
|
|
1411
|
+
"allowed": "on|off|gzip(-[1-9])?|zstd(-([1-9]|1[0-9]|2[0-2]))?",
|
|
1412
|
+
"transform": "normalizeProfilingUploadCompression"
|
|
1381
1413
|
}
|
|
1382
1414
|
],
|
|
1383
1415
|
"DD_PROFILING_ENABLED": [
|
|
@@ -1464,7 +1496,8 @@
|
|
|
1464
1496
|
{
|
|
1465
1497
|
"implementation": "A",
|
|
1466
1498
|
"type": "int",
|
|
1467
|
-
"default": "524288"
|
|
1499
|
+
"default": "524288",
|
|
1500
|
+
"allowed": "[1-9]\\d*"
|
|
1468
1501
|
}
|
|
1469
1502
|
],
|
|
1470
1503
|
"DD_PROFILING_PPROF_PREFIX": [
|
|
@@ -2633,9 +2666,9 @@
|
|
|
2633
2666
|
],
|
|
2634
2667
|
"DD_TRACE_FS_ENABLED": [
|
|
2635
2668
|
{
|
|
2636
|
-
"implementation": "
|
|
2669
|
+
"implementation": "B",
|
|
2637
2670
|
"type": "boolean",
|
|
2638
|
-
"default": "
|
|
2671
|
+
"default": "false"
|
|
2639
2672
|
}
|
|
2640
2673
|
],
|
|
2641
2674
|
"DD_TRACE_GCP_PUBSUB_PUSH_ENABLED": [
|
|
@@ -3298,6 +3331,13 @@
|
|
|
3298
3331
|
"default": "true"
|
|
3299
3332
|
}
|
|
3300
3333
|
],
|
|
3334
|
+
"DD_TRACE_OTEL_SEMANTICS_ENABLED": [
|
|
3335
|
+
{
|
|
3336
|
+
"implementation": "A",
|
|
3337
|
+
"type": "boolean",
|
|
3338
|
+
"default": "false"
|
|
3339
|
+
}
|
|
3340
|
+
],
|
|
3301
3341
|
"DD_TRACE_OTEL_ENABLED": [
|
|
3302
3342
|
{
|
|
3303
3343
|
"implementation": "A",
|
|
@@ -5,6 +5,7 @@ const { getGeneratedPosition } = require('./source-maps')
|
|
|
5
5
|
const session = require('./session')
|
|
6
6
|
const { compile, compileSegments, templateRequiresEvaluation } = require('./condition')
|
|
7
7
|
const { MAX_SNAPSHOTS_PER_SECOND_PER_PROBE, MAX_NON_SNAPSHOTS_PER_SECOND_PER_PROBE } = require('./defaults')
|
|
8
|
+
const { compileBreakpointCondition, getRemoveProbeExpression } = require('./probe_sampler')
|
|
8
9
|
const {
|
|
9
10
|
DEFAULT_MAX_REFERENCE_DEPTH,
|
|
10
11
|
DEFAULT_MAX_COLLECTION_SIZE,
|
|
@@ -17,6 +18,7 @@ const {
|
|
|
17
18
|
locationToBreakpoint,
|
|
18
19
|
breakpointToProbes,
|
|
19
20
|
probeToLocation,
|
|
21
|
+
samplingIndexToProbe,
|
|
20
22
|
} = require('./state')
|
|
21
23
|
const log = require('./log')
|
|
22
24
|
|
|
@@ -26,6 +28,7 @@ const log = require('./log')
|
|
|
26
28
|
|
|
27
29
|
let sessionStarted = false
|
|
28
30
|
const probes = new Map()
|
|
31
|
+
let nextSamplingIndex = 0
|
|
29
32
|
let scriptLoadingStabilizedResolve
|
|
30
33
|
const scriptLoadingStabilized = new Promise((resolve) => { scriptLoadingStabilizedResolve = resolve })
|
|
31
34
|
|
|
@@ -55,6 +58,8 @@ async function addBreakpoint (probe) {
|
|
|
55
58
|
if (!sessionStarted) await start()
|
|
56
59
|
|
|
57
60
|
probes.set(probe.id, probe)
|
|
61
|
+
probe.samplingIndex = nextSamplingIndex++
|
|
62
|
+
samplingIndexToProbe.set(probe.samplingIndex, probe)
|
|
58
63
|
|
|
59
64
|
const file = probe.where.sourceFile
|
|
60
65
|
let lineNumber = Number(probe.where.lines[0]) // Tracer doesn't support multiple-line breakpoints
|
|
@@ -75,8 +80,6 @@ async function addBreakpoint (probe) {
|
|
|
75
80
|
? MAX_SNAPSHOTS_PER_SECOND_PER_PROBE
|
|
76
81
|
: MAX_NON_SNAPSHOTS_PER_SECOND_PER_PROBE)
|
|
77
82
|
probe.nsBetweenSampling = BigInt(Math.trunc(1 / snapshotsPerSecond * 1e9))
|
|
78
|
-
// Initialize to a large negative value to ensure first probe hit is always captured
|
|
79
|
-
probe.lastCaptureNs = BigInt(Number.MIN_SAFE_INTEGER)
|
|
80
83
|
|
|
81
84
|
// Warning: The code below relies on undocumented behavior of the inspector!
|
|
82
85
|
// It expects that `await session.post('Debugger.enable')` will wait for all loaded scripts to be emitted as
|
|
@@ -174,7 +177,7 @@ async function addBreakpoint (probe) {
|
|
|
174
177
|
try {
|
|
175
178
|
result = /** @type {SetBreakpointResponse} */ (await session.post('Debugger.setBreakpoint', {
|
|
176
179
|
location,
|
|
177
|
-
condition: probe
|
|
180
|
+
condition: compileBreakpointCondition([probe]),
|
|
178
181
|
}))
|
|
179
182
|
} catch (err) {
|
|
180
183
|
throw new Error(`Error setting breakpoint for probe ${probe.id} (version: ${probe.version})`, { cause: err })
|
|
@@ -195,11 +198,14 @@ async function removeBreakpoint ({ id }) {
|
|
|
195
198
|
}
|
|
196
199
|
|
|
197
200
|
probes.delete(id)
|
|
201
|
+
await removeProbeFromSampler(id)
|
|
198
202
|
|
|
199
203
|
const locationKey = probeToLocation.get(id)
|
|
200
204
|
const breakpoint = locationToBreakpoint.get(locationKey)
|
|
201
205
|
const probesAtLocation = breakpointToProbes.get(breakpoint.id)
|
|
206
|
+
const probe = probesAtLocation.get(id)
|
|
202
207
|
|
|
208
|
+
samplingIndexToProbe.delete(probe.samplingIndex)
|
|
203
209
|
probesAtLocation.delete(id)
|
|
204
210
|
probeToLocation.delete(id)
|
|
205
211
|
|
|
@@ -229,35 +235,37 @@ async function modifyBreakpoint (probe) {
|
|
|
229
235
|
|
|
230
236
|
async function updateBreakpointInternal (breakpoint, probe) {
|
|
231
237
|
const probesAtLocation = breakpointToProbes.get(breakpoint.id)
|
|
232
|
-
const conditionBeforeNewProbe = compileCompoundCondition([...probesAtLocation.values()])
|
|
233
238
|
|
|
234
|
-
// If a probe is provided, add it to the breakpoint. If not, it's because we're removing a probe
|
|
235
|
-
//
|
|
239
|
+
// If a probe is provided, add it to the breakpoint. If not, it's because we're removing a probe. In both cases the
|
|
240
|
+
// breakpoint condition must be rebuilt to match the remaining probes at the location.
|
|
236
241
|
if (probe) {
|
|
237
242
|
probesAtLocation.set(probe.id, probe)
|
|
238
243
|
probeToLocation.set(probe.id, breakpoint.locationKey)
|
|
239
244
|
}
|
|
240
245
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
246
|
+
try {
|
|
247
|
+
await session.post('Debugger.removeBreakpoint', { breakpointId: breakpoint.id })
|
|
248
|
+
} catch (err) {
|
|
249
|
+
const message = probe
|
|
250
|
+
? `Error replacing breakpoint while adding probe ${probe.id} (version: ${probe.version})`
|
|
251
|
+
: `Error replacing breakpoint after removing probe from ${breakpoint.locationKey}`
|
|
252
|
+
throw new Error(message, { cause: err })
|
|
253
|
+
}
|
|
254
|
+
breakpointToProbes.delete(breakpoint.id)
|
|
255
|
+
let result
|
|
256
|
+
try {
|
|
257
|
+
result = /** @type {SetBreakpointResponse} */ (await session.post('Debugger.setBreakpoint', {
|
|
258
|
+
location: breakpoint.location,
|
|
259
|
+
condition: compileBreakpointCondition([...probesAtLocation.values()]),
|
|
260
|
+
}))
|
|
261
|
+
} catch (err) {
|
|
262
|
+
const message = probe
|
|
263
|
+
? `Error setting breakpoint while adding probe ${probe.id} (version: ${probe.version})`
|
|
264
|
+
: `Error setting breakpoint after removing probe from ${breakpoint.locationKey}`
|
|
265
|
+
throw new Error(message, { cause: err })
|
|
260
266
|
}
|
|
267
|
+
breakpoint.id = result.breakpointId
|
|
268
|
+
breakpointToProbes.set(result.breakpointId, probesAtLocation)
|
|
261
269
|
}
|
|
262
270
|
|
|
263
271
|
async function reEvaluateProbe (probe) {
|
|
@@ -269,6 +277,8 @@ async function reEvaluateProbe (probe) {
|
|
|
269
277
|
if (probeToLocation.has(probe.id)) {
|
|
270
278
|
await removeBreakpoint(probe)
|
|
271
279
|
}
|
|
280
|
+
// TODO: Revisit diagnostic status handling for probes that recover during re-evaluation. A probe can initially
|
|
281
|
+
// report ERROR because no script matched, then attach successfully here without reporting INSTALLED.
|
|
272
282
|
await addBreakpoint(probe)
|
|
273
283
|
}
|
|
274
284
|
}
|
|
@@ -303,16 +313,20 @@ function lock (fn) {
|
|
|
303
313
|
}
|
|
304
314
|
}
|
|
305
315
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
+
/**
|
|
317
|
+
* Remove cached sampling state for a probe from the runtime sampler.
|
|
318
|
+
*
|
|
319
|
+
* @param {string} id - The probe id.
|
|
320
|
+
* @returns {Promise<void>}
|
|
321
|
+
*/
|
|
322
|
+
async function removeProbeFromSampler (id) {
|
|
323
|
+
try {
|
|
324
|
+
await session.post('Runtime.evaluate', {
|
|
325
|
+
expression: getRemoveProbeExpression(id),
|
|
326
|
+
})
|
|
327
|
+
} catch (err) {
|
|
328
|
+
log.error('[debugger:devtools_client] Error removing probe %s from sampler', id, err)
|
|
329
|
+
}
|
|
316
330
|
}
|
|
317
331
|
|
|
318
332
|
function generateLocationKey (scriptId, lineNumber, columnNumber) {
|
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { randomUUID } = require('crypto')
|
|
4
|
+
const { workerData: { probeSamplerBuffer } } = require('worker_threads')
|
|
4
5
|
const { version } = require('../../../../../package.json')
|
|
5
|
-
const { NODE_MAJOR } = require('../../../../../version')
|
|
6
6
|
const processTags = require('../../process-tags')
|
|
7
|
-
const {
|
|
7
|
+
const {
|
|
8
|
+
MAX_SAMPLED_PROBES_PER_PAUSE,
|
|
9
|
+
SAMPLED_PROBE_COUNT_INDEX,
|
|
10
|
+
SAMPLED_PROBE_INDEXES_START,
|
|
11
|
+
SAMPLED_PROBE_OVERFLOW_INDEX,
|
|
12
|
+
} = require('../probe_sampler_constants')
|
|
13
|
+
const { breakpointToProbes, samplingIndexToProbe } = require('./state')
|
|
8
14
|
const session = require('./session')
|
|
9
15
|
const { getLocalStateForCallFrame, evaluateCaptureExpressions } = require('./snapshot')
|
|
10
16
|
const send = require('./send')
|
|
11
17
|
const { getStackFromCallFrames } = require('./state')
|
|
12
18
|
const { ackEmitting } = require('./status')
|
|
13
19
|
const config = require('./config')
|
|
14
|
-
const { MAX_SNAPSHOTS_PER_SECOND_GLOBALLY } = require('./defaults')
|
|
15
20
|
const log = require('./log')
|
|
16
21
|
|
|
17
22
|
require('./remote_config')
|
|
@@ -38,25 +43,7 @@ const getDDTagsExpression = `(() => {
|
|
|
38
43
|
// something that should be useful to a Node.js developer.
|
|
39
44
|
const threadId = config.parentThreadId === 0 ? `pid:${process.pid}` : `pid:${process.pid};tid:${config.parentThreadId}`
|
|
40
45
|
const threadName = config.parentThreadId === 0 ? 'MainThread' : `WorkerThread:${config.parentThreadId}`
|
|
41
|
-
|
|
42
|
-
const SUPPORT_ARRAY_BUFFER_RESIZE = NODE_MAJOR >= 20
|
|
43
|
-
const oneSecondNs = 1_000_000_000n
|
|
44
|
-
let globalSnapshotSamplingRateWindowStart = 0n
|
|
45
|
-
let snapshotsSampledWithinTheLastSecond = 0
|
|
46
|
-
|
|
47
|
-
// TODO: Change to const once we drop support for Node.js 18
|
|
48
|
-
let snapshotProbeIndexBuffer, snapshotProbeIndex
|
|
49
|
-
|
|
50
|
-
if (SUPPORT_ARRAY_BUFFER_RESIZE) {
|
|
51
|
-
// TODO: Is a limit of 256 snapshots ever going to be a problem?
|
|
52
|
-
// @ts-ignore - ArrayBuffer constructor with maxByteLength is available in Node.js 20+ but not in @types/node@18
|
|
53
|
-
// eslint-disable-next-line n/no-unsupported-features/es-syntax
|
|
54
|
-
snapshotProbeIndexBuffer = new ArrayBuffer(1, { maxByteLength: 256 })
|
|
55
|
-
// TODO: Is a limit of 256 probes ever going to be a problem?
|
|
56
|
-
snapshotProbeIndex = new Uint8Array(snapshotProbeIndexBuffer)
|
|
57
|
-
} else {
|
|
58
|
-
snapshotProbeIndex = new Uint8Array(1)
|
|
59
|
-
}
|
|
46
|
+
const sampledProbeIndexes = new Int32Array(probeSamplerBuffer)
|
|
60
47
|
|
|
61
48
|
// WARNING: The code above the line `await session.post('Debugger.resume')` is highly optimized. Please edit with care!
|
|
62
49
|
session.on('Debugger.paused', async ({ params }) => {
|
|
@@ -71,7 +58,6 @@ session.on('Debugger.paused', async ({ params }) => {
|
|
|
71
58
|
let maxCollectionSize = 0
|
|
72
59
|
let maxFieldCount = 0
|
|
73
60
|
let maxLength = 0
|
|
74
|
-
let sampled = false
|
|
75
61
|
let numberOfProbesWithSnapshots = 0
|
|
76
62
|
let probesWithCaptureExpressions = false
|
|
77
63
|
const probes = []
|
|
@@ -80,7 +66,15 @@ session.on('Debugger.paused', async ({ params }) => {
|
|
|
80
66
|
// V8 doesn't allow setting more than one breakpoint at a specific location, however, it's possible to set two
|
|
81
67
|
// breakpoints just next to each other that will "snap" to the same logical location, which in turn will be hit at the
|
|
82
68
|
// same time. E.g. index.js:1:1 and index.js:1:2.
|
|
83
|
-
|
|
69
|
+
const numberOfSampledProbeIndexes = Math.min(
|
|
70
|
+
Atomics.exchange(sampledProbeIndexes, SAMPLED_PROBE_COUNT_INDEX, 0),
|
|
71
|
+
MAX_SAMPLED_PROBES_PER_PAUSE
|
|
72
|
+
)
|
|
73
|
+
if (Atomics.exchange(sampledProbeIndexes, SAMPLED_PROBE_OVERFLOW_INDEX, 0) === 1) {
|
|
74
|
+
log.error(
|
|
75
|
+
'[debugger:devtools_client] Too many probes sampled at the same breakpoint location; skipping excess probes'
|
|
76
|
+
)
|
|
77
|
+
}
|
|
84
78
|
|
|
85
79
|
// TODO: Investigate if it will improve performance to create a fast-path for when there's only a single breakpoint
|
|
86
80
|
for (let i = 0; i < params.hitBreakpoints.length; i++) {
|
|
@@ -92,36 +86,23 @@ session.on('Debugger.paused', async ({ params }) => {
|
|
|
92
86
|
continue
|
|
93
87
|
}
|
|
94
88
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
if (SUPPORT_ARRAY_BUFFER_RESIZE) {
|
|
99
|
-
snapshotProbeIndexBuffer.resize(numberOfProbesOnBreakpoint)
|
|
100
|
-
} else {
|
|
101
|
-
snapshotProbeIndex = new Uint8Array(numberOfProbesOnBreakpoint)
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
89
|
+
for (let j = 0; j < numberOfSampledProbeIndexes; j++) {
|
|
90
|
+
const samplingIndex = Atomics.load(sampledProbeIndexes, SAMPLED_PROBE_INDEXES_START + j)
|
|
91
|
+
const probe = samplingIndexToProbe.get(samplingIndex)
|
|
105
92
|
|
|
106
|
-
|
|
107
|
-
|
|
93
|
+
if (probe === undefined) {
|
|
94
|
+
log.error('[debugger:devtools_client] No probe found for sampled probe index %d', samplingIndex)
|
|
95
|
+
continue
|
|
96
|
+
}
|
|
97
|
+
if (!probesAtLocation.has(probe.id)) {
|
|
98
|
+
log.error('[debugger:devtools_client] Sampled probe %s was not found at breakpoint %s',
|
|
99
|
+
probe.id, params.hitBreakpoints[i])
|
|
108
100
|
continue
|
|
109
101
|
}
|
|
110
102
|
|
|
111
103
|
if (probe.captureSnapshot === true || probe.compiledCaptureExpressions !== undefined) {
|
|
112
|
-
// This algorithm to calculate number of sampled snapshots within the last second is not perfect, as it's not a
|
|
113
|
-
// sliding window. But it's quick and easy :)
|
|
114
|
-
if (i === 0 && start - globalSnapshotSamplingRateWindowStart > oneSecondNs) {
|
|
115
|
-
snapshotsSampledWithinTheLastSecond = 1
|
|
116
|
-
globalSnapshotSamplingRateWindowStart = start
|
|
117
|
-
} else if (snapshotsSampledWithinTheLastSecond >= MAX_SNAPSHOTS_PER_SECOND_GLOBALLY) {
|
|
118
|
-
continue
|
|
119
|
-
} else {
|
|
120
|
-
snapshotsSampledWithinTheLastSecond++
|
|
121
|
-
}
|
|
122
|
-
|
|
123
104
|
if (probe.captureSnapshot === true) {
|
|
124
|
-
|
|
105
|
+
numberOfProbesWithSnapshots++
|
|
125
106
|
maxReferenceDepth = Math.max(probe.capture.maxReferenceDepth, maxReferenceDepth)
|
|
126
107
|
maxCollectionSize = Math.max(probe.capture.maxCollectionSize, maxCollectionSize)
|
|
127
108
|
maxFieldCount = Math.max(probe.capture.maxFieldCount, maxFieldCount)
|
|
@@ -131,23 +112,6 @@ session.on('Debugger.paused', async ({ params }) => {
|
|
|
131
112
|
}
|
|
132
113
|
}
|
|
133
114
|
|
|
134
|
-
if (probe.condition !== undefined) {
|
|
135
|
-
// TODO: Bundle all conditions and evaluate them in a single call
|
|
136
|
-
// TODO: Handle errors
|
|
137
|
-
const { result } = /** @type {EvaluateOnCallFrameResult} */ (
|
|
138
|
-
// eslint-disable-next-line no-await-in-loop
|
|
139
|
-
await session.post('Debugger.evaluateOnCallFrame', {
|
|
140
|
-
callFrameId: params.callFrames[0].callFrameId,
|
|
141
|
-
expression: probe.condition,
|
|
142
|
-
returnByValue: true,
|
|
143
|
-
})
|
|
144
|
-
)
|
|
145
|
-
if (result.value !== true) continue
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
sampled = true
|
|
149
|
-
probe.lastCaptureNs = start
|
|
150
|
-
|
|
151
115
|
if (probe.templateRequiresEvaluation) {
|
|
152
116
|
templateExpressions += `,${probe.template}`
|
|
153
117
|
}
|
|
@@ -156,7 +120,8 @@ session.on('Debugger.paused', async ({ params }) => {
|
|
|
156
120
|
}
|
|
157
121
|
}
|
|
158
122
|
|
|
159
|
-
if
|
|
123
|
+
// This can happen if sampled probe indexes are inconsistent with the worker state. Those cases are logged above.
|
|
124
|
+
if (probes.length === 0) {
|
|
160
125
|
return session.post('Debugger.resume')
|
|
161
126
|
}
|
|
162
127
|
|