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
@@ -7,8 +7,8 @@ const Module = require('module')
7
7
  const dc = require('dc-polyfill')
8
8
 
9
9
  const parse = require('../../../vendor/dist/module-details-from-path')
10
- const { getEnvironmentVariable } = require('../../dd-trace/src/config-helper')
11
10
  const { isRelativeRequire } = require('../../datadog-instrumentations/src/helpers/shared-utils')
11
+ const { getEnvironmentVariable, getValueFromEnvSources } = require('./config/helper')
12
12
 
13
13
  const origRequire = Module.prototype.require
14
14
  // derived from require-in-the-middle@3 with tweaks
@@ -63,6 +63,7 @@ function Hook (modules, options, onrequire) {
63
63
  */
64
64
  let filename
65
65
  try {
66
+ // @ts-expect-error Module._resolveFilename is not typed
66
67
  filename = Module._resolveFilename(request, this)
67
68
  } catch {
68
69
  return _origRequire.apply(this, arguments)
@@ -71,9 +72,10 @@ function Hook (modules, options, onrequire) {
71
72
  let name, basedir, hooks
72
73
  // return known patched modules immediately
73
74
  if (cache[filename]) {
75
+ const externalCacheEntry = require.cache[filename]
74
76
  // require.cache was potentially altered externally
75
- if (require.cache[filename] && require.cache[filename].exports !== cache[filename].original) {
76
- return require.cache[filename].exports
77
+ if (externalCacheEntry && externalCacheEntry.exports !== cache[filename].original) {
78
+ return externalCacheEntry.exports
77
79
  }
78
80
 
79
81
  return cache[filename].exports
@@ -113,7 +115,7 @@ function Hook (modules, options, onrequire) {
113
115
  name = filename
114
116
  } else {
115
117
  const inAWSLambda = getEnvironmentVariable('AWS_LAMBDA_FUNCTION_NAME') !== undefined
116
- const hasLambdaHandler = getEnvironmentVariable('DD_LAMBDA_HANDLER') !== undefined
118
+ const hasLambdaHandler = getValueFromEnvSources('DD_LAMBDA_HANDLER') !== undefined
117
119
  const segments = filename.split(path.sep)
118
120
  const filenameFromNodeModule = segments.includes('node_modules')
119
121
  // decide how to assign the stat
@@ -127,6 +129,7 @@ function Hook (modules, options, onrequire) {
127
129
  hooks = moduleHooks[name]
128
130
  if (!hooks) return exports // abort if module name isn't on whitelist
129
131
 
132
+ // @ts-expect-error Module._resolveLookupPaths is not typed
130
133
  const paths = Module._resolveLookupPaths(name, this, true)
131
134
  if (!paths) {
132
135
  // abort if _resolveLookupPaths return null
@@ -135,6 +138,7 @@ function Hook (modules, options, onrequire) {
135
138
 
136
139
  let res
137
140
  try {
141
+ // @ts-expect-error Module._findPath is not typed
138
142
  res = Module._findPath(name, [basedir, ...paths])
139
143
  } catch {
140
144
  // case where the file specified in package.json "main" doesn't exist
@@ -8,12 +8,12 @@ const process = require('process')
8
8
  const { performance, PerformanceObserver, monitorEventLoopDelay } = require('perf_hooks')
9
9
  const { DogStatsDClient, MetricsAggregationClient } = require('../dogstatsd')
10
10
  const log = require('../log')
11
- const { getEnvironmentVariable } = require('../config-helper')
11
+ const { getValueFromEnvSources } = require('../config/helper')
12
12
 
13
13
  const { NODE_MAJOR } = require('../../../../version')
14
14
  // TODO: This environment variable may not be changed, since the agent expects a flush every ten seconds.
15
15
  // It is only a variable for testing. Think about alternatives.
16
- const DD_RUNTIME_METRICS_FLUSH_INTERVAL = getEnvironmentVariable('DD_RUNTIME_METRICS_FLUSH_INTERVAL') ?? '10000'
16
+ const DD_RUNTIME_METRICS_FLUSH_INTERVAL = getValueFromEnvSources('DD_RUNTIME_METRICS_FLUSH_INTERVAL') ?? '10000'
17
17
  const INTERVAL = Number.parseInt(DD_RUNTIME_METRICS_FLUSH_INTERVAL, 10)
18
18
 
19
19
  const eventLoopDelayResolution = 4
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const { getEnvironmentVariable } = require('./config-helper')
3
+ const { getEnvironmentVariable, getValueFromEnvSources } = require('./config/helper')
4
4
  const { isFalse } = require('./util')
5
5
 
6
6
  function getIsGCPFunction () {
@@ -19,7 +19,7 @@ function getIsGCPFunction () {
19
19
  * PUSH: GCP sends HTTP POST requests to the service with message data in headers.
20
20
  */
21
21
  function enableGCPPubSubPushSubscription () {
22
- const isGCPPubSubPushSubscriptionEnabled = getEnvironmentVariable('DD_TRACE_GCP_PUBSUB_PUSH_ENABLED')
22
+ const isGCPPubSubPushSubscriptionEnabled = getValueFromEnvSources('DD_TRACE_GCP_PUBSUB_PUSH_ENABLED')
23
23
  return getEnvironmentVariable('K_SERVICE') !== undefined && !isFalse(isGCPPubSubPushSubscriptionEnabled)
24
24
  }
25
25
 
@@ -4,8 +4,8 @@ const log = require('./log')
4
4
  const spanFormat = require('./span_format')
5
5
  const SpanSampler = require('./span_sampler')
6
6
  const GitMetadataTagger = require('./git_metadata_tagger')
7
- const { getEnvironmentVariable } = require('./config-helper')
8
7
  const processTags = require('./process-tags')
8
+ const { getValueFromEnvSources } = require('./config/helper')
9
9
 
10
10
  const startedSpans = new WeakSet()
11
11
  const finishedSpans = new WeakSet()
@@ -88,7 +88,7 @@ class SpanProcessor {
88
88
  }
89
89
 
90
90
  _erase (trace, active) {
91
- if (getEnvironmentVariable('DD_TRACE_EXPERIMENTAL_STATE_TRACKING') === 'true') {
91
+ if (getValueFromEnvSources('DD_TRACE_EXPERIMENTAL_STATE_TRACKING') === 'true') {
92
92
  const started = new Set()
93
93
  const startedIds = new Set()
94
94
  const finished = new Set()
@@ -2,9 +2,8 @@
2
2
 
3
3
  const os = require('os')
4
4
  const { inspect } = require('util')
5
-
6
5
  const tracerVersion = require('../../../package.json').version
7
- const defaults = require('./config_defaults')
6
+ const defaults = require('./config/defaults')
8
7
  const { info, warn } = require('./log/writer')
9
8
 
10
9
  const errors = {}
@@ -15,23 +14,15 @@ let samplingRules = []
15
14
  let alreadyRan = false
16
15
 
17
16
  /**
18
- * @param {{ agentError: { code: string, message: string } }} [options]
17
+ * @param {{ status: number, message: string } } [agentError]
19
18
  */
20
- function startupLog ({ agentError } = {}) {
21
- if (!config || !pluginManager) {
22
- return
23
- }
24
-
25
- if (alreadyRan) {
19
+ function startupLog (agentError) {
20
+ if (alreadyRan || !config || !config.startupLogs || !pluginManager) {
26
21
  return
27
22
  }
28
23
 
29
24
  alreadyRan = true
30
25
 
31
- if (!config.startupLogs) {
32
- return
33
- }
34
-
35
26
  const out = tracerInfo()
36
27
 
37
28
  if (agentError) {
@@ -42,8 +33,8 @@ function startupLog ({ agentError } = {}) {
42
33
  if (agentError) {
43
34
  warn('DATADOG TRACER DIAGNOSTIC - Agent Error: ' + agentError.message)
44
35
  errors.agentError = {
45
- code: agentError.code ?? '',
46
- message: `Agent Error:${agentError.message}`
36
+ code: agentError.status,
37
+ message: `Agent Error: ${agentError.message}`
47
38
  }
48
39
  }
49
40
  }
@@ -3,35 +3,75 @@
3
3
  const dc = require('dc-polyfill')
4
4
  const { sendData } = require('./send-data')
5
5
 
6
+ /**
7
+ * RetryData is information that `telemetry.js` keeps in-memory to be merged into the next payload.
8
+ *
9
+ * @callback GetRetryData
10
+ * @returns {{ payload: Record<string, unknown>, reqType: string } | null}
11
+ */
12
+ /**
13
+ * @typedef {import('./send-data').TelemetryConfig & {
14
+ * appsec?: { apiSecurity?: { endpointCollectionEnabled?: boolean, endpointCollectionMessageLimit?: number } }
15
+ * }} TelemetryConfig
16
+ */
17
+
6
18
  const fastifyRouteCh = dc.channel('apm:fastify:route:added')
7
19
  const expressRouteCh = dc.channel('apm:express:route:added')
8
20
  const routerRouteCh = dc.channel('apm:router:route:added')
9
21
 
22
+ /** @type {TelemetryConfig} */
10
23
  let config
24
+
25
+ /** @type {import('./send-data').TelemetryApplication} */
11
26
  let application
27
+
28
+ /** @type {import('./send-data').TelemetryHost} */
12
29
  let host
30
+
31
+ /** @type {GetRetryData} */
13
32
  let getRetryData
33
+
34
+ /** @type {import('./send-data').SendDataCallback} */
14
35
  let updateRetryData
15
36
 
16
37
  /**
17
38
  * Keep track of endpoints that still need to be sent.
18
39
  * Map key is `${METHOD} ${PATH}`, value is { method, path, operationName }
19
40
  */
41
+ /** @type {Map<string, { method: string, path: string, operationName: string }>} */
20
42
  const pendingEndpoints = new Map()
43
+
44
+ /** @type {Set<string>} */
21
45
  const wildcardEndpoints = new Set()
22
46
  let flushScheduled = false
23
47
  let isFirstPayload = true
24
48
 
49
+ /**
50
+ * @param {string} method
51
+ * @param {string} path
52
+ * @returns {string}
53
+ */
25
54
  function endpointKey (method, path) {
26
55
  return `${method.toUpperCase()} ${path}`
27
56
  }
28
57
 
58
+ /**
59
+ * @returns {void}
60
+ */
29
61
  function scheduleFlush () {
30
62
  if (flushScheduled) return
31
63
  flushScheduled = true
32
- setImmediate(flushAndSend).unref()
64
+ // this used to be setImmediate() instead, but it was making the system test flaky
65
+ // don't ask me why
66
+ setTimeout(flushAndSend).unref()
33
67
  }
34
68
 
69
+ /**
70
+ * @param {string} method
71
+ * @param {string} path
72
+ * @param {string} operationName
73
+ * @returns {void}
74
+ */
35
75
  function recordEndpoint (method, path, operationName) {
36
76
  const key = endpointKey(method, path)
37
77
  if (pendingEndpoints.has(key)) return
@@ -40,6 +80,9 @@ function recordEndpoint (method, path, operationName) {
40
80
  scheduleFlush()
41
81
  }
42
82
 
83
+ /**
84
+ * @param {{ routeOptions?: { path?: string, method: string | string[] } } | null | undefined} routeData
85
+ */
43
86
  function onFastifyRoute (routeData) {
44
87
  const routeOptions = routeData?.routeOptions
45
88
  if (!routeOptions?.path) return
@@ -50,6 +93,9 @@ function onFastifyRoute (routeData) {
50
93
  }
51
94
  }
52
95
 
96
+ /**
97
+ * @param {{ method?: string, path?: string }} param0
98
+ */
53
99
  function onExpressRoute ({ method, path }) {
54
100
  if (!method || !path) return
55
101
 
@@ -70,6 +116,9 @@ function onExpressRoute ({ method, path }) {
70
116
  }
71
117
  }
72
118
 
119
+ /**
120
+ * @param {{ method: string, path: string, operationName: string }[]} endpoints
121
+ */
73
122
  function buildEndpointObjects (endpoints) {
74
123
  return endpoints.map(({ method, path, operationName }) => {
75
124
  return {
@@ -82,6 +131,9 @@ function buildEndpointObjects (endpoints) {
82
131
  })
83
132
  }
84
133
 
134
+ /**
135
+ * @returns {void}
136
+ */
85
137
  function flushAndSend () {
86
138
  flushScheduled = false
87
139
  if (pendingEndpoints.size === 0) return
@@ -90,7 +142,8 @@ function flushAndSend () {
90
142
  for (const [key, endpoint] of pendingEndpoints) {
91
143
  batchEndpoints.push(endpoint)
92
144
  pendingEndpoints.delete(key)
93
- if (batchEndpoints.length >= config.appsec?.apiSecurity?.endpointCollectionMessageLimit) break
145
+ // Config is set when endpoint collection is enabled; message limit is optional
146
+ if (batchEndpoints.length >= (config.appsec?.apiSecurity?.endpointCollectionMessageLimit ?? 0)) break
94
147
  }
95
148
 
96
149
  const payloadObj = {
@@ -98,7 +151,10 @@ function flushAndSend () {
98
151
  endpoints: buildEndpointObjects(batchEndpoints)
99
152
  }
100
153
 
154
+ /** @type {import('./send-data').TelemetryRequestType} */
101
155
  let reqType = 'app-endpoints'
156
+
157
+ /** @type {import('./send-data').TelemetryPayload} */
102
158
  let payload = payloadObj
103
159
 
104
160
  const retryData = getRetryData()
@@ -120,8 +176,15 @@ function flushAndSend () {
120
176
  if (pendingEndpoints.size) scheduleFlush()
121
177
  }
122
178
 
123
- function start (_config = {}, _application, _host, getRetryDataFunction, updateRetryDataFunction) {
124
- if (!_config?.appsec?.apiSecurity?.endpointCollectionEnabled) return
179
+ /**
180
+ * @param {TelemetryConfig} _config
181
+ * @param {import('./send-data').TelemetryApplication} _application
182
+ * @param {import('./send-data').TelemetryHost} _host
183
+ * @param {GetRetryData} getRetryDataFunction
184
+ * @param {import('./send-data').SendDataCallback} updateRetryDataFunction
185
+ */
186
+ function start (_config, _application, _host, getRetryDataFunction, updateRetryDataFunction) {
187
+ if (!_config.appsec?.apiSecurity?.endpointCollectionEnabled) return
125
188
 
126
189
  config = _config
127
190
  application = _application
@@ -141,7 +204,6 @@ function stop () {
141
204
 
142
205
  pendingEndpoints.clear()
143
206
  flushScheduled = false
144
- config = application = host = getRetryData = updateRetryData = null
145
207
  }
146
208
 
147
209
  module.exports = {
@@ -3,10 +3,93 @@
3
3
  const request = require('../exporters/common/request')
4
4
  const log = require('../log')
5
5
  const { isTrue } = require('../util')
6
- const { getEnvironmentVariable } = require('../config-helper')
6
+ const { getValueFromEnvSources } = require('../config/helper')
7
+
8
+ /**
9
+ * @typedef {Record<string, unknown>} TelemetryPayloadObject
10
+ */
11
+ /**
12
+ * Telemetry "request_type" values sent by this library.
13
+ *
14
+ * @typedef {'app-started'
15
+ * | 'app-integrations-change'
16
+ * | 'app-heartbeat'
17
+ * | 'app-extended-heartbeat'
18
+ * | 'app-client-configuration-change'
19
+ * | 'app-closing'
20
+ * | 'app-dependencies-loaded'
21
+ * | 'app-endpoints'
22
+ * | 'generate-metrics'
23
+ * | 'distributions'
24
+ * | 'logs'
25
+ * | 'message-batch'} TelemetryRequestType
26
+ */
27
+ /**
28
+ * @typedef {{ request_type: string, payload: TelemetryPayloadObject }} MessageBatchItem
29
+ */
30
+ /**
31
+ * @typedef {MessageBatchItem[]} MessageBatchPayload
32
+ */
33
+ /**
34
+ * Telemetry payloads are usually single objects, but some request types (e.g. `message-batch`)
35
+ * send arrays.
36
+ *
37
+ * @typedef {TelemetryPayloadObject | MessageBatchPayload} TelemetryPayload
38
+ */
39
+ /**
40
+ * @typedef {{language_name: string, tracer_version: string} & Record<string, unknown>} TelemetryApplication
41
+ */
42
+ /**
43
+ * @typedef {Exclude<TelemetryRequestType, 'message-batch'>} NonBatchTelemetryRequestType
44
+ */
45
+ /**
46
+ * @typedef {{
47
+ * payload: TelemetryPayloadObject,
48
+ * reqType: NonBatchTelemetryRequestType
49
+ * } | {
50
+ * payload: MessageBatchPayload,
51
+ * reqType: 'message-batch'
52
+ * }} SendDataRetryObject
53
+ */
54
+ /**
55
+ * @typedef {{
56
+ * hostname: string,
57
+ * os: string,
58
+ * architecture: string,
59
+ * os_version?: string,
60
+ * kernel_version?: string,
61
+ * kernel_release?: string,
62
+ * kernel_name?: string
63
+ * } & Record<string, unknown>} TelemetryHost
64
+ */
65
+ /**
66
+ * @typedef {{
67
+ * hostname?: string,
68
+ * port?: string | number,
69
+ * url?: string | URL,
70
+ * site?: string,
71
+ * apiKey?: string,
72
+ * isCiVisibility?: boolean,
73
+ * spanAttributeSchema?: string,
74
+ * tags: Record<string, string>,
75
+ * telemetry?: { debug?: boolean }
76
+ * }} TelemetryConfig
77
+ */
78
+ /**
79
+ * @callback SendDataCallback
80
+ * @param {Error | null | undefined} error
81
+ * @param {SendDataRetryObject} retryObj
82
+ * @returns {void}
83
+ */
7
84
 
8
85
  let agentTelemetry = true
9
86
 
87
+ /**
88
+ * @param {TelemetryConfig} config
89
+ * @param {TelemetryApplication} application
90
+ * @param {TelemetryRequestType} reqType
91
+ * @returns {Record<string, string>}
92
+ */
10
93
  function getHeaders (config, application, reqType) {
11
94
  const headers = {
12
95
  'content-type': 'application/json',
@@ -25,6 +108,9 @@ function getHeaders (config, application, reqType) {
25
108
  return headers
26
109
  }
27
110
 
111
+ /**
112
+ * @param {string | undefined} site
113
+ */
28
114
  function getAgentlessTelemetryEndpoint (site) {
29
115
  if (site === 'datad0g.com') { // staging
30
116
  return 'https://all-http-intake.logs.datad0g.com'
@@ -34,6 +120,10 @@ function getAgentlessTelemetryEndpoint (site) {
34
120
 
35
121
  let seqId = 0
36
122
 
123
+ /**
124
+ * @param {TelemetryPayload} payload
125
+ * @returns {TelemetryPayload}
126
+ */
37
127
  function getPayload (payload) {
38
128
  // Some telemetry endpoints payloads accept collections of elements such as the 'logs' endpoint.
39
129
  // 'logs' request type payload is meant to send library logs to Datadog’s backend.
@@ -44,6 +134,15 @@ function getPayload (payload) {
44
134
  return trimmedPayload
45
135
  }
46
136
 
137
+ // TODO(BridgeAR): Simplify this code. A lot does not need to be recalculated on every call.
138
+ /**
139
+ * @param {TelemetryConfig} config
140
+ * @param {TelemetryApplication} application
141
+ * @param {TelemetryHost} host
142
+ * @param {TelemetryRequestType} reqType
143
+ * @param {TelemetryPayload} [payload]
144
+ * @param {SendDataCallback} [cb]
145
+ */
47
146
  function sendData (config, application, host, reqType, payload = {}, cb = () => {}) {
48
147
  const {
49
148
  hostname,
@@ -54,7 +153,7 @@ function sendData (config, application, host, reqType, payload = {}, cb = () =>
54
153
  let url = config.url
55
154
 
56
155
  const isCiVisibilityAgentlessMode = isCiVisibility &&
57
- isTrue(getEnvironmentVariable('DD_CIVISIBILITY_AGENTLESS_ENABLED'))
156
+ isTrue(getValueFromEnvSources('DD_CIVISIBILITY_AGENTLESS_ENABLED'))
58
157
 
59
158
  if (isCiVisibilityAgentlessMode) {
60
159
  try {
@@ -88,14 +187,14 @@ function sendData (config, application, host, reqType, payload = {}, cb = () =>
88
187
  })
89
188
 
90
189
  request(data, options, (error) => {
91
- if (error && getEnvironmentVariable('DD_API_KEY') && config.site) {
190
+ if (error && getValueFromEnvSources('DD_API_KEY') && config.site) {
92
191
  if (agentTelemetry) {
93
192
  log.warn('Agent telemetry failed, started agentless telemetry')
94
193
  agentTelemetry = false
95
194
  }
96
195
  // figure out which data center to send to
97
196
  const backendUrl = getAgentlessTelemetryEndpoint(config.site)
98
- const backendHeader = { ...options.headers, 'DD-API-KEY': getEnvironmentVariable('DD_API_KEY') }
197
+ const backendHeader = { ...options.headers, 'DD-API-KEY': getValueFromEnvSources('DD_API_KEY') }
99
198
  const backendOptions = {
100
199
  ...options,
101
200
  url: backendUrl,