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,34 +1,202 @@
1
1
  'use strict'
2
2
 
3
3
  const RemoteConfigCapabilities = require('../remote_config/capabilities')
4
+ const log = require('../log')
5
+
6
+ module.exports = {
7
+ enable
8
+ }
9
+
10
+ /**
11
+ * @typedef {object} RemoteConfigOptions
12
+ * @property {boolean} [dynamic_instrumentation_enabled] - Enable Dynamic Instrumentation
13
+ * @property {boolean} [code_origin_enabled] - Enable code origin tagging for spans
14
+ * @property {Array<{header: string, tag_name?: string}>} [tracing_header_tags] - HTTP headers to tag
15
+ * @property {Array<string>} [tracing_tags] - Global tags (format: "key:value")
16
+ * @property {number} [tracing_sampling_rate] - Global sampling rate (0.0-1.0)
17
+ * @property {boolean} [log_injection_enabled] - Enable trace context log injection
18
+ * @property {boolean} [tracing_enabled] - Enable/disable tracing globally
19
+ * @property {Array<object>} [tracing_sampling_rules] - Trace sampling rules configuration
20
+ */
21
+
22
+ /**
23
+ * @typedef {ReturnType<import('../config')>} Config
24
+ */
25
+
26
+ /**
27
+ * Manages multiple APM_TRACING configurations with priority-based merging
28
+ */
29
+ class RCClientLibConfigManager {
30
+ /**
31
+ * @param {string} currentService - Current service name
32
+ * @param {string} currentEnv - Current environment name
33
+ */
34
+ constructor (currentService, currentEnv) {
35
+ this.configs = new Map() // config_id -> { conf, priority }
36
+ this.currentService = currentService
37
+ this.currentEnv = currentEnv
38
+ }
39
+
40
+ /**
41
+ * Calculate priority based on target specificity. Higher values take precedence.
42
+ * Priority order (highest → lowest):
43
+ * Service+Env (5) > Service (4) > Env (3) > Cluster (2) > Org (1)
44
+ *
45
+ * @param {object} conf - Remote config object with service_target and k8s_target_v2 properties
46
+ * @returns {number} Priority value from 1 (org-level) to 5 (service+env specific)
47
+ */
48
+ calculatePriority (conf) {
49
+ const serviceTarget = conf.service_target
50
+ const k8sTarget = conf.k8s_target_v2
51
+
52
+ if (serviceTarget) {
53
+ const service = serviceTarget.service
54
+ const env = serviceTarget.env
55
+
56
+ const hasSpecificService = service && service !== '*'
57
+ const hasSpecificEnv = env && env !== '*'
58
+
59
+ if (hasSpecificService && hasSpecificEnv) return 5
60
+ if (hasSpecificService) return 4
61
+ if (hasSpecificEnv) return 3
62
+ }
63
+
64
+ if (k8sTarget) return 2
65
+
66
+ return 1 // Org level
67
+ }
68
+
69
+ /**
70
+ * Check if config matches current service/env
71
+ *
72
+ * @param {object} conf - Remote config object with service_target property
73
+ * @returns {boolean} True if config matches current service/env or has no filter
74
+ */
75
+ matchesCurrentServiceEnv (conf) {
76
+ const serviceTarget = conf.service_target
77
+ if (!serviceTarget) return true // No filter means match all
78
+
79
+ const service = serviceTarget.service
80
+ const env = serviceTarget.env
81
+
82
+ // Check service match
83
+ if (service && service !== '*' && service !== this.currentService) {
84
+ log.debug('[config/remote_config] Ignoring config for service: %s (current: %s)',
85
+ service, this.currentService)
86
+ return false
87
+ }
88
+
89
+ // Check env match
90
+ if (env && env !== '*' && env !== this.currentEnv) {
91
+ log.debug('[config/remote_config] Ignoring config for env: %s (current: %s)',
92
+ env, this.currentEnv)
93
+ return false
94
+ }
95
+
96
+ return true
97
+ }
98
+
99
+ /**
100
+ * Add or update a config
101
+ *
102
+ * @param {string} configId - Unique identifier for the config
103
+ * @param {object} conf - Remote config object to add
104
+ */
105
+ addConfig (configId, conf) {
106
+ if (!this.matchesCurrentServiceEnv(conf)) {
107
+ return
108
+ }
109
+
110
+ const priority = this.calculatePriority(conf)
111
+ this.configs.set(configId, { conf, priority })
112
+
113
+ log.debug('[config/remote_config] Added config %s with priority %d', configId, priority)
114
+ }
115
+
116
+ /**
117
+ * Remove a config
118
+ *
119
+ * @param {string} configId - Unique identifier for the config to remove
120
+ */
121
+ removeConfig (configId) {
122
+ const removed = this.configs.delete(configId)
123
+ if (removed) {
124
+ log.debug('[config/remote_config] Removed config %s', configId)
125
+ }
126
+ }
127
+
128
+ /**
129
+ * Get merged lib_config with higher priority configs overriding lower priority ones
130
+ *
131
+ * @returns {RemoteConfigOptions|null} Merged config object or null if no configs present
132
+ */
133
+ getMergedLibConfig () {
134
+ if (this.configs.size === 0) return null
135
+
136
+ let hasLibConfig = false
137
+
138
+ const merged = [...this.configs.values()]
139
+ .sort((a, b) => a.priority - b.priority)
140
+ .reduce((merged, { conf }) => {
141
+ if (conf.lib_config != null) hasLibConfig = true
142
+ return Object.assign(merged, conf.lib_config)
143
+ }, {})
144
+
145
+ return hasLibConfig ? merged : null
146
+ }
147
+ }
4
148
 
