dd-trace 5.82.0 → 5.84.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 (150) hide show
  1. package/LICENSE-3rdparty.csv +77 -79
  2. package/ci/init.js +6 -6
  3. package/index.d.ts +213 -4
  4. package/loader-hook.mjs +1 -1
  5. package/package.json +59 -56
  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/compiler.js +6 -0
  15. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +2 -1
  16. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +73 -16
  17. package/packages/datadog-instrumentations/src/http/client.js +2 -2
  18. package/packages/datadog-instrumentations/src/jest.js +124 -64
  19. package/packages/datadog-instrumentations/src/koa.js +2 -1
  20. package/packages/datadog-instrumentations/src/light-my-request.js +2 -2
  21. package/packages/datadog-instrumentations/src/mocha/main.js +2 -2
  22. package/packages/datadog-instrumentations/src/mocha/worker.js +1 -1
  23. package/packages/datadog-instrumentations/src/mocha.js +1 -1
  24. package/packages/datadog-instrumentations/src/mysql.js +1 -1
  25. package/packages/datadog-instrumentations/src/mysql2.js +2 -2
  26. package/packages/datadog-instrumentations/src/net.js +13 -5
  27. package/packages/datadog-instrumentations/src/nyc.js +1 -1
  28. package/packages/datadog-instrumentations/src/otel-sdk-trace.js +4 -4
  29. package/packages/datadog-instrumentations/src/pg.js +4 -2
  30. package/packages/datadog-instrumentations/src/playwright.js +15 -11
  31. package/packages/datadog-instrumentations/src/selenium.js +2 -2
  32. package/packages/datadog-instrumentations/src/undici.js +12 -1
  33. package/packages/datadog-plugin-aws-sdk/src/base.js +4 -4
  34. package/packages/datadog-plugin-azure-event-hubs/src/producer.js +2 -2
  35. package/packages/datadog-plugin-azure-service-bus/src/producer.js +2 -2
  36. package/packages/datadog-plugin-cucumber/src/index.js +35 -34
  37. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +2 -2
  38. package/packages/datadog-plugin-dd-trace-api/src/index.js +2 -2
  39. package/packages/datadog-plugin-express/src/code_origin.js +21 -15
  40. package/packages/datadog-plugin-fastify/src/code_origin.js +17 -4
  41. package/packages/datadog-plugin-jest/src/index.js +2 -2
  42. package/packages/datadog-plugin-mocha/src/index.js +2 -2
  43. package/packages/datadog-plugin-mongodb-core/src/index.js +2 -2
  44. package/packages/datadog-plugin-playwright/src/index.js +26 -26
  45. package/packages/datadog-plugin-undici/src/index.js +305 -2
  46. package/packages/datadog-plugin-vitest/src/index.js +5 -5
  47. package/packages/datadog-shimmer/src/shimmer.js +2 -5
  48. package/packages/dd-trace/index.js +19 -0
  49. package/packages/dd-trace/src/agent/info.js +57 -0
  50. package/packages/dd-trace/src/agent/url.js +28 -0
  51. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +1 -1
  52. package/packages/dd-trace/src/appsec/index.js +47 -7
  53. package/packages/dd-trace/src/appsec/rasp/index.js +2 -4
  54. package/packages/dd-trace/src/azure_metadata.js +8 -3
  55. package/packages/dd-trace/src/baggage.js +36 -11
  56. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +5 -1
  57. package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +2 -2
  58. package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +3 -4
  59. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +2 -2
  60. package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +5 -5
  61. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +2 -2
  62. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +5 -11
  63. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +3 -3
  64. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +4 -4
  65. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +1 -1
  66. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +2 -2
  67. package/packages/dd-trace/src/ci-visibility/log-submission/log-submission-plugin.js +4 -4
  68. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +4 -4
  69. package/packages/dd-trace/src/ci-visibility/telemetry.js +6 -2
  70. package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +2 -2
  71. package/packages/dd-trace/src/{config_defaults.js → config/defaults.js} +3 -3
  72. package/packages/dd-trace/src/{config-helper.js → config/helper.js} +88 -15
  73. package/packages/dd-trace/src/{config.js → config/index.js} +107 -46
  74. package/packages/dd-trace/src/config/remote_config.js +188 -19
  75. package/packages/dd-trace/src/{config_stable.js → config/stable.js} +20 -32
  76. package/packages/dd-trace/src/{supported-configurations.json → config/supported-configurations.json} +3 -1
  77. package/packages/dd-trace/src/crashtracking/crashtracker.js +2 -5
  78. package/packages/dd-trace/src/datastreams/processor.js +1 -1
  79. package/packages/dd-trace/src/datastreams/writer.js +2 -8
  80. package/packages/dd-trace/src/debugger/devtools_client/condition.js +1 -1
  81. package/packages/dd-trace/src/debugger/devtools_client/config.js +2 -7
  82. package/packages/dd-trace/src/debugger/devtools_client/json-buffer.js +10 -11
  83. package/packages/dd-trace/src/debugger/devtools_client/send.js +3 -3
  84. package/packages/dd-trace/src/debugger/devtools_client/snapshot/constants.js +1 -1
  85. package/packages/dd-trace/src/debugger/index.js +83 -15
  86. package/packages/dd-trace/src/dogstatsd.js +5 -11
  87. package/packages/dd-trace/src/encode/0.4.js +2 -2
  88. package/packages/dd-trace/src/exporter.js +1 -1
  89. package/packages/dd-trace/src/exporters/agent/index.js +5 -11
  90. package/packages/dd-trace/src/exporters/agent/writer.js +12 -16
  91. package/packages/dd-trace/src/exporters/common/{agent-info-exporter.js → buffering-exporter.js} +10 -37
  92. package/packages/dd-trace/src/exporters/common/docker.js +2 -2
  93. package/packages/dd-trace/src/exporters/common/request.js +1 -1
  94. package/packages/dd-trace/src/exporters/common/util.js +2 -2
  95. package/packages/dd-trace/src/exporters/span-stats/index.js +3 -10
  96. package/packages/dd-trace/src/flare/index.js +1 -1
  97. package/packages/dd-trace/src/guardrails/telemetry.js +1 -1
  98. package/packages/dd-trace/src/index.js +4 -4
  99. package/packages/dd-trace/src/lambda/handler.js +2 -2
  100. package/packages/dd-trace/src/lambda/index.js +2 -2
  101. package/packages/dd-trace/src/lambda/runtime/patch.js +2 -2
  102. package/packages/dd-trace/src/lambda/runtime/ritm.js +2 -2
  103. package/packages/dd-trace/src/llmobs/constants/tags.js +8 -1
  104. package/packages/dd-trace/src/llmobs/index.js +2 -2
  105. package/packages/dd-trace/src/llmobs/noop.js +2 -0
  106. package/packages/dd-trace/src/llmobs/plugins/openai/index.js +3 -4
  107. package/packages/dd-trace/src/llmobs/sdk.js +33 -6
  108. package/packages/dd-trace/src/llmobs/span_processor.js +17 -7
  109. package/packages/dd-trace/src/llmobs/tagger.js +175 -1
  110. package/packages/dd-trace/src/llmobs/writers/base.js +118 -45
  111. package/packages/dd-trace/src/llmobs/writers/spans.js +4 -3
  112. package/packages/dd-trace/src/llmobs/writers/util.js +3 -9
  113. package/packages/dd-trace/src/log/index.js +50 -35
  114. package/packages/dd-trace/src/log/writer.js +13 -78
  115. package/packages/dd-trace/src/noop/proxy.js +3 -3
  116. package/packages/dd-trace/src/openfeature/writers/base.js +9 -16
  117. package/packages/dd-trace/src/openfeature/writers/util.js +3 -8
  118. package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +2 -2
  119. package/packages/dd-trace/src/opentelemetry/tracer.js +48 -6
  120. package/packages/dd-trace/src/opentracing/propagation/text_map.js +45 -21
  121. package/packages/dd-trace/src/opentracing/span.js +4 -4
  122. package/packages/dd-trace/src/plugin_manager.js +8 -6
  123. package/packages/dd-trace/src/plugins/util/ci.js +5 -8
  124. package/packages/dd-trace/src/plugins/util/git-cache.js +3 -3
  125. package/packages/dd-trace/src/plugins/util/test.js +1 -1
  126. package/packages/dd-trace/src/plugins/util/user-provided-git.js +41 -43
  127. package/packages/dd-trace/src/profiler.js +4 -39
  128. package/packages/dd-trace/src/profiling/config.js +74 -34
  129. package/packages/dd-trace/src/profiling/exporter_cli.js +5 -5
  130. package/packages/dd-trace/src/profiling/exporters/agent.js +1 -1
  131. package/packages/dd-trace/src/profiling/exporters/event_serializer.js +9 -2
  132. package/packages/dd-trace/src/profiling/index.js +1 -1
  133. package/packages/dd-trace/src/profiling/libuv-size.js +1 -1
  134. package/packages/dd-trace/src/profiling/profiler.js +57 -2
  135. package/packages/dd-trace/src/proxy.js +34 -5
  136. package/packages/dd-trace/src/remote_config/capabilities.js +4 -0
  137. package/packages/dd-trace/src/remote_config/index.js +2 -7
  138. package/packages/dd-trace/src/ritm.js +8 -4
  139. package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +2 -2
  140. package/packages/dd-trace/src/serverless.js +2 -2
  141. package/packages/dd-trace/src/span_processor.js +2 -2
  142. package/packages/dd-trace/src/startup-log.js +7 -16
  143. package/packages/dd-trace/src/telemetry/endpoints.js +67 -5
  144. package/packages/dd-trace/src/telemetry/send-data.js +103 -4
  145. package/packages/dd-trace/src/telemetry/telemetry.js +229 -110
  146. package/vendor/dist/@isaacs/ttlcache/index.js +1 -1
  147. package/vendor/dist/esquery/index.js +1 -1
  148. package/vendor/dist/meriyah/index.js +1 -1
  149. package/vendor/dist/protobufjs/index.js +1 -1
  150. /package/packages/dd-trace/src/{git_properties.js → config/git_properties.js} +0 -0
