dd-trace 5.109.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.
Files changed (128) hide show
  1. package/ci/init.js +4 -3
  2. package/index.d.ts +66 -24
  3. package/loader-hook.mjs +88 -2
  4. package/package.json +18 -14
  5. package/packages/datadog-esbuild/index.js +26 -0
  6. package/packages/datadog-esbuild/src/utils.js +46 -3
  7. package/packages/datadog-instrumentations/src/connect.js +4 -3
  8. package/packages/datadog-instrumentations/src/fastify.js +4 -12
  9. package/packages/datadog-instrumentations/src/graphql.js +17 -6
  10. package/packages/datadog-instrumentations/src/helpers/check-require-cache.js +81 -8
  11. package/packages/datadog-instrumentations/src/helpers/instrument.js +27 -2
  12. package/packages/datadog-instrumentations/src/helpers/optional-peer-bundler.js +65 -0
  13. package/packages/datadog-instrumentations/src/helpers/register.js +6 -4
  14. package/packages/datadog-instrumentations/src/helpers/require-optional-peer.js +17 -0
  15. package/packages/datadog-instrumentations/src/helpers/rewriter/loader.mjs +18 -2
  16. package/packages/datadog-instrumentations/src/koa.js +3 -2
  17. package/packages/datadog-instrumentations/src/mariadb.js +4 -2
  18. package/packages/datadog-instrumentations/src/mocha/main.js +3 -3
  19. package/packages/datadog-instrumentations/src/next.js +10 -10
  20. package/packages/datadog-instrumentations/src/otel-sdk-trace.js +7 -6
  21. package/packages/datadog-instrumentations/src/playwright.js +1 -1
  22. package/packages/datadog-instrumentations/src/restify.js +4 -3
  23. package/packages/datadog-instrumentations/src/router.js +18 -5
  24. package/packages/datadog-instrumentations/src/selenium.js +1 -2
  25. package/packages/datadog-instrumentations/src/tedious.js +28 -0
  26. package/packages/datadog-instrumentations/src/vitest.js +264 -7
  27. package/packages/datadog-plugin-avsc/src/schema_iterator.js +2 -2
  28. package/packages/datadog-plugin-aws-sdk/src/base.js +13 -9
  29. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +43 -6
  30. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +83 -91
  31. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +9 -1
  32. package/packages/datadog-plugin-http/src/client.js +8 -3
  33. package/packages/datadog-plugin-http2/src/client.js +5 -2
  34. package/packages/datadog-plugin-mysql/src/index.js +7 -2
  35. package/packages/datadog-plugin-protobufjs/src/schema_iterator.js +2 -2
  36. package/packages/datadog-plugin-undici/src/index.js +5 -2
  37. package/packages/datadog-plugin-vitest/src/index.js +7 -1
  38. package/packages/datadog-webpack/index.js +17 -1
  39. package/packages/datadog-webpack/src/optional-peer-loader.js +17 -0
  40. package/packages/dd-trace/src/aiguard/sdk.js +13 -1
  41. package/packages/dd-trace/src/appsec/api_security/index.js +55 -0
  42. package/packages/dd-trace/src/appsec/api_security/sampler.js +147 -0
  43. package/packages/dd-trace/src/appsec/index.js +10 -6
  44. package/packages/dd-trace/src/appsec/reporter.js +1 -0
  45. package/packages/dd-trace/src/appsec/telemetry/api_security.js +34 -0
  46. package/packages/dd-trace/src/appsec/telemetry/index.js +26 -0
  47. package/packages/dd-trace/src/ci-visibility/requests/request.js +1 -17
  48. package/packages/dd-trace/src/config/defaults.js +22 -3
  49. package/packages/dd-trace/src/config/generated-config-types.d.ts +535 -1
  50. package/packages/dd-trace/src/config/helper.js +133 -33
  51. package/packages/dd-trace/src/config/index.js +4 -1
  52. package/packages/dd-trace/src/config/parsers.js +19 -1
  53. package/packages/dd-trace/src/config/supported-configurations.json +21 -3
  54. package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +47 -35
  55. package/packages/dd-trace/src/debugger/devtools_client/index.js +31 -66
  56. package/packages/dd-trace/src/debugger/devtools_client/probe_sampler.js +83 -0
  57. package/packages/dd-trace/src/debugger/devtools_client/state.js +1 -0
  58. package/packages/dd-trace/src/debugger/index.js +5 -0
  59. package/packages/dd-trace/src/debugger/probe_sampler.js +112 -0
  60. package/packages/dd-trace/src/debugger/probe_sampler_constants.js +19 -0
  61. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +77 -26
  62. package/packages/dd-trace/src/exporters/common/request.js +1 -20
  63. package/packages/dd-trace/src/exporters/common/url.js +34 -0
  64. package/packages/dd-trace/src/exporters/span-stats/writer.js +1 -3
  65. package/packages/dd-trace/src/guardrails/index.js +8 -5
  66. package/packages/dd-trace/src/index.js +6 -4
  67. package/packages/dd-trace/src/llmobs/constants/tags.js +6 -0
  68. package/packages/dd-trace/src/llmobs/index.js +16 -5
  69. package/packages/dd-trace/src/llmobs/plugins/genai/util.js +3 -3
  70. package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +5 -1
  71. package/packages/dd-trace/src/llmobs/sdk.js +5 -3
  72. package/packages/dd-trace/src/llmobs/span_processor.js +4 -0
  73. package/packages/dd-trace/src/llmobs/tagger.js +55 -0
  74. package/packages/dd-trace/src/llmobs/telemetry.js +1 -0
  75. package/packages/dd-trace/src/log/index.js +18 -20
  76. package/packages/dd-trace/src/openfeature/flagging_provider.js +2 -7
  77. package/packages/dd-trace/src/opentelemetry/bridge-span-base.js +5 -4
  78. package/packages/dd-trace/src/opentelemetry/metrics/instruments.js +2 -1
  79. package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +4 -3
  80. package/packages/dd-trace/src/opentelemetry/metrics/time.js +19 -0
  81. package/packages/dd-trace/src/opentelemetry/otlp/common.proto +2 -2
  82. package/packages/dd-trace/src/opentelemetry/otlp/logs.proto +1 -1
  83. package/packages/dd-trace/src/opentelemetry/otlp/logs_service.proto +1 -1
  84. package/packages/dd-trace/src/opentelemetry/otlp/metrics.proto +1 -1
  85. package/packages/dd-trace/src/opentelemetry/otlp/metrics_service.proto +1 -1
  86. package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +11 -4
  87. package/packages/dd-trace/src/opentelemetry/span-helpers.js +29 -13
  88. package/packages/dd-trace/src/opentelemetry/span.js +14 -3
  89. package/packages/dd-trace/src/opentelemetry/span_context.js +1 -0
  90. package/packages/dd-trace/src/opentelemetry/trace/index.js +2 -1
  91. package/packages/dd-trace/src/opentelemetry/trace/otlp_http_trace_exporter.js +3 -2
  92. package/packages/dd-trace/src/opentelemetry/trace/otlp_transformer.js +26 -13
  93. package/packages/dd-trace/src/opentracing/propagation/text_map.js +3 -3
  94. package/packages/dd-trace/src/opentracing/span_context.js +17 -0
  95. package/packages/dd-trace/src/plugin_manager.js +7 -1
  96. package/packages/dd-trace/src/plugins/ci_plugin.js +9 -1
  97. package/packages/dd-trace/src/plugins/util/http-otel-semantics.js +276 -0
  98. package/packages/dd-trace/src/plugins/util/test.js +80 -0
  99. package/packages/dd-trace/src/plugins/util/url.js +68 -1
  100. package/packages/dd-trace/src/plugins/util/web.js +19 -36
  101. package/packages/dd-trace/src/priority_sampler.js +1 -13
  102. package/packages/dd-trace/src/profiling/config.js +129 -198
  103. package/packages/dd-trace/src/profiling/constants.js +4 -7
  104. package/packages/dd-trace/src/profiling/exporter_cli.js +10 -10
  105. package/packages/dd-trace/src/profiling/exporters/agent.js +23 -16
  106. package/packages/dd-trace/src/profiling/exporters/event_serializer.js +45 -14
  107. package/packages/dd-trace/src/profiling/exporters/file.js +16 -5
  108. package/packages/dd-trace/src/profiling/oom.js +71 -0
  109. package/packages/dd-trace/src/profiling/profiler.js +35 -23
  110. package/packages/dd-trace/src/profiling/profilers/events.js +14 -7
  111. package/packages/dd-trace/src/profiling/profilers/space.js +27 -18
  112. package/packages/dd-trace/src/profiling/profilers/wall.js +35 -25
  113. package/packages/dd-trace/src/ritm.js +4 -2
  114. package/packages/dd-trace/src/serverless.js +1 -2
  115. package/packages/dd-trace/src/service-naming/schemas/util.js +36 -5
  116. package/packages/dd-trace/src/service-naming/schemas/v1/web.js +5 -3
  117. package/packages/dd-trace/src/span_format.js +2 -1
  118. package/packages/dd-trace/src/span_processor.js +6 -0
  119. package/packages/dd-trace/src/telemetry/send-data.js +12 -10
  120. package/packages/dd-trace/src/tracer.js +15 -1
  121. package/packages/dd-trace/src/util.js +14 -0
  122. package/register.js +58 -1
  123. package/vendor/dist/@apm-js-collab/code-transformer/index.js +1 -1
  124. package/vendor/dist/@datadog/sketches-js/index.js +1 -1
  125. package/vendor/dist/pprof-format/index.js +1 -1
  126. package/vendor/dist/protobufjs/index.js +1 -1
  127. package/vendor/dist/protobufjs/minimal/index.js +1 -1
  128. package/packages/dd-trace/src/appsec/api_security_sampler.js +0 -117