5
149
  /**
6
150
  * Configures remote config for core APM tracing functionality
7
151
  *
8
- * @param {object} rc - RemoteConfig instance
9
- * @param {object} config - Tracer config
10
- * @param {Function} enableOrDisableTracing - Function to enable/disable tracing based on config
152
+ * @param {import('../remote_config')} rc - RemoteConfig instance
153
+ * @param {Config} config - Tracer config
154
+ * @param {() => void} onConfigUpdated - Function to call when config is updated
11
155
  */
12
- function enable (rc, config, enableOrDisableTracing) {
13
- // Register core APM tracing capabilities
156
+ function enable (rc, config, onConfigUpdated) {
157
+ // This tracer supports receiving config subsets via the APM_TRACING product handler.
158
+ rc.updateCapabilities(RemoteConfigCapabilities.APM_TRACING_MULTICONFIG, true)
159
+
160
+ // Tracing
161
+ rc.updateCapabilities(RemoteConfigCapabilities.APM_TRACING_ENABLED, true)
162
+ rc.updateCapabilities(RemoteConfigCapabilities.APM_TRACING_SAMPLE_RATE, true)
163
+ rc.updateCapabilities(RemoteConfigCapabilities.APM_TRACING_SAMPLE_RULES, true)
14
164
  rc.updateCapabilities(RemoteConfigCapabilities.APM_TRACING_CUSTOM_TAGS, true)
15
165
  rc.updateCapabilities(RemoteConfigCapabilities.APM_TRACING_HTTP_HEADER_TAGS, true)
166
+
167
+ // Log Management
16
168
  rc.updateCapabilities(RemoteConfigCapabilities.APM_TRACING_LOGS_INJECTION, true)
17
- rc.updateCapabilities(RemoteConfigCapabilities.APM_TRACING_SAMPLE_RATE, true)
18
- rc.updateCapabilities(RemoteConfigCapabilities.APM_TRACING_ENABLED, true)
19
- rc.updateCapabilities(RemoteConfigCapabilities.APM_TRACING_SAMPLE_RULES, true)
20
169
 
21
- // APM_TRACING product handler - manages tracer configuration
22
- rc.setProductHandler('APM_TRACING', (action, conf) => {
23
- if (action === 'unapply') {
24
- config.configure({}, true)
25
- } else {
26
- config.configure(conf.lib_config, true)
170
+ // Debugger
171
+ rc.updateCapabilities(RemoteConfigCapabilities.APM_TRACING_ENABLE_DYNAMIC_INSTRUMENTATION, true)
172
+
173
+ // Code Origin
174
+ rc.updateCapabilities(RemoteConfigCapabilities.APM_TRACING_ENABLE_CODE_ORIGIN, true)
175
+
176
+ const rcClientLibConfigManager = new RCClientLibConfigManager(config.service, config.env)
177
+
178
+ // Subscribe to APM_TRACING product (setBatchHandler used below doesn't automatically subscribe)
179
+ rc.subscribeProducts('APM_TRACING')
180
+
181
+ // Use a batch handler to process all changes before updating the config. This is important in case there's
182
+ // conflicting configs between, for example, the org and service level.
183
+ rc.setBatchHandler(['APM_TRACING'], (transaction) => {
184
+ const { toUnapply, toApply, toModify } = transaction
185
+
186
+ for (const item of toUnapply) {
187
+ rcClientLibConfigManager.removeConfig(item.id)
188
+ transaction.ack(item.path)
27
189
  }
28
- enableOrDisableTracing(config, rc)
29
- })
30
- }
31
190
 
32
- module.exports = {
33
- enable
191
+ for (const item of [...toApply, ...toModify]) {
192
+ rcClientLibConfigManager.addConfig(item.id, item.file)
193
+ transaction.ack(item.path)
194
+ }
195
+
196
+ // Get merged config and apply it
197
+ const mergedLibConfig = rcClientLibConfigManager.getMergedLibConfig()
198
+ config.setRemoteConfig(mergedLibConfig)
199
+
200
+ onConfigUpdated()
201
+ })
34
202
  }
@@ -2,7 +2,7 @@
2
2
 
3
3
  const os = require('os')
4
4
  const fs = require('fs')
5
- const { getEnvironmentVariable } = require('../../dd-trace/src/config-helper')
5
+ const { getEnvironmentVariable } = require('./helper')
6
6
 
7
7
  class StableConfig {
8
8
  constructor () {
@@ -11,14 +11,10 @@ class StableConfig {
11
11
  this.fleetEntries = {}
12
12
  this.wasm_loaded = false
13
13
 
14
- const { localConfigPath, fleetConfigPath } = this._getStableConfigPaths()
15
- if (!fs.existsSync(localConfigPath) && !fs.existsSync(fleetConfigPath)) {
16
- // Bail out early if files don't exist to avoid unnecessary library loading
17
- return
18
- }
14
+ const { localConfigPath, fleetConfigPath } = this.#getStableConfigPaths()
19
15
 
20
- const localConfig = this._readConfigFromPath(localConfigPath)
21
- const fleetConfig = this._readConfigFromPath(fleetConfigPath)
16
+ const localConfig = this.#readConfigFromPath(localConfigPath)
17
+ const fleetConfig = this.#readConfigFromPath(fleetConfigPath)
22
18
  if (!localConfig && !fleetConfig) {
23
19
  // Bail out early if files are empty or we can't read them to avoid unnecessary library loading
24
20
  return
@@ -47,7 +43,7 @@ class StableConfig {
47
43
  // eslint-disable-next-line eslint-rules/eslint-process-env
48
44
  configurator.set_envp(Object.entries(process.env).map(([key, value]) => `${key}=${value}`))
49
45
  configurator.set_args(process.argv)
50
- configurator.get_configuration(localConfig.toString(), fleetConfig.toString()).forEach((entry) => {
46
+ configurator.get_configuration(localConfig, fleetConfig).forEach((entry) => {
51
47
  if (entry.source === 'local_stable_config') {
52
48
  this.localEntries[entry.name] = entry.value
53
49
  } else if (entry.source === 'fleet_stable_config') {
@@ -59,43 +55,35 @@ class StableConfig {
59
55
  }
60
56
  }
61
57
 
62
- _readConfigFromPath (path) {
58
+ #readConfigFromPath (path) {
63
59
  try {
64
60
  return fs.readFileSync(path, 'utf8')
65
61
  } catch (err) {
66
62
  if (err.code !== 'ENOENT') {
67
63
  this.warnings.push(`Error reading config file at ${path}. ${err.code}: ${err.message}`)
68
64
  }
69
- return '' // Always return a string to avoid undefined.toString() errors
65
+ return '' // Always return a string for configurator.get_configuration()
70
66
  }
71
67
  }
72
68
 
73
- _getStableConfigPaths () {
74
- let localConfigPath = ''
75
- let fleetConfigPath = ''
76
- switch (os.type().toLowerCase()) {
77
- case 'linux':
78
- localConfigPath = '/etc/datadog-agent/application_monitoring.yaml'
79
- fleetConfigPath = '/etc/datadog-agent/managed/datadog-agent/stable/application_monitoring.yaml'
80
- break
69
+ #getStableConfigPaths () {
70
+ // TODO(BridgeAR): Remove these environment variables once we have a proper way to test the stable config.
71
+ // Allow overriding the paths for testing
72
+ let localConfigPath = getEnvironmentVariable('DD_TEST_LOCAL_CONFIG_PATH')
73
+ let fleetConfigPath = getEnvironmentVariable('DD_TEST_FLEET_CONFIG_PATH')
74
+ switch (os.platform()) {
81
75
  case 'darwin':
82
- localConfigPath = '/opt/datadog-agent/etc/application_monitoring.yaml'
83
- fleetConfigPath = '/opt/datadog-agent/etc/managed/datadog-agent/stable/application_monitoring.yaml'
76
+ localConfigPath ??= '/opt/datadog-agent/etc/application_monitoring.yaml'
77
+ fleetConfigPath ??= '/opt/datadog-agent/etc/managed/datadog-agent/stable/application_monitoring.yaml'
84
78
  break
85
79
  case 'win32':
86
- localConfigPath = String.raw`C:\ProgramData\Datadog\application_monitoring.yaml`
87
- fleetConfigPath = String.raw`C:\ProgramData\Datadog\managed\datadog-agent\stable\application_monitoring.yaml`
80
+ localConfigPath ??= String.raw`C:\ProgramData\Datadog\application_monitoring.yaml`
81
+ fleetConfigPath ??= String.raw`C:\ProgramData\Datadog\managed\datadog-agent\stable\application_monitoring.yaml`
88
82
  break
89
83
  default:
90
- break
91
- }
92
-
93
- // Allow overriding the paths for testing
94
- if (getEnvironmentVariable('DD_TEST_LOCAL_CONFIG_PATH') !== undefined) {
95
- localConfigPath = getEnvironmentVariable('DD_TEST_LOCAL_CONFIG_PATH')
96
- }
97
- if (getEnvironmentVariable('DD_TEST_FLEET_CONFIG_PATH') !== undefined) {
98
- fleetConfigPath = getEnvironmentVariable('DD_TEST_FLEET_CONFIG_PATH')
84
+ // Linux and other platforms as fallback
85
+ localConfigPath ??= '/etc/datadog-agent/application_monitoring.yaml'
86
+ fleetConfigPath ??= '/etc/datadog-agent/managed/datadog-agent/stable/application_monitoring.yaml'
99
87
  }
100
88
 
101
89
  return { localConfigPath, fleetConfigPath }
@@ -93,6 +93,7 @@
93
93
  "DD_GIT_TAG": ["A"],
94
94
  "DD_GIT_PULL_REQUEST_BASE_BRANCH": ["A"],
95
95
  "DD_GIT_PULL_REQUEST_BASE_BRANCH_SHA": ["A"],
96
+ "DD_GIT_COMMIT_HEAD_SHA": ["A"],
96
97
  "DD_GRPC_CLIENT_ERROR_STATUSES": ["A"],
97
98
  "DD_GRPC_SERVER_ERROR_STATUSES": ["A"],
98
99
  "DD_HEAP_SNAPSHOT_COUNT": ["A"],
@@ -112,6 +113,7 @@
112
113
  "DD_IAST_TELEMETRY_VERBOSITY": ["A"],
113
114
  "DD_INJECT_FORCE": ["A"],
114
115
  "DD_INJECTION_ENABLED": ["A"],
116
+ "DD_ENABLE_NX_SERVICE_NAME": ["A"],
115
117
  "DD_INSTRUMENTATION_CONFIG_ID": ["A"],
116
118
  "DD_INSTRUMENTATION_INSTALL_ID": ["A"],
117
119
  "DD_INSTRUMENTATION_INSTALL_TIME": ["A"],
@@ -7,7 +7,7 @@ const libdatadog = require('@datadog/libdatadog')
7
7
  const binding = libdatadog.load('crashtracker')
8
8
 
9
9
  const log = require('../log')
10
- const defaults = require('../config_defaults')
10
+ const defaults = require('../config/defaults')
11
11
  const pkg = require('../../../../package.json')
12
12
  const processTags = require('../process-tags')
13
13
 
@@ -156,7 +156,7 @@ class DataStreamsProcessor {
156
156
  this.timer = setInterval(this.onInterval.bind(this), flushInterval)
157
157
  this.timer.unref()
158
158
  }
159
- process.once('beforeExit', () => this.onInterval())
159
+ globalThis[Symbol.for('dd-trace')].beforeExitHandlers.add(this.onInterval.bind(this))
160
160
  }
161
161
 
162
162
  onInterval () {
@@ -6,7 +6,7 @@ const pkg = require('../../../../package.json')
6
6
  const log = require('../log')
7
7
  const request = require('../exporters/common/request')
8
8
  const { MsgpackEncoder } = require('../msgpack')
9
- const defaults = require('../config_defaults')
9
+ const defaults = require('../config/defaults')
10
10
 
11
11
  const msgpack = new MsgpackEncoder()
12
12
 
@@ -206,7 +206,7 @@ function isTypedArray (variable) {
206
206
  }
207
207
 
208
208
  function isInstanceOfCoreType (type, variable, fallback = `${variable} instanceof ${type}`) {
209
- return `(process[Symbol.for('datadog:node:util:types')]?.is${type}?.(${variable}) ?? ${fallback})`
209
+ return `(globalThis[Symbol.for('dd-trace')].utilTypes?.is${type}?.(${variable}) ?? ${fallback})`
210
210
  }
211
211
 
212
212
  function getSize (variable) {
@@ -2,7 +2,7 @@
2
2
 
3
3
  const { workerData: { config: parentConfig, parentThreadId, configPort } } = require('node:worker_threads')
4
4
  const { format } = require('node:url')
5
- const defaults = require('../../config_defaults')
5
+ const defaults = require('../../config/defaults')
6
6
  const log = require('./log')
7
7
 
8
8
  const config = module.exports = {
@@ -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
 
@@ -8,7 +8,7 @@ const { URL, format } = require('url')
8
8
  const request = require('./exporters/common/request')
9
9
  const log = require('./log')
10
10
  const Histogram = require('./histogram')
11
- const defaults = require('./config_defaults')
11
+ const defaults = require('./config/defaults')
12
12
 
13
13
  const MAX_BUFFER_SIZE = 1024 // limit from the agent
14
14
 
@@ -360,7 +360,7 @@ class CustomMetrics {
360
360
  // TODO(bengl) this magic number should be configurable
361
361
  setInterval(flush, 10 * 1000).unref()
362
362
 
363
- process.once('beforeExit', flush)
363
+ globalThis[Symbol.for('dd-trace')].beforeExitHandlers.add(flush)
364
364
  }
365
365
 
366
366
  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) {
@@ -2,7 +2,7 @@
2
2
 
3
3
  const { URL, format } = require('url')
4
4
  const log = require('../../log')
5
- const defaults = require('../../config_defaults')
5
+ const defaults = require('../../config/defaults')
6
6
  const Writer = require('./writer')
7
7
 
8
8
  class AgentExporter {
@@ -31,9 +31,7 @@ class AgentExporter {
31
31
  config
32
32
  })
33
33
 
34
- process.once('beforeExit', () => {
35
- this.flush()
36
- })
34
+ globalThis[Symbol.for('dd-trace')].beforeExitHandlers.add(this.flush.bind(this))
37
35
  }
38
36
 
39
37
  setUrl (url) {