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
@@ -13,22 +13,119 @@ const { sendData } = require('./send-data')
13
13
  const { manager: metricsManager } = require('./metrics')
14
14
  const telemetryLogger = require('./logs')
15
15
 
16
+ /**
17
+ * @typedef {Record<string, unknown>} TelemetryPayloadObject
18
+ */
19
+ /**
20
+ * @typedef {string | number | boolean | null | undefined | URL | Record<string, unknown> | unknown[]} ConfigValue
21
+ */
22
+ /**
23
+ * @typedef {{
24
+ * name: string,
25
+ * enabled: boolean,
26
+ * auto_enabled: boolean,
27
+ * process_tags: typeof processTags.tagsObject
28
+ * }} Integration
29
+ */
30
+ /**
31
+ * @typedef {{ _enabled: boolean }} Plugin
32
+ */
33
+ /**
34
+ * @typedef {{ _pluginsByName: Record<string, Plugin> }} PluginManager
35
+ */
36
+ /**
37
+ * @typedef {{
38
+ * service_name: string | undefined,
39
+ * env: string | undefined,
40
+ * service_version: string | undefined,
41
+ * tracer_version: string,
42
+ * language_name: 'nodejs',
43
+ * language_version: string
44
+ * process_tags: typeof processTags.tagsObject
45
+ * }} TelemetryApplication
46
+ */
47
+ /**
48
+ * @typedef {{
49
+ * hostname: string,
50
+ * os: string,
51
+ * architecture: string,
52
+ * os_version?: string,
53
+ * kernel_version?: string,
54
+ * kernel_release?: string,
55
+ * kernel_name?: string
56
+ * }} TelemetryHost
57
+ */
58
+ /**
59
+ * @typedef {{
60
+ * telemetry: {
61
+ * enabled: boolean,
62
+ * heartbeatInterval: number,
63
+ * debug?: boolean,
64
+ * dependencyCollection?: boolean,
65
+ * logCollection?: boolean
66
+ * },
67
+ * service: string | undefined,
68
+ * env: string | undefined,
69
+ * version: string | undefined,
70
+ * tags: Record<string, string>,
71
+ * url?: string | URL,
72
+ * hostname?: string,
73
+ * port?: string | number,
74
+ * site?: string,
75
+ * apiKey?: string,
76
+ * isCiVisibility?: boolean,
77
+ * spanAttributeSchema?: string,
78
+ * installSignature?: { id?: string, time?: string, type?: string },
79
+ * sca?: { enabled?: boolean },
80
+ * appsec: { enabled: boolean, apiSecurity?: {
81
+ * endpointCollectionEnabled?: boolean,
82
+ * endpointCollectionMessageLimit?: number
83
+ * } },
84
+ * profiling: { enabled: boolean | 'true' | 'false' | 'auto' }
85
+ * }} TelemetryConfig
86
+ */
87
+
16
88
  const telemetryStartChannel = dc.channel('datadog:telemetry:start')
17
89
  const telemetryStopChannel = dc.channel('datadog:telemetry:stop')
18
90
  const telemetryAppClosingChannel = dc.channel('datadog:telemetry:app-closing')
19
91
 
92
+ /** @type {TelemetryConfig | undefined} */
20
93
  let config
94
+
95
+ /** @type {PluginManager} */
21
96
  let pluginManager
22
97
 
98
+ /** @type {TelemetryApplication} */
23
99
  let application
24
- let host
25
- let heartbeatTimeout
100
+
101
+ /** @type {TelemetryHost} */
102
+ const host = createHostObject()
103
+
104
+ /** @type {ReturnType<typeof setInterval> | undefined} */
26
105
  let heartbeatInterval
106
+
107
+ /** @type {ReturnType<typeof setInterval> | undefined} */
27
108
  let extendedInterval
109
+
110
+ /** @type {Integration[]} */
28
111
  let integrations
112
+
113
+ /** @type {Map<string, { name: string, value: ConfigValue, origin: string, seq_id: number }>} */
29
114
  const configWithOrigin = new Map()