@@ -0,0 +1,147 @@
1
+ 'use strict'
2
+
3
+ const { TTLCache } = require('../../../../../vendor/dist/@isaacs/ttlcache')
4
+ const web = require('../../plugins/util/web')
5
+ const log = require('../../log')
6
+ const { AUTO_REJECT, USER_REJECT } = require('../../../../../ext/priority')
7
+ const { keepTrace } = require('../../priority_sampler')
8
+ const { ASM } = require('../../standalone/product')
9
+ const { isBlocked } = require('../blocking')
10
+
11
+ const MAX_SIZE = 4096
12
+
13
+ const SamplingDecision = Object.freeze({
14
+ SAMPLE: 'sample',
15
+ MISSING_ROUTE: 'missing_route',
16
+ SKIP: 'skip',
17
+ })
18
+
19
+ let enabled
20
+ let asmStandaloneEnabled
21
+
22
+ /**
23
+ * @type {TTLCache}
24
+ */
25
+ let sampledRequests
26
+
27
+ class NoopTTLCache {
28
+ clear () {}
29
+ set (_key, _value) {}
30
+ has (_key) { return false }
31
+ }
32
+
33
+ function configure ({ appsec, apmTracingEnabled }) {
34
+ enabled = appsec.apiSecurity.enabled
35
+ asmStandaloneEnabled = apmTracingEnabled === false
36
+ sampledRequests = appsec.apiSecurity.sampleDelay === 0
37
+ ? new NoopTTLCache()
38
+ : new TTLCache({ max: MAX_SIZE, ttl: appsec.apiSecurity.sampleDelay * 1000 })
39
+ }
40
+
41
+ function disable () {
42
+ enabled = false
43
+ sampledRequests?.clear()
44
+ }
45
+
46
+ /**
47
+ * @param {import('http').IncomingMessage} req
48
+ * @param {import('http').ServerResponse} res
49
+ * @param {boolean} record When true and the decision is SAMPLE, records the endpoint in the TTL cache
50
+ * @returns {'sample' | 'missing_route' | 'skip'}
51
+ */
52
+ function sampleRequest (req, res, record = false) {
53
+ if (!enabled) return SamplingDecision.SKIP
54
+
55
+ const rootSpan = web.root(req)
56
+ if (!rootSpan) return SamplingDecision.SKIP
57
+
58
+ if (!asmStandaloneEnabled) {
59
+ let priority = getSpanPriority(rootSpan)
60
+ if (!priority) {
61
+ rootSpan._prioritySampler?.sample(rootSpan)
62
+ priority = getSpanPriority(rootSpan)
63
+ }
64
+
65
+ if (priority === AUTO_REJECT || priority === USER_REJECT) {
66
+ return SamplingDecision.SKIP
67
+ }
68
+ }
69
+
70
+ const resolved = resolveSamplingKey(req, res)
71
+ if (!resolved) return SamplingDecision.SKIP
72
+
73
+ if (record && resolved.route === null) {
74
+ if (resolved.status === 404 || isBlocked(res)) return SamplingDecision.SKIP
75
+ return SamplingDecision.MISSING_ROUTE
76
+ }
77
+
78
+ if (sampledRequests.has(resolved.key)) return SamplingDecision.SKIP
79
+
80
+ if (asmStandaloneEnabled) {
81
+ keepTrace(rootSpan, ASM)
82
+ }
83
+
84
+ if (record) {
85
+ sampledRequests.set(resolved.key, undefined)
86
+ }
87
+
88
+ return SamplingDecision.SAMPLE
89
+ }
90
+
91
+ /**
92
+ * @param {import('http').IncomingMessage} req
93
+ * @param {import('http').ServerResponse} res
94
+ * @returns {boolean} Whether this request's endpoint is currently recorded in the TTL cache.
95
+ */
96
+ function wasSampled (req, res) {
97
+ const resolved = resolveSamplingKey(req, res)
98
+ return resolved !== null && sampledRequests.has(resolved.key)
99
+ }
100
+
101
+ function resolveSamplingKey (req, res) {
102
+ const method = req.method
103
+ const status = res.statusCode
104
+
105
+ if (!method || !status) {
106
+ log.warn('[ASM] Unsupported groupkey for API security')
107
+ return null
108
+ }
109
+
110
+ const context = web.getContext(req)
111
+ const route = getRouteOrEndpoint(context, status)
112
+
113
+ // route === null signals "no route information at all". An empty string is still a valid
114
+ // route (dd-trace-js represents the express root path '/' as an empty path segment).
115
+ return { method, status, route, key: method + (route ?? '') + status }
116
+ }
117
+
118
+ function getRouteOrEndpoint (context, statusCode) {
119
+ // The router plugin populates `context.paths` whenever the framework matched something.
120
+ // For express's root '/' route the matched path is normalized to '' (see datadog-plugin-router),
121
+ // so `paths.length > 0` is the signal that the framework provided route information — even when
122
+ // the joined string is empty. An empty `paths` array means no router involvement at all.
123
+ const paths = context?.paths
124
+ if (paths !== undefined && paths.length > 0) {
125
+ return paths.join('')
126
+ }
127
+
128
+ if (statusCode === 404) return null
129
+
130
+ const endpoint = context?.span?.context()?.getTag?.('http.endpoint')
131
+ if (endpoint) return endpoint
132
+
133
+ return null
134
+ }
135
+
136
+ function getSpanPriority (span) {
137
+ const spanContext = span.context?.()
138
+ return spanContext._sampling?.priority
139
+ }
140
+
141
+ module.exports = {
142
+ configure,
143
+ disable,
144
+ sampleRequest,
145
+ wasSampled,
146
+ SamplingDecision,
147
+ }
@@ -38,7 +38,7 @@ const waf = require('./waf')
38
38
  const addresses = require('./addresses')