@@ -1,8 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  const { workerData: { config: parentConfig, parentThreadId, configPort } } = require('node:worker_threads')
4
- const { format } = require('node:url')
5
- const defaults = require('../../config_defaults')
4
+ const { getAgentUrl } = require('../../agent/url')
6
5
  const log = require('./log')
7
6
 
8
7
  const config = module.exports = {
@@ -19,11 +18,7 @@ configPort.on('messageerror', (err) =>
19
18
  )
20
19
 
21
20
  function updateUrl (updates) {
22
- config.url = updates.url || format({
23
- protocol: 'http:',
24
- hostname: updates.hostname || defaults.hostname,
25
- port: updates.port
26
- })
21
+ config.url = getAgentUrl(updates)
27
22
 
28
23
  config.dynamicInstrumentation.captureTimeoutNs = BigInt(updates.dynamicInstrumentation.captureTimeoutMs) * 1_000_000n
29
24
  }
@@ -11,26 +11,25 @@ class JSONBuffer {
11
11
  this.#maxSize = size
12
12
  this.#timeout = timeout
13
13
  this.#onFlush = onFlush
14
- this.#reset()
15
- }
16
-
17
- #reset () {
18
- clearTimeout(this.#timer)
19
- this.#timer = undefined
20
- this.#partialJson = undefined
21
14
  }
22
15
 
23
16
  #flush () {
24
17
  const json = `${this.#partialJson}]`
25
- this.#reset()
18
+ this.#partialJson = undefined
26
19
  this.#onFlush(json)
27
20
  }
