dd-trace 6.17.0 → 6.18.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/index.d.ts +52 -9
- package/package.json +1 -1
- package/packages/datadog-instrumentations/src/cucumber.js +10 -5
- package/packages/datadog-instrumentations/src/cypress-config.js +27 -15
- package/packages/datadog-instrumentations/src/helpers/bundler-register.js +6 -0
- package/packages/datadog-instrumentations/src/helpers/check-require-cache.js +2 -1
- package/packages/datadog-instrumentations/src/helpers/hooks.js +0 -6
- package/packages/datadog-instrumentations/src/helpers/register.js +20 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +41 -4
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentation-registry.js +15 -13
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +43 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +13 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/targets.js +28 -3
- package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +4 -0
- package/packages/datadog-instrumentations/src/jest.js +27 -3
- package/packages/datadog-instrumentations/src/mocha/main.js +7 -5
- package/packages/datadog-instrumentations/src/mocha/utils.js +8 -8
- package/packages/datadog-instrumentations/src/playwright-reporter.js +3 -4
- package/packages/datadog-instrumentations/src/playwright.js +47 -6
- package/packages/datadog-instrumentations/src/undici.js +7 -3
- package/packages/datadog-instrumentations/src/vitest-main.js +91 -20
- package/packages/datadog-instrumentations/src/webdriverio.js +28 -12
- package/packages/datadog-instrumentations/src/ws.js +41 -1
- package/packages/datadog-plugin-cucumber/src/index.js +3 -4
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +44 -14
- package/packages/datadog-plugin-cypress/src/index.js +3 -1
- package/packages/datadog-plugin-jest/src/index.js +3 -4
- package/packages/datadog-plugin-mocha/src/index.js +3 -4
- package/packages/datadog-plugin-playwright/src/index.js +11 -6
- package/packages/datadog-plugin-vitest/src/index.js +3 -4
- package/packages/datadog-plugin-ws/src/producer.js +1 -1
- package/packages/datadog-shimmer/src/shimmer.js +14 -10
- package/packages/datadog-turbopack/index.js +4 -1
- package/packages/datadog-turbopack/src/loader.js +6 -2
- package/packages/dd-trace/src/agent/info.js +5 -4
- package/packages/dd-trace/src/config/generated-config-types.d.ts +15 -15
- package/packages/dd-trace/src/config/index.js +7 -6
- package/packages/dd-trace/src/config/supported-configurations.json +11 -0
- package/packages/dd-trace/src/debugger/devtools_client/config.js +2 -1
- package/packages/dd-trace/src/debugger/devtools_client/send.js +1 -1
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/redaction.js +5 -3
- package/packages/dd-trace/src/debugger/devtools_client/status.js +1 -1
- package/packages/dd-trace/src/debugger/index.js +1 -1
- package/packages/dd-trace/src/evp_proxy/constants.js +2 -0
- package/packages/dd-trace/src/evp_proxy/direct.js +17 -13
- package/packages/dd-trace/src/evp_proxy/discovery.js +14 -10
- package/packages/dd-trace/src/evp_proxy/path.js +21 -7
- package/packages/dd-trace/src/exporters/common/url.js +33 -2
- package/packages/dd-trace/src/llmobs/prompts/manager.js +10 -2
- package/packages/dd-trace/src/llmobs/prompts/prompt.js +77 -11
- package/packages/dd-trace/src/llmobs/tagger.js +9 -4
- package/packages/dd-trace/src/openfeature/configuration_source.js +4 -1
- package/packages/dd-trace/src/openfeature/flagging_provider.js +3 -3
- package/packages/dd-trace/src/openfeature/index.js +6 -2
- package/packages/dd-trace/src/openfeature/writers/base.js +90 -17
- package/packages/dd-trace/src/openfeature/writers/exposures.js +4 -0
- package/packages/dd-trace/src/openfeature/writers/util.js +104 -33
- package/packages/dd-trace/src/opentracing/tracer.js +3 -3
- package/packages/dd-trace/src/plugin_manager.js +27 -8
- package/packages/dd-trace/src/plugins/ci_plugin.js +1 -1
- package/packages/dd-trace/src/plugins/util/test.js +9 -4
- package/packages/dd-trace/src/proxy.js +2 -2
- package/packages/dd-trace/src/telemetry/send-data.js +2 -1
- package/packages/dd-trace/src/telemetry/telemetry.js +1 -1
- package/packages/dd-trace/src/tracer.js +5 -4
- package/packages/datadog-instrumentations/src/azure-cosmos.js +0 -7
- package/packages/datadog-instrumentations/src/bullmq.js +0 -11
- package/packages/datadog-instrumentations/src/langchain.js +0 -7
- package/packages/datadog-instrumentations/src/langgraph.js +0 -7
- package/packages/datadog-instrumentations/src/mercurius.js +0 -11
|
@@ -414,27 +414,21 @@ export interface GeneratedConfig {
|
|
|
414
414
|
};
|
|
415
415
|
dsmEnabled: boolean;
|
|
416
416
|
dynamicInstrumentation: {
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
417
|
+
DD_DYNAMIC_INSTRUMENTATION_CAPTURE_TIMEOUT_MS: number;
|
|
418
|
+
DD_DYNAMIC_INSTRUMENTATION_ENABLED: boolean;
|
|
419
|
+
DD_DYNAMIC_INSTRUMENTATION_PROBE_FILE: string | undefined;
|
|
420
|
+
DD_DYNAMIC_INSTRUMENTATION_REDACTED_IDENTIFIERS: string[];
|
|
421
|
+
DD_DYNAMIC_INSTRUMENTATION_REDACTION_EXCLUDED_IDENTIFIERS: string[];
|
|
422
|
+
DD_DYNAMIC_INSTRUMENTATION_UPLOAD_INTERVAL_SECONDS: number;
|
|
423
423
|
};
|
|
424
424
|
env: string | undefined;
|
|
425
425
|
experimental: {
|
|
426
426
|
b3: boolean;
|
|
427
|
-
enableGetRumData: boolean;
|
|
428
|
-
exporter: string;
|
|
429
|
-
flaggingProvider: {
|
|
430
|
-
enabled: boolean;
|
|
431
|
-
initializationTimeoutMs: number;
|
|
432
|
-
spanEnrichment: {
|
|
433
|
-
enabled: boolean;
|
|
434
|
-
};
|
|
435
|
-
};
|
|
436
427
|
};
|
|
437
428
|
featureFlags: {
|
|
429
|
+
DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED: boolean;
|
|
430
|
+
DD_EXPERIMENTAL_FLAGGING_PROVIDER_INITIALIZATION_TIMEOUT_MS: number;
|
|
431
|
+
DD_EXPERIMENTAL_FLAGGING_PROVIDER_SPAN_ENRICHMENT_ENABLED: boolean;
|
|
438
432
|
DD_FEATURE_FLAGS_CONFIGURATION_SOURCE: string;
|
|
439
433
|
DD_FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_BASE_URL: string | undefined;
|
|
440
434
|
DD_FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_POLL_INTERVAL_SECONDS: number;
|
|
@@ -522,6 +516,9 @@ export interface GeneratedConfig {
|
|
|
522
516
|
pollInterval: number;
|
|
523
517
|
};
|
|
524
518
|
reportHostname: boolean;
|
|
519
|
+
rum: {
|
|
520
|
+
DD_TRACE_EXPERIMENTAL_GET_RUM_DATA_ENABLED: boolean;
|
|
521
|
+
};
|
|
525
522
|
runtimeMetrics: {
|
|
526
523
|
enabled: boolean;
|
|
527
524
|
eventLoop: boolean;
|
|
@@ -594,6 +591,9 @@ export interface GeneratedConfig {
|
|
|
594
591
|
traceWebsocketMessagesEnabled: boolean;
|
|
595
592
|
traceWebsocketMessagesInheritSampling: boolean;
|
|
596
593
|
traceWebsocketMessagesSeparateTraces: boolean;
|
|
594
|
+
tracing: {
|
|
595
|
+
DD_TRACE_EXPERIMENTAL_EXPORTER: string;
|
|
596
|
+
};
|
|
597
597
|
url: string | URL;
|
|
598
598
|
version: string | undefined;
|
|
599
599
|
vertexai: {
|
|
@@ -370,8 +370,8 @@ class Config extends ConfigBase {
|
|
|
370
370
|
|
|
371
371
|
if (this.featureFlags.DD_FEATURE_FLAGS_ENABLED &&
|
|
372
372
|
!trackedConfigOrigins.has('featureFlags.DD_FEATURE_FLAGS_CONFIGURATION_SOURCE') &&
|
|
373
|
-
trackedConfigOrigins.has('
|
|
374
|
-
if (this.
|
|
373
|
+
trackedConfigOrigins.has('featureFlags.DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED')) {
|
|
374
|
+
if (this.featureFlags.DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED) {
|
|
375
375
|
setAndTrack(this, 'featureFlags.DD_FEATURE_FLAGS_CONFIGURATION_SOURCE', 'remote_config')
|
|
376
376
|
} else {
|
|
377
377
|
setAndTrack(this, 'featureFlags.DD_FEATURE_FLAGS_ENABLED', false)
|
|
@@ -505,7 +505,8 @@ class Config extends ConfigBase {
|
|
|
505
505
|
// dd-trace's own sampling policy in that case.
|
|
506
506
|
if (!trackedConfigOrigins.has('sampleRate') &&
|
|
507
507
|
(trackedConfigOrigins.has('OTEL_TRACES_SAMPLER') ||
|
|
508
|
-
(this.OTEL_TRACES_EXPORTER === 'otlp' &&
|
|
508
|
+
(this.OTEL_TRACES_EXPORTER === 'otlp' &&
|
|
509
|
+
this.tracing.DD_TRACE_EXPERIMENTAL_EXPORTER !== 'electron'))) {
|
|
509
510
|
setAndTrack(this, 'sampleRate',
|
|
510
511
|
getFromOtelSamplerMap(this.OTEL_TRACES_SAMPLER, this.OTEL_TRACES_SAMPLER_ARG))
|
|
511
512
|
}
|
|
@@ -638,7 +639,7 @@ class Config extends ConfigBase {
|
|
|
638
639
|
}
|
|
639
640
|
|
|
640
641
|
const isTestOptimizationWorker = this.isCiVisibility &&
|
|
641
|
-
TEST_OPTIMIZATION_WORKER_EXPORTERS.has(this.
|
|
642
|
+
TEST_OPTIMIZATION_WORKER_EXPORTERS.has(this.tracing.DD_TRACE_EXPERIMENTAL_EXPORTER)
|
|
642
643
|
if (isTestOptimizationWorker) {
|
|
643
644
|
setAndTrack(this, 'telemetry.DD_INSTRUMENTATION_TELEMETRY_ENABLED', false)
|
|
644
645
|
}
|
|
@@ -651,7 +652,7 @@ class Config extends ConfigBase {
|
|
|
651
652
|
setAndTrack(this, 'llmobs.DD_LLMOBS_AGENTLESS_ENABLED', true)
|
|
652
653
|
setAndTrack(this, 'featureFlags.DD_FEATURE_FLAGS_CONFIGURATION_SOURCE', 'agentless')
|
|
653
654
|
if (this.DD_API_KEY === undefined) {
|
|
654
|
-
setAndTrack(this, 'dynamicInstrumentation.
|
|
655
|
+
setAndTrack(this, 'dynamicInstrumentation.DD_DYNAMIC_INSTRUMENTATION_ENABLED', false)
|
|
655
656
|
}
|
|
656
657
|
setAndTrack(this, 'runtimeMetrics.enabled', false)
|
|
657
658
|
setAndTrack(this, 'dsmEnabled', false)
|
|
@@ -667,7 +668,7 @@ class Config extends ConfigBase {
|
|
|
667
668
|
}
|
|
668
669
|
|
|
669
670
|
if (agentlessTracingEnabled && !this.isCiVisibility) {
|
|
670
|
-
setAndTrack(this, '
|
|
671
|
+
setAndTrack(this, 'tracing.DD_TRACE_EXPERIMENTAL_EXPORTER', 'agentless')
|
|
671
672
|
// Disable client-side stats computation
|
|
672
673
|
setAndTrack(this, 'stats.DD_TRACE_STATS_COMPUTATION_ENABLED', false)
|
|
673
674
|
// Enable hostname reporting
|
|
@@ -802,6 +802,7 @@
|
|
|
802
802
|
{
|
|
803
803
|
"implementation": "A",
|
|
804
804
|
"type": "int",
|
|
805
|
+
"namespace": "dynamicInstrumentation",
|
|
805
806
|
"configurationNames": [
|
|
806
807
|
"dynamicInstrumentation.captureTimeoutMs"
|
|
807
808
|
],
|
|
@@ -812,6 +813,7 @@
|
|
|
812
813
|
{
|
|
813
814
|
"implementation": "A",
|
|
814
815
|
"type": "boolean",
|
|
816
|
+
"namespace": "dynamicInstrumentation",
|
|
815
817
|
"configurationNames": [
|
|
816
818
|
"dynamicInstrumentation.enabled"
|
|
817
819
|
],
|
|
@@ -822,6 +824,7 @@
|
|
|
822
824
|
{
|
|
823
825
|
"implementation": "B",
|
|
824
826
|
"type": "string",
|
|
827
|
+
"namespace": "dynamicInstrumentation",
|
|
825
828
|
"configurationNames": [
|
|
826
829
|
"dynamicInstrumentation.probeFile"
|
|
827
830
|
],
|
|
@@ -832,6 +835,7 @@
|
|
|
832
835
|
{
|
|
833
836
|
"implementation": "A",
|
|
834
837
|
"type": "array",
|
|
838
|
+
"namespace": "dynamicInstrumentation",
|
|
835
839
|
"configurationNames": [
|
|
836
840
|
"dynamicInstrumentation.redactedIdentifiers"
|
|
837
841
|
],
|
|
@@ -842,6 +846,7 @@
|
|
|
842
846
|
{
|
|
843
847
|
"implementation": "C",
|
|
844
848
|
"type": "array",
|
|
849
|
+
"namespace": "dynamicInstrumentation",
|
|
845
850
|
"configurationNames": [
|
|
846
851
|
"dynamicInstrumentation.redactionExcludedIdentifiers"
|
|
847
852
|
],
|
|
@@ -852,6 +857,7 @@
|
|
|
852
857
|
{
|
|
853
858
|
"implementation": "C",
|
|
854
859
|
"type": "decimal",
|
|
860
|
+
"namespace": "dynamicInstrumentation",
|
|
855
861
|
"configurationNames": [
|
|
856
862
|
"dynamicInstrumentation.uploadIntervalSeconds"
|
|
857
863
|
],
|
|
@@ -890,6 +896,7 @@
|
|
|
890
896
|
{
|
|
891
897
|
"implementation": "A",
|
|
892
898
|
"type": "int",
|
|
899
|
+
"namespace": "featureFlags",
|
|
893
900
|
"configurationNames": [
|
|
894
901
|
"experimental.flaggingProvider.initializationTimeoutMs"
|
|
895
902
|
],
|
|
@@ -900,6 +907,7 @@
|
|
|
900
907
|
{
|
|
901
908
|
"implementation": "A",
|
|
902
909
|
"type": "boolean",
|
|
910
|
+
"namespace": "featureFlags",
|
|
903
911
|
"configurationNames": [
|
|
904
912
|
"experimental.flaggingProvider.enabled"
|
|
905
913
|
],
|
|
@@ -910,6 +918,7 @@
|
|
|
910
918
|
{
|
|
911
919
|
"implementation": "A",
|
|
912
920
|
"type": "boolean",
|
|
921
|
+
"namespace": "featureFlags",
|
|
913
922
|
"configurationNames": [
|
|
914
923
|
"experimental.flaggingProvider.spanEnrichment.enabled"
|
|
915
924
|
],
|
|
@@ -2871,6 +2880,7 @@
|
|
|
2871
2880
|
"configurationNames": [
|
|
2872
2881
|
"experimental.exporter"
|
|
2873
2882
|
],
|
|
2883
|
+
"namespace": "tracing",
|
|
2874
2884
|
"default": ""
|
|
2875
2885
|
}
|
|
2876
2886
|
],
|
|
@@ -2881,6 +2891,7 @@
|
|
|
2881
2891
|
"configurationNames": [
|
|
2882
2892
|
"experimental.enableGetRumData"
|
|
2883
2893
|
],
|
|
2894
|
+
"namespace": "rum",
|
|
2884
2895
|
"default": "false"
|
|
2885
2896
|
}
|
|
2886
2897
|
],
|
|
@@ -25,5 +25,6 @@ function updateConfig (updates) {
|
|
|
25
25
|
// The worker receives a serialized config (see ../config.js) where `url` is a string, so it is
|
|
26
26
|
// reconstructed into a URL here rather than read directly off a Config instance.
|
|
27
27
|
config.url = new URL(updates.url)
|
|
28
|
-
config.dynamicInstrumentation.captureTimeoutNs =
|
|
28
|
+
config.dynamicInstrumentation.captureTimeoutNs =
|
|
29
|
+
BigInt(updates.dynamicInstrumentation.DD_DYNAMIC_INSTRUMENTATION_CAPTURE_TIMEOUT_MS) * 1_000_000n
|
|
29
30
|
}
|
|
@@ -32,7 +32,7 @@ setInputPath(config.inputPath)
|
|
|
32
32
|
const jsonBuffer = new JSONBuffer({
|
|
33
33
|
size: config.maxTotalPayloadSize,
|
|
34
34
|
maxQueueBytes: config.queueMaxBytes,
|
|
35
|
-
timeout: config.dynamicInstrumentation.
|
|
35
|
+
timeout: config.dynamicInstrumentation.DD_DYNAMIC_INSTRUMENTATION_UPLOAD_INTERVAL_SECONDS * 1000,
|
|
36
36
|
onFlush,
|
|
37
37
|
})
|
|
38
38
|
|
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
const config = require('../config')
|
|
4
4
|
|
|
5
|
-
const excludedIdentifiers = new Set(
|
|
6
|
-
.
|
|
5
|
+
const excludedIdentifiers = new Set(
|
|
6
|
+
config.dynamicInstrumentation.DD_DYNAMIC_INSTRUMENTATION_REDACTION_EXCLUDED_IDENTIFIERS
|
|
7
|
+
.map((name) => normalizeName(name))
|
|
8
|
+
)
|
|
7
9
|
|
|
8
10
|
const REDACTED_IDENTIFIERS = new Set(
|
|
9
11
|
[
|
|
@@ -95,7 +97,7 @@ const REDACTED_IDENTIFIERS = new Set(
|
|
|
95
97
|
'x_forwarded_for',
|
|
96
98
|
'x_real_ip',
|
|
97
99
|
'XSRF-TOKEN',
|
|
98
|
-
...config.dynamicInstrumentation.
|
|
100
|
+
...config.dynamicInstrumentation.DD_DYNAMIC_INSTRUMENTATION_REDACTED_IDENTIFIERS,
|
|
99
101
|
]
|
|
100
102
|
.map(normalizeIdentifier)
|
|
101
103
|
.filter(isIncludedIdentifier)
|
|
@@ -35,7 +35,7 @@ const cache = new TTLSet(60 * 60 * 1000) // 1 hour
|
|
|
35
35
|
const jsonBuffer = new JSONBuffer({
|
|
36
36
|
size: config.maxTotalPayloadSize,
|
|
37
37
|
maxQueueBytes: DIAGNOSTICS_QUEUE_MAX_BYTES,
|
|
38
|
-
timeout: config.dynamicInstrumentation.
|
|
38
|
+
timeout: config.dynamicInstrumentation.DD_DYNAMIC_INSTRUMENTATION_UPLOAD_INTERVAL_SECONDS * 1000,
|
|
39
39
|
onFlush,
|
|
40
40
|
})
|
|
41
41
|
|
|
@@ -96,7 +96,7 @@ function start (config, rcInstance) {
|
|
|
96
96
|
|
|
97
97
|
const probeSamplerBuffer = installProbeSampler(guardrailMetrics)
|
|
98
98
|
|
|
99
|
-
readProbeFile(config.dynamicInstrumentation.
|
|
99
|
+
readProbeFile(config.dynamicInstrumentation.DD_DYNAMIC_INSTRUMENTATION_PROBE_FILE, (probes) => {
|
|
100
100
|
const action = 'apply'
|
|
101
101
|
for (const probe of probes) {
|
|
102
102
|
probeChannel.port2.postMessage({ action, probe })
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
module.exports = {
|
|
4
|
+
EVP_ORIGIN_HEADER_NAME: 'DD-EVP-ORIGIN',
|
|
5
|
+
EVP_ORIGIN_VERSION_HEADER_NAME: 'DD-EVP-ORIGIN-VERSION',
|
|
4
6
|
EVP_PROXY_PATH_V2: '/evp_proxy/v2',
|
|
5
7
|
EVP_PROXY_PATH_V4: '/evp_proxy/v4',
|
|
6
8
|
EVP_SUBDOMAIN_HEADER_NAME: 'X-Datadog-EVP-Subdomain',
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
const { createSiteUrl } = require('../exporters/common/url')
|
|
4
4
|
const log = require('../log')
|
|
5
5
|
|
|
6
|
+
let invalidSiteWarningLogged = false
|
|
7
|
+
|
|
6
8
|
/**
|
|
7
9
|
* @typedef {object} DirectEVPRoute
|
|
8
10
|
* @property {URL} url - Direct intake URL
|
|
@@ -21,21 +23,23 @@ const log = require('../log')
|
|
|
21
23
|
*/
|
|
22
24
|
function createDirectEVPRoute (config, intake) {
|
|
23
25
|
const apiKey = config.DD_API_KEY
|
|
24
|
-
if (!apiKey
|
|
25
|
-
|
|
26
|
-
try {
|
|
27
|
-
const url = createSiteUrl(config.site, intake)
|
|
28
|
-
if (url === undefined) throw new Error('Invalid direct EVP intake URL')
|
|
26
|
+
if (!apiKey) return
|
|
29
27
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
},
|
|
28
|
+
const url = createSiteUrl(config.site, intake)
|
|
29
|
+
if (url === undefined) {
|
|
30
|
+
if (!invalidSiteWarningLogged) {
|
|
31
|
+
invalidSiteWarningLogged = true
|
|
32
|
+
log.warn('Feature Flags direct event delivery is disabled because DD_SITE is invalid.')
|
|
36
33
|
}
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
return
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
url,
|
|
39
|
+
basePath: '',
|
|
40
|
+
headers: {
|
|
41
|
+
'DD-API-KEY': apiKey,
|
|
42
|
+
},
|
|
39
43
|
}
|
|
40
44
|
}
|
|
41
45
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const { fetchAgentInfo } = require('../agent/info')
|
|
4
4
|
const log = require('../log')
|
|
5
|
-
const { stripTrailingSlashes } = require('./path')
|
|
5
|
+
const { joinAgentURLPath, stripTrailingSlashes } = require('./path')
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Receiver discovery contract
|
|
@@ -25,13 +25,13 @@ const { stripTrailingSlashes } = require('./path')
|
|
|
25
25
|
* serverless-init image or deployment type.
|
|
26
26
|
*
|
|
27
27
|
* This module only discovers a candidate route. A missing or unresponsive
|
|
28
|
-
* `/info` endpoint returns an error
|
|
29
|
-
*
|
|
28
|
+
* `/info` endpoint returns an error after the request's bounded retry policy.
|
|
29
|
+
* Callers can disable retries to make discovery a single attempt. A valid
|
|
30
|
+
* response without a compatible path returns no route.
|
|
30
31
|
* Discovery sends no events, so the caller can safely select direct intake
|
|
31
32
|
* after either result. The caller also owns later delivery failures. Exposure
|
|
32
|
-
* delivery
|
|
33
|
-
*
|
|
34
|
-
* for future batches.
|
|
33
|
+
* delivery decides whether a failed batch can be replayed and which route
|
|
34
|
+
* future batches use.
|
|
35
35
|
*
|
|
36
36
|
* Reference implementations:
|
|
37
37
|
*
|
|
@@ -62,17 +62,17 @@ function selectEVPProxyPath (agentInfo, { supportedPaths, requiredHeaders = [] }
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
const allowedHeaders = agentInfo.evp_proxy_allowed_headers
|
|
65
|
-
if (allowedHeaders !== undefined) {
|
|
65
|
+
if (requiredHeaders.length > 0 || allowedHeaders !== undefined) {
|
|
66
66
|
if (!Array.isArray(allowedHeaders)) return
|
|
67
67
|
|
|
68
68
|
const normalizedHeaders = new Set()
|
|
69
69
|
for (const header of allowedHeaders) {
|
|
70
70
|
if (typeof header === 'string') {
|
|
71
|
-
normalizedHeaders.add(header.toLowerCase())
|
|
71
|
+
normalizedHeaders.add(header.trim().toLowerCase())
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
if (requiredHeaders.some(header => !normalizedHeaders.has(header.toLowerCase()))) {
|
|
75
|
+
if (requiredHeaders.some(header => !normalizedHeaders.has(header.trim().toLowerCase()))) {
|
|
76
76
|
return
|
|
77
77
|
}
|
|
78
78
|
}
|
|
@@ -105,6 +105,7 @@ function selectEVPProxyPath (agentInfo, { supportedPaths, requiredHeaders = [] }
|
|
|
105
105
|
* @param {string[]} options.supportedPaths - Supported paths in preference order
|
|
106
106
|
* @param {string[]} [options.requiredHeaders] - Headers that the proxy must forward unchanged to intake. Each
|
|
107
107
|
* header must appear in `evp_proxy_allowed_headers`. Do not include routing headers that the Agent consumes.
|
|
108
|
+
* @param {boolean} [options.retry] - Set false to disable the request's default bounded retries
|
|
108
109
|
* @param {(error: Error|null, route?: {url: URL, basePath: string}) => void} callback - Result callback
|
|
109
110
|
*/
|
|
110
111
|
function discoverEVPProxy (url, options, callback) {
|
|
@@ -121,7 +122,10 @@ function discoverEVPProxy (url, options, callback) {
|
|
|
121
122
|
}
|
|
122
123
|
|
|
123
124
|
log.debug('EVP proxy route %s discovered through the configured local receiver', basePath)
|
|
124
|
-
callback(null, { url, basePath })
|
|
125
|
+
callback(null, { url, basePath: joinAgentURLPath(url, basePath) })
|
|
126
|
+
}, {
|
|
127
|
+
path: joinAgentURLPath(url, '/info'),
|
|
128
|
+
retry: options.retry,
|
|
125
129
|
})
|
|
126
130
|
}
|
|
127
131
|
|
|
@@ -16,14 +16,28 @@ function stripTrailingSlashes (value) {
|
|
|
16
16
|
*
|
|
17
17
|
* This utility does not perform EVP proxy discovery.
|
|
18
18
|
*
|
|
19
|
-
* @param {string}
|
|
20
|
-
* @param {string} endpoint - Product intake endpoint
|
|
19
|
+
* @param {...string} paths - URL path components
|
|
21
20
|
*/
|
|
22
|
-
function joinEVPProxyPath (
|
|
23
|
-
|
|
24
|
-
const
|
|
21
|
+
function joinEVPProxyPath (...paths) {
|
|
22
|
+
let joined = ''
|
|
23
|
+
for (const path of paths) {
|
|
24
|
+
const normalized = stripTrailingSlashes(path).replace(LEADING_SLASHES, '')
|
|
25
|
+
if (normalized) joined += `/${normalized}`
|
|
26
|
+
}
|
|
25
27
|
|
|
26
|
-
return
|
|
28
|
+
return joined || '/'
|
|
27
29
|
}
|
|
28
30
|
|
|
29
|
-
|
|
31
|
+
/**
|
|
32
|
+
* Joins an HTTP Agent URL path prefix with an EVP proxy path.
|
|
33
|
+
* Unix URL pathnames identify the socket itself and are not HTTP path prefixes.
|
|
34
|
+
*
|
|
35
|
+
* @param {URL} url - Configured Agent URL
|
|
36
|
+
* @param {...string} paths - EVP path components
|
|
37
|
+
*/
|
|
38
|
+
function joinAgentURLPath (url, ...paths) {
|
|
39
|
+
const prefix = url.protocol === 'http:' || url.protocol === 'https:' ? url.pathname : ''
|
|
40
|
+
return joinEVPProxyPath(prefix, ...paths)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
module.exports = { joinAgentURLPath, joinEVPProxyPath, stripTrailingSlashes }
|
|
@@ -5,6 +5,9 @@ const { format } = require('node:url')
|
|
|
5
5
|
|
|
6
6
|
const { urlToHttpOptions } = require('./url-to-http-options-polyfill')
|
|
7
7
|
|
|
8
|
+
const DEFAULT_SITE = 'datadoghq.com'
|
|
9
|
+
const DNS_LABEL = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/
|
|
10
|
+
|
|
8
11
|
/**
|
|
9
12
|
* @param {string} hostname
|
|
10
13
|
*/
|
|
@@ -31,7 +34,11 @@ function canSendApiKey (protocol, hostname) {
|
|
|
31
34
|
* @returns {URL | undefined}
|
|
32
35
|
*/
|
|
33
36
|
function createSiteUrl (site, intake) {
|
|
34
|
-
const
|
|
37
|
+
const normalizedSite = normalizeSite(site)
|
|
38
|
+
if (normalizedSite === undefined) return
|
|
39
|
+
|
|
40
|
+
const hostname = `${intake === undefined ? '' : `${intake}.`}${normalizedSite}`
|
|
41
|
+
if (hostname.length > 253) return
|
|
35
42
|
|
|
36
43
|
try {
|
|
37
44
|
const url = new URL(format({
|
|
@@ -53,6 +60,30 @@ function createSiteUrl (site, intake) {
|
|
|
53
60
|
} catch {}
|
|
54
61
|
}
|
|
55
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Normalizes a Datadog site as a DNS suffix.
|
|
65
|
+
*
|
|
66
|
+
* @param {string | undefined} site
|
|
67
|
+
* @returns {string | undefined}
|
|
68
|
+
*/
|
|
69
|
+
function normalizeSite (site) {
|
|
70
|
+
if (site === undefined) return DEFAULT_SITE
|
|
71
|
+
if (typeof site !== 'string') return
|
|
72
|
+
for (let index = 0; index < site.length; index++) {
|
|
73
|
+
if (site.charCodeAt(index) > 127) return
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const normalized = site.trim().toLowerCase() || DEFAULT_SITE
|
|
77
|
+
if (normalized.length > 253) return
|
|
78
|
+
|
|
79
|
+
const labels = normalized.split('.')
|
|
80
|
+
for (const label of labels) {
|
|
81
|
+
if (!DNS_LABEL.test(label)) return
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return normalized
|
|
85
|
+
}
|
|
86
|
+
|
|
56
87
|
/**
|
|
57
88
|
* Convert an agent/intake URL into Node http(s) request options.
|
|
58
89
|
*
|
|
@@ -80,4 +111,4 @@ function parseUrl (urlObjOrString) {
|
|
|
80
111
|
return url
|
|
81
112
|
}
|
|
82
113
|
|
|
83
|
-
module.exports = { canSendApiKey, createSiteUrl, isLoopbackHost, parseUrl }
|
|
114
|
+
module.exports = { canSendApiKey, createSiteUrl, isLoopbackHost, normalizeSite, parseUrl }
|
|
@@ -77,6 +77,7 @@ function promptFromData (data, source) {
|
|
|
77
77
|
version: String(version),
|
|
78
78
|
source,
|
|
79
79
|
template: template || data.chat_template || [],
|
|
80
|
+
config: data.config,
|
|
80
81
|
promptUuid: data.prompt_uuid,
|
|
81
82
|
promptVersionUuid: data.prompt_version_uuid || data.id || data.ID,
|
|
82
83
|
})
|
|
@@ -488,6 +489,9 @@ class PromptManager {
|
|
|
488
489
|
if (requireAppKey && !this.config.DD_APP_KEY) {
|
|
489
490
|
throw new PromptAPIError(0, 'DD_APP_KEY is required for prompt write operations', ERROR_NAMES.AUTH)
|
|
490
491
|
}
|
|
492
|
+
if (body?.config !== undefined && !isPlainObject(body.config)) {
|
|
493
|
+
throw new PromptAPIError(0, 'config must be a JSON object', ERROR_NAMES.VALIDATION)
|
|
494
|
+
}
|
|
491
495
|
|
|
492
496
|
const headers = {
|
|
493
497
|
'Content-Type': 'application/json',
|
|
@@ -523,7 +527,8 @@ class PromptManager {
|
|
|
523
527
|
* Create a text or chat prompt and its first version.
|
|
524
528
|
* @param {string} promptId
|
|
525
529
|
* @param {string | Array<{role: string, content: string}>} template
|
|
526
|
-
* @param {{title?: string, description?: string, userVersion?: string, envIds?: string[]
|
|
530
|
+
* @param {{title?: string, description?: string, userVersion?: string, envIds?: string[],
|
|
531
|
+
* config?: Record<string, unknown>}} [options]
|
|
527
532
|
* @returns {Promise<object | object[]>}
|
|
528
533
|
*/
|
|
529
534
|
async createPrompt (promptId, template, options = {}) {
|
|
@@ -532,6 +537,7 @@ class PromptManager {
|
|
|
532
537
|
if (options.description) body.description = options.description
|
|
533
538
|
if (options.userVersion) body.user_version = options.userVersion
|
|
534
539
|
if (options.envIds !== undefined) body.env_ids = options.envIds
|
|
540
|
+
if (options.config !== undefined) body.config = options.config
|
|
535
541
|
const response = await this.#request('POST', PROMPTS_PATH, body, true)
|
|
536
542
|
this.#evictPrompt(promptId)
|
|
537
543
|
return response
|
|
@@ -541,7 +547,8 @@ class PromptManager {
|
|
|
541
547
|
* Add a text or chat version to an existing prompt.
|
|
542
548
|
* @param {string} promptId
|
|
543
549
|
* @param {string | Array<{role: string, content: string}>} template
|
|
544
|
-
* @param {{description?: string, userVersion?: string, envIds?: string[]
|
|
550
|
+
* @param {{description?: string, userVersion?: string, envIds?: string[],
|
|
551
|
+
* config?: Record<string, unknown>}} [options]
|
|
545
552
|
* @returns {Promise<object | object[]>}
|
|
546
553
|
*/
|
|
547
554
|
async createPromptVersion (promptId, template, options = {}) {
|
|
@@ -549,6 +556,7 @@ class PromptManager {
|
|
|
549
556
|
if (options.description) body.description = options.description
|
|
550
557
|
if (options.userVersion) body.user_version = options.userVersion
|
|
551
558
|
if (options.envIds !== undefined) body.env_ids = options.envIds
|
|
559
|
+
if (options.config !== undefined) body.config = options.config
|
|
552
560
|
const path = `${PROMPTS_PATH}/${encodeURIComponent(promptId)}/versions`
|
|
553
561
|
const response = await this.#request('POST', path, body, true)
|
|
554
562
|
this.#evictPrompt(promptId)
|