39
39
  const Reporter = require('./reporter')
40
40
  const appsecTelemetry = require('./telemetry')
41
- const apiSecuritySampler = require('./api_security_sampler')
41
+ const apiSecurity = require('./api_security')
42
42
  const { isBlocked, block, callBlockDelegation, setTemplates, getBlockingAction } = require('./blocking')
43
43
  const { getActiveRequest } = require('./store')
44
44
  const UserTracking = require('./user_tracking')
@@ -71,7 +71,7 @@ function enable (_config) {
71
71
 
72
72
  Reporter.init(_config.appsec, _config.inferredProxyServicesEnabled)
73
73
 
74
- apiSecuritySampler.configure(_config)
74
+ apiSecurity.configure(_config)
75
75
 
76
76
  UserTracking.setCollectionMode(_config.appsec.eventTracking.mode, false)
77
77
 
@@ -233,14 +233,18 @@ function incomingHttpEndTranslator ({ req, res }) {
233
233
  // This hook runs before span finish, so ensure route/endpoint tags are available before API Security sampling runs.
234
234
  web.setRouteOrEndpointTag(req)
235
235
 
236
- if (apiSecuritySampler.sampleRequest(req, res, true)) {
236
+ const apiSecSamplingDecision = apiSecurity.sampleRequest(req, res, true)
237
+ if (apiSecSamplingDecision === apiSecurity.SamplingDecision.SAMPLE) {
237
238
  persistent[addresses.WAF_CONTEXT_PROCESSOR] = { 'extract-schema': true }
238
239
  }
239
240
 
241
+ let wafResult
240
242
  if (!isEmpty(persistent)) {
241
- waf.run({ persistent }, req)
243
+ wafResult = waf.run({ persistent }, req)
242
244
  }
243
245
 
246
+ apiSecurity.reportRequest(req, apiSecSamplingDecision, wafResult)
247
+
244
248
  waf.disposeContext(req)
245
249
 
246
250
  const storedHeaders = storedResponseHeaders.get(req) || {}
@@ -339,7 +343,7 @@ function onRequestProcessParams ({ req, res, abortController, params }) {
339
343
 
340
344
  function onResponseBody ({ req, res, body }) {
341
345
  if (!body || typeof body !== 'object') return
342
- if (!apiSecuritySampler.sampleRequest(req, res)) return
346
+ if (apiSecurity.sampleRequest(req, res) !== apiSecurity.SamplingDecision.SAMPLE) return
343
347
 
344
348
  // we don't support blocking at this point, so no results needed
345
349
  waf.run({
@@ -513,7 +517,7 @@ function disable () {
513
517
 
514
518
  appsecRemoteConfig.disableWafUpdate()
515
519
 
516
- apiSecuritySampler.disable()
520
+ apiSecurity.disable()
517
521
 
518
522
  // Channel#unsubscribe() is undefined for non active channels
519
523
  if (bodyParser.hasSubscribers) bodyParser.unsubscribe(onRequestBodyParsed)
@@ -615,4 +615,5 @@ module.exports = {
615
615
  finishRequest,
616
616
  mapHeaderAndTags,
617
617
  truncateRequestBody,
618
+ isSchemaAttribute,
618
619
  }
@@ -0,0 +1,34 @@
1
+ 'use strict'
2
+
3
+ const telemetryMetrics = require('../../telemetry/metrics')
4
+
5
+ const appsecMetrics = telemetryMetrics.manager.namespace('appsec')
6
+
7
+ const normalizedFrameworkCache = new Map()
8
+
9
+ function normalizeFramework (framework) {
10
+ let normalized = normalizedFrameworkCache.get(framework)
11
+ if (normalized === undefined) {
12
+ normalized = framework ? framework.toLowerCase().replaceAll(' ', '_') : 'unknown'
13
+ normalizedFrameworkCache.set(framework, normalized)
14
+ }
15
+ return normalized
16
+ }
17
+
18
+ function incrementApiSecRequestSchema (framework) {
19
+ appsecMetrics.count('api_security.request.schema', { framework: normalizeFramework(framework) }).inc()
20
+ }
21
+
22
+ function incrementApiSecRequestNoSchema (framework) {
23
+ appsecMetrics.count('api_security.request.no_schema', { framework: normalizeFramework(framework) }).inc()
24
+ }
25
+
26
+ function incrementApiSecMissingRoute (framework) {
27
+ appsecMetrics.count('api_security.missing_route', { framework: normalizeFramework(framework) }).inc()
28
+ }
29
+
30
+ module.exports = {
31
+ incrementApiSecRequestSchema,
32
+ incrementApiSecRequestNoSchema,
33
+ incrementApiSecMissingRoute,
34
+ }
@@ -1,5 +1,10 @@
1
1
  'use strict'
2
2
 
3
+ const {
4
+ incrementApiSecMissingRoute,
5
+ incrementApiSecRequestNoSchema,
6
+ incrementApiSecRequestSchema,
7
+ } = require('./api_security')
3
8
  const { DD_TELEMETRY_REQUEST_METRICS } = require('./common')
4
9
  const { incrementMissingUserId, incrementMissingUserLogin, incrementSdkEvent } = require('./user')
5
10
  const {
@@ -155,6 +160,24 @@ function incrementSdkEventMetric (eventType, sdkVersion) {
155
160
  incrementSdkEvent(eventType, sdkVersion)
156
161
  }
157
162
 
163
+ function incrementApiSecRequestSchemaMetric (framework) {
164
+ if (!enabled) return
165
+
166
+ incrementApiSecRequestSchema(framework)
167
+ }
168
+
169
+ function incrementApiSecRequestNoSchemaMetric (framework) {
170
+ if (!enabled) return
171
+
172
+ incrementApiSecRequestNoSchema(framework)
173
+ }
174
+
175
+ function incrementApiSecMissingRouteMetric (framework) {
176
+ if (!enabled) return
177
+
178
+ incrementApiSecMissingRoute(framework)
179
+ }
180
+
158
181
  function getRequestMetrics (req) {
159
182
  if (req) {
160
183
  const store = getStore(req)
@@ -179,6 +202,9 @@ module.exports = {
179
202
  incrementMissingUserLoginMetric,
180
203
  incrementMissingUserIdMetric,
181
204
  incrementSdkEventMetric,
205
+ incrementApiSecRequestSchemaMetric,
206
+ incrementApiSecRequestNoSchemaMetric,
207
+ incrementApiSecMissingRouteMetric,
182
208
 
183
209
  getRequestMetrics,
184
210
  }
@@ -12,26 +12,10 @@ const {
12
12
  isRetriableNetworkError,
13
13
  singleJitteredDelay,
14
14
  } = require('../../exporters/common/retry')
15
- const { urlToHttpOptions } = require('../../exporters/common/url-to-http-options-polyfill')
15
+ const { parseUrl } = require('../../exporters/common/url')
16
16
 
17
17
  const legacyStorage = storage('legacy')
18
18
 
19
- function parseUrl (urlObjOrString) {
20
- if (urlObjOrString !== null && typeof urlObjOrString === 'object') {
21
- return urlToHttpOptions(urlObjOrString)
22
- }
23
-
24
- const url = urlToHttpOptions(new URL(urlObjOrString))
25
-
26
- if (url.protocol === 'unix:' && url.hostname === '.') {
27
- const udsPath = urlObjOrString.slice(5)
28
- url.path = udsPath
29
- url.pathname = udsPath
30
- }
31
-
32
- return url
33
- }
34
-
35
19
  /**
36
20
  * Simplified HTTP request for test optimization (library config). Uses common HTTP agents.
37
21
  * Retries: 429 (with X-ratelimit-reset, max 30s wait),
@@ -1,6 +1,5 @@
1
1
  'use strict'
2
2
 
3
- const dns = require('dns')
4
3
  const util = require('util')
5
4
 
6
5
  const { DD_MAJOR } = require('../../../../version')
@@ -51,7 +50,6 @@ const defaults = {
51
50
  isServiceUserProvided: false,
52
51
  plugins: true,
53
52
  isCiVisibility: false,
54
- lookup: dns.lookup,
55
53
  logger: undefined,
56
54
  }
57
55
 
@@ -218,6 +216,14 @@ for (const [canonicalName, entries] of Object.entries(supportedConfigurations))
218
216
  )
219
217
  }
220
218
  for (const entry of entries) {
219
+ // A deprecated entry that only aliases a canonical option must not surface as
220
+ // its own Config property/default: the canonical entry already owns the value
221
+ // and the alias is resolved by helper.js. helper.js drops these from the shared
222
+ // supported-configurations object (after registering the deprecation), but that
223
+ // mutation is order-dependent on which module loads first. Skip here too so
224
+ // `defaults` is identical regardless of load order (it differed in v5, where
225
+ // major-overrides keeps these entries instead of deleting them outright).
226
+ if (entry.deprecated && entry.aliases) continue
221
227
  if (entry.sensitive) {
222
228
  sensitiveConfigurations.add(canonicalName)
223
229
  }
@@ -285,7 +291,7 @@ for (const [canonicalName, entries] of Object.entries(supportedConfigurations))
285
291
 
286
292
  // Replace the alias with the canonical property name.
287
293
  for (const [fullPropertyName, alias] of fallbackConfigurations) {
288
- if (configurationsTable[alias].property) {
294
+ if (configurationsTable[alias]?.property) {
289
295
  fallbackConfigurations.set(fullPropertyName, configurationsTable[alias].property)
290
296
  }
291
297
  }
@@ -347,3 +353,16 @@ module.exports = {
347
353
 
348
354
  generateTelemetry,
349
355
  }
356
+
357
+ // `dns` is instrumented, so requiring it pulls in the dns plugin, which loads
358
+ // `log`, whose bootstrap calls back into `require('./defaults')`. Resolve the
359
+ // `lookup` default last — after the exports above are fully built — so that the
360
+ // re-entrant require during that cascade sees the complete module instead of a
361
+ // half-initialized one.
362
+ defaults.lookup = require('dns').lookup
363
+ configWithOrigin.set('lookupdefault', {
364
+ name: 'lookup',
365
+ value: defaults.lookup,
366
+ origin: 'default',
367
+ seq_id: seqId++,
368
+ })