28
21
 
29
22
  write (str, size = Buffer.byteLength(str)) {
30
- if (this.#timer === undefined) {
23
+ if (this.#partialJson === undefined) {
31
24
  this.#partialJson = `[${str}`
32
- this.#timer = setTimeout(() => this.#flush(), this.#timeout)
33
- } else if (Buffer.byteLength(/** @type {string} */ (this.#partialJson)) + size + 2 > this.#maxSize) {
25
+ if (this.#timer === undefined) {
26
+ this.#timer = setTimeout(() => this.#flush(), this.#timeout)
27
+ } else {
28
+ this.#timer.refresh()
29
+ }
30
+ } else if (Buffer.byteLength(this.#partialJson) + size + 2 > this.#maxSize) {
31
+ clearTimeout(this.#timer)
32
+ this.#timer = undefined
34
33
  this.#flush()
35
34
  this.write(str, size)
36
35
  } else {
@@ -6,7 +6,7 @@ const { stringify } = require('querystring')
6
6
  const request = require('../../exporters/common/request')
7
7
  const { GIT_COMMIT_SHA, GIT_REPOSITORY_URL } = require('../../plugins/util/tags')
8
8
  const { version } = require('../../../../../package.json')
9
- const { getEnvironmentVariable } = require('../../config-helper')
9
+ const { getValueFromEnvSources } = require('../../config/helper')
10
10
  const log = require('./log')
11
11
  const JSONBuffer = require('./json-buffer')
12
12
  const config = require('./config')
@@ -23,8 +23,8 @@ const hostname = getHostname()
23
23
  const service = config.service
24
24
 
25
25
  const ddtags = [
26
- ['env', getEnvironmentVariable('DD_ENV')],
27
- ['version', getEnvironmentVariable('DD_VERSION')],
26
+ ['env', getValueFromEnvSources('DD_ENV')],
27
+ ['version', getValueFromEnvSources('DD_VERSION')],
28
28
  ['debugger_version', version],
29
29
  ['host_name', hostname],
30
30
  [GIT_COMMIT_SHA, config.commitSHA],
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const { getEnvironmentVariable } = require('../../../config-helper')
3
+ const { getEnvironmentVariable } = require('../../../config/helper')
4
4
 
5
5
  const largeObjectSkipThreshold = Number(
6
6
  getEnvironmentVariable('_DD_DYNAMIC_INSTRUMENTATION_EXPERIMENTAL_LARGE_OBJECT_SKIP_THRESHOLD')
@@ -10,26 +10,49 @@ const getDebuggerConfig = require('./config')
10
10
  let worker = null
11
11
  let configChannel = null
12
12
  let ackId = 0
13
+ let rcAckCallbacks = null
14
+ let rc = null
13
15
 
14
16
  // eslint-disable-next-line eslint-rules/eslint-process-env
15
17
  const { NODE_OPTIONS, ...env } = process.env
16
18
 
17
19
  module.exports = {
20
+ isStarted,
18
21
  start,
19
- configure
22
+ configure,
23
+ stop
20
24
  }
21
25
 
22
- function start (config, rc) {
26
+ /**
27
+ * Check if the Debugger worker is currently running
28
+ *
29
+ * @returns {boolean} True if the worker is started, false otherwise
30
+ */
31
+ function isStarted () {
32
+ return worker !== null
33
+ }
34
+
35
+ /**
36
+ * Start the Debugger worker thread.
37
+ * Creates a worker thread, sets up message channels, and registers
38
+ * the LIVE_DEBUGGING product handler with remote config.
39
+ * Does nothing if the worker is already started.
40
+ *
41
+ * @param {object} config - The tracer configuration object
42
+ * @param {object} rcInstance - The RemoteConfig instance
43
+ */
44
+ function start (config, rcInstance) {
23
45
  if (worker !== null) return
24
46
 
25
47
  log.debug('[debugger] Starting Dynamic Instrumentation client...')
26
48
 
27
- const rcAckCallbacks = new Map()
49
+ rc = rcInstance
50
+ rcAckCallbacks = new Map()
28
51
  const probeChannel = new MessageChannel()
29
52
  const logChannel = new MessageChannel()
30
53
  configChannel = new MessageChannel()
31
54
 
32
- process[Symbol.for('datadog:node:util:types')] = types
55
+ globalThis[Symbol.for('dd-trace')].utilTypes = types
33
56
 
34
57
  readProbeFile(config.dynamicInstrumentation.probeFile, (probes) => {
35
58
  const action = 'apply'
@@ -84,19 +107,10 @@ function start (config, rc) {
84
107
  worker.on('error', (err) => log.error('[debugger] worker thread error', err))
85
108
  worker.on('messageerror', (err) => log.error('[debugger] received "messageerror" from worker', err))
86
109
 
87
- worker.on('exit', (code) => {
110
+ worker.once('exit', (code) => {
88
111
  const error = new Error(`Dynamic Instrumentation worker thread exited unexpectedly with code ${code}`)
89
-
90
112
  log.error('[debugger] worker thread exited unexpectedly', error)
91
-
92
- // Be nice, clean up now that the worker thread encountered an issue and we can't continue
93
- rc.removeProductHandler('LIVE_DEBUGGING')
94
- worker.removeAllListeners()
95
- configChannel = null
96
- for (const ackId of rcAckCallbacks.keys()) {
97
- rcAckCallbacks.get(ackId)(error)
98
- rcAckCallbacks.delete(ackId)
99
- }
113
+ cleanup(error) // Be nice, clean up now that the worker thread encountered an issue and we can't continue
100
114
  })
101
115
 
102
116
  worker.unref()
@@ -108,11 +122,65 @@ function start (config, rc) {
108
122
  configChannel.port2.unref()
109
123
  }
110
124
 
125
+ /**
126
+ * Reconfigure the Debugger worker with updated settings.
127
+ * Sends the new configuration to the worker thread via the config channel.
128
+ * Does nothing if the worker is not started.
129
+ *
130
+ * @param {object} config - The updated tracer configuration object
131
+ */
111
132
  function configure (config) {
112
133
  if (configChannel === null) return
113
134
  configChannel.port2.postMessage(getDebuggerConfig(config))
114
135
  }
115
136
 
137
+ /**
138
+ * Stop the Debugger worker thread.
139
+ * Terminates the worker and cleans up resources.
140
+ * Safe to call even if the worker is not started.
141
+ */
142
+ function stop () {
143
+ if (worker === null) return
144
+
145
+ log.debug('[debugger] Stopping Dynamic Instrumentation client...')
146
+
147
+ try {
148
+ worker.terminate()
149
+ cleanup() // Graceful shutdown - termination succeeded
150
+ } catch (err) {
151
+ log.error('[debugger] Error terminating worker', err)
152
+ cleanup(err) // Cleanup with error - termination failed
153
+ }
154
+ }
155
+
156
+ /**
157
+ * Internal cleanup function to reset all debugger resources.
158
+ * Called when stopping the debugger or when the worker exits unexpectedly.
159
+ *
160
+ * @param {Error} [error] - Optional error to pass to pending ack callbacks (for unexpected exits)
161
+ */
162
+ function cleanup (error) {
163
+ if (rc) {
164
+ rc.removeProductHandler('LIVE_DEBUGGING')
165
+ rc = null
166
+ }
167
+ if (worker) {
168
+ worker.removeAllListeners()
169
+ worker = null
170
+ }
171
+ configChannel = null
172
+
173
+ // Call any pending ack callbacks
174
+ // Pass error for unexpected exits, or undefined for graceful shutdown
175
+ if (rcAckCallbacks) {
176
+ for (const ackId of rcAckCallbacks.keys()) {
177
+ rcAckCallbacks.get(ackId)(error)
178
+ rcAckCallbacks.delete(ackId)
179
+ }
180
+ rcAckCallbacks = null
181
+ }
182
+ }
183
+
116
184
  function readProbeFile (path, cb) {
117
185
  if (!path) return
118
186
 
@@ -3,12 +3,12 @@
3
3
  const lookup = require('dns').lookup // cache to avoid instrumentation
4
4
  const dgram = require('dgram')
5
5
  const isIP = require('net').isIP
6
- const { URL, format } = require('url')
7
6
 
8
7
  const request = require('./exporters/common/request')
9
8
  const log = require('./log')
10
9
  const Histogram = require('./histogram')
11
- const defaults = require('./config_defaults')
10
+ const defaults = require('./config/defaults')
11
+ const { getAgentUrl } = require('./agent/url')
12
12
 
13
13
  const MAX_BUFFER_SIZE = 1024 // limit from the agent
14
14
 
@@ -179,14 +179,8 @@ class DogStatsDClient {
179
179
  tags
180
180
  }
181
181
 
182
- if (config.url) {
183
- clientConfig.metricsProxyUrl = config.url
184
- } else if (config.port) {
185
- clientConfig.metricsProxyUrl = new URL(format({
186
- protocol: 'http:',
187
- hostname: config.hostname || defaults.hostname,
188
- port: config.port
189
- }))
182
+ if (config.url || config.port) {
183
+ clientConfig.metricsProxyUrl = getAgentUrl(config)
190
184
  }
191
185
 
192
186
  return clientConfig
@@ -360,7 +354,7 @@ class CustomMetrics {
360
354
  // TODO(bengl) this magic number should be configurable
361
355
  setInterval(flush, 10 * 1000).unref()
362
356
 
363
- process.once('beforeExit', flush)
357
+ globalThis[Symbol.for('dd-trace')].beforeExitHandlers.add(flush)
364
358
  }
365
359
 
366
360
  increment (stat, value = 1, tags) {
@@ -4,7 +4,7 @@ const { MsgpackChunk, MsgpackEncoder } = require('../msgpack')
4
4
  const log = require('../log')
5
5
  const { isTrue } = require('../util')
6
6
  const { memoize } = require('../log/utils')
7
- const { getEnvironmentVariable } = require('../config-helper')
7
+ const { getValueFromEnvSources } = require('../config/helper')
8
8
  const { truncateSpan, normalizeSpan } = require('./tags-processors')
9
9
 
10
10
  const SOFT_LIMIT = 8 * 1024 * 1024 // 8MB
@@ -31,7 +31,7 @@ class AgentEncoder {
31
31
  this._stringBytes = new MsgpackChunk()
32
32
  this._writer = writer
33
33
  this._reset()
34
- this._debugEncoding = isTrue(getEnvironmentVariable('DD_TRACE_ENCODING_DEBUG'))
34
+ this._debugEncoding = isTrue(getValueFromEnvSources('DD_TRACE_ENCODING_DEBUG'))
35
35
  this._config = this._writer?._config
36
36
  }
37
37
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  const fs = require('fs')
4
4
  const exporters = require('../../../ext/exporters')
5
- const { getEnvironmentVariable } = require('../../dd-trace/src/config-helper')
5
+ const { getEnvironmentVariable } = require('../../dd-trace/src/config/helper')
6
6
  const constants = require('./constants')
7
7
 
8
8
  module.exports = function getExporter (name) {
@@ -1,8 +1,8 @@
1
1
  'use strict'
2
2
 
3
- const { URL, format } = require('url')
3
+ const { URL } = require('url')
4
4
  const log = require('../../log')
5
- const defaults = require('../../config_defaults')
5
+ const { getAgentUrl } = require('../../agent/url')
6
6
  const Writer = require('./writer')
7
7
 
8
8
  class AgentExporter {
@@ -10,12 +10,8 @@ class AgentExporter {
10
10
 
11
11
  constructor (config, prioritySampler) {
12
12
  this._config = config
13
- const { url, hostname = defaults.hostname, port, lookup, protocolVersion, stats = {}, apmTracingEnabled } = config
14
- this._url = url || new URL(format({
15
- protocol: 'http:',
16
- hostname,
17
- port
18
- }))
13
+ const { lookup, protocolVersion, stats = {}, apmTracingEnabled } = config
14
+ this._url = getAgentUrl(config)
19
15
 
20
16
  const headers = {}
21
17
  if (stats.enabled || apmTracingEnabled === false) {
@@ -31,9 +27,7 @@ class AgentExporter {
31
27
  config
32
28
  })
33
29
 
34
- process.once('beforeExit', () => {
35
- this.flush()
36
- })
30
+ globalThis[Symbol.for('dd-trace')].beforeExitHandlers.add(this.flush.bind(this))
37
31
  }
38
32
 
39
33
  setUrl (url) {
@@ -1,5 +1,7 @@
1
1
  'use strict'
2
2
 
3
+ const { inspect } = require('util')
4
+
3
5
  const request = require('../common/request')
4
6
  const { startupLog } = require('../../startup-log')
5
7
  const runtimeMetrics = require('../../runtime_metrics')
@@ -10,8 +12,9 @@ const BaseWriter = require('../common/writer')
10
12
  const METRIC_PREFIX = 'datadog.tracer.node.exporter.agent'
11
13
 
12
14
  class AgentWriter extends BaseWriter {
13
- constructor ({ prioritySampler, lookup, protocolVersion, headers, config = {} }) {
14
- super(...arguments)
15
+ constructor (...args) {
16
+ super(...args)
17
+ const { prioritySampler, lookup, protocolVersion, headers, config = {} } = args[0]
15
18
  const AgentEncoder = getEncoder(protocolVersion)
16
19
 
17
20
  this._prioritySampler = prioritySampler
@@ -26,7 +29,10 @@ class AgentWriter extends BaseWriter {
26
29
  runtimeMetrics.increment(`${METRIC_PREFIX}.requests`, true)
27
30
 
28
31
  const { _headers, _lookup, _protocolVersion, _url } = this
29
- makeRequest(_protocolVersion, data, count, _url, _headers, _lookup, true, (err, res, status) => {
32
+ makeRequest(_protocolVersion, data, count, _url, _headers, _lookup, (err, res, status) => {
33
+ // Note that logging will only happen once, regardless of how many times this is called.
34
+ startupLog(status !== 404 && status !== 200 ? { status, message: err?.message ?? inspect(err) } : undefined)
35
+
30
36
  if (status) {
31
37
  runtimeMetrics.increment(`${METRIC_PREFIX}.responses`, true)
32
38
  runtimeMetrics.increment(`${METRIC_PREFIX}.responses.by.status`, `status:${status}`, true)
@@ -39,8 +45,6 @@ class AgentWriter extends BaseWriter {
39
45
  }
40
46
  }
41
47
 
42
- startupLog({ agentError: err })
43
-
44
48
  if (err) {
45
49
  log.errorWithoutTelemetry('Error sending payload to the agent (status code: %s)', err.status, err)
46
50
  done()
@@ -68,7 +72,7 @@ function getEncoder (protocolVersion) {
68
72
  : require('../../encode/0.4').AgentEncoder
69
73
  }
70
74
 
71
- function makeRequest (version, data, count, url, headers, lookup, needsStartupLog, cb) {
75
+ function makeRequest (version, data, count, url, headers, lookup, cb) {
72
76
  const options = {
73
77
  path: `/v${version}/traces`,
74
78
  method: 'PUT',
@@ -79,7 +83,7 @@ function makeRequest (version, data, count, url, headers, lookup, needsStartupLo
79
83
  'X-Datadog-Trace-Count': String(count),
80
84
  'Datadog-Meta-Lang': 'nodejs',
81
85
  'Datadog-Meta-Lang-Version': process.version,
82
- 'Datadog-Meta-Lang-Interpreter': process.jsEngine || 'v8'
86
+ 'Datadog-Meta-Lang-Interpreter': process.versions.bun ? 'JavaScriptCore' : 'v8'
83
87
  },
84
88
  lookup,
85
89
  url
@@ -87,15 +91,7 @@ function makeRequest (version, data, count, url, headers, lookup, needsStartupLo
87
91
 
88
92
  log.debug('Request to the agent: %j', options)
89
93
 
90
- request(data, options, (err, res, status) => {
91
- if (needsStartupLog) {
92
- // Note that logging will only happen once, regardless of how many times this is called.
93
- startupLog({
94
- agentError: status !== 404 && status !== 200 ? err : undefined
95
- })
96
- }
97
- cb(err, res, status)
98
- })
94
+ request(data, options, cb)
99
95
  }
100
96
 
101
97
  module.exports = AgentWriter
@@ -1,47 +1,20 @@
1
1
  'use strict'
2
2
 
3
- const { URL, format } = require('url')
4
-
5
- const defaults = require('../../config_defaults')
6
3
  const { incrementCountMetric, TELEMETRY_EVENTS_ENQUEUED_FOR_SERIALIZATION } = require('../../ci-visibility/telemetry')
7
- const request = require('./request')
8
-
9
- function fetchAgentInfo (url, callback) {
10
- request('', {
11
- path: '/info',
12
- url
13
- }, (err, res) => {
14
- if (err) {
15
- return callback(err)
16
- }
17
- try {
18
- const response = JSON.parse(res)
19
- return callback(null, response)
20
- } catch (e) {
21
- return callback(e)
22
- }
23
- })
24
- }
4
+ const { getAgentUrl } = require('../../agent/url')
25
5
 
26
6
  /**
27
- * Exporter that exposes a way to query /info endpoint from the agent and gives you the response.
28
- * While this._writer is not initialized, exported traces are stored as is.
7
+ * Base exporter that buffers traces until a writer is initialized.
8
+ * Provides common export logic with flush intervals.
29
9
  */
30
- class AgentInfoExporter {
10
+ class BufferingExporter {
11
+ _traceBuffer = []
12
+ _isInitialized = false
13
+ _writer
14
+
31
15
  constructor (tracerConfig) {
32
16
  this._config = tracerConfig
33
- const { url, hostname = defaults.hostname, port } = this._config
34
- this._url = url || new URL(format({
35
- protocol: 'http:',
36
- hostname,
37
- port
38
- }))
39
- this._traceBuffer = []
40
- this._isInitialized = false
41
- }
42
-
43
- getAgentInfo (onReceivedInfo) {
44
- fetchAgentInfo(this._url, onReceivedInfo)
17
+ this._url = getAgentUrl(tracerConfig)
45
18
  }
46
19
 
47
20
  export (trace) {
@@ -86,4 +59,4 @@ class AgentInfoExporter {
86
59
  }
87
60
  }
88
61
 
89
- module.exports = AgentInfoExporter
62
+ module.exports = BufferingExporter
@@ -1,9 +1,9 @@
1
1
  'use strict'
2
2
 
3
3
  const fs = require('fs')
4
- const { getEnvironmentVariable } = require('../../config-helper')
4
+ const { getValueFromEnvSources } = require('../../config/helper')
5
5
 
6
- const DD_EXTERNAL_ENV = getEnvironmentVariable('DD_EXTERNAL_ENV')
6
+ const DD_EXTERNAL_ENV = getValueFromEnvSources('DD_EXTERNAL_ENV')
7
7
 
8
8
  // The second part is the PCF / Garden regexp. We currently assume no suffix($) to avoid matching pod UIDs
9
9
  // See https://github.com/DataDog/datadog-agent/blob/7.40.x/pkg/util/cgroups/reader.go#L50
@@ -77,7 +77,7 @@ function request (data, options, callback) {
77
77
  res.on('data', chunk => {
78
78
  chunks.push(chunk)
79
79
  })
80
- res.on('end', () => {
80
+ res.once('end', () => {
81
81
  activeRequests--
82
82
  const buffer = Buffer.concat(chunks)
83
83
 
@@ -1,12 +1,12 @@
1
1
  'use strict'
2
2
 
3
- const { getEnvironmentVariable } = require('../../config-helper')
3
+ const { getValueFromEnvSources } = require('../../config/helper')
4
4
 
5
5
  function safeJSONStringify (value) {
6
6
  return JSON.stringify(
7
7
  value,
8
8
  (key, value) => key === 'dd-api-key' ? undefined : value,
9
- getEnvironmentVariable('DD_TRACE_BEAUTIFUL_LOGS') ? 2 : undefined
9
+ getValueFromEnvSources('DD_TRACE_BEAUTIFUL_LOGS') ? 2 : undefined
10
10
  )
11
11
  }
12
12
 
@@ -1,19 +1,12 @@
1
1
  'use strict'
2
2
 
3
- const { URL, format } = require('url')
4
-
5
- const defaults = require('../../config_defaults')
3
+ const { getAgentUrl } = require('../../agent/url')
6
4
  const { Writer } = require('./writer')
7
5
 
8
6
  class SpanStatsExporter {
9
7
  constructor (config) {
10
- const { hostname = defaults.hostname, port = defaults.port, tags, url } = config
11
- this._url = url || new URL(format({
12
- protocol: 'http:',
13
- hostname,
14
- port
15
- }))
16
- this._writer = new Writer({ url: this._url, tags })
8
+ this._url = getAgentUrl(config)
9
+ this._writer = new Writer({ url: this._url })
17
10
  }
18
11
 
19
12
  export (payload) {
@@ -64,7 +64,7 @@ const flare = {
64
64
  },
65
65
 
66
66
  _sendFile (task, file, filename) {
67
- if (!file) return
67
+ if (!file || file.length === 0) return
68
68
 
69
69
  const form = new FormData()
70
70
 
@@ -80,7 +80,7 @@ function sendTelemetry (name, tags, resultMetadata) {
80
80
  proc.on('error', function () {
81
81
  log.error('Failed to spawn telemetry forwarder')
82
82
  })
83
- proc.on('exit', function (code) {
83
+ proc.once('exit', function (code) {
84
84
  if (code !== 0) {
85
85
  log.error('Telemetry forwarder exited with code', code)
86
86
  }
@@ -1,14 +1,14 @@
1
1
  'use strict'
2
2
 
3
- const { getEnvironmentVariable } = require('../../dd-trace/src/config-helper')
3
+ const { getValueFromEnvSources } = require('./config/helper')
4
4
  const { isFalse } = require('./util')
5
5
 
6
6
  // Global `jest` is only present in Jest workers.
7
7
  const inJestWorker = typeof jest !== 'undefined'
8
8
 
9
- const ddTraceDisabled = getEnvironmentVariable('DD_TRACE_ENABLED')
10
- ? isFalse(getEnvironmentVariable('DD_TRACE_ENABLED'))
11
- : String(getEnvironmentVariable('OTEL_TRACES_EXPORTER')).toLowerCase() === 'none'
9
+ const ddTraceDisabled = getValueFromEnvSources('DD_TRACE_ENABLED')
10
+ ? isFalse(getValueFromEnvSources('DD_TRACE_ENABLED'))
11
+ : String(getValueFromEnvSources('OTEL_TRACES_EXPORTER')).toLowerCase() === 'none'
12
12
 
13
13
  module.exports = ddTraceDisabled || inJestWorker
14
14
  ? require('./noop/proxy')
@@ -3,7 +3,7 @@
3
3
  const log = require('../log')
4
4
  const { channel } = require('../../../datadog-instrumentations/src/helpers/instrument')
5
5
  const { ERROR_MESSAGE, ERROR_TYPE } = require('../constants')
6
- const { getEnvironmentVariable } = require('../config-helper')
6
+ const { getValueFromEnvSources } = require('../config/helper')
7
7
  const { ImpendingTimeout } = require('./runtime/errors')
8
8
 
9
9
  const globalTracer = global._ddtrace
@@ -26,7 +26,7 @@ let __lambdaTimeout
26
26
  function checkTimeout (context) {
27
27
  const remainingTimeInMillis = context.getRemainingTimeInMillis()
28
28
 
29
- let apmFlushDeadline = Number.parseInt(getEnvironmentVariable('DD_APM_FLUSH_DEADLINE_MILLISECONDS')) || 100
29
+ let apmFlushDeadline = Number.parseInt(getValueFromEnvSources('DD_APM_FLUSH_DEADLINE_MILLISECONDS')) || 100
30
30
  apmFlushDeadline = apmFlushDeadline < 0 ? 100 : apmFlushDeadline
31
31
 
32
32
  __lambdaTimeout = setTimeout(() => {
@@ -1,13 +1,13 @@
1
1
  'use strict'
2
2
 
3
- const { getEnvironmentVariable } = require('../config-helper')
3
+ const { getValueFromEnvSources } = require('../config/helper')
4
4
  const { registerLambdaHook } = require('./runtime/ritm')
5
5
 
6
6
  /**
7
7
  * It is safe to do it this way, since customers will never be expected to disable
8
8
  * this specific instrumentation through the init config object.
9
9
  */
10
- const _DD_TRACE_DISABLED_INSTRUMENTATIONS = getEnvironmentVariable('DD_TRACE_DISABLED_INSTRUMENTATIONS') || ''
10
+ const _DD_TRACE_DISABLED_INSTRUMENTATIONS = getValueFromEnvSources('DD_TRACE_DISABLED_INSTRUMENTATIONS') || ''
11
11
  const _disabledInstrumentations = new Set(
12
12
  _DD_TRACE_DISABLED_INSTRUMENTATIONS ? _DD_TRACE_DISABLED_INSTRUMENTATIONS.split(',') : []
13
13
  )
@@ -5,7 +5,7 @@ const path = require('path')
5
5
  const { datadog } = require('../handler')
6
6
  const { addHook } = require('../../../../datadog-instrumentations/src/helpers/instrument')
7
7
  const shimmer = require('../../../../datadog-shimmer')
8
- const { getEnvironmentVariable } = require('../../config-helper')
8
+ const { getEnvironmentVariable, getValueFromEnvSources } = require('../../config/helper')
9
9
  const { _extractModuleNameAndHandlerPath, _extractModuleRootAndHandler, _getLambdaFilePaths } = require('./ritm')
10
10
 
11
11
  /**
@@ -59,7 +59,7 @@ function patchLambdaHandler (lambdaHandler) {
59
59
  }
60
60
 
61
61
  const lambdaTaskRoot = getEnvironmentVariable('LAMBDA_TASK_ROOT')
62
- const originalLambdaHandler = getEnvironmentVariable('DD_LAMBDA_HANDLER')
62
+ const originalLambdaHandler = getValueFromEnvSources('DD_LAMBDA_HANDLER')
63
63
 
64
64
  if (originalLambdaHandler === undefined) {
65
65
  // Instrumentation is done manually.
@@ -10,7 +10,7 @@
10
10
  const path = require('path')
11
11
 
12
12
  const log = require('../../log')
13
- const { getEnvironmentVariable } = require('../../config-helper')
13
+ const { getEnvironmentVariable, getValueFromEnvSources } = require('../../config/helper')
14
14
  const Hook = require('../../../../datadog-instrumentations/src/helpers/hook')
15
15
  const instrumentations = require('../../../../datadog-instrumentations/src/helpers/instrumentations')
16
16
  const {
@@ -79,7 +79,7 @@ function _getLambdaFilePaths (lambdaStylePath) {
79
79
  */
80
80
  const registerLambdaHook = () => {
81
81
  const lambdaTaskRoot = getEnvironmentVariable('LAMBDA_TASK_ROOT')
82
- const originalLambdaHandler = getEnvironmentVariable('DD_LAMBDA_HANDLER')
82
+ const originalLambdaHandler = getValueFromEnvSources('DD_LAMBDA_HANDLER')
83
83
 
84
84
  if (originalLambdaHandler !== undefined && lambdaTaskRoot !== undefined) {
85
85
  const [moduleRoot, moduleAndHandler] = _extractModuleRootAndHandler(originalLambdaHandler)