dd-trace 5.82.0 → 5.83.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 (134) hide show
  1. package/LICENSE-3rdparty.csv +78 -79
  2. package/ci/init.js +6 -6
  3. package/index.d.ts +152 -3
  4. package/loader-hook.mjs +1 -1
  5. package/package.json +58 -55
  6. package/packages/datadog-core/src/storage.js +7 -7
  7. package/packages/datadog-esbuild/index.js +6 -0
  8. package/packages/datadog-instrumentations/src/ai.js +7 -3
  9. package/packages/datadog-instrumentations/src/child_process.js +1 -1
  10. package/packages/datadog-instrumentations/src/cucumber.js +1 -1
  11. package/packages/datadog-instrumentations/src/graphql.js +1 -1
  12. package/packages/datadog-instrumentations/src/helpers/instrumentations.js +4 -3
  13. package/packages/datadog-instrumentations/src/helpers/register.js +3 -7
  14. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +1 -1
  15. package/packages/datadog-instrumentations/src/http/client.js +2 -2
  16. package/packages/datadog-instrumentations/src/jest.js +35 -14
  17. package/packages/datadog-instrumentations/src/koa.js +2 -1
  18. package/packages/datadog-instrumentations/src/light-my-request.js +2 -2
  19. package/packages/datadog-instrumentations/src/mocha/main.js +2 -2
  20. package/packages/datadog-instrumentations/src/mocha/worker.js +1 -1
  21. package/packages/datadog-instrumentations/src/mocha.js +1 -1
  22. package/packages/datadog-instrumentations/src/mysql.js +1 -1
  23. package/packages/datadog-instrumentations/src/mysql2.js +2 -2
  24. package/packages/datadog-instrumentations/src/net.js +13 -5
  25. package/packages/datadog-instrumentations/src/nyc.js +1 -1
  26. package/packages/datadog-instrumentations/src/otel-sdk-trace.js +4 -4
  27. package/packages/datadog-instrumentations/src/pg.js +4 -2
  28. package/packages/datadog-instrumentations/src/playwright.js +3 -3
  29. package/packages/datadog-instrumentations/src/selenium.js +2 -2
  30. package/packages/datadog-instrumentations/src/undici.js +12 -1
  31. package/packages/datadog-plugin-aws-sdk/src/base.js +4 -4
  32. package/packages/datadog-plugin-azure-event-hubs/src/producer.js +2 -2
  33. package/packages/datadog-plugin-azure-service-bus/src/producer.js +2 -2
  34. package/packages/datadog-plugin-cucumber/src/index.js +2 -2
  35. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +2 -2
  36. package/packages/datadog-plugin-dd-trace-api/src/index.js +2 -2
  37. package/packages/datadog-plugin-express/src/code_origin.js +21 -15
  38. package/packages/datadog-plugin-fastify/src/code_origin.js +17 -4
  39. package/packages/datadog-plugin-jest/src/index.js +2 -2
  40. package/packages/datadog-plugin-mocha/src/index.js +2 -2
  41. package/packages/datadog-plugin-mongodb-core/src/index.js +2 -2
  42. package/packages/datadog-plugin-playwright/src/index.js +3 -3
  43. package/packages/datadog-plugin-undici/src/index.js +305 -2
  44. package/packages/datadog-plugin-vitest/src/index.js +5 -5
  45. package/packages/dd-trace/index.js +19 -0
  46. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +1 -1
  47. package/packages/dd-trace/src/appsec/rasp/index.js +2 -4
  48. package/packages/dd-trace/src/azure_metadata.js +8 -3
  49. package/packages/dd-trace/src/baggage.js +36 -11
  50. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +5 -1
  51. package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +2 -2
  52. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +2 -2
  53. package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +2 -2
  54. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +2 -2
  55. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +3 -2
  56. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +3 -3
  57. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +4 -4
  58. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +1 -1
  59. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +2 -2
  60. package/packages/dd-trace/src/ci-visibility/log-submission/log-submission-plugin.js +4 -4
  61. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +4 -4
  62. package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +2 -2
  63. package/packages/dd-trace/src/{config_defaults.js → config/defaults.js} +3 -3
  64. package/packages/dd-trace/src/{config-helper.js → config/helper.js} +88 -15
  65. package/packages/dd-trace/src/{config.js → config/index.js} +92 -45
  66. package/packages/dd-trace/src/config/remote_config.js +187 -19
  67. package/packages/dd-trace/src/{config_stable.js → config/stable.js} +20 -32
  68. package/packages/dd-trace/src/{supported-configurations.json → config/supported-configurations.json} +2 -0
  69. package/packages/dd-trace/src/crashtracking/crashtracker.js +1 -1
  70. package/packages/dd-trace/src/datastreams/processor.js +1 -1
  71. package/packages/dd-trace/src/datastreams/writer.js +1 -1
  72. package/packages/dd-trace/src/debugger/devtools_client/condition.js +1 -1
  73. package/packages/dd-trace/src/debugger/devtools_client/config.js +1 -1
  74. package/packages/dd-trace/src/debugger/devtools_client/send.js +3 -3
  75. package/packages/dd-trace/src/debugger/devtools_client/snapshot/constants.js +1 -1
  76. package/packages/dd-trace/src/debugger/index.js +83 -15
  77. package/packages/dd-trace/src/dogstatsd.js +2 -2
  78. package/packages/dd-trace/src/encode/0.4.js +2 -2
  79. package/packages/dd-trace/src/exporter.js +1 -1
  80. package/packages/dd-trace/src/exporters/agent/index.js +2 -4
  81. package/packages/dd-trace/src/exporters/agent/writer.js +9 -14
  82. package/packages/dd-trace/src/exporters/common/agent-info-exporter.js +1 -1
  83. package/packages/dd-trace/src/exporters/common/docker.js +2 -2
  84. package/packages/dd-trace/src/exporters/common/request.js +1 -1
  85. package/packages/dd-trace/src/exporters/common/util.js +2 -2
  86. package/packages/dd-trace/src/exporters/span-stats/index.js +1 -1
  87. package/packages/dd-trace/src/flare/index.js +1 -1
  88. package/packages/dd-trace/src/guardrails/telemetry.js +1 -1
  89. package/packages/dd-trace/src/index.js +4 -4
  90. package/packages/dd-trace/src/lambda/handler.js +2 -2
  91. package/packages/dd-trace/src/lambda/index.js +2 -2
  92. package/packages/dd-trace/src/lambda/runtime/patch.js +2 -2
  93. package/packages/dd-trace/src/lambda/runtime/ritm.js +2 -2
  94. package/packages/dd-trace/src/llmobs/constants/tags.js +8 -1
  95. package/packages/dd-trace/src/llmobs/index.js +2 -2
  96. package/packages/dd-trace/src/llmobs/noop.js +2 -0
  97. package/packages/dd-trace/src/llmobs/plugins/openai/index.js +3 -4
  98. package/packages/dd-trace/src/llmobs/sdk.js +33 -6
  99. package/packages/dd-trace/src/llmobs/span_processor.js +17 -7
  100. package/packages/dd-trace/src/llmobs/tagger.js +175 -1
  101. package/packages/dd-trace/src/llmobs/writers/base.js +116 -37
  102. package/packages/dd-trace/src/llmobs/writers/spans.js +4 -3
  103. package/packages/dd-trace/src/log/index.js +5 -5
  104. package/packages/dd-trace/src/noop/proxy.js +3 -3
  105. package/packages/dd-trace/src/openfeature/writers/base.js +7 -8
  106. package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +2 -2
  107. package/packages/dd-trace/src/opentelemetry/tracer.js +48 -6
  108. package/packages/dd-trace/src/opentracing/propagation/text_map.js +45 -21
  109. package/packages/dd-trace/src/opentracing/span.js +4 -4
  110. package/packages/dd-trace/src/plugin_manager.js +8 -6
  111. package/packages/dd-trace/src/plugins/util/ci.js +5 -8
  112. package/packages/dd-trace/src/plugins/util/git-cache.js +3 -3
  113. package/packages/dd-trace/src/plugins/util/test.js +1 -1
  114. package/packages/dd-trace/src/plugins/util/user-provided-git.js +41 -43
  115. package/packages/dd-trace/src/profiler.js +4 -39
  116. package/packages/dd-trace/src/profiling/config.js +74 -31
  117. package/packages/dd-trace/src/profiling/exporter_cli.js +5 -5
  118. package/packages/dd-trace/src/profiling/exporters/agent.js +1 -1
  119. package/packages/dd-trace/src/profiling/exporters/event_serializer.js +9 -2
  120. package/packages/dd-trace/src/profiling/index.js +1 -1
  121. package/packages/dd-trace/src/profiling/libuv-size.js +1 -1
  122. package/packages/dd-trace/src/profiling/profiler.js +57 -2
  123. package/packages/dd-trace/src/proxy.js +34 -5
  124. package/packages/dd-trace/src/remote_config/capabilities.js +3 -0
  125. package/packages/dd-trace/src/remote_config/index.js +1 -1
  126. package/packages/dd-trace/src/ritm.js +8 -4
  127. package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +2 -2
  128. package/packages/dd-trace/src/serverless.js +2 -2
  129. package/packages/dd-trace/src/span_processor.js +2 -2
  130. package/packages/dd-trace/src/startup-log.js +6 -15
  131. package/packages/dd-trace/src/telemetry/endpoints.js +67 -5
  132. package/packages/dd-trace/src/telemetry/send-data.js +103 -4
  133. package/packages/dd-trace/src/telemetry/telemetry.js +229 -110
  134. /package/packages/dd-trace/src/{git_properties.js → config/git_properties.js} +0 -0
