dd-trace 6.12.0 → 6.14.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 +3 -1
- package/ci/init.js +8 -3
- package/ci/test-optimization-validation/ci-package-scripts.js +2 -2
- package/ci/test-optimization-validation/ci-remediation.js +6 -6
- package/ci/test-optimization-validation/command-blocker.js +7 -5
- package/ci/test-optimization-validation/framework-adapters/cucumber.js +1 -1
- package/ci/test-optimization-validation/framework-adapters/cypress.js +9 -11
- package/ci/test-optimization-validation/framework-adapters/vitest.js +3 -3
- package/ci/test-optimization-validation/package-check.js +1 -1
- package/ci/test-optimization-validation/report-writer.js +7 -5
- package/ci/test-optimization-validation/scenarios/ci-wiring.js +5 -4
- package/ci/vitest-no-worker-init-runner-setup.mjs +8 -0
- package/ci/vitest-no-worker-init-setup.mjs +13 -13
- package/ci/vitest-no-worker-init-v5-setup.mjs +4 -0
- package/index.d.ts +127 -26
- package/package.json +22 -19
- package/packages/datadog-esbuild/index.js +3 -1
- package/packages/datadog-instrumentations/src/bunyan.js +4 -2
- package/packages/datadog-instrumentations/src/cypress-config.js +19 -17
- package/packages/datadog-instrumentations/src/fs.js +24 -20
- package/packages/datadog-instrumentations/src/google-cloud-vertexai.js +2 -2
- package/packages/datadog-instrumentations/src/graphql.js +16 -16
- package/packages/datadog-instrumentations/src/helpers/bunyan.js +12 -3
- package/packages/datadog-instrumentations/src/helpers/graphql-jit-runtime.js +504 -0
- package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
- package/packages/datadog-instrumentations/src/helpers/pool-acquire.js +266 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/compiler.js +1 -2
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +95 -30
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/ai.js +0 -25
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/graphql-jit.js +83 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/graphql.js +85 -1
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/mercurius.js +30 -12
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +13 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +279 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +12 -1
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +562 -27
- package/packages/datadog-instrumentations/src/jest.js +165 -38
- package/packages/datadog-instrumentations/src/knex.js +76 -0
- package/packages/datadog-instrumentations/src/mariadb-bundle.js +1597 -0
- package/packages/datadog-instrumentations/src/mariadb.js +13 -0
- package/packages/datadog-instrumentations/src/mocha/common.js +59 -2
- package/packages/datadog-instrumentations/src/mocha/main.js +25 -15
- package/packages/datadog-instrumentations/src/mocha/utils.js +2 -1
- package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +98 -0
- package/packages/datadog-instrumentations/src/mocha/worker.js +12 -8
- package/packages/datadog-instrumentations/src/net.js +14 -17
- package/packages/datadog-instrumentations/src/next.js +212 -62
- package/packages/datadog-instrumentations/src/openai.js +42 -40
- package/packages/datadog-instrumentations/src/pg.js +15 -0
- package/packages/datadog-instrumentations/src/pino.js +15 -4
- package/packages/datadog-instrumentations/src/playwright.js +137 -27
- package/packages/datadog-instrumentations/src/rum-browser-scripts.js +40 -0
- package/packages/datadog-instrumentations/src/sequelize.js +94 -2
- package/packages/datadog-instrumentations/src/undici.js +53 -4
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +44 -7
- package/packages/datadog-instrumentations/src/vitest-main.js +92 -9
- package/packages/datadog-instrumentations/src/vitest-worker.js +82 -14
- package/packages/datadog-instrumentations/src/webdriverio.js +986 -1
- package/packages/datadog-instrumentations/src/winston.js +6 -3
- package/packages/datadog-plugin-amqp10/src/consumer.js +3 -1
- package/packages/datadog-plugin-amqp10/src/producer.js +3 -1
- package/packages/datadog-plugin-amqp10/src/util.js +2 -1
- package/packages/datadog-plugin-avsc/src/schema_iterator.js +6 -1
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +16 -5
- package/packages/datadog-plugin-cassandra-driver/src/index.js +8 -3
- package/packages/datadog-plugin-cucumber/src/index.js +0 -2
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +262 -48
- package/packages/datadog-plugin-cypress/src/support.js +1 -0
- package/packages/datadog-plugin-google-cloud-pubsub/src/client.js +4 -1
- package/packages/datadog-plugin-graphql/src/execute.js +998 -196
- package/packages/datadog-plugin-graphql/src/index.js +27 -7
- package/packages/datadog-plugin-graphql/src/jit.js +136 -0
- package/packages/datadog-plugin-graphql/src/request.js +18 -27
- package/packages/datadog-plugin-graphql/src/resolve-error.js +108 -0
- package/packages/datadog-plugin-graphql/src/tools/signature.js +1 -2
- package/packages/datadog-plugin-graphql/src/tools/transforms.js +45 -3
- package/packages/datadog-plugin-graphql/src/utils.js +208 -120
- package/packages/datadog-plugin-graphql/src/validate.js +10 -23
- package/packages/datadog-plugin-http/src/client.js +2 -15
- package/packages/datadog-plugin-http2/src/client.js +2 -15
- package/packages/datadog-plugin-jest/src/index.js +0 -6
- package/packages/datadog-plugin-langchain/src/tracing.js +7 -0
- package/packages/datadog-plugin-mocha/src/index.js +403 -75
- package/packages/datadog-plugin-mongodb-core/src/query.js +6 -0
- package/packages/datadog-plugin-mysql/src/index.js +41 -15
- package/packages/datadog-plugin-net/src/tcp.js +3 -1
- package/packages/datadog-plugin-next/src/index.js +63 -29
- package/packages/datadog-plugin-openai-agents/src/integration.js +15 -11
- package/packages/datadog-plugin-playwright/src/index.js +176 -28
- package/packages/datadog-plugin-undici/src/index.js +29 -56
- package/packages/datadog-plugin-vitest/src/index.js +6 -12
- package/packages/dd-trace/src/aiguard/evaluation.js +96 -21
- package/packages/dd-trace/src/aiguard/integrations/vercel-ai.js +2 -3
- package/packages/dd-trace/src/aiguard/messages/anthropic.js +29 -10
- package/packages/dd-trace/src/aiguard/messages/openai.js +8 -1
- package/packages/dd-trace/src/aiguard/messages/vercel-ai.js +20 -6
- package/packages/dd-trace/src/aiguard/noop.js +9 -1
- package/packages/dd-trace/src/aiguard/redaction.js +183 -0
- package/packages/dd-trace/src/aiguard/sdk.js +7 -2
- package/packages/dd-trace/src/aiguard/tags.js +2 -0
- package/packages/dd-trace/src/appsec/api_security/index.js +23 -6
- package/packages/dd-trace/src/appsec/api_security/sampler.js +99 -40
- package/packages/dd-trace/src/appsec/graphql.js +6 -2
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +3 -3
- package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +2 -1
- package/packages/dd-trace/src/appsec/iast/telemetry/span-tags.js +8 -2
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +11 -36
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/url-sensitive-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +10 -9
- package/packages/dd-trace/src/appsec/lambda.js +44 -26
- package/packages/dd-trace/src/appsec/rule_manager.js +2 -0
- package/packages/dd-trace/src/ci-visibility/encode/json-encoder.js +32 -2
- package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +8 -8
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +6 -4
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +20 -4
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/request-tracker.js +7 -150
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +7 -6
- package/packages/dd-trace/src/ci-visibility/exporters/agents.js +54 -0
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/writer.js +1 -2
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +397 -234
- package/packages/dd-trace/src/ci-visibility/exporters/limits.js +9 -0
- package/packages/dd-trace/src/ci-visibility/exporters/request.js +323 -31
- package/packages/dd-trace/src/ci-visibility/exporters/settings-cache-key.js +42 -0
- package/packages/dd-trace/src/ci-visibility/final-flush.js +21 -0
- package/packages/dd-trace/src/ci-visibility/requests/fs-cache.js +57 -18
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +0 -3
- package/packages/dd-trace/src/ci-visibility/requests/upload-test-screenshot.js +164 -71
- package/packages/dd-trace/src/ci-visibility/requests/video-request.js +176 -0
- package/packages/dd-trace/src/ci-visibility/telemetry.js +10 -7
- package/packages/dd-trace/src/ci-visibility/test-video.js +61 -0
- package/packages/dd-trace/src/config/generated-config-types.d.ts +10 -0
- package/packages/dd-trace/src/config/index.js +75 -14
- package/packages/dd-trace/src/config/parsers.js +11 -1
- package/packages/dd-trace/src/config/stable.js +3 -3
- package/packages/dd-trace/src/config/supported-configurations.json +47 -2
- package/packages/dd-trace/src/crashtracking/crashtracker.js +82 -18
- package/packages/dd-trace/src/debugger/config.js +12 -1
- package/packages/dd-trace/src/debugger/constants.js +1 -0
- package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +2 -1
- package/packages/dd-trace/src/debugger/devtools_client/request-options.js +33 -0
- package/packages/dd-trace/src/debugger/devtools_client/send.js +7 -39
- package/packages/dd-trace/src/debugger/devtools_client/status.js +11 -6
- package/packages/dd-trace/src/debugger/devtools_client/tags.js +41 -0
- package/packages/dd-trace/src/debugger/index.js +23 -3
- package/packages/dd-trace/src/dogstatsd.js +532 -71
- package/packages/dd-trace/src/encode/0.4-cross-payload.js +170 -0
- package/packages/dd-trace/src/encode/0.4.js +5 -5
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +9 -8
- package/packages/dd-trace/src/evp_proxy/direct.js +27 -23
- package/packages/dd-trace/src/exporters/agent/index.js +24 -3
- package/packages/dd-trace/src/exporters/agent/writer.js +28 -11
- package/packages/dd-trace/src/exporters/agentless/index.js +7 -9
- package/packages/dd-trace/src/exporters/agentless/writer.js +100 -118
- package/packages/dd-trace/src/exporters/common/agents.js +28 -6
- package/packages/dd-trace/src/exporters/common/buffering-exporter.js +2 -2
- package/packages/dd-trace/src/exporters/common/final-flush-request-tracker.js +191 -0
- package/packages/dd-trace/src/exporters/common/request.js +31 -11
- package/packages/dd-trace/src/exporters/common/url.js +40 -1
- package/packages/dd-trace/src/exporters/common/writer.js +31 -7
- package/packages/dd-trace/src/exporters/span-stats/index.js +23 -4
- package/packages/dd-trace/src/external-logger/src/index.js +4 -3
- package/packages/dd-trace/src/flush.js +105 -0
- package/packages/dd-trace/src/id.js +14 -0
- package/packages/dd-trace/src/index.js +5 -2
- package/packages/dd-trace/src/llmobs/experiments/client.js +4 -0
- package/packages/dd-trace/src/llmobs/experiments/dataset.js +52 -2
- package/packages/dd-trace/src/llmobs/experiments/experiment.js +420 -105
- package/packages/dd-trace/src/llmobs/experiments/index.js +54 -42
- package/packages/dd-trace/src/llmobs/experiments/noop.js +39 -8
- package/packages/dd-trace/src/llmobs/experiments/result.js +1 -0
- package/packages/dd-trace/src/llmobs/experiments/util.js +21 -0
- package/packages/dd-trace/src/llmobs/index.js +111 -48
- package/packages/dd-trace/src/llmobs/noop.js +2 -1
- package/packages/dd-trace/src/llmobs/plugins/ai/ddTelemetry.js +22 -71
- package/packages/dd-trace/src/llmobs/plugins/ai/vercelTelemetry.js +23 -13
- package/packages/dd-trace/src/llmobs/plugins/anthropic/util.js +8 -4
- package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/index.js +6 -3
- package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +7 -0
- package/packages/dd-trace/src/llmobs/plugins/openai/utils.js +13 -6
- package/packages/dd-trace/src/llmobs/plugins/openai-agents/utils.js +5 -7
- package/packages/dd-trace/src/llmobs/util.js +0 -33
- package/packages/dd-trace/src/llmobs/writers/base.js +106 -53
- package/packages/dd-trace/src/log/index.js +7 -1
- package/packages/dd-trace/src/log-submission/log-submission-plugin.js +249 -0
- package/packages/dd-trace/src/noop/span.js +5 -0
- package/packages/dd-trace/src/openfeature/writers/base.js +14 -12
- package/packages/dd-trace/src/openfeature/writers/exposures.js +8 -1
- package/packages/dd-trace/src/openfeature/writers/util.js +1 -1
- package/packages/dd-trace/src/opentelemetry/logs/batch_log_processor.js +45 -3
- package/packages/dd-trace/src/opentelemetry/logs/index.js +9 -25
- package/packages/dd-trace/src/opentelemetry/logs/logger_provider.js +7 -4
- package/packages/dd-trace/src/opentelemetry/logs/otlp_http_log_exporter.js +14 -4
- package/packages/dd-trace/src/opentelemetry/metrics/index.js +18 -23
- package/packages/dd-trace/src/opentelemetry/metrics/meter_provider.js +8 -0
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_http_metric_exporter.js +18 -6
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_exporter.js +14 -2
- package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +25 -5
- package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +61 -25
- package/packages/dd-trace/src/opentelemetry/otlp/otlp_transformer_base.js +19 -4
- package/packages/dd-trace/src/opentelemetry/resource-attributes.js +55 -0
- package/packages/dd-trace/src/opentelemetry/trace/index.js +6 -1
- package/packages/dd-trace/src/opentelemetry/trace/otlp_http_trace_exporter.js +10 -0
- package/packages/dd-trace/src/opentelemetry/tracer.js +26 -2
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +494 -351
- package/packages/dd-trace/src/opentracing/span.js +28 -0
- package/packages/dd-trace/src/otel-thread-ctx.js +23 -5
- package/packages/dd-trace/src/payload-tagging/index.js +2 -1
- package/packages/dd-trace/src/plugin_manager.js +2 -0
- package/packages/dd-trace/src/plugins/ci_plugin.js +1 -6
- package/packages/dd-trace/src/plugins/tracing.js +12 -10
- package/packages/dd-trace/src/plugins/util/ci.js +3 -1
- package/packages/dd-trace/src/plugins/util/inferred_proxy.js +16 -15
- package/packages/dd-trace/src/plugins/util/status-validator.js +98 -0
- package/packages/dd-trace/src/plugins/util/test.js +157 -41
- package/packages/dd-trace/src/plugins/util/url.js +2 -2
- package/packages/dd-trace/src/plugins/util/web.js +6 -74
- package/packages/dd-trace/src/profiling/config.js +1 -0
- package/packages/dd-trace/src/profiling/oom.js +11 -5
- package/packages/dd-trace/src/profiling/profiler.js +30 -13
- package/packages/dd-trace/src/profiling/profilers/events.js +3 -3
- package/packages/dd-trace/src/profiling/profilers/space.js +38 -11
- package/packages/dd-trace/src/profiling/profilers/wall.js +14 -14
- package/packages/dd-trace/src/profiling/webspan-utils.js +7 -4
- package/packages/dd-trace/src/proxy.js +108 -10
- package/packages/dd-trace/src/remote_config/index.js +319 -101
- package/packages/dd-trace/src/remote_config/scheduler.js +37 -12
- package/packages/dd-trace/src/runtime_metrics/client.js +37 -8
- package/packages/dd-trace/src/runtime_metrics/index.js +5 -0
- package/packages/dd-trace/src/runtime_metrics/otlp_runtime_metrics.js +10 -1
- package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +22 -7
- package/packages/dd-trace/src/sampling_rule.js +36 -9
- package/packages/dd-trace/src/serverless/telemetry-delivery-tracker.js +51 -0
- package/packages/dd-trace/src/serverless/vercel.js +155 -0
- package/packages/dd-trace/src/serverless.js +45 -21
- package/packages/dd-trace/src/service-naming/schemas/util.js +1 -1
- package/packages/dd-trace/src/span_stats.js +64 -31
- package/packages/dd-trace/src/startup-log.js +3 -2
- package/packages/dd-trace/src/telemetry/agentless-url.js +28 -0
- package/packages/dd-trace/src/telemetry/send-data.js +18 -16
- package/packages/dd-trace/src/telemetry/session-propagation.js +3 -2
- package/packages/dd-trace/src/tracer.js +26 -5
- package/packages/dd-trace/src/tracer_metadata.js +11 -3
- package/packages/dd-trace/src/web-tags-cache.js +67 -13
- package/vendor/dist/@datadog/openfeature-node-server/index.js +1 -1
- package/vendor/dist/@datadog/sketches-js/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/playwright-browser-scripts.js +0 -27
- package/packages/dd-trace/src/ci-visibility/log-submission/log-submission-plugin.js +0 -53
- package/packages/dd-trace/src/encode/agentless-json.js +0 -209
|
@@ -13,6 +13,7 @@ const { storage } = require('../../../../datadog-core')
|
|
|
13
13
|
const legacyStorage = storage('legacy')
|
|
14
14
|
const urlFilter = require('./urlfilter')
|
|
15
15
|
const { createInferredProxySpan, finishInferredProxySpan } = require('./inferred_proxy')
|
|
16
|
+
const { getServerStatusValidator } = require('./status-validator')
|
|
16
17
|
const { extractURL, obfuscateQs, getQsObfuscator, calculateHttpEndpoint } = require('./url')
|
|
17
18
|
const { NETWORK_PEER_ADDRESS } = require('./http-otel-semantics')
|
|
18
19
|
|
|
@@ -34,12 +35,6 @@ const HTTP_CLIENT_IP = tags.HTTP_CLIENT_IP
|
|
|
34
35
|
const MANUAL_DROP = tags.MANUAL_DROP
|
|
35
36
|
|
|
36
37
|
const contexts = new WeakMap()
|
|
37
|
-
const requests = new WeakMap()
|
|
38
|
-
const statusCodeRangesPattern = /^[1-5]\d{2}(?:-[1-5]\d{2})?(?:,[1-5]\d{2}(?:-[1-5]\d{2})?)*$/
|
|
39
|
-
const whitespacePattern = /\s/g
|
|
40
|
-
const MAX_HTTP_STATUS_CODE = 599
|
|
41
|
-
|
|
42
|
-
/** @typedef {(code: number) => boolean} StatusValidator */
|
|
43
38
|
|
|
44
39
|
// TODO: change this to no longer rely on creating a dummy plugin to be able to access startSpan
|
|
45
40
|
function createWebPlugin (tracer, config = {}) {
|
|
@@ -65,7 +60,7 @@ const web = {
|
|
|
65
60
|
// Ensure the configuration has the correct structure and defaults.
|
|
66
61
|
normalizeConfig (config) {
|
|
67
62
|
const headers = getHeadersToRecord(config)
|
|
68
|
-
const validateStatus =
|
|
63
|
+
const validateStatus = getServerStatusValidator(config)
|
|
69
64
|
const hooks = getHooks(config)
|
|
70
65
|
const filter = urlFilter.getFilter(config)
|
|
71
66
|
const middleware = getMiddlewareSetting(config)
|
|
@@ -133,7 +128,6 @@ const web = {
|
|
|
133
128
|
context.tracer = tracer
|
|
134
129
|
context.span = span
|
|
135
130
|
context.res = res
|
|
136
|
-
requests.set(span, req)
|
|
137
131
|
|
|
138
132
|
this.setConfig(req, config)
|
|
139
133
|
addRequestTags(context, this.TYPE)
|
|
@@ -318,7 +312,6 @@ const web = {
|
|
|
318
312
|
web.finishMiddleware(context)
|
|
319
313
|
|
|
320
314
|
web.finishSpan(context, spanType)
|
|
321
|
-
requests.delete(context.span)
|
|
322
315
|
|
|
323
316
|
finishInferredProxySpan(context)
|
|
324
317
|
},
|
|
@@ -348,9 +341,6 @@ const web = {
|
|
|
348
341
|
getContext (req) {
|
|
349
342
|
return contexts.get(req)
|
|
350
343
|
},
|
|
351
|
-
getRequest (span) {
|
|
352
|
-
return requests.get(span)
|
|
353
|
-
},
|
|
354
344
|
setRouteOrEndpointTag (req) {
|
|
355
345
|
const context = contexts.get(req)
|
|
356
346
|
|
|
@@ -515,9 +505,10 @@ function addResourceTag (context) {
|
|
|
515
505
|
|
|
516
506
|
if (spanContext.getTag(RESOURCE_NAME)) return
|
|
517
507
|
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
508
|
+
let resource = req.method
|
|
509
|
+
const route = spanContext.getTag(HTTP_ROUTE)
|
|
510
|
+
|
|
511
|
+
if (route) resource += ` ${route}`
|
|
521
512
|
|
|
522
513
|
span.setTag(RESOURCE_NAME, resource)
|
|
523
514
|
}
|
|
@@ -563,65 +554,6 @@ function getHeadersToRecord (config) {
|
|
|
563
554
|
return []
|
|
564
555
|
}
|
|
565
556
|
|
|
566
|
-
function isNot500ErrorCode (code) {
|
|
567
|
-
return code < 500
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
/**
|
|
571
|
-
* @param {{ validateStatus?: unknown, DD_TRACE_HTTP_SERVER_ERROR_STATUSES?: unknown }} config
|
|
572
|
-
* @returns {StatusValidator}
|
|
573
|
-
*/
|
|
574
|
-
function getStatusValidator (config) {
|
|
575
|
-
if (typeof config.validateStatus === 'function') {
|
|
576
|
-
return /** @type {StatusValidator} */ (config.validateStatus)
|
|
577
|
-
} else if (config.hasOwnProperty('validateStatus')) {
|
|
578
|
-
log.error('Expected `validateStatus` to be a function.')
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
const { DD_TRACE_HTTP_SERVER_ERROR_STATUSES } = config
|
|
582
|
-
if (DD_TRACE_HTTP_SERVER_ERROR_STATUSES === undefined) return isNot500ErrorCode
|
|
583
|
-
if (typeof DD_TRACE_HTTP_SERVER_ERROR_STATUSES !== 'string') {
|
|
584
|
-
log.error('Expected `DD_TRACE_HTTP_SERVER_ERROR_STATUSES` to be a string.')
|
|
585
|
-
return isNot500ErrorCode
|
|
586
|
-
}
|
|
587
|
-
if (DD_TRACE_HTTP_SERVER_ERROR_STATUSES === '500-599') return isNot500ErrorCode
|
|
588
|
-
|
|
589
|
-
const normalized = DD_TRACE_HTTP_SERVER_ERROR_STATUSES.replaceAll(whitespacePattern, '')
|
|
590
|
-
if (normalized === '500-599') return isNot500ErrorCode
|
|
591
|
-
if (!statusCodeRangesPattern.test(normalized)) {
|
|
592
|
-
log.error(
|
|
593
|
-
'`DD_TRACE_HTTP_SERVER_ERROR_STATUSES` must contain comma-separated status codes or ranges from 100 to 599.'
|
|
594
|
-
)
|
|
595
|
-
return isNot500ErrorCode
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
const errorStatusCodes = new Uint8Array(MAX_HTTP_STATUS_CODE + 1)
|
|
599
|
-
const ranges = normalized.split(',')
|
|
600
|
-
for (const range of ranges) {
|
|
601
|
-
const separator = range.indexOf('-')
|
|
602
|
-
if (separator === -1) {
|
|
603
|
-
errorStatusCodes[Number(range)] = 1
|
|
604
|
-
continue
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
const first = Number(range.slice(0, separator))
|
|
608
|
-
const second = Number(range.slice(separator + 1))
|
|
609
|
-
const start = Math.min(first, second)
|
|
610
|
-
const end = Math.max(first, second)
|
|
611
|
-
errorStatusCodes.fill(1, start, end + 1)
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
/**
|
|
615
|
-
* @param {number} code
|
|
616
|
-
* @returns {boolean}
|
|
617
|
-
*/
|
|
618
|
-
function isValidStatusCode (code) {
|
|
619
|
-
return errorStatusCodes[code] !== 1
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
return isValidStatusCode
|
|
623
|
-
}
|
|
624
|
-
|
|
625
557
|
const noop = () => {}
|
|
626
558
|
|
|
627
559
|
function getHooks (config) {
|
|
@@ -54,18 +54,24 @@ function strategiesToCallbackMode (strategies, callbackMode) {
|
|
|
54
54
|
* @returns {string[]}
|
|
55
55
|
*/
|
|
56
56
|
function buildExportCommand (exporters, tags) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
let tagString = ''
|
|
58
|
+
for (const [key, value] of Object.entries(tags)) {
|
|
59
|
+
if (tagString) tagString += ','
|
|
60
|
+
tagString += `${key}:${value}`
|
|
61
|
+
}
|
|
62
|
+
if (tagString) tagString += ','
|
|
63
|
+
tagString += `snapshot:${snapshotKinds.ON_OUT_OF_MEMORY}`
|
|
64
|
+
let urls = ''
|
|
60
65
|
for (const exporter of exporters) {
|
|
61
66
|
const url = exporter.getExportUrl()
|
|
62
67
|
if (url !== undefined) {
|
|
63
|
-
urls
|
|
68
|
+
if (urls) urls += ','
|
|
69
|
+
urls += url.toString()
|
|
64
70
|
}
|
|
65
71
|
}
|
|
66
72
|
return [process.execPath,
|
|
67
73
|
path.join(__dirname, 'exporter_cli.js'),
|
|
68
|
-
urls
|
|
74
|
+
urls, tagString, 'space']
|
|
69
75
|
}
|
|
70
76
|
|
|
71
77
|
module.exports = { oomExportStrategies, ensureOOMExportStrategies, strategiesToCallbackMode, buildExportCommand }
|
|
@@ -4,7 +4,7 @@ const { EventEmitter } = require('events')
|
|
|
4
4
|
const dc = require('dc-polyfill')
|
|
5
5
|
const crashtracker = require('../crashtracking')
|
|
6
6
|
const log = require('../log')
|
|
7
|
-
const { buildProfilingRuntime } = require('./config')
|
|
7
|
+
const { buildProfilingRuntime, getProfilingTags } = require('./config')
|
|
8
8
|
const { snapshotKinds } = require('./constants')
|
|
9
9
|
const { threadNamePrefix } = require('./profilers/shared')
|
|
10
10
|
const { isWebServerSpan, endpointNameFromTags, getStartedSpans } = require('./webspan-utils')
|
|
@@ -54,6 +54,7 @@ class Profiler extends EventEmitter {
|
|
|
54
54
|
#compressionFn
|
|
55
55
|
#compressionFnInitialized = false
|
|
56
56
|
#compressionOptions
|
|
57
|
+
#config
|
|
57
58
|
#customLabelKeys = new Set()
|
|
58
59
|
#enabled = false
|
|
59
60
|
#endpointCounts = new Map()
|
|
@@ -64,7 +65,7 @@ class Profiler extends EventEmitter {
|
|
|
64
65
|
#profilers
|
|
65
66
|
#spanFinishListener
|
|
66
67
|
#systemInfoReport
|
|
67
|
-
#
|
|
68
|
+
#currentSnapshotTags
|
|
68
69
|
#timer
|
|
69
70
|
#uploadCompression
|
|
70
71
|
|
|
@@ -95,6 +96,10 @@ class Profiler extends EventEmitter {
|
|
|
95
96
|
for (const key of keys) {
|
|
96
97
|
this.#customLabelKeys.add(key)
|
|
97
98
|
}
|
|
99
|
+
this.#applyCustomLabelKeys()
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
#applyCustomLabelKeys () {
|
|
98
103
|
if (this.#profilers) {
|
|
99
104
|
for (const profiler of this.#profilers) {
|
|
100
105
|
profiler.setCustomLabelKeys?.(this.#customLabelKeys)
|
|
@@ -152,7 +157,7 @@ class Profiler extends EventEmitter {
|
|
|
152
157
|
}
|
|
153
158
|
}
|
|
154
159
|
} else {
|
|
155
|
-
const zstdCompress = require('@datadog/libdatadog')
|
|
160
|
+
const { zstd_compress: zstdCompress } = require('@datadog/libdatadog')
|
|
156
161
|
const level = clevel ?? 0 // 0 is zstd default compression level
|
|
157
162
|
this.#compressionFn = (buffer) => Promise.resolve(Buffer.from(zstdCompress(buffer, level)))
|
|
158
163
|
}
|
|
@@ -172,14 +177,18 @@ class Profiler extends EventEmitter {
|
|
|
172
177
|
if (this.enabled) return true
|
|
173
178
|
this.#enabled = true
|
|
174
179
|
|
|
175
|
-
const { tags, exporters, flushInterval, profilers, uploadCompression, systemInfoReport } =
|
|
180
|
+
const { tags: snapshotTags, exporters, flushInterval, profilers, uploadCompression, systemInfoReport } =
|
|
176
181
|
buildProfilingRuntime(config)
|
|
177
|
-
this.#
|
|
182
|
+
this.#config = config
|
|
178
183
|
this.#exporters = exporters
|
|
179
184
|
this.#flushInterval = flushInterval
|
|
180
185
|
this.#profilers = profilers
|
|
186
|
+
this.#currentSnapshotTags = snapshotTags
|
|
181
187
|
this.#uploadCompression = uploadCompression
|
|
182
188
|
this.#systemInfoReport = systemInfoReport
|
|
189
|
+
if (this.#customLabelKeys.size > 0) {
|
|
190
|
+
this.#applyCustomLabelKeys()
|
|
191
|
+
}
|
|
183
192
|
|
|
184
193
|
this._setInterval()
|
|
185
194
|
// Log errors if the source map finder fails, but don't prevent the rest
|
|
@@ -241,7 +250,7 @@ class Profiler extends EventEmitter {
|
|
|
241
250
|
processInfo(infos, info, profileType)
|
|
242
251
|
this.#submit({
|
|
243
252
|
[profileType]: encodedProfile,
|
|
244
|
-
}, infos, start, end, snapshotKinds.ON_OUT_OF_MEMORY)
|
|
253
|
+
}, infos, start, end, this.#currentSnapshotTags, snapshotKinds.ON_OUT_OF_MEMORY)
|
|
245
254
|
}
|
|
246
255
|
|
|
247
256
|
_setInterval () {
|
|
@@ -325,6 +334,7 @@ class Profiler extends EventEmitter {
|
|
|
325
334
|
|
|
326
335
|
const startDate = this.#lastStart
|
|
327
336
|
const endDate = new Date()
|
|
337
|
+
const snapshotTags = this.#currentSnapshotTags
|
|
328
338
|
const profiles = []
|
|
329
339
|
|
|
330
340
|
crashtracker.withProfilerSerializing(() => {
|
|
@@ -341,6 +351,7 @@ class Profiler extends EventEmitter {
|
|
|
341
351
|
})
|
|
342
352
|
|
|
343
353
|
if (restart) {
|
|
354
|
+
this.#currentSnapshotTags = getProfilingTags(this.#config)
|
|
344
355
|
this._capture(this._timeoutInterval, endDate)
|
|
345
356
|
}
|
|
346
357
|
|
|
@@ -378,7 +389,7 @@ class Profiler extends EventEmitter {
|
|
|
378
389
|
}))
|
|
379
390
|
|
|
380
391
|
if (hasEncoded) {
|
|
381
|
-
await this.#submit(encodedProfiles, infos, startDate, endDate, snapshotKind)
|
|
392
|
+
await this.#submit(encodedProfiles, infos, startDate, endDate, snapshotTags, snapshotKind)
|
|
382
393
|
profileSubmittedChannel.publish()
|
|
383
394
|
log.debug('Submitted profiles')
|
|
384
395
|
}
|
|
@@ -388,9 +399,15 @@ class Profiler extends EventEmitter {
|
|
|
388
399
|
}
|
|
389
400
|
}
|
|
390
401
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
402
|
+
/**
|
|
403
|
+
* @param {Record<string, Buffer|string>} profiles
|
|
404
|
+
* @param {Record<string, unknown>} infos
|
|
405
|
+
* @param {Date} start
|
|
406
|
+
* @param {Date} end
|
|
407
|
+
* @param {Record<string, string|number|boolean|undefined>} snapshotTags
|
|
408
|
+
* @param {string} snapshotKind
|
|
409
|
+
*/
|
|
410
|
+
#submit (profiles, infos, start, end, snapshotTags, snapshotKind) {
|
|
394
411
|
// Flatten endpoint counts
|
|
395
412
|
const endpointCounts = {}
|
|
396
413
|
for (const [endpoint, { count }] of this.#endpointCounts) {
|
|
@@ -398,12 +415,12 @@ class Profiler extends EventEmitter {
|
|
|
398
415
|
}
|
|
399
416
|
this.#endpointCounts.clear()
|
|
400
417
|
|
|
401
|
-
|
|
402
|
-
|
|
418
|
+
snapshotTags.snapshot = snapshotKind
|
|
419
|
+
snapshotTags.profile_seq = this.#profileSeq++
|
|
403
420
|
const customAttributes = this.#customLabelKeys.size > 0
|
|
404
421
|
? [...this.#customLabelKeys]
|
|
405
422
|
: undefined
|
|
406
|
-
const exportSpec = { profiles, infos, start, end, tags, endpointCounts, customAttributes }
|
|
423
|
+
const exportSpec = { profiles, infos, start, end, tags: snapshotTags, endpointCounts, customAttributes }
|
|
407
424
|
const tasks = this.#exporters.map(exporter =>
|
|
408
425
|
exporter.export(exportSpec).catch(error => {
|
|
409
426
|
log.warn(error)
|
|
@@ -124,13 +124,13 @@ class GCDecorator {
|
|
|
124
124
|
}
|
|
125
125
|
let reasonLabel = this.reasonLabels[flags]
|
|
126
126
|
if (!reasonLabel) {
|
|
127
|
-
|
|
127
|
+
let reasonStr = ''
|
|
128
128
|
for (const [key, value] of Object.entries(this.flagObj)) {
|
|
129
129
|
if (value & flags) {
|
|
130
|
-
|
|
130
|
+
if (reasonStr) reasonStr += ','
|
|
131
|
+
reasonStr += key
|
|
131
132
|
}
|
|
132
133
|
}
|
|
133
|
-
const reasonStr = reasons.join(',')
|
|
134
134
|
reasonLabel = labelFromStr(this.stringTable, this.reasonLabelKey, reasonStr)
|
|
135
135
|
this.reasonLabels[flags] = reasonLabel
|
|
136
136
|
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const { channel } = require('dc-polyfill')
|
|
4
|
+
|
|
5
|
+
const log = require('../../log')
|
|
3
6
|
const { oomExportStrategies, ensureOOMExportStrategies, strategiesToCallbackMode, buildExportCommand } =
|
|
4
7
|
require('../oom')
|
|
5
8
|
const { encodeProfileAsync, getThreadLabels } = require('./shared')
|
|
@@ -11,10 +14,12 @@ const { encodeProfileAsync, getThreadLabels } = require('./shared')
|
|
|
11
14
|
*/
|
|
12
15
|
|
|
13
16
|
const STACK_DEPTH = 64
|
|
17
|
+
const identityRefreshChannel = channel('datadog:identity:refresh')
|
|
14
18
|
|
|
15
19
|
class NativeSpaceProfiler {
|
|
16
20
|
#config
|
|
17
21
|
#exporters
|
|
22
|
+
#identityRefreshListener
|
|
18
23
|
#mapper
|
|
19
24
|
#pprof
|
|
20
25
|
#samplingInterval
|
|
@@ -39,20 +44,36 @@ class NativeSpaceProfiler {
|
|
|
39
44
|
start ({ mapper, nearOOMCallback } = {}) {
|
|
40
45
|
if (this.#started) return
|
|
41
46
|
|
|
42
|
-
const config = this.#config
|
|
43
47
|
this.#mapper = mapper
|
|
44
48
|
this.#pprof = require('@datadog/pprof')
|
|
45
|
-
this.#pprof.heap.start(this.#samplingInterval, STACK_DEPTH, config.DD_PROFILING_ALLOCATION_ENABLED)
|
|
46
|
-
|
|
49
|
+
this.#pprof.heap.start(this.#samplingInterval, STACK_DEPTH, this.#config.DD_PROFILING_ALLOCATION_ENABLED)
|
|
50
|
+
|
|
51
|
+
if (this.#config.DD_PROFILING_EXPERIMENTAL_OOM_MONITORING_ENABLED) {
|
|
52
|
+
const config = this.#config
|
|
47
53
|
const strategies = ensureOOMExportStrategies(config.DD_PROFILING_EXPERIMENTAL_OOM_EXPORT_STRATEGIES)
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
const monitorOutOfMemory = () => {
|
|
55
|
+
this.#pprof.heap.monitorOutOfMemory(
|
|
56
|
+
config.DD_PROFILING_EXPERIMENTAL_OOM_HEAP_LIMIT_EXTENSION_SIZE,
|
|
57
|
+
config.DD_PROFILING_EXPERIMENTAL_OOM_MAX_HEAP_EXTENSION_COUNT,
|
|
58
|
+
strategies.includes(oomExportStrategies.LOGS),
|
|
59
|
+
strategies.includes(oomExportStrategies.PROCESS) ? buildExportCommand(this.#exporters, this.#tags) : [],
|
|
60
|
+
(profile) => nearOOMCallback(this.type, this.#pprof.encodeSync(profile), this.getInfo()),
|
|
61
|
+
strategiesToCallbackMode(strategies, this.#pprof.heap.CallbackMode)
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
monitorOutOfMemory()
|
|
65
|
+
|
|
66
|
+
if (strategies.includes(oomExportStrategies.PROCESS)) {
|
|
67
|
+
this.#identityRefreshListener = () => {
|
|
68
|
+
try {
|
|
69
|
+
Object.assign(this.#tags, config.tags)
|
|
70
|
+
monitorOutOfMemory()
|
|
71
|
+
} catch (error) {
|
|
72
|
+
log.error(error)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
identityRefreshChannel.subscribe(this.#identityRefreshListener)
|
|
76
|
+
}
|
|
56
77
|
}
|
|
57
78
|
|
|
58
79
|
this.#started = true
|
|
@@ -74,6 +95,12 @@ class NativeSpaceProfiler {
|
|
|
74
95
|
|
|
75
96
|
stop () {
|
|
76
97
|
if (!this.#started) return
|
|
98
|
+
|
|
99
|
+
if (this.#identityRefreshListener !== undefined) {
|
|
100
|
+
identityRefreshChannel.unsubscribe(this.#identityRefreshListener)
|
|
101
|
+
this.#identityRefreshListener = undefined
|
|
102
|
+
}
|
|
103
|
+
|
|
77
104
|
this.#pprof.heap.stop()
|
|
78
105
|
this.#started = false
|
|
79
106
|
}
|
|
@@ -138,7 +138,7 @@ class NativeWallProfiler {
|
|
|
138
138
|
|
|
139
139
|
this.#pprof.time.start({
|
|
140
140
|
collectCpuTime: this.#cpuProfilingEnabled,
|
|
141
|
-
columnNumbers: '
|
|
141
|
+
columnNumbers: 'emit',
|
|
142
142
|
durationMillis: this.#flushIntervalMillis,
|
|
143
143
|
intervalMicros: this.#samplingIntervalMicros,
|
|
144
144
|
lineNumbers: false,
|
|
@@ -168,8 +168,8 @@ class NativeWallProfiler {
|
|
|
168
168
|
spanFinishCh.subscribe(this.#boundSpanFinished)
|
|
169
169
|
if (this.#endpointCollectionEnabled) {
|
|
170
170
|
// Web-tags cache publishes once per span at the moment its
|
|
171
|
-
// walk-result
|
|
172
|
-
//
|
|
171
|
+
// walk-result changes — exactly when we need to refresh the
|
|
172
|
+
// ProfilingContext snapshot.
|
|
173
173
|
webTagsCache.resolvedCh.subscribe(this.#boundSpanTagsUpdated)
|
|
174
174
|
// Turn on the cache's own tagsUpdate subscription — it's
|
|
175
175
|
// ref-counted, so this composes with any other active consumer.
|
|
@@ -229,13 +229,12 @@ class NativeWallProfiler {
|
|
|
229
229
|
} else if (current !== sampleContext) {
|
|
230
230
|
this.#pprof.time.setContext(sampleContext)
|
|
231
231
|
}
|
|
232
|
-
// Every setContext() call in ACF mode allocates a fresh contextHolder
|
|
233
|
-
// (a node::ObjectWrap with its own v8::Global<v8::Value>) in the native
|
|
234
|
-
// profiler. Skip the call if the CPED already holds this sampleContext,
|
|
235
|
-
// which is the common case when the same span is repeatedly activated:
|
|
236
|
-
// #getProfilingContext caches profilingContext on span[ProfilingContext],
|
|
237
|
-
// so identity comparison short-circuits.
|
|
238
232
|
} else if (current !== sampleContext) {
|
|
233
|
+
// Every setContext() call in ACF mode allocates a fresh contextHolder
|
|
234
|
+
// (a node::ObjectWrap with its own v8::Global<v8::Value>) in the native
|
|
235
|
+
// profiler. We're only incurring the cost when current !== sampleContext
|
|
236
|
+
// and skip it when current === sampleContext, which is the common case
|
|
237
|
+
// when the same span is repeatedly activated.
|
|
239
238
|
this.#pprof.time.setContext(sampleContext)
|
|
240
239
|
}
|
|
241
240
|
} else {
|
|
@@ -266,8 +265,8 @@ class NativeWallProfiler {
|
|
|
266
265
|
}
|
|
267
266
|
|
|
268
267
|
// webTags is snapshotted into the sample context at getProfilingContext
|
|
269
|
-
// time; if the answer
|
|
270
|
-
// web-server
|
|
268
|
+
// time; if the answer changes later — the span or an ancestor becomes a
|
|
269
|
+
// web-server span — #spanTagsUpdated refreshes this field via the shared
|
|
271
270
|
// cache (see web-tags-cache.js).
|
|
272
271
|
const webTags = this.#endpointCollectionEnabled ? webTagsCache.getCachedWebTags(span) : undefined
|
|
273
272
|
|
|
@@ -291,9 +290,10 @@ class NativeWallProfiler {
|
|
|
291
290
|
}
|
|
292
291
|
|
|
293
292
|
// Invoked (via webTagsCache.resolvedCh) once per span at the moment the
|
|
294
|
-
// shared cache
|
|
295
|
-
//
|
|
296
|
-
//
|
|
293
|
+
// shared cache changes its webTags answer: an empty one promoted into a real
|
|
294
|
+
// value, or an outer request's tag bag replaced by a nearer one. Refresh the
|
|
295
|
+
// ProfilingContext snapshot in place so samples already holding it — including
|
|
296
|
+
// those of a span that stays active across the promotion — pick it up.
|
|
297
297
|
#spanTagsUpdated (span) {
|
|
298
298
|
if (!this.#started) return
|
|
299
299
|
const profilingContext = span[ProfilingContext]
|
|
@@ -8,10 +8,13 @@ function isWebServerSpan (tags) {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
function endpointNameFromTags (tags) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
]
|
|
11
|
+
const resource = tags[RESOURCE_NAME]
|
|
12
|
+
if (resource) return resource
|
|
13
|
+
|
|
14
|
+
let endpoint = tags[HTTP_METHOD] || ''
|
|
15
|
+
const route = tags[HTTP_ROUTE]
|
|
16
|
+
if (route) endpoint += endpoint ? ` ${route}` : route
|
|
17
|
+
return endpoint
|
|
15
18
|
}
|
|
16
19
|
|
|
17
20
|
// The endpoint name a web-server span's tag bag yields changes over the span's
|