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
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { DD_TRACE_SYMBOL, PROBE_SAMPLER_SYMBOL } = require('../probe_sampler_constants')
|
|
4
|
+
|
|
5
|
+
const SAMPLER_EXPRESSION = `globalThis[Symbol.for(${JSON.stringify(DD_TRACE_SYMBOL)})]?.` +
|
|
6
|
+
`[Symbol.for(${JSON.stringify(PROBE_SAMPLER_SYMBOL)})]`
|
|
7
|
+
|
|
8
|
+
module.exports = {
|
|
9
|
+
compileBreakpointCondition,
|
|
10
|
+
getRemoveProbeExpression,
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Build the expression that removes a probe from runtime sampler state. Called by the devtools worker and evaluated on
|
|
15
|
+
* the debuggee.
|
|
16
|
+
*
|
|
17
|
+
* @param {string} id - The probe id.
|
|
18
|
+
* @returns {string}
|
|
19
|
+
*/
|
|
20
|
+
function getRemoveProbeExpression (id) {
|
|
21
|
+
return `${SAMPLER_EXPRESSION}?.remove(${JSON.stringify(id)})`
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Build a Chrome DevTools breakpoint condition that samples all matching probes at a location. Called by the devtools
|
|
26
|
+
* worker.
|
|
27
|
+
*
|
|
28
|
+
* @param {{
|
|
29
|
+
* id: string,
|
|
30
|
+
* samplingIndex: number,
|
|
31
|
+
* nsBetweenSampling: bigint,
|
|
32
|
+
* condition?: string,
|
|
33
|
+
* captureSnapshot?: boolean,
|
|
34
|
+
* compiledCaptureExpressions?: object[]
|
|
35
|
+
* }[]} probes - The probes at the breakpoint location.
|
|
36
|
+
* @returns {string}
|
|
37
|
+
*/
|
|
38
|
+
function compileBreakpointCondition (probes) {
|
|
39
|
+
const probeConditions = []
|
|
40
|
+
for (const probe of probes) {
|
|
41
|
+
probeConditions.push(compileProbeCondition(probe))
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// NOTE: $dd_sampler is read from the realm-local `globalThis` where it was installed (the main
|
|
45
|
+
// realm). A probe whose code runs in a different V8 realm (e.g. a `vm.createContext` script with a
|
|
46
|
+
// file-path filename) won't see it and will silently never fire. Known limitation: a breakpoint
|
|
47
|
+
// condition has no realm-independent handle to reach, so we degrade rather than crash.
|
|
48
|
+
return `(() => {
|
|
49
|
+
const $dd_sampler = ${SAMPLER_EXPRESSION}
|
|
50
|
+
if ($dd_sampler === undefined) return false
|
|
51
|
+
let $dd_sampled = false
|
|
52
|
+
${probeConditions.join('\n ')}
|
|
53
|
+
return $dd_sampled
|
|
54
|
+
})()`
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Build the condition fragment for a single probe. Called by the devtools worker while building breakpoint conditions.
|
|
59
|
+
*
|
|
60
|
+
* @param {{
|
|
61
|
+
* id: string,
|
|
62
|
+
* samplingIndex: number,
|
|
63
|
+
* nsBetweenSampling: bigint,
|
|
64
|
+
* condition?: string,
|
|
65
|
+
* captureSnapshot?: boolean,
|
|
66
|
+
* compiledCaptureExpressions?: object[]
|
|
67
|
+
* }} probe - The probe to sample.
|
|
68
|
+
* @returns {string}
|
|
69
|
+
*/
|
|
70
|
+
function compileProbeCondition (probe) {
|
|
71
|
+
const sample = `$dd_sampler.makeSampleDecision(${probe.samplingIndex}, ${JSON.stringify(probe.id)}, ` +
|
|
72
|
+
`${probe.nsBetweenSampling}n, ${probe.captureSnapshot === true || probe.compiledCaptureExpressions !== undefined})`
|
|
73
|
+
|
|
74
|
+
if (probe.condition === undefined) {
|
|
75
|
+
return `$dd_sampled = ${sample} || $dd_sampled`
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return `try {
|
|
79
|
+
if ((${probe.condition}) === true) {
|
|
80
|
+
$dd_sampled = ${sample} || $dd_sampled
|
|
81
|
+
}
|
|
82
|
+
} catch {}`
|
|
83
|
+
}
|
|
@@ -33,6 +33,7 @@ module.exports = {
|
|
|
33
33
|
locationToBreakpoint: new Map(),
|
|
34
34
|
breakpointToProbes: new Map(),
|
|
35
35
|
probeToLocation: new Map(),
|
|
36
|
+
samplingIndexToProbe: new Map(),
|
|
36
37
|
|
|
37
38
|
_loadedScripts: loadedScripts, // Only exposed for testing
|
|
38
39
|
_scriptUrls: scriptUrls, // Only exposed for testing
|
|
@@ -8,6 +8,7 @@ const log = require('../log')
|
|
|
8
8
|
const { fetchAgentInfo } = require('../agent/info')
|
|
9
9
|
const getDebuggerConfig = require('./config')
|
|
10
10
|
const { DEBUGGER_DIAGNOSTICS_V1, DEBUGGER_INPUT_V2 } = require('./constants')
|
|
11
|
+
const { installProbeSampler, uninstallProbeSampler } = require('./probe_sampler')
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* @typedef {ReturnType<import('../config')>} Config
|
|
@@ -65,6 +66,8 @@ function start (config, rcInstance) {
|
|
|
65
66
|
|
|
66
67
|
globalThis[Symbol.for('dd-trace')].utilTypes = types
|
|
67
68
|
|
|
69
|
+
const probeSamplerBuffer = installProbeSampler()
|
|
70
|
+
|
|
68
71
|
readProbeFile(config.dynamicInstrumentation.probeFile, (probes) => {
|
|
69
72
|
const action = 'apply'
|
|
70
73
|
for (const probe of probes) {
|
|
@@ -110,6 +113,7 @@ function start (config, rcInstance) {
|
|
|
110
113
|
probePort: probeChannel.port1,
|
|
111
114
|
logPort: logChannel.port1,
|
|
112
115
|
configPort: configChannel.port1,
|
|
116
|
+
probeSamplerBuffer,
|
|
113
117
|
},
|
|
114
118
|
transferList: [probeChannel.port1, logChannel.port1, configChannel.port1],
|
|
115
119
|
}
|
|
@@ -187,6 +191,7 @@ function cleanup (error) {
|
|
|
187
191
|
worker.removeAllListeners()
|
|
188
192
|
worker = null
|
|
189
193
|
}
|
|
194
|
+
uninstallProbeSampler()
|
|
190
195
|
configChannel = null
|
|
191
196
|
inputPath = null
|
|
192
197
|
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { MAX_SNAPSHOTS_PER_SECOND_GLOBALLY } = require('./devtools_client/defaults')
|
|
4
|
+
const {
|
|
5
|
+
DD_TRACE_SYMBOL,
|
|
6
|
+
MAX_SAMPLED_PROBES_PER_PAUSE,
|
|
7
|
+
PROBE_SAMPLER_SYMBOL,
|
|
8
|
+
SAMPLED_PROBE_COUNT_INDEX,
|
|
9
|
+
SAMPLED_PROBE_INDEXES_START,
|
|
10
|
+
SAMPLED_PROBE_OVERFLOW_INDEX,
|
|
11
|
+
} = require('./probe_sampler_constants')
|
|
12
|
+
|
|
13
|
+
const ddTraceGlobal = /** @type {Record<symbol, SharedArrayBuffer | object | undefined>} */ (
|
|
14
|
+
/** @type {Record<symbol, unknown>} */ (globalThis)[Symbol.for(DD_TRACE_SYMBOL)]
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
module.exports = {
|
|
18
|
+
installProbeSampler,
|
|
19
|
+
uninstallProbeSampler,
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Install the runtime sampler in the debuggee context.
|
|
24
|
+
*
|
|
25
|
+
* @returns {SharedArrayBuffer} The shared sampler buffer to pass to the debugger worker.
|
|
26
|
+
*/
|
|
27
|
+
function installProbeSampler () {
|
|
28
|
+
const buffer = createProbeSamplerBuffer()
|
|
29
|
+
|
|
30
|
+
const lastCaptureNsByProbeId = new Map()
|
|
31
|
+
const sampledProbeIndexes = new Int32Array(buffer)
|
|
32
|
+
Atomics.store(sampledProbeIndexes, SAMPLED_PROBE_COUNT_INDEX, 0)
|
|
33
|
+
Atomics.store(sampledProbeIndexes, SAMPLED_PROBE_OVERFLOW_INDEX, 0)
|
|
34
|
+
|
|
35
|
+
const oneSecondNs = 1_000_000_000n
|
|
36
|
+
let globalSnapshotSamplingRateWindowStart = 0n
|
|
37
|
+
let snapshotsSampledWithinTheLastSecond = 0
|
|
38
|
+
|
|
39
|
+
ddTraceGlobal[Symbol.for(PROBE_SAMPLER_SYMBOL)] = {
|
|
40
|
+
/**
|
|
41
|
+
* Decide if a probe should be sampled and store sampled probe indexes for the debugger worker.
|
|
42
|
+
*
|
|
43
|
+
* @param {number} probeIndex - The worker-side probe sampling index.
|
|
44
|
+
* @param {string} probeId - The probe id.
|
|
45
|
+
* @param {bigint} nsBetweenSampling - Minimum nanoseconds between samples for this probe.
|
|
46
|
+
* @param {boolean} isSnapshotProducingProbe - Whether this probe counts toward the global snapshot sample limit.
|
|
47
|
+
* @returns {boolean} Whether this probe should make the breakpoint condition pause.
|
|
48
|
+
*/
|
|
49
|
+
makeSampleDecision (probeIndex, probeId, nsBetweenSampling, isSnapshotProducingProbe) {
|
|
50
|
+
const now = process.hrtime.bigint()
|
|
51
|
+
const lastCaptureNs = lastCaptureNsByProbeId.get(probeId)
|
|
52
|
+
if (lastCaptureNs !== undefined && now - lastCaptureNs < nsBetweenSampling) return false
|
|
53
|
+
|
|
54
|
+
let shouldResetGlobalSnapshotRateWindow = false
|
|
55
|
+
if (isSnapshotProducingProbe === true) {
|
|
56
|
+
if (now - globalSnapshotSamplingRateWindowStart > oneSecondNs) {
|
|
57
|
+
shouldResetGlobalSnapshotRateWindow = true
|
|
58
|
+
} else if (snapshotsSampledWithinTheLastSecond >= MAX_SNAPSHOTS_PER_SECOND_GLOBALLY) {
|
|
59
|
+
return false
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const sampledProbeCount = Atomics.add(sampledProbeIndexes, SAMPLED_PROBE_COUNT_INDEX, 1)
|
|
64
|
+
if (sampledProbeCount >= MAX_SAMPLED_PROBES_PER_PAUSE) {
|
|
65
|
+
Atomics.store(sampledProbeIndexes, SAMPLED_PROBE_OVERFLOW_INDEX, 1)
|
|
66
|
+
return false
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (isSnapshotProducingProbe === true) {
|
|
70
|
+
if (shouldResetGlobalSnapshotRateWindow === true) {
|
|
71
|
+
snapshotsSampledWithinTheLastSecond = 1
|
|
72
|
+
globalSnapshotSamplingRateWindowStart = now
|
|
73
|
+
} else {
|
|
74
|
+
snapshotsSampledWithinTheLastSecond++
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
lastCaptureNsByProbeId.set(probeId, now)
|
|
79
|
+
Atomics.store(sampledProbeIndexes, SAMPLED_PROBE_INDEXES_START + sampledProbeCount, probeIndex)
|
|
80
|
+
return true
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Remove cached sampling state for a probe.
|
|
85
|
+
*
|
|
86
|
+
* @param {string} probeId - The probe id.
|
|
87
|
+
*/
|
|
88
|
+
remove (probeId) {
|
|
89
|
+
lastCaptureNsByProbeId.delete(probeId)
|
|
90
|
+
},
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return buffer
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Remove the runtime sampler from the debuggee context.
|
|
98
|
+
*/
|
|
99
|
+
function uninstallProbeSampler () {
|
|
100
|
+
delete ddTraceGlobal[Symbol.for(PROBE_SAMPLER_SYMBOL)]
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Create the shared buffer used to hand sampled probe indexes from breakpoint conditions to the debugger worker.
|
|
105
|
+
*
|
|
106
|
+
* @returns {SharedArrayBuffer}
|
|
107
|
+
*/
|
|
108
|
+
function createProbeSamplerBuffer () {
|
|
109
|
+
return new SharedArrayBuffer(
|
|
110
|
+
(SAMPLED_PROBE_INDEXES_START + MAX_SAMPLED_PROBES_PER_PAUSE) * Int32Array.BYTES_PER_ELEMENT
|
|
111
|
+
)
|
|
112
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const DD_TRACE_SYMBOL = 'dd-trace'
|
|
4
|
+
const PROBE_SAMPLER_SYMBOL = 'dd-trace.debugger.probeSampler'
|
|
5
|
+
|
|
6
|
+
// Shared sampler contract used by the main debugger bootstrap and the devtools worker.
|
|
7
|
+
const MAX_SAMPLED_PROBES_PER_PAUSE = 256
|
|
8
|
+
const SAMPLED_PROBE_COUNT_INDEX = 0
|
|
9
|
+
const SAMPLED_PROBE_OVERFLOW_INDEX = 1
|
|
10
|
+
const SAMPLED_PROBE_INDEXES_START = 2
|
|
11
|
+
|
|
12
|
+
module.exports = {
|
|
13
|
+
DD_TRACE_SYMBOL,
|
|
14
|
+
MAX_SAMPLED_PROBES_PER_PAUSE,
|
|
15
|
+
PROBE_SAMPLER_SYMBOL,
|
|
16
|
+
SAMPLED_PROBE_COUNT_INDEX,
|
|
17
|
+
SAMPLED_PROBE_INDEXES_START,
|
|
18
|
+
SAMPLED_PROBE_OVERFLOW_INDEX,
|
|
19
|
+
}
|
|
@@ -3,11 +3,14 @@
|
|
|
3
3
|
const dgram = require('dgram')
|
|
4
4
|
const isIP = require('net').isIP
|
|
5
5
|
|
|
6
|
+
const { storage } = require('../../datadog-core')
|
|
6
7
|
const request = require('./exporters/common/request')
|
|
7
8
|
const log = require('./log')
|
|
8
9
|
const Histogram = require('./histogram')
|
|
9
10
|
const { entityId } = require('./exporters/common/docker')
|
|
10
11
|
|
|
12
|
+
const legacyStorage = storage('legacy')
|
|
13
|
+
|
|
11
14
|
const MAX_BUFFER_SIZE = 1024 // limit from the agent
|
|
12
15
|
|
|
13
16
|
const TYPE_COUNTER = 'c'
|
|
@@ -98,14 +101,18 @@ class DogStatsDClient {
|
|
|
98
101
|
}
|
|
99
102
|
|
|
100
103
|
_sendUdp (queue) {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
104
|
+
// dgram resolves the local address via the instrumented dns.lookup when it
|
|
105
|
+
// binds on first send; the noop store keeps that self-traffic off the trace.
|
|
106
|
+
legacyStorage.run({ noop: true }, () => {
|
|
107
|
+
if (this._family === 0) {
|
|
108
|
+
this.#lookup(this._host, (error, address, family) => {
|
|
109
|
+
if (error) return log.error('DogStatsDClient: Host not found', error)
|
|
110
|
+
this._sendUdpFromQueue(queue, address, family)
|
|
111
|
+
})
|
|
112
|
+
} else {
|
|
113
|
+
this._sendUdpFromQueue(queue, this._host, this._family)
|
|
114
|
+
}
|
|
115
|
+
})
|
|
109
116
|
}
|
|
110
117
|
|
|
111
118
|
_sendUdpFromQueue (queue, address, family) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
const { version: ddTraceVersion } = require('../../../../package.json')
|
|
3
|
-
const { ITR_CORRELATION_ID } = require('../../src/plugins/util/test')
|
|
3
|
+
const { ITR_CORRELATION_ID, TEST_LEVELS_METADATA } = require('../../src/plugins/util/test')
|
|
4
4
|
const id = require('../../src/id')
|
|
5
5
|
const {
|
|
6
6
|
distributionMetric,
|
|
@@ -9,10 +9,15 @@ const {
|
|
|
9
9
|
} = require('../ci-visibility/telemetry')
|
|
10
10
|
const { MsgpackChunk } = require('../msgpack')
|
|
11
11
|
const { AgentEncoder } = require('./0.4')
|
|
12
|
-
const {
|
|
12
|
+
const {
|
|
13
|
+
truncateSpanTestOpt,
|
|
14
|
+
normalizeSpan,
|
|
15
|
+
MAX_META_VALUE_LENGTH_TEST_OPTIMIZATION,
|
|
16
|
+
} = require('./tags-processors')
|
|
13
17
|
|
|
14
18
|
const ENCODING_VERSION = 1
|
|
15
19
|
const ALLOWED_CONTENT_TYPES = new Set(['test_session_end', 'test_module_end', 'test_suite_end', 'test'])
|
|
20
|
+
const ALLOWED_METADATA_TARGETS = new Set([...ALLOWED_CONTENT_TYPES, TEST_LEVELS_METADATA])
|
|
16
21
|
|
|
17
22
|
const TEST_SUITE_KEYS_LENGTH = 12
|
|
18
23
|
const TEST_MODULE_KEYS_LENGTH = 11
|
|
@@ -36,6 +41,33 @@ function formatSpan (span) {
|
|
|
36
41
|
}
|
|
37
42
|
}
|
|
38
43
|
|
|
44
|
+
function isAllowedMetadataTarget (target) {
|
|
45
|
+
return ALLOWED_METADATA_TARGETS.has(target)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function isEncodableMetadataValue (value) {
|
|
49
|
+
return typeof value === 'string' || typeof value === 'number'
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function truncateTestLevelMetadataValue (value) {
|
|
53
|
+
if (typeof value !== 'string' || value.length <= MAX_META_VALUE_LENGTH_TEST_OPTIMIZATION) {
|
|
54
|
+
return value
|
|
55
|
+
}
|
|
56
|
+
return `${value.slice(0, MAX_META_VALUE_LENGTH_TEST_OPTIMIZATION)}...`
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function truncateTestLevelMetadataTags (tags) {
|
|
60
|
+
const truncatedTags = {}
|
|
61
|
+
let hasTags = false
|
|
62
|
+
for (const key of Object.keys(tags)) {
|
|
63
|
+
const value = truncateTestLevelMetadataValue(tags[key])
|
|
64
|
+
if (!isEncodableMetadataValue(value)) continue
|
|
65
|
+
truncatedTags[key] = value
|
|
66
|
+
hasTags = true
|
|
67
|
+
}
|
|
68
|
+
return hasTags ? truncatedTags : undefined
|
|
69
|
+
}
|
|
70
|
+
|
|
39
71
|
class AgentlessCiVisibilityEncoder extends AgentEncoder {
|
|
40
72
|
constructor (writer, { runtimeId, service, env }) {
|
|
41
73
|
super(writer, INTAKE_SOFT_LIMIT)
|
|
@@ -49,6 +81,7 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
|
|
|
49
81
|
|
|
50
82
|
this.metadataTags = {}
|
|
51
83
|
this.wildcardMetadataTags = {}
|
|
84
|
+
this.testLevelsMetadataKeys = []
|
|
52
85
|
|
|
53
86
|
this.reset()
|
|
54
87
|
}
|
|
@@ -60,12 +93,39 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
|
|
|
60
93
|
...tags['*'],
|
|
61
94
|
}
|
|
62
95
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
96
|
+
|
|
97
|
+
for (const target of Object.keys(tags)) {
|
|
98
|
+
if (target === '*' || !tags[target] || !isAllowedMetadataTarget(target)) continue
|
|
99
|
+
|
|
100
|
+
const targetTags = target === TEST_LEVELS_METADATA
|
|
101
|
+
? truncateTestLevelMetadataTags(tags[target])
|
|
102
|
+
: tags[target]
|
|
103
|
+
if (!targetTags) continue
|
|
104
|
+
|
|
105
|
+
this.metadataTags[target] = {
|
|
106
|
+
...this.metadataTags[target],
|
|
107
|
+
...targetTags,
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (target === TEST_LEVELS_METADATA) {
|
|
111
|
+
this.testLevelsMetadataKeys = Object.keys(this.metadataTags[target])
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
_removeDuplicateTestLevelsMetadata (event) {
|
|
117
|
+
if (!ALLOWED_CONTENT_TYPES.has(event.type)) return
|
|
118
|
+
|
|
119
|
+
const meta = event.content.meta
|
|
120
|
+
if (!meta) return
|
|
121
|
+
|
|
122
|
+
const testLevelsMetadataTags = this.metadataTags[TEST_LEVELS_METADATA]
|
|
123
|
+
const testLevelsMetadataKeys = this.testLevelsMetadataKeys
|
|
124
|
+
|
|
125
|
+
for (let i = 0; i < testLevelsMetadataKeys.length; i++) {
|
|
126
|
+
const key = testLevelsMetadataKeys[i]
|
|
127
|
+
if (meta[key] === testLevelsMetadataTags[key]) {
|
|
128
|
+
delete meta[key]
|
|
69
129
|
}
|
|
70
130
|
}
|
|
71
131
|
}
|
|
@@ -276,7 +336,11 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
|
|
|
276
336
|
|
|
277
337
|
this._eventCount += events.length
|
|
278
338
|
|
|
339
|
+
const hasTestLevelsMetadata = this.testLevelsMetadataKeys.length !== 0
|
|
279
340
|
for (const event of events) {
|
|
341
|
+
if (hasTestLevelsMetadata) {
|
|
342
|
+
this._removeDuplicateTestLevelsMetadata(event)
|
|
343
|
+
}
|
|
280
344
|
this._encodeEvent(bytes, event)
|
|
281
345
|
}
|
|
282
346
|
distributionMetric(
|
|
@@ -343,24 +407,11 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
|
|
|
343
407
|
this._encodeString(bytes, 'version')
|
|
344
408
|
bytes.writeNumber(payload.version)
|
|
345
409
|
this._encodeString(bytes, 'metadata')
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
this.
|
|
351
|
-
this._encodeMap(bytes, payload.metadata.test)
|
|
352
|
-
}
|
|
353
|
-
if (payload.metadata.test_suite_end) {
|
|
354
|
-
this._encodeString(bytes, 'test_suite_end')
|
|
355
|
-
this._encodeMap(bytes, payload.metadata.test_suite_end)
|
|
356
|
-
}
|
|
357
|
-
if (payload.metadata.test_module_end) {
|
|
358
|
-
this._encodeString(bytes, 'test_module_end')
|
|
359
|
-
this._encodeMap(bytes, payload.metadata.test_module_end)
|
|
360
|
-
}
|
|
361
|
-
if (payload.metadata.test_session_end) {
|
|
362
|
-
this._encodeString(bytes, 'test_session_end')
|
|
363
|
-
this._encodeMap(bytes, payload.metadata.test_session_end)
|
|
410
|
+
const metadataKeys = Object.keys(payload.metadata)
|
|
411
|
+
bytes.writeMapPrefix(metadataKeys.length)
|
|
412
|
+
for (const metadataKey of metadataKeys) {
|
|
413
|
+
this._encodeString(bytes, metadataKey)
|
|
414
|
+
this._encodeMap(bytes, payload.metadata[metadataKey])
|
|
364
415
|
}
|
|
365
416
|
this._encodeString(bytes, 'events')
|
|
366
417
|
this._eventsOffset = bytes.length
|
|
@@ -7,6 +7,7 @@ const log = require('../../log')
|
|
|
7
7
|
const { entityId } = require('../common/docker')
|
|
8
8
|
const tracerVersion = require('../../../../../package.json').version
|
|
9
9
|
const Writer = require('./writer')
|
|
10
|
+
const { computeIntakeUrl } = require('./intake')
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Agentless exporter for APM trace intake.
|
|
@@ -15,6 +16,7 @@ const Writer = require('./writer')
|
|
|
15
16
|
*/
|
|
16
17
|
class AgentlessExporter {
|
|
17
18
|
#timer
|
|
19
|
+
#config
|
|
18
20
|
|
|
19
21
|
/**
|
|
20
22
|
* @param {object} config - Configuration object
|
|
@@ -24,13 +26,13 @@ class AgentlessExporter {
|
|
|
24
26
|
* @param {object} [config.tags] - Tags including runtime-id
|
|
25
27
|
*/
|
|
26
28
|
constructor (config) {
|
|
27
|
-
this
|
|
29
|
+
this.#config = config
|
|
28
30
|
const site = config.site ?? 'datadoghq.com'
|
|
29
31
|
|
|
30
32
|
try {
|
|
31
|
-
// Agentless traffic carries the Datadog API key, so the intake is always
|
|
32
|
-
//
|
|
33
|
-
this._url = new URL(
|
|
33
|
+
// Agentless traffic carries the Datadog API key, so the intake is always an https endpoint
|
|
34
|
+
// derived from the site; never config.url (the agent's cleartext http) or the key leaks.
|
|
35
|
+
this._url = new URL(computeIntakeUrl(site))
|
|
34
36
|
} catch (err) {
|
|
35
37
|
log.error('Invalid site for agentless exporter. site=%s. Error: %s', site, err.message)
|
|
36
38
|
this._url = null
|
|
@@ -89,7 +91,7 @@ class AgentlessExporter {
|
|
|
89
91
|
export (spans) {
|
|
90
92
|
this._writer.append(spans)
|
|
91
93
|
|
|
92
|
-
const { flushInterval } = this
|
|
94
|
+
const { flushInterval } = this.#config
|
|
93
95
|
|
|
94
96
|
if (flushInterval === 0) {
|
|
95
97
|
try {
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
// Per-site hosts for the agentless JSON span intake. Regional data centers serve it from
|
|
4
|
+
// browser-intake-* hosts rather than public-trace-http-intake.logs.<site>, so a single template
|
|
5
|
+
// silently drops spans on us3/us5/ap1/ap2. Mirrors dd-trace-py's AgentlessTraceWriter.INTAKE_URLS
|
|
6
|
+
// (DataDog/dd-trace-py#18514).
|
|
7
|
+
const INTAKE_URLS = {
|
|
8
|
+
'datadoghq.com': 'https://public-trace-http-intake.logs.datadoghq.com',
|
|
9
|
+
'datadoghq.eu': 'https://public-trace-http-intake.logs.datadoghq.eu',
|
|
10
|
+
'us3.datadoghq.com': 'https://trace.browser-intake-us3-datadoghq.com',
|
|
11
|
+
'us5.datadoghq.com': 'https://trace.browser-intake-us5-datadoghq.com',
|
|
12
|
+
'ap1.datadoghq.com': 'https://browser-intake-ap1-datadoghq.com',
|
|
13
|
+
'ap2.datadoghq.com': 'https://browser-intake-ap2-datadoghq.com',
|
|
14
|
+
'uk1.datadoghq.com': 'https://browser-intake-uk1-datadoghq.com',
|
|
15
|
+
'datad0g.com': 'https://public-trace-http-intake.logs.datad0g.com',
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Path of the JSON span intake on every intake host.
|
|
19
|
+
const INTAKE_PATH = '/api/v2/spans'
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Resolves the agentless intake origin for a Datadog site.
|
|
23
|
+
*
|
|
24
|
+
* Unknown sites fall back to the browser-intake naming: strip the TLD, dash-join the rest, then
|
|
25
|
+
* reattach the TLD, e.g. 'us2.ddog-gov.com' -> 'https://browser-intake-us2-ddog-gov.com'.
|
|
26
|
+
*
|
|
27
|
+
* @param {string} [site] - The Datadog site, e.g. 'us3.datadoghq.com'. Defaults to 'datadoghq.com'.
|
|
28
|
+
* @returns {string} The intake origin, without a path.
|
|
29
|
+
*/
|
|
30
|
+
function computeIntakeUrl (site = 'datadoghq.com') {
|
|
31
|
+
const normalized = site.toLowerCase()
|
|
32
|
+
const known = INTAKE_URLS[normalized]
|
|
33
|
+
if (known !== undefined) {
|
|
34
|
+
return known
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const lastDot = normalized.lastIndexOf('.')
|
|
38
|
+
const prefix = lastDot === -1 ? '' : normalized.slice(0, lastDot)
|
|
39
|
+
const tld = lastDot === -1 ? normalized : normalized.slice(lastDot + 1)
|
|
40
|
+
return `https://browser-intake-${prefix.replaceAll('.', '-')}.${tld}`
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
module.exports = { INTAKE_URLS, INTAKE_PATH, computeIntakeUrl }
|
|
@@ -7,6 +7,7 @@ const tracerVersion = require('../../../../../package.json').version
|
|
|
7
7
|
|
|
8
8
|
const BaseWriter = require('../common/writer')
|
|
9
9
|
const { AgentlessJSONEncoder } = require('../../encode/agentless-json')
|
|
10
|
+
const { computeIntakeUrl, INTAKE_PATH } = require('./intake')
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Writer for agentless APM trace intake.
|
|
@@ -28,7 +29,7 @@ class AgentlessWriter extends BaseWriter {
|
|
|
28
29
|
|
|
29
30
|
if (!url) {
|
|
30
31
|
try {
|
|
31
|
-
this._url = new URL(
|
|
32
|
+
this._url = new URL(computeIntakeUrl(site))
|
|
32
33
|
} catch (err) {
|
|
33
34
|
log.error(
|
|
34
35
|
'Invalid site value for agentless intake: %s. Cannot construct URL. Error: %s',
|
|
@@ -121,7 +122,7 @@ class AgentlessWriter extends BaseWriter {
|
|
|
121
122
|
this.#apiKeyMissing = false
|
|
122
123
|
|
|
123
124
|
const options = {
|
|
124
|
-
path:
|
|
125
|
+
path: INTAKE_PATH,
|
|
125
126
|
method: 'POST',
|
|
126
127
|
headers: {
|
|
127
128
|
'Content-Type': 'application/json',
|
|
@@ -140,7 +141,7 @@ class AgentlessWriter extends BaseWriter {
|
|
|
140
141
|
|
|
141
142
|
request(data, options, (err, res, statusCode) => {
|
|
142
143
|
if (err) {
|
|
143
|
-
this
|
|
144
|
+
this.#logRequestError(err, statusCode, count)
|
|
144
145
|
done()
|
|
145
146
|
return
|
|
146
147
|
}
|
|
@@ -156,7 +157,7 @@ class AgentlessWriter extends BaseWriter {
|
|
|
156
157
|
* @param {number} statusCode - HTTP status code (if available)
|
|
157
158
|
* @param {number} count - Number of traces that were being sent
|
|
158
159
|
*/
|
|
159
|
-
|
|
160
|
+
#logRequestError (err, statusCode, count) {
|
|
160
161
|
if (statusCode === 401 || statusCode === 403) {
|
|
161
162
|
log.error(
|
|
162
163
|
'Authentication failed sending %d trace(s) (status %s). Verify DD_API_KEY is valid.',
|
|
@@ -11,7 +11,7 @@ const zlib = require('zlib')
|
|
|
11
11
|
|
|
12
12
|
const { storage } = require('../../../../datadog-core')
|
|
13
13
|
const log = require('../../log')
|
|
14
|
-
const {
|
|
14
|
+
const { parseUrl } = require('./url')
|
|
15
15
|
const docker = require('./docker')
|
|
16
16
|
const { httpAgent, httpsAgent } = require('./agents')
|
|
17
17
|
const {
|
|
@@ -27,25 +27,6 @@ const maxActiveBufferSize = 1024 * 1024 * 64
|
|
|
27
27
|
|
|
28
28
|
let activeBufferSize = 0
|
|
29
29
|
|
|
30
|
-
/**
|
|
31
|
-
* @param {string|URL|object} urlObjOrString
|
|
32
|
-
* @returns {object}
|
|
33
|
-
*/
|
|
34
|
-
function parseUrl (urlObjOrString) {
|
|
35
|
-
if (urlObjOrString !== null && typeof urlObjOrString === 'object') return urlToHttpOptions(urlObjOrString)
|
|
36
|
-
|
|
37
|
-
const url = urlToHttpOptions(new URL(urlObjOrString))
|
|
38
|
-
|
|
39
|
-
// Special handling if we're using named pipes on Windows
|
|
40
|
-
if (url.protocol === 'unix:' && url.hostname === '.') {
|
|
41
|
-
const udsPath = urlObjOrString.slice(5)
|
|
42
|
-
url.path = udsPath
|
|
43
|
-
url.pathname = udsPath
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return url
|
|
47
|
-
}
|
|
48
|
-
|
|
49
30
|
/**
|
|
50
31
|
* @param {string} hostname Host as resolved by {@link parseUrl}; IPv6 is unbracketed (`::1`).
|
|
51
32
|
*/
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { urlToHttpOptions } = require('./url-to-http-options-polyfill')
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Convert an agent/intake URL into Node http(s) request options.
|
|
7
|
+
*
|
|
8
|
+
* A Windows named pipe (`unix://./pipe/<name>`) parses the `.` as the URL
|
|
9
|
+
* authority, dropping it from the path. Fold it back so the socket path stays
|
|
10
|
+
* `//./pipe/<name>`; otherwise it collapses to `/pipe/<name>` and misses the
|
|
11
|
+
* pipe. Exporters receive `config.url` as a URL object, so this must run for
|
|
12
|
+
* both string and object input.
|
|
13
|
+
*
|
|
14
|
+
* @param {string|URL|object} urlObjOrString
|
|
15
|
+
* @returns {object}
|
|
16
|
+
*/
|
|
17
|
+
function parseUrl (urlObjOrString) {
|
|
18
|
+
// `urlToHttpOptions` returns `pathname` at runtime, but @types/node narrows it
|
|
19
|
+
// to `ClientRequestArgs`, which omits it; cast so the named-pipe fold below can
|
|
20
|
+
// read and rewrite it.
|
|
21
|
+
const url = /** @type {import('node:http').ClientRequestArgs & { pathname: string }} */ (
|
|
22
|
+
urlObjOrString !== null && typeof urlObjOrString === 'object'
|
|
23
|
+
? urlToHttpOptions(urlObjOrString)
|
|
24
|
+
: urlToHttpOptions(new URL(urlObjOrString))
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
if (url.protocol === 'unix:' && url.hostname === '.') {
|
|
28
|
+
url.path = url.pathname = `//.${url.pathname}`
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return url
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
module.exports = { parseUrl }
|
|
@@ -37,9 +37,7 @@ function makeRequest (data, url, cb) {
|
|
|
37
37
|
'Datadog-Meta-Tracer-Version': pkg.version,
|
|
38
38
|
'Content-Type': 'application/msgpack',
|
|
39
39
|
},
|
|
40
|
-
|
|
41
|
-
hostname: url.hostname,
|
|
42
|
-
port: url.port,
|
|
40
|
+
url,
|
|
43
41
|
}
|
|
44
42
|
|
|
45
43
|
log.debug('Request to the intake: %j', options)
|