@@ -1,10 +1,313 @@
1
1
  'use strict'
2
2
 
3
- const FetchPlugin = require('../../datadog-plugin-fetch/src/index.js')
3
+ const HttpClientPlugin = require('../../datadog-plugin-http/src/client')
4
+ const { storage } = require('../../datadog-core')
5
+ const tags = require('../../../ext/tags')
6
+ const formats = require('../../../ext/formats')
7
+ const HTTP_HEADERS = formats.HTTP_HEADERS
8
+ const log = require('../../dd-trace/src/log')
9
+ const { CLIENT_PORT_KEY } = require('../../dd-trace/src/constants')
4
10
 
5
- class UndiciPlugin extends FetchPlugin {
11
+ const {
12
+ HTTP_STATUS_CODE,
13
+ HTTP_REQUEST_HEADERS,
14
+ HTTP_RESPONSE_HEADERS,
15
+ } = tags
16
+
17
+ // WeakMap to store span context for native undici request objects
18
+ const requestContexts = new WeakMap()
19
+
20
+ class UndiciPlugin extends HttpClientPlugin {
6
21
  static id = 'undici'
7
22
  static prefix = 'tracing:apm:undici:fetch'
23
+
24
+ constructor (...args) {
25
+ super(...args)
26
+
27
+ // Subscribe to native undici diagnostic channels for undici >= 4.7.0
28
+ // These channels fire for ALL undici requests (fetch, request, stream, etc.)
29
+ this.addSub('undici:request:create', this.#onNativeRequestCreate.bind(this))
30
+ this.addSub('undici:request:headers', this.#onNativeRequestHeaders.bind(this))
31
+ this.addSub('undici:request:trailers', this.#onNativeRequestTrailers.bind(this))
32
+ this.addSub('undici:request:error', this.#onNativeRequestError.bind(this))
33
+ }
34
+
35
+ // ===========================================
36
+ // Native undici diagnostic channel handlers
37
+ // These fire for undici >= 4.7.0 for ALL request types (fetch, request, stream, etc.)
38
+ // ===========================================
39
+
40
+ #onNativeRequestCreate ({ request }) {
41
+ if (!request) return
42
+
43
+ const store = storage('legacy').getStore()
44
+ const { origin = '', path = '/' } = request
45
+ const method = request.method?.toUpperCase() ?? 'GET'
46
+
47
+ // Parse origin to extract protocol, hostname, port
48
+ let protocol = 'http:'
49
+ let hostname = 'localhost'
50
+ let port = ''
51
+
52
+ try {
53
+ const url = new URL(origin)
54
+ protocol = url.protocol
55
+ hostname = url.hostname
56
+ port = url.port
57
+ } catch {
58
+ // If origin is not a valid URL, use defaults
59
+ }
60
+
61
+ const host = port ? `${hostname}:${port}` : hostname
62
+ const pathname = path.split(/[?#]/)[0]
63
+ const uri = `${protocol}//${host}${pathname}`
64
+
65
+ const allowed = this.config.filter(uri)
66
+ const childOf = store && allowed ? store.span : null
67
+
68
+ const span = this.startSpan(this.operationName(), {
69
+ childOf,
70
+ meta: {
71
+ 'span.kind': 'client',
72
+ 'http.method': method,
73
+ 'http.url': uri,
74
+ 'out.host': hostname
75
+ },
76
+ metrics: {
77
+ [CLIENT_PORT_KEY]: port ? Number.parseInt(port, 10) : undefined
78
+ },
79
+ service: this.serviceName({ pluginConfig: this.config, sessionDetails: { host: hostname, port } }),
80
+ resource: method,
81
+ type: 'http'
82
+ }, false)
83
+
84
+ // Disable recording if not allowed
85
+ if (!allowed) {
86
+ span._spanContext._trace.record = false
87
+ }
88
+
89
+ // Capture request headers if configured
90
+ if (request.headers && this.config.headers) {
91
+ addConfiguredHeaders(span, request.headers, this.config.headers, HTTP_REQUEST_HEADERS)
92
+ }
93
+
94
+ // Inject trace headers if propagation is allowed
95
+ if (this.config.propagationFilter(uri)) {
96
+ const headers = {}
97
+ this.tracer.inject(span, HTTP_HEADERS, headers)
98
+
99
+ // Use addHeader if available (undici provides this on the request object)
100
+ if (typeof request.addHeader === 'function') {
101
+ for (const [name, value] of Object.entries(headers)) {
102
+ request.addHeader(name, value)
103
+ }
104
+ }
105
+ }
106
+
107
+ // Store span context for request for later retrieval
108
+ requestContexts.set(request, {
109
+ span,
110
+ store,
111
+ uri
112
+ })
113
+
114
+ // Enter the span context
115
+ storage('legacy').enterWith({ ...store, span })
116
+ }
117
+
118
+ #onNativeRequestHeaders ({ request, response }) {
119
+ const ctx = requestContexts.get(request)
120
+ if (!ctx) return
121
+
122
+ const { span } = ctx
123
+ const statusCode = response?.statusCode
124
+
125
+ if (statusCode) {
126
+ span.setTag(HTTP_STATUS_CODE, statusCode)
127
+
128
+ if (!this.config.validateStatus(statusCode)) {
129
+ span.setTag('error', 1)
130
+ }
131
+ }
132
+
133
+ // Add response headers if configured
134
+ if (response?.headers && this.config.headers) {
135
+ addConfiguredHeaders(span, response.headers, this.config.headers, HTTP_RESPONSE_HEADERS)
136
+ }
137
+ }
138
+
139
+ #onNativeRequestTrailers ({ request }) {
140
+ const ctx = requestContexts.get(request)
141
+ if (!ctx) return
142
+
143
+ const { span, store } = ctx
144
+
145
+ // Call the request hook if configured
146
+ this.config.hooks.request(span, null, null)
147
+
148
+ // Finish the span
149
+ span.finish()
150
+
151
+ // Clean up
152
+ requestContexts.delete(request)
153
+
154
+ // Restore parent store
155
+ if (store) {
156
+ storage('legacy').enterWith(store)
157
+ }
158
+ }
159
+
160
+ #onNativeRequestError ({ request, error }) {
161
+ const ctx = requestContexts.get(request)
162
+ if (!ctx) return
163
+
164
+ const { span, store } = ctx
165
+
166
+ // Don't record AbortError as an error - it's user-initiated cancellation
167
+ if (error && error.name !== 'AbortError') {
168
+ span.setTag('error', error)
169
+ }
170
+
171
+ // Call the request hook if configured
172
+ this.config.hooks.request(span, null, null)
173
+
174
+ // Finish the span
175
+ span.finish()
176
+
177
+ // Clean up
178
+ requestContexts.delete(request)
179
+
180
+ // Restore parent store
181
+ if (store) {
182
+ storage('legacy').enterWith(store)
183
+ }
184
+ }
185
+
186
+ // ===========================================
187
+ // Fetch-based tracing channel handlers
188
+ // These handle fetch() for undici < 4.7.0 (before native DC was added)
189
+ // ===========================================
190
+
191
+ bindStart (ctx) {
192
+ const req = ctx.req
193
+ const options = new URL(req.url)
194
+ options.headers = Object.fromEntries(req.headers.entries())
195
+ options.method = req.method
196
+
197
+ ctx.args = { options }
198
+
199
+ const store = super.bindStart(ctx)
200
+
201
+ // Inject trace headers back into the request
202
+ for (const name of Object.keys(options.headers)) {
203
+ if (!req.headers.has(name)) {
204
+ req.headers.set(name, options.headers[name])
205
+ }
206
+ }
207
+
208
+ return store
209
+ }
210
+
211
+ error (ctx) {
212
+ // Don't record AbortError as an error - it's user-initiated cancellation
213
+ if (!ctx.error || ctx.error.name !== 'AbortError') {
214
+ return super.error(ctx)
215
+ }
216
+ }
217
+
218
+ asyncEnd (ctx) {
219
+ ctx.res = ctx.result
220
+ return this.finish(ctx)
221
+ }
222
+
223
+ configure (config) {
224
+ return super.configure(normalizeConfig(config))
225
+ }
226
+ }
227
+
228
+ // Add configured headers to span with appropriate tags
229
+ function addConfiguredHeaders (span, rawHeaders, configuredHeaders, headerType) {
230
+ const headers = normalizeHeaders(rawHeaders)
231
+
232
+ for (const [key, tag] of configuredHeaders) {
233
+ const value = headers[key]
234
+ if (value) {
235
+ span.setTag(tag || `${headerType}.${key}`, value)
236
+ }
237
+ }
8
238
  }
9
239
 
240
+ // Normalize headers to an object, handling different undici formats:
241
+ // - Array format: alternating key-value pairs (undici >= 6.0.0)
242
+ // - String format: HTTP header lines like "key: value\r\n" (undici 5.x)
243
+ // - Object format: already a headers object
244
+ function normalizeHeaders (headers) {
245
+ if (!headers) return {}
246
+
247
+ // String format (undici 5.x): "key: value\r\nkey2: value2\r\n"
248
+ if (typeof headers === 'string') {
249
+ const result = {}
250
+ const lines = headers.split('\r\n')
251
+ for (const line of lines) {
252
+ if (!line) continue
253
+ const colonIndex = line.indexOf(':')
254
+ if (colonIndex > 0) {
255
+ const key = line.slice(0, colonIndex).toLowerCase().trim()
256
+ const value = line.slice(colonIndex + 1).trim()
257
+ result[key] = value
258
+ }
259
+ }
260
+ return result
261
+ }
262
+
263
+ // Array format (undici >= 6.0.0): alternating key-value pairs
264
+ if (Array.isArray(headers)) {
265
+ const result = {}
266
+ for (let i = 0; i < headers.length; i += 2) {
267
+ const key = headers[i]
268
+ if (typeof key === 'string') {
269
+ result[key.toLowerCase()] = headers[i + 1]
270
+ } else if (Buffer.isBuffer(key)) {
271
+ result[key.toString().toLowerCase()] = headers[i + 1]?.toString?.() || headers[i + 1]
272
+ }
273
+ }
274
+ return result
275
+ }
276
+
277
+ // Object format: use as-is
278
+ return headers
279
+ }
280
+
281
+ function normalizeConfig (config) {
282
+ const validateStatus = getStatusValidator(config)
283
+ const hooks = getHooks(config)
284
+
285
+ return {
286
+ ...config,
287
+ validateStatus,
288
+ hooks
289
+ }
290
+ }
291
+
292
+ function getStatusValidator (config) {
293
+ if (typeof config.validateStatus === 'function') {
294
+ return config.validateStatus
295
+ } else if (Object.hasOwn(config, 'validateStatus')) {
296
+ log.error('Expected `validateStatus` to be a function.')
297
+ }
298
+ return defaultValidateStatus
299
+ }
300
+
301
+ function defaultValidateStatus (code) {
302
+ return code < 400 || code >= 500
303
+ }
304
+
305
+ function getHooks (config) {
306
+ const request = config.hooks?.request ?? noop
307
+
308
+ return { request }
309
+ }
310
+
311
+ function noop () {}
312
+
10
313
  module.exports = UndiciPlugin
@@ -2,7 +2,7 @@
2
2
 
3
3
  const CiPlugin = require('../../dd-trace/src/plugins/ci_plugin')
4
4
  const { storage } = require('../../datadog-core')
5
- const { getEnvironmentVariable } = require('../../dd-trace/src/config-helper')
5
+ const { getValueFromEnvSources } = require('../../dd-trace/src/config/helper')
6
6
 
7
7
  const {
8
8
  TEST_STATUS,
@@ -281,11 +281,11 @@ class VitestPlugin extends CiPlugin {
281
281
  this.addBind('ci:vitest:test-suite:start', (ctx) => {
282
282
  const { testSuiteAbsolutePath, frameworkVersion } = ctx
283
283
 
284
- this.command = getEnvironmentVariable('DD_CIVISIBILITY_TEST_COMMAND')
284
+ this.command = getValueFromEnvSources('DD_CIVISIBILITY_TEST_COMMAND')
285
285
  this.frameworkVersion = frameworkVersion
286
286
  const testSessionSpanContext = this.tracer.extract('text_map', {
287
- 'x-datadog-trace-id': getEnvironmentVariable('DD_CIVISIBILITY_TEST_SESSION_ID'),
288
- 'x-datadog-parent-id': getEnvironmentVariable('DD_CIVISIBILITY_TEST_MODULE_ID')
287
+ 'x-datadog-trace-id': getValueFromEnvSources('DD_CIVISIBILITY_TEST_SESSION_ID'),
288
+ 'x-datadog-parent-id': getValueFromEnvSources('DD_CIVISIBILITY_TEST_MODULE_ID')
289
289
  })
290
290
 
291
291
  const trimmedCommand = DD_MAJOR < 6 ? this.command : 'vitest run'
@@ -405,7 +405,7 @@ class VitestPlugin extends CiPlugin {
405
405
  finishAllTraceSpans(this.testSessionSpan)
406
406
  this.telemetry.count(TELEMETRY_TEST_SESSION, {
407
407
  provider: this.ciProviderName,
408
- autoInjected: !!getEnvironmentVariable('DD_CIVISIBILITY_AUTO_INSTRUMENTATION_PROVIDER')
408
+ autoInjected: !!getValueFromEnvSources('DD_CIVISIBILITY_AUTO_INSTRUMENTATION_PROVIDER')
409
409
  })
410
410
  this.tracer._exporter.flush(onFinish)
411
411
  })
@@ -10,6 +10,25 @@ if (!global._ddtrace) {
10
10
  writable: true
11
11
  })
12
12
 
13
+ const ddTraceSymbol = Symbol.for('dd-trace')
14
+
15
+ Object.defineProperty(globalThis, ddTraceSymbol, {
16
+ value: {
17
+ beforeExitHandlers: new Set(),
18
+ },
19
+ enumerable: false,
20
+ configurable: true, // Allow this to be overridden by loading the tracer
21
+ writable: false
22
+ })
23
+
24
+ process.once('beforeExit', function mainBeforeExit () {
25
+ if (globalThis[ddTraceSymbol]?.beforeExitHandlers) {
26
+ for (const handler of globalThis[ddTraceSymbol].beforeExitHandlers) {
27
+ handler()
28
+ }
29
+ }
30
+ })
31
+
13
32
  global._ddtrace.default = global._ddtrace
14
33
  global._ddtrace.tracer = global._ddtrace
15
34
  }
@@ -12,7 +12,7 @@ const { getName } = require('../telemetry/verbosity')
12
12
  const telemetry = require('../telemetry')
13
13
  const log = require('../../../log')
14
14
  const orchestrionConfig = require('../../../../../datadog-instrumentations/src/orchestrion-config')
15
- const { getEnvironmentVariable } = require('../../../config-helper')
15
+ const { getEnvironmentVariable } = require('../../../config/helper')
16
16
  const { LOG_MESSAGE, REWRITTEN_MESSAGE } = require('./constants')
17
17
  const { incrementTelemetryIfNeeded } = require('./rewriter-telemetry')
18
18
  const { csiMethods } = require('./csi-methods')
@@ -73,16 +73,14 @@ function handleUncaughtExceptionMonitor (error) {
73
73
  }
74
74
  } else {
75
75
  const cleanUp = removeAllListeners(process, 'uncaughtException')
76
- const handler = () => {
77
- process.removeListener('uncaughtException', handler)
78
- }
76
+ const handler = () => {}
79
77
 
80
78
  setTimeout(() => {
81
79
  process.removeListener('uncaughtException', handler)
82
80
  cleanUp()
83
81
  })
84
82
 
85
- process.on('uncaughtException', handler)
83
+ process.once('uncaughtException', handler)
86
84
  }
87
85
  }
88
86
 
@@ -3,7 +3,11 @@
3
3
  // Modeled after https://github.com/DataDog/libdatadog/blob/f3994857a59bb5679a65967138c5a3aec418a65f/ddcommon/src/azure_app_services.rs
4
4
 
5
5
  const os = require('os')
6
- const { getEnvironmentVariable, getEnvironmentVariables } = require('../../dd-trace/src/config-helper')
6
+ const {
7
+ getEnvironmentVariable,
8
+ getEnvironmentVariables,
9
+ getValueFromEnvSources
10
+ } = require('./config/helper')
7
11
  const { getIsAzureFunction, getIsFlexConsumptionAzureFunction } = require('./serverless')
8
12
 
9
13
  function extractSubscriptionID (ownerName) {
@@ -37,8 +41,6 @@ function trimObject (obj) {
37
41
  function buildMetadata () {
38
42
  const {
39
43
  COMPUTERNAME,
40
- DD_AAS_DOTNET_EXTENSION_VERSION,
41
- DD_AZURE_RESOURCE_GROUP,
42
44
  FUNCTIONS_EXTENSION_VERSION,
43
45
  FUNCTIONS_WORKER_RUNTIME,
44
46
  FUNCTIONS_WORKER_RUNTIME_VERSION,
@@ -49,6 +51,9 @@ function buildMetadata () {
49
51
  WEBSITE_SITE_NAME
50
52
  } = getEnvironmentVariables()
51
53
 
54
+ const DD_AAS_DOTNET_EXTENSION_VERSION = getValueFromEnvSources('DD_AAS_DOTNET_EXTENSION_VERSION')
55
+ const DD_AZURE_RESOURCE_GROUP = getValueFromEnvSources('DD_AZURE_RESOURCE_GROUP')
56
+
52
57
  const subscriptionID = extractSubscriptionID(WEBSITE_OWNER_NAME)
53
58
 
54
59
  const siteName = WEBSITE_SITE_NAME
@@ -1,41 +1,66 @@
1
1
  'use strict'
2
2
 
3
3
  const { storage } = require('../../datadog-core')
4
- const baggageStorage = storage('baggage')
5
4
 
5
+ /**
6
+ * Spec (API semantics):
7
+ * - OpenTelemetry Baggage API: https://opentelemetry.io/docs/specs/otel/baggage/api/
8
+ *
9
+ * In-process baggage is a string->string map stored in async local storage.
10
+ * @typedef {import('../../datadog-core/src/storage').Store<string>} BaggageStore
11
+ */
12
+
13
+ /**
14
+ * @type {{ enterWith: (store?: BaggageStore) => void, getStore: () => (BaggageStore | undefined) }}
15
+ */
16
+ const baggageStorage =
17
+ /** @type {{ enterWith: (store?: BaggageStore) => void, getStore: () => (BaggageStore | undefined) }} */ (
18
+ /** @type {unknown} */ (storage('baggage'))
19
+ )
20
+
21
+ // TODO: Implement metadata https://opentelemetry.io/docs/specs/otel/baggage/api/#set-value
6
22
  /**
7
23
  * @param {string} key
8
24
  * @param {string} value
25
+ * @param {object} [metadata] Not used yet
9
26
  */
10
- function setBaggageItem (key, value) {
11
- storage('baggage').enterWith({ ...baggageStorage.getStore(), [key]: value })
12
- return storage('baggage').getStore()
27
+ function setBaggageItem (key, value, metadata) {
28
+ if (typeof key !== 'string' || typeof value !== 'string' || key === '') {
29
+ return baggageStorage.getStore() ?? {}
30
+ }
31
+
32
+ const store = baggageStorage.getStore()
33
+ const newStore = { ...store, [key]: value }
34
+ baggageStorage.enterWith(newStore)
35
+ return newStore
13
36
  }
14
37
 
15
38
  /**
16
39
  * @param {string} key
40
+ * @returns {string | undefined}
17
41
  */
18
42
  function getBaggageItem (key) {
19
- return storage('baggage').getStore()?.[key]
43
+ return baggageStorage.getStore()?.[key]
20
44
  }
21
45
 
22
46
  function getAllBaggageItems () {
23
- return storage('baggage').getStore() ?? {}
47
+ return baggageStorage.getStore() ?? {}
24
48
  }
25
49
 
26
50
  /**
27
51
  * @param {string} keyToRemove
28
- * @returns {Record<string, unknown>}
29
52
  */
30
53
  function removeBaggageItem (keyToRemove) {
31
- const { [keyToRemove]: _, ...newBaggage } = storage('baggage').getStore()
32
- storage('baggage').enterWith(newBaggage)
54
+ const store = baggageStorage.getStore() ?? {}
55
+ const { [keyToRemove]: _, ...newBaggage } = store
56
+ baggageStorage.enterWith(newBaggage)
33
57
  return newBaggage
34
58
  }
35
59
 
36
60
  function removeAllBaggageItems () {
37
- storage('baggage').enterWith()
38
- return storage('baggage').getStore()
61
+ const newContext = /** @type {BaggageStore} */ ({})
62
+ baggageStorage.enterWith(newContext)
63
+ return newContext
39
64
  }
40
65
 
41
66
  module.exports = {
@@ -4,7 +4,7 @@ const { join } = require('path')
4
4
  const { Worker, threadId: parentThreadId } = require('worker_threads')
5
5
  const { randomUUID } = require('crypto')
6
6
  const log = require('../../log')
7
- const { getEnvironmentVariables } = require('../../config-helper')
7
+ const { getEnvironmentVariables } = require('../../config/helper')
8
8
  const getDebuggerConfig = require('../../debugger/config')
9
9
 
10
10
  const probeIdToResolveBreakpointSet = new Map()
@@ -74,6 +74,10 @@ class TestVisDynamicInstrumentation {
74
74
  // for PnP support, hence why we deviate from the DI pattern here.
75
75
  // To avoid infinite initialization loops, we're disabling DI and tracing in the worker.
76
76
  env: {
77
+ // NOTE: We intentionally use `getEnvironmentVariables()` here (raw env)
78
+ // instead of stable-config resolution helpers. The DI worker is a forked
79
+ // process that should see exactly the parent process's environment, and
80
+ // we explicitly override a few DD_ vars below to disable tracing/DI there.
77
81
  ...getEnvironmentVariables(),
78
82
  DD_CIVISIBILITY_ENABLED: 'false',
79
83
  DD_TRACE_ENABLED: 'false',
@@ -3,7 +3,7 @@
3
3
  const request = require('../../exporters/common/request')
4
4
  const id = require('../../id')
5
5
  const log = require('../../log')
6
- const { getEnvironmentVariable } = require('../../config-helper')
6
+ const { getValueFromEnvSources } = require('../../config/helper')
7
7
 
8
8
  const {
9
9
  incrementCountMetric,
@@ -51,7 +51,7 @@ function getKnownTests ({
51
51
  options.path = `${evpProxyPrefix}/api/v2/ci/libraries/tests`
52
52
  options.headers['X-Datadog-EVP-Subdomain'] = 'api'
53
53
  } else {
54
- const apiKey = getEnvironmentVariable('DD_API_KEY')
54
+ const apiKey = getValueFromEnvSources('DD_API_KEY')
55
55
  if (!apiKey) {
56
56
  return done(new Error('Known tests were not fetched because Datadog API key is not defined.'))
57
57
  }
@@ -2,7 +2,7 @@
2
2
  const request = require('../../../exporters/common/request')
3
3
  const log = require('../../../log')
4
4
  const { safeJSONStringify } = require('../../../exporters/common/util')
5
- const { getEnvironmentVariable } = require('../../../config-helper')
5
+ const { getValueFromEnvSources } = require('../../../config/helper')
6
6
 
7
7
  const { CoverageCIVisibilityEncoder } = require('../../../encode/coverage-ci-visibility')
8
8
  const BaseWriter = require('../../../exporters/common/writer')
@@ -29,7 +29,7 @@ class Writer extends BaseWriter {
29
29
  path: '/api/v2/citestcov',
30
30
  method: 'POST',
31
31
  headers: {
32
- 'dd-api-key': getEnvironmentVariable('DD_API_KEY'),
32
+ 'dd-api-key': getValueFromEnvSources('DD_API_KEY'),
33
33
  ...form.getHeaders()
34
34
  },
35
35
  timeout: 15_000,
@@ -3,7 +3,7 @@ const request = require('../../../exporters/common/request')
3
3
  const log = require('../../../log')
4
4
  const { safeJSONStringify } = require('../../../exporters/common/util')
5
5
  const { JSONEncoder } = require('../../encode/json-encoder')
6
- const { getEnvironmentVariable } = require('../../../config-helper')
6
+ const { getValueFromEnvSources } = require('../../../config/helper')
7
7
 
8
8
  const BaseWriter = require('../../../exporters/common/writer')
9
9
 
@@ -24,7 +24,7 @@ class DynamicInstrumentationLogsWriter extends BaseWriter {
24
24
  path: '/api/v2/logs',
25
25
  method: 'POST',
26
26
  headers: {
27
- 'dd-api-key': getEnvironmentVariable('DD_API_KEY'),
27
+ 'dd-api-key': getValueFromEnvSources('DD_API_KEY'),
28
28
  'Content-Type': 'application/json'
29
29
  },
30
30
  // TODO: what's a good value for timeout for the logs intake?
@@ -2,7 +2,7 @@
2
2
  const request = require('../../../exporters/common/request')
3
3
  const { safeJSONStringify } = require('../../../exporters/common/util')
4
4
  const log = require('../../../log')
5
- const { getEnvironmentVariable } = require('../../../config-helper')
5
+ const { getValueFromEnvSources } = require('../../../config/helper')
6
6
 
7
7
  const { AgentlessCiVisibilityEncoder } = require('../../../encode/agentless-ci-visibility')
8
8
  const BaseWriter = require('../../../exporters/common/writer')
@@ -30,7 +30,7 @@ class Writer extends BaseWriter {
30
30
  path: '/api/v2/citestcycle',
31
31
  method: 'POST',
32
32
  headers: {
33
- 'dd-api-key': getEnvironmentVariable('DD_API_KEY'),
33
+ 'dd-api-key': getValueFromEnvSources('DD_API_KEY'),
34
34
  'Content-Type': 'application/msgpack'
35
35
  },
36
36
  timeout: 15_000,
@@ -68,7 +68,7 @@ class CiVisibilityExporter extends AgentInfoExporter {
68
68
  }
69
69
  })
70
70
 
71
- process.once('beforeExit', () => {
71
+ const flush = () => {
72
72
  if (this._writer) {
73
73
  this._writer.flush()
74
74
  }
@@ -78,7 +78,8 @@ class CiVisibilityExporter extends AgentInfoExporter {
78
78
  if (this._logsWriter) {
79
79
  this._logsWriter.flush()
80
80
  }
81
- })
81
+ }
82
+ globalThis[Symbol.for('dd-trace')].beforeExitHandlers.add(flush.bind(this))
82
83
  }
83
84
 
84
85
  shouldRequestSkippableSuites () {
@@ -5,7 +5,7 @@ const path = require('path')
5
5
 
6
6
  const FormData = require('../../../exporters/common/form-data')
7
7
  const request = require('../../../exporters/common/request')
8
- const { getEnvironmentVariable } = require('../../../config-helper')
8
+ const { getValueFromEnvSources } = require('../../../config/helper')
9
9
 
10
10
  const log = require('../../../log')
11
11
  const { isFalse } = require('../../../util')
@@ -51,7 +51,7 @@ function getCommonRequestOptions (url) {
51
51
  return {
52
52
  method: 'POST',
53
53
  headers: {
54
- 'dd-api-key': getEnvironmentVariable('DD_API_KEY')
54
+ 'dd-api-key': getValueFromEnvSources('DD_API_KEY')
55
55
  },
56
56
  timeout: 15_000,
57
57
  url
@@ -288,7 +288,7 @@ function sendGitMetadata (url, { isEvpProxy, evpProxyPrefix }, configRepositoryU
288
288
  }
289
289
  // Otherwise we unshallow and get commits to upload again
290
290
  log.debug('It is shallow clone, unshallowing...')
291
- if (!isFalse(getEnvironmentVariable('DD_CIVISIBILITY_GIT_UNSHALLOW_ENABLED'))) {
291
+ if (!isFalse(getValueFromEnvSources('DD_CIVISIBILITY_GIT_UNSHALLOW_ENABLED'))) {
292
292
  unshallowRepository(false)
293
293
  }
294
294