115
+
116
+ /**
117
+ * Retry information that `telemetry.js` keeps in-memory to be merged into the next payload.
118
+ *
119
+ * @typedef {{ payload: TelemetryPayloadObject, reqType: string }} RetryData
120
+ */
121
+ /** @type {{ payload: TelemetryPayloadObject, reqType: string } | null} */
30
122
  let retryData = null
31
- const extendedHeartbeatPayload = {}
123
+
124
+ /** @type {TelemetryPayloadObject[]} */
125
+ let heartbeatFailedIntegrations = []
126
+
127
+ /** @type {TelemetryPayloadObject[]} */
128
+ let heartbeatFailedDependencies = []
32
129
 
33
130
  const sentIntegrations = new Set()
34
131
 
@@ -38,59 +135,58 @@ function getRetryData () {
38
135
  return retryData
39
136
  }
40
137
 
138
+ /**
139
+ * @param {Error | null | undefined} error
140
+ * @param {import('./send-data').SendDataRetryObject} retryObj
141
+ */
41
142
  function updateRetryData (error, retryObj) {
42
- if (error) {
43
- if (retryObj.reqType === 'message-batch') {
44
- const payload = retryObj.payload[0].payload
45
- const reqType = retryObj.payload[0].request_type
46
- retryData = { payload, reqType }
47
-
48
- // Since this payload failed twice it now gets save in to the extended heartbeat
49
- const failedPayload = retryObj.payload[1].payload
50
- const failedReqType = retryObj.payload[1].request_type
51
-
52
- // save away the dependencies and integration request for extended heartbeat.
53
- if (failedReqType === 'app-integrations-change') {
54
- if (extendedHeartbeatPayload.integrations) {
55
- extendedHeartbeatPayload.integrations.push(failedPayload)
56
- } else {
57
- extendedHeartbeatPayload.integrations = [failedPayload]
58
- }
59
- }
60
- if (failedReqType === 'app-dependencies-loaded') {
61
- if (extendedHeartbeatPayload.dependencies) {
62
- extendedHeartbeatPayload.dependencies.push(failedPayload)
63
- } else {
64
- extendedHeartbeatPayload.dependencies = [failedPayload]
65
- }
66
- }
67
- } else {
68
- retryData = retryObj
69
- }
70
- } else {
143
+ if (!error) {
71
144
  retryData = null
145
+ return
146
+ }
147
+ if (retryObj.reqType !== 'message-batch') {
148
+ retryData = retryObj
149
+ return
150
+ }
151
+
152
+ retryData = {
153
+ payload: retryObj.payload[0].payload,
154
+ reqType: retryObj.payload[0].request_type,
155
+ }
156
+
157
+ // Since this payload failed twice it now gets save in to the extended heartbeat
158
+ const failedPayload = retryObj.payload[1].payload
159
+ const failedReqType = retryObj.payload[1].request_type
160
+
161
+ // save away the dependencies and integration request for extended heartbeat.
162
+ if (failedReqType === 'app-integrations-change') {
163
+ heartbeatFailedIntegrations.push(failedPayload)
164
+ } else if (failedReqType === 'app-dependencies-loaded') {
165
+ heartbeatFailedDependencies.push(failedPayload)
72
166
  }
73
167
  }
74
168
 
75
169
  function getIntegrations () {
76
- const newIntegrations = []
77
- for (const pluginName in pluginManager._pluginsByName) {
78
- if (sentIntegrations.has(pluginName)) {
79
- continue
170
+ const newIntegrations = /** @type {Integration[]} */ ([])
171
+ for (const pluginName of Object.keys(pluginManager._pluginsByName ?? {})) {
172
+ if (!sentIntegrations.has(pluginName)) {
173
+ newIntegrations.push({
174
+ name: pluginName,
175
+ enabled: pluginManager._pluginsByName[pluginName]._enabled,
176
+ auto_enabled: true,
177
+ [processTags.TELEMETRY_FIELD_NAME]: processTags.tagsObject
178
+ })
179
+ sentIntegrations.add(pluginName)
80
180
  }
81
- newIntegrations.push({
82
- name: pluginName,
83
- enabled: pluginManager._pluginsByName[pluginName]._enabled,
84
- auto_enabled: true,
85
- [processTags.TELEMETRY_FIELD_NAME]: processTags.tagsObject
86
- })
87
- sentIntegrations.add(pluginName)
88
181
  }
89
182
  return newIntegrations
90
183
  }
91
184
 
185
+ /**
186
+ * @param {TelemetryConfig} config
187
+ */
92
188
  function getProducts (config) {
93
- const products = {
189
+ return {
94
190
  appsec: {
95
191
  enabled: config.appsec.enabled
96
192
  },
@@ -99,13 +195,11 @@ function getProducts (config) {
99
195
  enabled: profilingEnabledToBoolean(config.profiling.enabled)
100
196
  }
101
197
  }
102
- if (errors.profilingError) {
103
- products.profiler.error = errors.profilingError
104
- errors.profilingError = {}
105
- }
106
- return products
107
198
  }
108
199
 
200
+ /**
201
+ * @param {TelemetryConfig} config
202
+ */
109
203
  function getInstallSignature (config) {
110
204
  const { installSignature: sig } = config
111
205
  if (sig && (sig.id || sig.time || sig.type)) {
@@ -117,6 +211,9 @@ function getInstallSignature (config) {
117
211
  }
118
212
  }
119
213
 
214
+ /**
215
+ * @param {TelemetryConfig} config
216
+ */
120
217
  function appStarted (config) {
121
218
  const app = {
122
219
  products: getProducts(config),
@@ -126,11 +223,10 @@ function appStarted (config) {
126
223
  if (installSignature) {
127
224
  app.install_signature = installSignature
128
225
  }
129
- // TODO: add app.error with correct error codes
130
- // if (errors.agentError) {
131
- // app.error = errors.agentError
132
- // errors.agentError = {}
133
- // }
226
+ if (errors.agentError) {
227
+ app.error = errors.agentError
228
+ errors.agentError = undefined
229
+ }
134
230
  return app
135
231
  }
136
232
 
@@ -147,11 +243,10 @@ function appClosing () {
147
243
  telemetryLogger.send(config, application, host)
148
244
  }
149
245
 
150
- function onBeforeExit () {
151
- process.removeListener('beforeExit', onBeforeExit)
152
- appClosing()
153
- }
154
-
246
+ /**
247
+ * @param {TelemetryConfig} config
248
+ * @returns {TelemetryApplication}
249
+ */
155
250
  function createAppObject (config) {
156
251
  return {
157
252
  service_name: config.service,
@@ -164,50 +259,55 @@ function createAppObject (config) {
164
259
  }
165
260
  }
166
261
 
262
+ /**
263
+ * @returns {TelemetryHost}
264
+ */
167
265
  function createHostObject () {
168
266
  const osName = os.type()
169
-
170
- if (osName === 'Linux' || osName === 'Darwin') {
171
- return {
172
- hostname: os.hostname(),
173
- os: osName,
174
- architecture: os.arch(),
175
- kernel_version: os.version(),
176
- kernel_release: os.release(),
177
- kernel_name: osName
178
- }
267
+ const base = {
268
+ hostname: os.hostname(),
269
+ os: osName,
270
+ architecture: os.arch(),
179
271
  }
180
272
 
181
- if (osName === 'Windows_NT') {
182
- return {
183
- hostname: os.hostname(),
184
- os: osName,
185
- architecture: os.arch(),
186
- os_version: os.version()
187
- }
273
+ if (os.platform() === 'win32') {
274
+ base.os_version = os.version() // Optional
275
+ } else {
276
+ base.kernel_version = os.version()
277
+ base.kernel_release = os.release()
278
+ base.kernel_name = osName
188
279
  }
189
280
 
190
- return {
191
- hostname: os.hostname(), // TODO is this enough?
192
- os: osName
193
- }
281
+ return base
194
282
  }
195
283
 
196
284
  function getTelemetryData () {
197
- return { config, application, host, heartbeatInterval }
285
+ return { config, application, host, heartbeatInterval: config?.telemetry.heartbeatInterval }
198
286
  }
199
287
 
288
+ /**
289
+ * @param {{ reqType: string, payload: TelemetryPayloadObject }[]} payload
290
+ */
200
291
  function createBatchPayload (payload) {
201
- const batchPayload = payload.map(item => {
292
+ return payload.map(item => {
202
293
  return {
203
294
  request_type: item.reqType,
204
295
  payload: item.payload
205
296
  }
206
297
  })
207
-
208
- return batchPayload
209
298
  }
210
299
 
300
+ /**
301
+ * @param {import('./send-data').NonBatchTelemetryRequestType} currReqType
302
+ * @param {TelemetryPayloadObject} [currPayload]
303
+ * @returns {{
304
+ * reqType: 'message-batch',
305
+ * payload: import('./send-data').MessageBatchPayload
306
+ * } | {
307
+ * reqType: import('./send-data').NonBatchTelemetryRequestType,
308
+ * payload: TelemetryPayloadObject
309
+ * }}
310
+ */
211
311
  function createPayload (currReqType, currPayload = {}) {
212
312
  if (getRetryData()) {
213
313
  const payload = { reqType: currReqType, payload: currPayload }
@@ -218,31 +318,42 @@ function createPayload (currReqType, currPayload = {}) {
218
318
  return { reqType: currReqType, payload: currPayload }
219
319
  }
220
320
 
221
- function heartbeat (config, application, host) {
222
- heartbeatTimeout = setTimeout(() => {
321
+ /**
322
+ * @param {TelemetryConfig} config
323
+ * @param {TelemetryApplication} application
324
+ */
325
+ function heartbeat (config, application) {
326
+ heartbeatInterval = setInterval(() => {
223
327
  metricsManager.send(config, application, host)
224
328
  telemetryLogger.send(config, application, host)
225
329
 
226
330
  const { reqType, payload } = createPayload('app-heartbeat')
227
331
  sendData(config, application, host, reqType, payload, updateRetryData)
228
- heartbeat(config, application, host)
229
- }, heartbeatInterval).unref()
230
- return heartbeatTimeout
332
+ }, config.telemetry.heartbeatInterval).unref()
231
333
  }
232
334
 
335
+ /**
336
+ * @param {TelemetryConfig} config
337
+ */
233
338
  function extendedHeartbeat (config) {
234
339
  extendedInterval = setInterval(() => {
235
340
  const appPayload = appStarted(config)
236
- const payload = {
237
- ...appPayload,
238
- ...extendedHeartbeatPayload
341
+ if (heartbeatFailedIntegrations.length > 0) {
342
+ appPayload.integrations = heartbeatFailedIntegrations
343
+ heartbeatFailedIntegrations = []
344
+ }
345
+ if (heartbeatFailedDependencies.length > 0) {
346
+ appPayload.dependencies = heartbeatFailedDependencies
347
+ heartbeatFailedDependencies = []
239
348
  }
240
- sendData(config, application, host, 'app-extended-heartbeat', payload)
241
- Object.keys(extendedHeartbeatPayload).forEach(key => delete extendedHeartbeatPayload[key])
349
+ sendData(config, application, host, 'app-extended-heartbeat', appPayload)
242
350
  }, 1000 * 60 * 60 * 24).unref()
243
- return extendedInterval
244
351
  }
245
352
 
353
+ /**
354
+ * @param {TelemetryConfig} aConfig
355
+ * @param {PluginManager} thePluginManager
356
+ */
246
357
  function start (aConfig, thePluginManager) {
247
358
  if (!aConfig.telemetry.enabled) {
248
359
  if (aConfig.sca?.enabled) {
@@ -254,8 +365,6 @@ function start (aConfig, thePluginManager) {
254
365
  config = aConfig
255
366
  pluginManager = thePluginManager
256
367
  application = createAppObject(config)
257
- host = createHostObject()
258
- heartbeatInterval = config.telemetry.heartbeatInterval
259
368
  integrations = getIntegrations()
260
369
 
261
370
  dependencies.start(config, application, host, getRetryData, updateRetryData)
@@ -269,11 +378,11 @@ function start (aConfig, thePluginManager) {
269
378
  { integrations }, updateRetryData)
270
379
  }
271
380
 
272
- heartbeat(config, application, host)
381
+ heartbeat(config, application)
273
382
 
274
383
  extendedHeartbeat(config)
275
384
 
276
- process.on('beforeExit', onBeforeExit)
385
+ globalThis[Symbol.for('dd-trace')].beforeExitHandlers.add(appClosing)
277
386
  telemetryStartChannel.publish(getTelemetryData())
278
387
  }
279
388
 
@@ -282,8 +391,8 @@ function stop () {
282
391
  return
283
392
  }
284
393
  clearInterval(extendedInterval)
285
- clearTimeout(heartbeatTimeout)
286
- process.removeListener('beforeExit', onBeforeExit)
394
+ clearInterval(heartbeatInterval)
395
+ globalThis[Symbol.for('dd-trace')].beforeExitHandlers.delete(appClosing)
287
396
 
288
397
  telemetryStopChannel.publish(getTelemetryData())
289
398
 
@@ -305,6 +414,9 @@ function updateIntegrations () {
305
414
  sendData(config, application, host, reqType, payload, updateRetryData)
306
415
  }
307
416
 
417
+ /**
418
+ * @param {Record<string, string | number | boolean> | null | undefined} map
419
+ */
308
420
  function formatMapForTelemetry (map) {
309
421
  // format from an object to a string map in order for
310
422
  // telemetry intake to accept the configuration
@@ -359,6 +471,10 @@ const nameMapping = {
359
471
 
360
472
  const namesNeedFormatting = new Set(['DD_TAGS', 'peerServiceMapping', 'serviceMapping'])
361
473
 
474
+ /**
475
+ * @param {{ name: string, value: ConfigValue, origin: string }[]} changes
476
+ * @param {TelemetryConfig} config
477
+ */
362
478
  function updateConfig (changes, config) {
363
479
  if (!config.telemetry.enabled) return
364
480
  if (changes.length === 0) return
@@ -366,7 +482,6 @@ function updateConfig (changes, config) {
366
482
  logger.trace(changes)
367
483
 
368
484
  const application = createAppObject(config)
369
- const host = createHostObject()
370
485
 
371
486
  const changed = configWithOrigin.size > 0
372
487
 
@@ -375,15 +490,16 @@ function updateConfig (changes, config) {
375
490
  const { origin, value } = change
376
491
  const entry = { name, value, origin, seq_id: seqId++ }
377
492
 
378
- if (namesNeedFormatting.has(entry.name)) {
379
- entry.value = formatMapForTelemetry(entry.value)
380
- } else if (entry.name === 'url') {
381
- if (entry.value) {
382
- entry.value = entry.value.toString()
493
+ if (namesNeedFormatting.has(name)) {
494
+ // @ts-expect-error entry.value is known to be a map for these config names
495
+ entry.value = formatMapForTelemetry(value)
496
+ } else if (name === 'url') {
497
+ if (value) {
498
+ entry.value = value.toString()
383
499
  }
384
- } else if (entry.name === 'DD_TRACE_SAMPLING_RULES') {
385
- entry.value = JSON.stringify(entry.value)
386
- } else if (Array.isArray(entry.value)) {
500
+ } else if (name === 'DD_TRACE_SAMPLING_RULES') {
501
+ entry.value = JSON.stringify(value)
502
+ } else if (Array.isArray(value)) {
387
503
  entry.value = value.join(',')
388
504
  }
389
505
 
@@ -400,6 +516,9 @@ function updateConfig (changes, config) {
400
516
  }
401
517
  }
402
518
 
519
+ /**
520
+ * @param {TelemetryConfig['profiling']['enabled']} profilingEnabled
521
+ */
403
522
  function profilingEnabledToBoolean (profilingEnabled) {
404
523
  if (typeof profilingEnabled === 'boolean') {
405
524
  return profilingEnabled