dd-trace 5.96.0 → 5.98.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 (173) hide show
  1. package/index.d.ts +60 -2
  2. package/package.json +9 -7
  3. package/packages/datadog-esbuild/index.js +20 -9
  4. package/packages/datadog-instrumentations/src/child_process.js +7 -17
  5. package/packages/datadog-instrumentations/src/crypto.js +1 -2
  6. package/packages/datadog-instrumentations/src/cucumber.js +69 -4
  7. package/packages/datadog-instrumentations/src/cypress-config.js +318 -0
  8. package/packages/datadog-instrumentations/src/cypress.js +86 -4
  9. package/packages/datadog-instrumentations/src/dns.js +1 -2
  10. package/packages/datadog-instrumentations/src/express.js +4 -4
  11. package/packages/datadog-instrumentations/src/fs.js +27 -29
  12. package/packages/datadog-instrumentations/src/graphql.js +1 -1
  13. package/packages/datadog-instrumentations/src/helpers/bundler-register.js +41 -13
  14. package/packages/datadog-instrumentations/src/helpers/hook.js +31 -6
  15. package/packages/datadog-instrumentations/src/helpers/hooks.js +12 -19
  16. package/packages/datadog-instrumentations/src/helpers/instrument.js +27 -13
  17. package/packages/datadog-instrumentations/src/helpers/register.js +103 -142
  18. package/packages/datadog-instrumentations/src/http/client.js +2 -3
  19. package/packages/datadog-instrumentations/src/http/server.js +2 -5
  20. package/packages/datadog-instrumentations/src/http2/client.js +1 -3
  21. package/packages/datadog-instrumentations/src/http2/server.js +1 -3
  22. package/packages/datadog-instrumentations/src/jest.js +117 -16
  23. package/packages/datadog-instrumentations/src/limitd-client.js +1 -1
  24. package/packages/datadog-instrumentations/src/mocha/utils.js +12 -1
  25. package/packages/datadog-instrumentations/src/net.js +2 -8
  26. package/packages/datadog-instrumentations/src/pino.js +1 -1
  27. package/packages/datadog-instrumentations/src/playwright.js +4 -1
  28. package/packages/datadog-instrumentations/src/prisma.js +1 -2
  29. package/packages/datadog-instrumentations/src/redis.js +12 -6
  30. package/packages/datadog-instrumentations/src/selenium.js +4 -1
  31. package/packages/datadog-instrumentations/src/sequelize.js +1 -1
  32. package/packages/datadog-instrumentations/src/url.js +1 -3
  33. package/packages/datadog-instrumentations/src/vitest.js +5 -1
  34. package/packages/datadog-instrumentations/src/vm.js +1 -3
  35. package/packages/datadog-plugin-aws-sdk/src/base.js +5 -4
  36. package/packages/datadog-plugin-aws-sdk/src/services/dynamodb.js +1 -0
  37. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +1 -0
  38. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +1 -0
  39. package/packages/datadog-plugin-aws-sdk/src/services/redshift.js +1 -0
  40. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +1 -0
  41. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +1 -0
  42. package/packages/datadog-plugin-cucumber/src/index.js +13 -3
  43. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +166 -6
  44. package/packages/datadog-plugin-cypress/src/index.js +59 -2
  45. package/packages/datadog-plugin-fs/src/index.js +1 -1
  46. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +2 -1
  47. package/packages/datadog-plugin-google-cloud-pubsub/src/pubsub-push-subscription.js +2 -7
  48. package/packages/datadog-plugin-graphql/src/resolve.js +1 -1
  49. package/packages/datadog-plugin-http/src/client.js +1 -1
  50. package/packages/datadog-plugin-http/src/server.js +10 -2
  51. package/packages/datadog-plugin-http2/src/client.js +1 -1
  52. package/packages/datadog-plugin-http2/src/server.js +10 -2
  53. package/packages/datadog-plugin-jest/src/index.js +4 -2
  54. package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +31 -4
  55. package/packages/datadog-plugin-mocha/src/index.js +5 -2
  56. package/packages/datadog-plugin-mongodb-core/src/index.js +3 -3
  57. package/packages/datadog-plugin-mysql/src/index.js +1 -1
  58. package/packages/datadog-plugin-next/src/index.js +10 -16
  59. package/packages/datadog-plugin-openai/src/services.js +1 -0
  60. package/packages/datadog-plugin-pg/src/index.js +1 -1
  61. package/packages/datadog-plugin-tedious/src/index.js +1 -1
  62. package/packages/datadog-plugin-ws/src/close.js +1 -1
  63. package/packages/datadog-plugin-ws/src/receiver.js +1 -1
  64. package/packages/datadog-webpack/index.js +3 -3
  65. package/packages/dd-trace/index.js +12 -10
  66. package/packages/dd-trace/src/agent/url.js +2 -2
  67. package/packages/dd-trace/src/aiguard/sdk.js +26 -22
  68. package/packages/dd-trace/src/appsec/blocked_templates.js +4 -3
  69. package/packages/dd-trace/src/appsec/blocking.js +64 -33
  70. package/packages/dd-trace/src/appsec/iast/iast-plugin.js +1 -1
  71. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +1 -1
  72. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +1 -1
  73. package/packages/dd-trace/src/appsec/remote_config.js +1 -0
  74. package/packages/dd-trace/src/appsec/sdk/index.js +4 -0
  75. package/packages/dd-trace/src/appsec/sdk/set_user.js +1 -1
  76. package/packages/dd-trace/src/appsec/sdk/track_event.js +5 -5
  77. package/packages/dd-trace/src/appsec/sdk/user_blocking.js +2 -2
  78. package/packages/dd-trace/src/appsec/sdk/utils.js +4 -2
  79. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +6 -1
  80. package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +4 -0
  81. package/packages/dd-trace/src/config/defaults.js +315 -146
  82. package/packages/dd-trace/src/config/generated-config-types.d.ts +9 -1
  83. package/packages/dd-trace/src/config/helper.js +59 -10
  84. package/packages/dd-trace/src/config/index.js +587 -1496
  85. package/packages/dd-trace/src/config/parsers.js +256 -0
  86. package/packages/dd-trace/src/config/remote_config.js +59 -2
  87. package/packages/dd-trace/src/config/supported-configurations.json +406 -432
  88. package/packages/dd-trace/src/constants.js +1 -0
  89. package/packages/dd-trace/src/crashtracking/crashtracker.js +7 -1
  90. package/packages/dd-trace/src/crashtracking/index.js +1 -7
  91. package/packages/dd-trace/src/debugger/devtools_client/snapshot/processor.js +5 -2
  92. package/packages/dd-trace/src/debugger/index.js +1 -1
  93. package/packages/dd-trace/src/dogstatsd.js +12 -9
  94. package/packages/dd-trace/src/encode/0.4.js +8 -7
  95. package/packages/dd-trace/src/encode/span-stats.js +4 -1
  96. package/packages/dd-trace/src/exporters/agent/writer.js +7 -1
  97. package/packages/dd-trace/src/exporters/common/request.js +9 -0
  98. package/packages/dd-trace/src/exporters/common/writer.js +12 -2
  99. package/packages/dd-trace/src/heap_snapshots.js +3 -0
  100. package/packages/dd-trace/src/index.js +5 -2
  101. package/packages/dd-trace/src/lambda/runtime/ritm.js +6 -6
  102. package/packages/dd-trace/src/llmobs/index.js +4 -1
  103. package/packages/dd-trace/src/llmobs/plugins/ai/index.js +5 -1
  104. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +60 -12
  105. package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +4 -2
  106. package/packages/dd-trace/src/llmobs/sdk.js +12 -8
  107. package/packages/dd-trace/src/llmobs/span_processor.js +1 -1
  108. package/packages/dd-trace/src/llmobs/tagger.js +9 -6
  109. package/packages/dd-trace/src/llmobs/writers/base.js +2 -0
  110. package/packages/dd-trace/src/llmobs/writers/util.js +3 -0
  111. package/packages/dd-trace/src/log/index.js +20 -59
  112. package/packages/dd-trace/src/log/writer.js +7 -19
  113. package/packages/dd-trace/src/noop/proxy.js +8 -0
  114. package/packages/dd-trace/src/openfeature/remote_config.js +6 -1
  115. package/packages/dd-trace/src/opentelemetry/context_manager.js +6 -4
  116. package/packages/dd-trace/src/opentelemetry/logs/index.js +1 -1
  117. package/packages/dd-trace/src/opentelemetry/metrics/index.js +1 -1
  118. package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +17 -2
  119. package/packages/dd-trace/src/opentelemetry/otlp/protobuf_loader.js +14 -2
  120. package/packages/dd-trace/src/opentelemetry/otlp/trace.proto +358 -0
  121. package/packages/dd-trace/src/opentelemetry/otlp/trace_service.proto +78 -0
  122. package/packages/dd-trace/src/opentelemetry/trace/index.js +75 -0
  123. package/packages/dd-trace/src/opentelemetry/trace/otlp_http_trace_exporter.js +66 -0
  124. package/packages/dd-trace/src/opentelemetry/trace/otlp_transformer.js +332 -0
  125. package/packages/dd-trace/src/opentracing/propagation/text_map.js +9 -4
  126. package/packages/dd-trace/src/opentracing/tracer.js +9 -4
  127. package/packages/dd-trace/src/payload-tagging/config/index.js +6 -5
  128. package/packages/dd-trace/src/plugin_manager.js +8 -6
  129. package/packages/dd-trace/src/plugins/ci_plugin.js +4 -0
  130. package/packages/dd-trace/src/plugins/log_plugin.js +3 -0
  131. package/packages/dd-trace/src/plugins/plugin.js +11 -13
  132. package/packages/dd-trace/src/plugins/storage.js +2 -2
  133. package/packages/dd-trace/src/plugins/tracing.js +22 -5
  134. package/packages/dd-trace/src/plugins/util/test.js +2 -0
  135. package/packages/dd-trace/src/plugins/util/web.js +6 -88
  136. package/packages/dd-trace/src/process-tags/index.js +3 -0
  137. package/packages/dd-trace/src/profiler.js +27 -2
  138. package/packages/dd-trace/src/profiling/config.js +73 -241
  139. package/packages/dd-trace/src/profiling/exporter_cli.js +1 -4
  140. package/packages/dd-trace/src/profiling/exporters/event_serializer.js +6 -2
  141. package/packages/dd-trace/src/profiling/profiler.js +78 -109
  142. package/packages/dd-trace/src/profiling/profilers/events.js +2 -3
  143. package/packages/dd-trace/src/profiling/profilers/wall.js +89 -6
  144. package/packages/dd-trace/src/profiling/ssi-heuristics.js +4 -1
  145. package/packages/dd-trace/src/propagation-hash/index.js +2 -1
  146. package/packages/dd-trace/src/proxy.js +40 -6
  147. package/packages/dd-trace/src/remote_config/index.js +3 -0
  148. package/packages/dd-trace/src/require-package-json.js +8 -4
  149. package/packages/dd-trace/src/ritm.js +58 -26
  150. package/packages/dd-trace/src/runtime_metrics/index.js +3 -0
  151. package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +18 -11
  152. package/packages/dd-trace/src/sampler.js +1 -1
  153. package/packages/dd-trace/src/service-naming/index.js +1 -1
  154. package/packages/dd-trace/src/service-naming/schemas/definition.js +4 -1
  155. package/packages/dd-trace/src/service-naming/schemas/util.js +15 -1
  156. package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +24 -1
  157. package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +60 -0
  158. package/packages/dd-trace/src/service-naming/schemas/v0/web.js +17 -1
  159. package/packages/dd-trace/src/service-naming/schemas/v0/websocket.js +5 -0
  160. package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +17 -0
  161. package/packages/dd-trace/src/service-naming/schemas/v1/web.js +11 -1
  162. package/packages/dd-trace/src/service-naming/schemas/v1/websocket.js +6 -0
  163. package/packages/dd-trace/src/span_stats.js +5 -1
  164. package/packages/dd-trace/src/standalone/index.js +3 -0
  165. package/packages/dd-trace/src/telemetry/index.js +2 -3
  166. package/packages/dd-trace/src/telemetry/send-data.js +5 -19
  167. package/packages/dd-trace/src/telemetry/session-propagation.js +19 -44
  168. package/packages/dd-trace/src/telemetry/telemetry.js +28 -171
  169. package/packages/dd-trace/src/tracer.js +2 -2
  170. package/packages/dd-trace/src/util.js +0 -9
  171. package/vendor/dist/@apm-js-collab/code-transformer/index.js +28 -6
  172. package/vendor/dist/protobufjs/index.js +1 -1
  173. package/packages/dd-trace/src/log/utils.js +0 -16
@@ -5,1685 +5,776 @@ const os = require('node:os')
5
5
  const { URL } = require('node:url')
6
6
  const path = require('node:path')
7
7
 
8
+ const rfdc = require('../../../../vendor/dist/rfdc')({ proto: false, circles: false })
8
9
  const uuid = require('../../../../vendor/dist/crypto-randomuuid') // we need to keep the old uuid dep because of cypress
9
-
10
10
  const set = require('../../../datadog-core/src/utils/src/set')
11
11
  const { DD_MAJOR } = require('../../../../version')
12
12
  const log = require('../log')
13
- const tagger = require('../tagger')
14
- const { isTrue, isFalse, normalizeProfilingEnabledValue } = require('../util')
13
+ const pkg = require('../pkg')
14
+ const { isTrue } = require('../util')
15
15
  const { GIT_REPOSITORY_URL, GIT_COMMIT_SHA } = require('../plugins/util/tags')
16
- const { updateConfig } = require('../telemetry')
16
+ const telemetry = require('../telemetry')
17
17
  const telemetryMetrics = require('../telemetry/metrics')
18
18
  const {
19
19
  IS_SERVERLESS,
20
20
  getIsGCPFunction,
21
21
  getIsAzureFunction,
22
- enableGCPPubSubPushSubscription,
23
22
  } = require('../serverless')
24
23
  const { ORIGIN_KEY, DATADOG_MINI_AGENT_PATH } = require('../constants')
25
24
  const { appendRules } = require('../payload-tagging/config')
26
25
  const { getGitMetadataFromGitProperties, removeUserSensitiveInfo, getRemoteOriginURL, resolveGitHeadSHA } =
27
26
  require('./git_properties')
28
- const { getEnvironmentVariable: getEnv, getEnvironmentVariables, getStableConfigSources } = require('./helper')
29
- const defaults = require('./defaults')
30
-
31
- const TELEMETRY_COUNTERS = new Map([
32
- ['otel.env.hiding', {}],
33
- ['otel.env.invalid', {}],
34
- ])
35
- const OTEL_DD_ENV_MAPPING = new Map([
36
- ['OTEL_LOG_LEVEL', 'DD_TRACE_LOG_LEVEL'],
37
- ['OTEL_PROPAGATORS', 'DD_TRACE_PROPAGATION_STYLE'],
38
- ['OTEL_SERVICE_NAME', 'DD_SERVICE'],
39
- ['OTEL_TRACES_SAMPLER', 'DD_TRACE_SAMPLE_RATE'],
40
- ['OTEL_TRACES_SAMPLER_ARG', 'DD_TRACE_SAMPLE_RATE'],
41
- ['OTEL_TRACES_EXPORTER', 'DD_TRACE_ENABLED'],
42
- ['OTEL_METRICS_EXPORTER', 'DD_RUNTIME_METRICS_ENABLED'],
43
- ['OTEL_RESOURCE_ATTRIBUTES', 'DD_TAGS'],
44
- ['OTEL_SDK_DISABLED', 'DD_TRACE_OTEL_ENABLED'],
45
- ['OTEL_LOGS_EXPORTER', undefined],
46
- ])
47
- const VALID_PROPAGATION_STYLES = new Set(['datadog', 'tracecontext', 'b3', 'b3 single header', 'none'])
48
- const VALID_PROPAGATION_BEHAVIOR_EXTRACT = new Set(['continue', 'restart', 'ignore'])
49
- const VALID_LOG_LEVELS = new Set(['debug', 'info', 'warn', 'error'])
50
- const DEFAULT_OTLP_PORT = 4318
27
+ const ConfigBase = require('./config-base')
28
+ const {
29
+ getEnvironmentVariable,
30
+ getEnvironmentVariables,
31
+ getStableConfigSources,
32
+ } = require('./helper')
33
+ const {
34
+ defaults,
35
+ fallbackConfigurations,
36
+ configurationsTable,
37
+ optionsTable,
38
+ configWithOrigin,
39
+ parseErrors,
40
+ generateTelemetry,
41
+ } = require('./defaults')
42
+ const { transformers } = require('./parsers')
43
+
51
44
  const RUNTIME_ID = uuid()
52
- // eslint-disable-next-line eslint-rules/eslint-process-env -- internal propagation, not user config
53
- const ROOT_SESSION_ID = process.env.DD_ROOT_JS_SESSION_ID || RUNTIME_ID
54
- const NAMING_VERSIONS = new Set(['v0', 'v1'])
55
- const DEFAULT_NAMING_VERSION = 'v0'
56
45
 
57
46
  const tracerMetrics = telemetryMetrics.manager.namespace('tracers')
58
- const changeTracker = {}
59
47
 
48
+ /**
49
+ * @typedef {'default'
50
+ * | 'code'
51
+ * | 'remote_config'
52
+ * | 'calculated'
53
+ * | 'env_var'
54
+ * | 'local_stable_config'
55
+ * | 'fleet_stable_config'} TelemetrySource
56
+ * @typedef {'remote_config' | 'calculated'} RevertibleTelemetrySource
57
+ * @typedef {import('../../../../index').TracerOptions} TracerOptions
58
+ * @typedef {import('./config-types').ConfigKey} ConfigKey
59
+ * @typedef {import('./config-types').ConfigPath} ConfigPath
60
+ * @typedef {{
61
+ * value: import('./config-types').ConfigPathValue<ConfigPath>,
62
+ * source: TelemetrySource
63
+ * }} TrackedConfigEntry
64
+ * @typedef {{
65
+ * baseValuesByPath: Partial<Record<ConfigPath, TrackedConfigEntry>>,
66
+ * remote_config: Set<ConfigPath>,
67
+ * calculated: Set<ConfigPath>,
68
+ * }} ChangeTracker
69
+ */
70
+
71
+ /** @type {Config | null} */
60
72
  let configInstance = null
61
73
 
74
+ // An entry that is undefined means it is the default value.
75
+ /** @type {Map<ConfigPath, TelemetrySource>} */
76
+ const trackedConfigOrigins = new Map()
77
+
78
+ // ChangeTracker tracks the changes to the config up to programmatic options (code).
79
+ /** @type {ChangeTracker} */
80
+ const changeTracker = {
81
+ baseValuesByPath: {},
82
+ remote_config: new Set(),
83
+ calculated: new Set(),
84
+ }
85
+
86
+ /**
87
+ * @param {Config} config
88
+ * @param {RevertibleTelemetrySource} source
89
+ */
90
+ function undo (config, source) {
91
+ for (const name of changeTracker[source]) {
92
+ const entry = changeTracker.baseValuesByPath[name] ?? { source: 'default', value: defaults[name] }
93
+ setAndTrack(config, name, entry.value, undefined, entry.source)
94
+ }
95
+ }
96
+
97
+ function get (object, path) {
98
+ // Fast path for simple property access.
99
+ if (object[path] !== undefined) {
100
+ return object[path]
101
+ }
102
+ let index = 0
103
+ while (true) {
104
+ const nextIndex = path.indexOf('.', index)
105
+ if (nextIndex === -1) {
106
+ return object[path.slice(index)]
107
+ }
108
+ object = object[path.slice(index, nextIndex)]
109
+ index = nextIndex + 1
110
+ }
111
+ }
112
+
113
+ /**
114
+ * @param {Config} config
115
+ * @template {ConfigPath} TPath
116
+ * @param {TPath} name
117
+ * @param {import('./config-types').ConfigPathValue<TPath>} value
118
+ * @param {unknown} [rawValue]
119
+ * @param {TelemetrySource} [source]
120
+ */
121
+ function setAndTrack (config, name, value, rawValue = value, source = 'calculated') {
122
+ // envs can not be undefined
123
+ if (value == null) {
124
+ // TODO: This works as before while ignoring undefined programmatic options is not ideal.
125
+ if (source !== 'default') {
126
+ return
127
+ }
128
+ } else if (source === 'calculated' || source === 'remote_config') {
129
+ if (source === 'calculated' && value === get(config, name)) {
130
+ return
131
+ }
132
+ changeTracker[source].add(name)
133
+ } else {
134
+ const copy = typeof value === 'object' && value !== null ? rfdc(value) : value
135
+ changeTracker.baseValuesByPath[name] = { value: copy, source }
136
+ }
137
+ set(config, name, value)
138
+
139
+ generateTelemetry(rawValue, source, name)
140
+ if (source === 'default') {
141
+ trackedConfigOrigins.delete(name)
142
+ } else {
143
+ trackedConfigOrigins.set(name, source)
144
+ }
145
+ }
146
+
62
147
  module.exports = getConfig
63
148
 
64
- class Config {
149
+ // We extend from ConfigBase to make our types work
150
+ class Config extends ConfigBase {
65
151
  /**
66
152
  * parsed DD_TAGS, usable as a standalone tag set across products
67
153
  * @type {Record<string, string>}
68
154
  */
69
- #parsedDdTags = {}
70
- #envUnprocessed = {}
71
- #optsUnprocessed = {}
72
- #remoteUnprocessed = {}
73
- #env = {}
74
- #options = {}
75
- #remote = {}
76
- #defaults = {}
77
- #optionsArg = {}
78
- #localStableConfig = {}
79
- #fleetStableConfig = {}
80
- #calculated = {}
155
+ #parsedDdTags
81
156
 
157
+ /**
158
+ * @type {Record<string, string>}
159
+ */
160
+ get parsedDdTags () {
161
+ return this.#parsedDdTags
162
+ }
163
+
164
+ /**
165
+ * @param {TracerOptions} [options={}]
166
+ */
82
167
  constructor (options = {}) {
83
- if (!IS_SERVERLESS) {
84
- const configEnvSources = getStableConfigSources()
85
- this.stableConfig = {
86
- fleetEntries: configEnvSources.fleetStableConfig,
87
- localEntries: configEnvSources.localStableConfig,
88
- warnings: configEnvSources.stableConfigWarnings,
89
- }
90
- }
168
+ super()
91
169
 
92
- options = {
93
- ...options,
94
- // TODO(BridgeAR): Remove the experimental prefix once we have a major version.
95
- // That also applies to index.d.ts
96
- appsec: options.appsec == null ? options.experimental?.appsec : options.appsec,
97
- iast: options.iast == null ? options.experimental?.iast : options.iast,
170
+ const configEnvSources = getStableConfigSources()
171
+ this.stableConfig = {
172
+ fleetEntries: configEnvSources.fleetStableConfig ?? {},
173
+ localEntries: configEnvSources.localStableConfig ?? {},
174
+ warnings: configEnvSources.stableConfigWarnings,
98
175
  }
99
176
 
100
177
  // Configure the logger first so it can be used to warn about other configs
101
- const logConfig = log.getConfig()
102
- this.debug = log.isEnabled(
103
- this.stableConfig?.fleetEntries?.DD_TRACE_DEBUG,
104
- this.stableConfig?.localEntries?.DD_TRACE_DEBUG
105
- )
106
- this.logger = options.logger ?? logConfig.logger
107
- this.logLevel = log.getLogLevel(
108
- options.logLevel,
109
- this.stableConfig?.fleetEntries?.DD_TRACE_LOG_LEVEL,
110
- this.stableConfig?.localEntries?.DD_TRACE_LOG_LEVEL
111
- )
112
- log.use(this.logger)
113
- log.toggle(this.debug, this.logLevel)
178
+ // TODO: Implement auto buffering of inside of log module before first
179
+ // configure call. That way the logger is always available and the
180
+ // application doesn't need to configure it first and the configuration
181
+ // happens inside of config instead of inside of log module. If the logger
182
+ // is not deactivated, the buffered logs would be discarded. That way stable
183
+ // config warnings can also be logged directly and do not need special
184
+ // handling.
185
+ this.debug = log.configure(options)
114
186
 
115
187
  // Process stable config warnings, if any
116
188
  for (const warning of this.stableConfig?.warnings ?? []) {
117
189
  log.warn(warning)
118
190
  }
119
191
 
120
- checkIfBothOtelAndDdEnvVarSet()
121
-
122
- if (typeof options.appsec === 'boolean') {
123
- options.appsec = {
124
- enabled: options.appsec,
125
- }
126
- }
127
-
128
- if (typeof options.runtimeMetrics === 'boolean') {
129
- options.runtimeMetrics = {
130
- enabled: options.runtimeMetrics,
131
- }
132
- }
133
-
134
- this.#defaults = defaults
135
192
  this.#applyDefaults()
136
- this.#applyStableConfig(this.stableConfig?.localEntries ?? {}, this.#localStableConfig)
137
- this.#applyEnvironment()
138
- this.#applyStableConfig(this.stableConfig?.fleetEntries ?? {}, this.#fleetStableConfig)
139
- this.#applyOptions(options)
193
+ // TODO: Update origin documentation to list all valid sources. Add local_stable_config and fleet_stable_config.
194
+ this.#applyEnvs(getEnvironmentVariables(this.stableConfig.localEntries, true), 'local_stable_config')
195
+ this.#applyEnvs(getEnvironmentVariables(undefined, true), 'env_var')
196
+ this.#applyEnvs(getEnvironmentVariables(this.stableConfig.fleetEntries, true), 'fleet_stable_config')
197
+
198
+ // Experimental options are applied first, so they can be overridden by non-experimental options.
199
+ // TODO: When using programmatic options, check if there is a higher
200
+ // priority name in the same options object. Use the highest priority name.
201
+ const { experimental, ...rest } = options
202
+ if (experimental) {
203
+ // @ts-expect-error - Difficult to type this correctly.
204
+ this.#applyOptions(experimental, 'code', 'experimental')
205
+ }
206
+ this.#applyOptions(rest, 'code')
140
207
  this.#applyCalculated()
141
- this.#merge()
142
208
 
143
- tagger.add(this.tags, {
144
- service: this.service,
145
- env: this.env,
146
- version: this.version,
147
- 'runtime-id': RUNTIME_ID,
148
- })
209
+ warnWrongOtelSettings()
149
210
 
150
- this.rootSessionId = ROOT_SESSION_ID
211
+ if (this.gitMetadataEnabled) {
212
+ this.#loadGitMetadata()
213
+ }
151
214
 
152
- if (this.isCiVisibility) {
153
- tagger.add(this.tags, {
154
- [ORIGIN_KEY]: 'ciapp-test',
155
- })
215
+ parseErrors.clear()
216
+ }
217
+
218
+ #applyDefaults () {
219
+ for (const [name, value] of Object.entries(defaults)) {
220
+ set(this, name, value)
156
221
  }
222
+ }
157
223
 
158
- if (this.gitMetadataEnabled) {
159
- this.#loadGitMetadata()
224
+ /**
225
+ * @param {import('./helper').TracerEnv} envs
226
+ * @param {'env_var' | 'local_stable_config' | 'fleet_stable_config'} source
227
+ */
228
+ #applyEnvs (envs, source) {
229
+ for (const [name, value] of Object.entries(envs)) {
230
+ const entry = configurationsTable[name]
231
+ const parsed = entry.parser(value, name, source)
232
+ const transformed = parsed !== undefined && entry.transformer ? entry.transformer(parsed, name, source) : parsed
233
+ const rawValue = transformed !== null && typeof transformed === 'object' ? value : parsed
234
+ setAndTrack(this, entry.property ?? name, transformed, rawValue, source)
160
235
  }
161
236
  }
162
237
 
163
- get parsedDdTags () {
164
- return this.#parsedDdTags
238
+ /**
239
+ * @param {TracerOptions} options
240
+ * @param {'code' | 'remote_config'} source
241
+ * @param {string} [root]
242
+ */
243
+ #applyOptions (options, source, root = '') {
244
+ for (const [name, value] of Object.entries(options)) {
245
+ const fullName = root ? `${root}.${name}` : name
246
+ let entry = optionsTable[fullName]
247
+ if (!entry) {
248
+ // TODO: Fix this by by changing remote config to use env styles.
249
+ if (name !== 'tracing' || source !== 'remote_config') {
250
+ log.warn('Unknown option %s with value %o', fullName, value)
251
+ continue
252
+ }
253
+ // @ts-expect-error - The entry is defined in the configurationsTable.
254
+ entry = configurationsTable.tracing
255
+ }
256
+
257
+ if (entry.nestedProperties) {
258
+ let matched = false
259
+ if (typeof value === 'object' && value !== null) {
260
+ for (const nestedProperty of entry.nestedProperties) {
261
+ // WARNING: if the property name might be part of the value we look at, this could conflict!
262
+ // Defining an option that receives an object as value may not contain a property that is also
263
+ // potentially a nested property!
264
+ if (Object.hasOwn(value, nestedProperty)) {
265
+ this.#applyOptions(value, source, fullName)
266
+ matched = true
267
+ break
268
+ }
269
+ }
270
+ }
271
+ if (matched) {
272
+ continue
273
+ }
274
+ if (entry.option) {
275
+ entry = entry.option
276
+ } else {
277
+ if (fullName === 'tracePropagationStyle') {
278
+ // TracePropagationStyle is special. It is a single option that is used to set both inject and extract.
279
+ // TODO: Consider what to do with this later
280
+ // @ts-expect-error - Difficult to type this correctly.
281
+ this.#applyOptions({ inject: value, extract: value }, source, 'tracePropagationStyle')
282
+ } else {
283
+ log.warn('Unknown option %s with value %o', fullName, value)
284
+ }
285
+ continue
286
+ }
287
+ }
288
+ // TODO: Coerce mismatched types to the expected type, if possible. E.g., strings <> numbers
289
+ const transformed = value !== undefined && entry.transformer ? entry.transformer(value, fullName, source) : value
290
+ setAndTrack(this, entry.property, transformed, value, source)
291
+ }
165
292
  }
166
293
 
167
294
  /**
168
295
  * Set the configuration with remote config settings.
169
296
  * Applies remote configuration, recalculates derived values, and merges all configuration sources.
170
297
  *
171
- * @param {import('./remote_config').RemoteConfigOptions|null} options - Configurations received via Remote
298
+ * @param {TracerOptions|null} options - Configurations received via Remote
172
299
  * Config or null to reset all remote configuration
173
300
  */
174
301
  setRemoteConfig (options) {
175
302
  // Clear all RC-managed fields to ensure previous values don't persist.
176
303
  // State is instead managed by the `RCClientLibConfigManager` class
177
- this.#remote = {}
178
- this.#remoteUnprocessed = {}
304
+ undo(this, 'remote_config')
179
305
 
180
306
  // Special case: if options is null, nothing to apply
181
307
  // This happens when all remote configs are removed
182
308
  if (options !== null) {
183
- this.#applyRemoteConfig(options)
309
+ this.#applyOptions(options, 'remote_config')
184
310
  }
185
311
 
186
312
  this.#applyCalculated()
187
- this.#merge()
188
313
  }
189
314
 
190
- // TODO: Remove the `updateOptions` method. We don't want to support updating the config this way
191
315
  /**
192
- * Updates the configuration with new programmatic options.
193
- *
194
- * @deprecated This method should not be used and will be removed in a future version.
195
- * @param {object} options - Configuration options to apply (same format as tracer init options)
316
+ * @param {ConfigPath} name
196
317
  */
197
- updateOptions (options) {
198
- this.#applyOptions(options)
199
- this.#applyCalculated()
200
- this.#merge()
201
- }
202
-
203
318
  getOrigin (name) {
204
- for (const { container, origin } of this.#getSourcesInOrder()) {
205
- const value = container[name]
206
- if (value != null || container === this.#defaults) {
207
- return origin
208
- }
209
- }
319
+ return trackedConfigOrigins.get(name) ?? 'default'
210
320
  }
211
321
 
212
- #getSourcesInOrder () {
213
- return [
214
- { container: this.#remote, origin: 'remote_config', unprocessed: this.#remoteUnprocessed },
215
- { container: this.#options, origin: 'code', unprocessed: this.#optsUnprocessed },
216
- { container: this.#fleetStableConfig, origin: 'fleet_stable_config' },
217
- { container: this.#env, origin: 'env_var', unprocessed: this.#envUnprocessed },
218
- { container: this.#localStableConfig, origin: 'local_stable_config' },
219
- { container: this.#calculated, origin: 'calculated' },
220
- { container: this.#defaults, origin: 'default' },
221
- ]
222
- }
322
+ // Handles values calculated from a mixture of options and env vars
323
+ #applyCalculated () {
324
+ undo(this, 'calculated')
325
+
326
+ if (this.DD_CIVISIBILITY_AGENTLESS_URL ||
327
+ this.url ||
328
+ os.type() !== 'Windows_NT' &&
329
+ !trackedConfigOrigins.has('hostname') &&
330
+ !trackedConfigOrigins.has('port') &&
331
+ !this.DD_CIVISIBILITY_AGENTLESS_ENABLED &&
332
+ fs.existsSync('/var/run/datadog/apm.socket')) {
333
+ setAndTrack(
334
+ this,
335
+ 'url',
336
+ new URL(this.DD_CIVISIBILITY_AGENTLESS_URL || this.url || 'unix:///var/run/datadog/apm.socket')
337
+ )
338
+ }
223
339
 
224
- #applyStableConfig (config, obj) {
225
- this.#applyConfigValues(config, obj, {})
226
- }
340
+ if (this.isCiVisibility) {
341
+ setAndTrack(this, 'isServiceUserProvided', trackedConfigOrigins.has('service'))
342
+ this.tags[ORIGIN_KEY] = 'ciapp-test'
343
+ }
344
+ // Compute OTLP logs and metrics URLs to send payloads to the active Datadog Agent
345
+ const agentHostname = this.hostname || /** @type {URL} */ (this.url).hostname
227
346
 
228
- // Set environment-dependent defaults that can be overridden by users
229
- #applyDefaults () {
230
- const defaults = this.#defaults
347
+ if (!trackedConfigOrigins.has('dogstatsd.hostname')) {
348
+ setAndTrack(this, 'dogstatsd.hostname', agentHostname)
349
+ }
350
+ // Disable log injection when OTEL logs are enabled
351
+ // OTEL logs and DD log injection are mutually exclusive
352
+ if (this.otelLogsEnabled) {
353
+ setAndTrack(this, 'logInjection', false)
354
+ }
355
+ if (this.otelMetricsEnabled &&
356
+ trackedConfigOrigins.has('OTEL_METRICS_EXPORTER') &&
357
+ this.OTEL_METRICS_EXPORTER === 'none') {
358
+ setAndTrack(this, 'otelMetricsEnabled', false)
359
+ }
231
360
 
232
- if (IS_SERVERLESS) {
233
- setBoolean(defaults, 'crashtracking.enabled', false)
234
- setString(defaults, 'profiling.enabled', 'false')
235
- setBoolean(defaults, 'telemetry.enabled', false)
236
- setBoolean(defaults, 'remoteConfig.enabled', false)
361
+ const otelTracesEnabled = trackedConfigOrigins.has('OTEL_TRACES_EXPORTER') &&
362
+ this.OTEL_TRACES_EXPORTER === 'otlp'
363
+ if (this.protocolVersion && this.protocolVersion !== '0.4' && otelTracesEnabled) {
364
+ log.warn('DD_TRACE_AGENT_PROTOCOL_VERSION is set, disabling OTLP traces export')
365
+ setAndTrack(this, 'otelTracesEnabled', false)
237
366
  } else {
238
- setBoolean(defaults, 'crashtracking.enabled', true)
367
+ setAndTrack(this, 'otelTracesEnabled', otelTracesEnabled)
239
368
  }
240
369
 
241
- if (getEnv('JEST_WORKER_ID')) {
242
- setBoolean(defaults, 'telemetry.enabled', false)
370
+ if (this.otelTracesProtocol && this.otelTracesProtocol !== 'http/json') {
371
+ log.warn(
372
+ 'OTEL_EXPORTER_OTLP_TRACES_PROTOCOL=%s is not yet supported; only http/json is currently implemented',
373
+ this.otelTracesProtocol
374
+ )
375
+ setAndTrack(this, 'otelTracesProtocol', 'http/json')
243
376
  }
244
- }
245
-
246
- #applyEnvironment () {
247
- this.#applyConfigValues(getEnvironmentVariables(), this.#env, this.#envUnprocessed)
248
- }
249
377
 
250
- #applyConfigValues (source, target, unprocessedTarget) {
251
- const {
252
- AWS_LAMBDA_FUNCTION_NAME,
253
- DD_AGENT_HOST,
254
- DD_AI_GUARD_BLOCK,
255
- DD_AI_GUARD_ENABLED,
256
- DD_AI_GUARD_ENDPOINT,
257
- DD_AI_GUARD_MAX_CONTENT_SIZE,
258
- DD_AI_GUARD_MAX_MESSAGES_LENGTH,
259
- DD_AI_GUARD_TIMEOUT,
260
- DD_API_KEY,
261
- DD_API_SECURITY_ENABLED,
262
- DD_API_SECURITY_SAMPLE_DELAY,
263
- DD_API_SECURITY_ENDPOINT_COLLECTION_ENABLED,
264
- DD_API_SECURITY_ENDPOINT_COLLECTION_MESSAGE_LIMIT,
265
- DD_API_SECURITY_DOWNSTREAM_BODY_ANALYSIS_SAMPLE_RATE,
266
- DD_API_SECURITY_MAX_DOWNSTREAM_REQUEST_BODY_ANALYSIS,
267
- DD_APM_TRACING_ENABLED,
268
- DD_APP_KEY,
269
- DD_APPSEC_AUTO_USER_INSTRUMENTATION_MODE,
270
- DD_APPSEC_COLLECT_ALL_HEADERS,
271
- DD_APPSEC_ENABLED,
272
- DD_APPSEC_GRAPHQL_BLOCKED_TEMPLATE_JSON,
273
- DD_APPSEC_HEADER_COLLECTION_REDACTION_ENABLED,
274
- DD_APPSEC_HTTP_BLOCKED_TEMPLATE_HTML,
275
- DD_APPSEC_HTTP_BLOCKED_TEMPLATE_JSON,
276
- DD_APPSEC_MAX_COLLECTED_HEADERS,
277
- DD_APPSEC_MAX_STACK_TRACES,
278
- DD_APPSEC_MAX_STACK_TRACE_DEPTH,
279
- DD_APPSEC_OBFUSCATION_PARAMETER_KEY_REGEXP,
280
- DD_APPSEC_OBFUSCATION_PARAMETER_VALUE_REGEXP,
281
- DD_APPSEC_RULES,
282
- DD_APPSEC_SCA_ENABLED,
283
- DD_APPSEC_STACK_TRACE_ENABLED,
284
- DD_APPSEC_RASP_ENABLED,
285
- DD_APPSEC_RASP_COLLECT_REQUEST_BODY,
286
- DD_APPSEC_TRACE_RATE_LIMIT,
287
- DD_APPSEC_WAF_TIMEOUT,
288
- DD_CRASHTRACKING_ENABLED,
289
- DD_CODE_ORIGIN_FOR_SPANS_ENABLED,
290
- DD_CODE_ORIGIN_FOR_SPANS_EXPERIMENTAL_EXIT_SPANS_ENABLED,
291
- DD_DATA_STREAMS_ENABLED,
292
- DD_DBM_PROPAGATION_MODE,
293
- DD_DBM_INJECT_SQL_BASEHASH,
294
- DD_DOGSTATSD_HOST,
295
- DD_DOGSTATSD_PORT,
296
- DD_DYNAMIC_INSTRUMENTATION_CAPTURE_TIMEOUT_MS,
297
- DD_DYNAMIC_INSTRUMENTATION_ENABLED,
298
- DD_DYNAMIC_INSTRUMENTATION_PROBE_FILE,
299
- DD_DYNAMIC_INSTRUMENTATION_REDACTED_IDENTIFIERS,
300
- DD_DYNAMIC_INSTRUMENTATION_REDACTION_EXCLUDED_IDENTIFIERS,
301
- DD_DYNAMIC_INSTRUMENTATION_UPLOAD_INTERVAL_SECONDS,
302
- DD_ENV,
303
- DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED,
304
- DD_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED,
305
- DD_PROFILING_ENABLED,
306
- DD_GRPC_CLIENT_ERROR_STATUSES,
307
- DD_GRPC_SERVER_ERROR_STATUSES,
308
- DD_HEAP_SNAPSHOT_COUNT,
309
- DD_HEAP_SNAPSHOT_DESTINATION,
310
- DD_HEAP_SNAPSHOT_INTERVAL,
311
- DD_IAST_DB_ROWS_TO_TAINT,
312
- DD_IAST_DEDUPLICATION_ENABLED,
313
- DD_IAST_ENABLED,
314
- DD_IAST_MAX_CONCURRENT_REQUESTS,
315
- DD_IAST_MAX_CONTEXT_OPERATIONS,
316
- DD_IAST_REDACTION_ENABLED,
317
- DD_IAST_REDACTION_NAME_PATTERN,
318
- DD_IAST_REDACTION_VALUE_PATTERN,
319
- DD_IAST_REQUEST_SAMPLING,
320
- DD_IAST_SECURITY_CONTROLS_CONFIGURATION,
321
- DD_IAST_TELEMETRY_VERBOSITY,
322
- DD_IAST_STACK_TRACE_ENABLED,
323
- DD_INJECTION_ENABLED,
324
- DD_INJECT_FORCE,
325
- DD_ENABLE_NX_SERVICE_NAME,
326
- DD_INSTRUMENTATION_TELEMETRY_ENABLED,
327
- DD_INSTRUMENTATION_CONFIG_ID,
328
- DD_LOGS_INJECTION,
329
- DD_LOGS_OTEL_ENABLED,
330
- DD_METRICS_OTEL_ENABLED,
331
- DD_LANGCHAIN_SPAN_CHAR_LIMIT,
332
- DD_LANGCHAIN_SPAN_PROMPT_COMPLETION_SAMPLE_RATE,
333
- DD_LLMOBS_AGENTLESS_ENABLED,
334
- DD_LLMOBS_ENABLED,
335
- DD_LLMOBS_ML_APP,
336
- DD_OPENAI_LOGS_ENABLED,
337
- DD_OPENAI_SPAN_CHAR_LIMIT,
338
- DD_PROFILING_EXPORTERS,
339
- DD_PROFILING_SOURCE_MAP,
340
- DD_INTERNAL_PROFILING_LONG_LIVED_THRESHOLD,
341
- DD_INSTRUMENTATION_INSTALL_ID,
342
- DD_INSTRUMENTATION_INSTALL_TIME,
343
- DD_INSTRUMENTATION_INSTALL_TYPE,
344
- DD_REMOTE_CONFIGURATION_ENABLED,
345
- DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS,
346
- DD_RUNTIME_METRICS_ENABLED,
347
- DD_RUNTIME_METRICS_EVENT_LOOP_ENABLED,
348
- DD_RUNTIME_METRICS_GC_ENABLED,
349
- DD_SERVICE,
350
- DD_SERVICE_MAPPING,
351
- DD_SITE,
352
- DD_SPAN_SAMPLING_RULES,
353
- DD_SPAN_SAMPLING_RULES_FILE,
354
- DD_TAGS,
355
- DD_TELEMETRY_DEBUG,
356
- DD_TELEMETRY_DEPENDENCY_COLLECTION_ENABLED,
357
- DD_TELEMETRY_HEARTBEAT_INTERVAL,
358
- DD_TELEMETRY_LOG_COLLECTION_ENABLED,
359
- DD_TELEMETRY_METRICS_ENABLED,
360
- DD_TEST_TIA_KEEP_COV_CONFIG,
361
- DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED,
362
- DD_TRACE_128_BIT_TRACEID_LOGGING_ENABLED,
363
- DD_TRACE_AGENT_PORT,
364
- DD_TRACE_AGENT_PROTOCOL_VERSION,
365
- DD_TRACE_AWS_ADD_SPAN_POINTERS,
366
- DD_TRACE_BAGGAGE_MAX_BYTES,
367
- DD_TRACE_BAGGAGE_MAX_ITEMS,
368
- DD_TRACE_BAGGAGE_TAG_KEYS,
369
- DD_TRACE_CLIENT_IP_ENABLED,
370
- DD_TRACE_CLIENT_IP_HEADER,
371
- DD_TRACE_CLOUD_REQUEST_PAYLOAD_TAGGING,
372
- DD_TRACE_CLOUD_RESPONSE_PAYLOAD_TAGGING,
373
- DD_TRACE_CLOUD_PAYLOAD_TAGGING_MAX_DEPTH,
374
- DD_TRACE_DYNAMODB_TABLE_PRIMARY_KEYS,
375
- DD_TRACE_ENABLED,
376
- DD_TRACE_EXPERIMENTAL_EXPORTER,
377
- DD_TRACE_EXPERIMENTAL_GET_RUM_DATA_ENABLED,
378
- DD_RUNTIME_METRICS_RUNTIME_ID_ENABLED,
379
- DD_TRACE_GIT_METADATA_ENABLED,
380
- DD_TRACE_GRAPHQL_ERROR_EXTENSIONS,
381
- DD_TRACE_HEADER_TAGS,
382
- DD_TRACE_LEGACY_BAGGAGE_ENABLED,
383
- DD_TRACE_MEMCACHED_COMMAND_ENABLED,
384
- DD_TRACE_MIDDLEWARE_TRACING_ENABLED,
385
- DD_TRACE_OBFUSCATION_QUERY_STRING_REGEXP,
386
- DD_TRACE_PARTIAL_FLUSH_MIN_SPANS,
387
- DD_TRACE_FLUSH_INTERVAL,
388
- DD_TRACE_PEER_SERVICE_MAPPING,
389
- DD_TRACE_PROPAGATION_EXTRACT_FIRST,
390
- DD_TRACE_PROPAGATION_BEHAVIOR_EXTRACT,
391
- DD_TRACE_PROPAGATION_STYLE,
392
- DD_TRACE_PROPAGATION_STYLE_INJECT,
393
- DD_TRACE_PROPAGATION_STYLE_EXTRACT,
394
- DD_TRACE_RATE_LIMIT,
395
- DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED,
396
- DD_TRACE_REPORT_HOSTNAME,
397
- DD_TRACE_RESOURCE_RENAMING_ENABLED,
398
- DD_TRACE_SAMPLE_RATE,
399
- DD_TRACE_SAMPLING_RULES,
400
- DD_TRACE_SCOPE,
401
- DD_TRACE_SPAN_ATTRIBUTE_SCHEMA,
402
- DD_TRACE_SPAN_LEAK_DEBUG,
403
- DD_TRACE_STARTUP_LOGS,
404
- DD_TRACE_TAGS,
405
- DD_TRACE_WEBSOCKET_MESSAGES_ENABLED,
406
- DD_TRACE_WEBSOCKET_MESSAGES_INHERIT_SAMPLING,
407
- DD_TRACE_WEBSOCKET_MESSAGES_SEPARATE_TRACES,
408
- DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH,
409
- DD_TRACING_ENABLED,
410
- DD_VERSION,
411
- DD_VERTEXAI_SPAN_PROMPT_COMPLETION_SAMPLE_RATE,
412
- DD_VERTEXAI_SPAN_CHAR_LIMIT,
413
- DD_TRACE_INFERRED_PROXY_SERVICES_ENABLED,
414
- DD_TRACE_NATIVE_SPAN_EVENTS,
415
- OTEL_METRICS_EXPORTER,
416
- OTEL_PROPAGATORS,
417
- OTEL_RESOURCE_ATTRIBUTES,
418
- OTEL_SERVICE_NAME,
419
- OTEL_TRACES_SAMPLER,
420
- OTEL_TRACES_SAMPLER_ARG,
421
- DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED,
422
- DD_EXPERIMENTAL_FLAGGING_PROVIDER_INITIALIZATION_TIMEOUT_MS,
423
- OTEL_EXPORTER_OTLP_LOGS_ENDPOINT,
424
- OTEL_EXPORTER_OTLP_LOGS_HEADERS,
425
- OTEL_EXPORTER_OTLP_LOGS_PROTOCOL,
426
- OTEL_EXPORTER_OTLP_LOGS_TIMEOUT,
427
- OTEL_EXPORTER_OTLP_METRICS_ENDPOINT,
428
- OTEL_EXPORTER_OTLP_METRICS_HEADERS,
429
- OTEL_EXPORTER_OTLP_METRICS_PROTOCOL,
430
- OTEL_EXPORTER_OTLP_METRICS_TIMEOUT,
431
- OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE,
432
- OTEL_METRIC_EXPORT_TIMEOUT,
433
- OTEL_EXPORTER_OTLP_PROTOCOL,
434
- OTEL_EXPORTER_OTLP_ENDPOINT,
435
- OTEL_EXPORTER_OTLP_HEADERS,
436
- OTEL_EXPORTER_OTLP_TIMEOUT,
437
- OTEL_BSP_SCHEDULE_DELAY,
438
- OTEL_BSP_MAX_EXPORT_BATCH_SIZE,
439
- OTEL_BSP_MAX_QUEUE_SIZE,
440
- OTEL_METRIC_EXPORT_INTERVAL,
441
- NX_TASK_TARGET_PROJECT,
442
- } = source
443
-
444
- const tags = {}
445
-
446
- tagger.add(tags, parseSpaceSeparatedTags(handleOtel(OTEL_RESOURCE_ATTRIBUTES)))
447
- tagger.add(tags, parseSpaceSeparatedTags(DD_TAGS))
448
- tagger.add(tags, DD_TRACE_TAGS)
449
-
450
- Object.assign(this.#parsedDdTags, tags)
451
-
452
- setString(target, 'apiKey', DD_API_KEY)
453
- setBoolean(target, 'otelLogsEnabled', DD_LOGS_OTEL_ENABLED)
454
- // Set OpenTelemetry logs configuration with specific _LOGS_ vars taking precedence over generic _EXPORTERS_ vars
455
- if (OTEL_EXPORTER_OTLP_ENDPOINT) {
456
- // Only set if there's a custom URL, otherwise let calc phase handle the default
457
- setString(target, 'otelUrl', OTEL_EXPORTER_OTLP_ENDPOINT)
378
+ if (this.telemetry.heartbeatInterval) {
379
+ setAndTrack(this, 'telemetry.heartbeatInterval', Math.floor(this.telemetry.heartbeatInterval * 1000))
458
380
  }
459
- if (OTEL_EXPORTER_OTLP_ENDPOINT || OTEL_EXPORTER_OTLP_LOGS_ENDPOINT) {
460
- setString(target, 'otelLogsUrl', OTEL_EXPORTER_OTLP_LOGS_ENDPOINT || target.otelUrl)
381
+ if (this.telemetry.extendedHeartbeatInterval) {
382
+ setAndTrack(this, 'telemetry.extendedHeartbeatInterval',
383
+ Math.floor(this.telemetry.extendedHeartbeatInterval * 1000))
461
384
  }
462
- setString(target, 'otelHeaders', OTEL_EXPORTER_OTLP_HEADERS)
463
- setString(target, 'otelLogsHeaders', OTEL_EXPORTER_OTLP_LOGS_HEADERS || target.otelHeaders)
464
- setString(target, 'otelProtocol', OTEL_EXPORTER_OTLP_PROTOCOL)
465
- setString(target, 'otelLogsProtocol', OTEL_EXPORTER_OTLP_LOGS_PROTOCOL || target.otelProtocol)
466
- const otelTimeout = nonNegInt(OTEL_EXPORTER_OTLP_TIMEOUT, 'OTEL_EXPORTER_OTLP_TIMEOUT')
467
- if (otelTimeout !== undefined) {
468
- target.otelTimeout = otelTimeout
385
+
386
+ // Enable resourceRenamingEnabled when appsec is enabled and only
387
+ // if DD_TRACE_RESOURCE_RENAMING_ENABLED is not explicitly set
388
+ if (!trackedConfigOrigins.has('resourceRenamingEnabled')) {
389
+ setAndTrack(this, 'resourceRenamingEnabled', this.appsec.enabled ?? false)
469
390
  }
470
- const otelLogsTimeout = nonNegInt(OTEL_EXPORTER_OTLP_LOGS_TIMEOUT, 'OTEL_EXPORTER_OTLP_LOGS_TIMEOUT')
471
- target.otelLogsTimeout = otelLogsTimeout === undefined ? target.otelTimeout : otelLogsTimeout
472
- const otelBatchTimeout = nonNegInt(OTEL_BSP_SCHEDULE_DELAY, 'OTEL_BSP_SCHEDULE_DELAY', false)
473
- if (otelBatchTimeout !== undefined) {
474
- target.otelBatchTimeout = otelBatchTimeout
391
+
392
+ if (!trackedConfigOrigins.has('spanComputePeerService') && this.spanAttributeSchema !== 'v0') {
393
+ setAndTrack(this, 'spanComputePeerService', true)
475
394
  }
476
- target.otelMaxExportBatchSize = nonNegInt(OTEL_BSP_MAX_EXPORT_BATCH_SIZE, 'OTEL_BSP_MAX_EXPORT_BATCH_SIZE', false)
477
- target.otelMaxQueueSize = nonNegInt(OTEL_BSP_MAX_QUEUE_SIZE, 'OTEL_BSP_MAX_QUEUE_SIZE', false)
478
-
479
- const otelMetricsExporterEnabled = OTEL_METRICS_EXPORTER?.toLowerCase() !== 'none'
480
- setBoolean(
481
- target,
482
- 'otelMetricsEnabled',
483
- DD_METRICS_OTEL_ENABLED && isTrue(DD_METRICS_OTEL_ENABLED) && otelMetricsExporterEnabled
484
- )
485
- // Set OpenTelemetry metrics configuration with specific _METRICS_ vars
486
- // taking precedence over generic _EXPORTERS_ vars
487
- if (OTEL_EXPORTER_OTLP_ENDPOINT || OTEL_EXPORTER_OTLP_METRICS_ENDPOINT) {
488
- setString(target, 'otelMetricsUrl', OTEL_EXPORTER_OTLP_METRICS_ENDPOINT || target.otelUrl)
395
+
396
+ if (!this.apmTracingEnabled) {
397
+ setAndTrack(this, 'stats.enabled', false)
398
+ } else if (!trackedConfigOrigins.has('stats.enabled')) {
399
+ setAndTrack(this, 'stats.enabled', getIsGCPFunction() || getIsAzureFunction())
489
400
  }
490
- setString(target, 'otelMetricsHeaders', OTEL_EXPORTER_OTLP_METRICS_HEADERS || target.otelHeaders)
491
- setString(target, 'otelMetricsProtocol', OTEL_EXPORTER_OTLP_METRICS_PROTOCOL || target.otelProtocol)
492
- const otelMetricsTimeout = nonNegInt(OTEL_EXPORTER_OTLP_METRICS_TIMEOUT, 'OTEL_EXPORTER_OTLP_METRICS_TIMEOUT')
493
- target.otelMetricsTimeout = otelMetricsTimeout === undefined ? target.otelTimeout : otelMetricsTimeout
494
- target.otelMetricsExportTimeout = nonNegInt(OTEL_METRIC_EXPORT_TIMEOUT, 'OTEL_METRIC_EXPORT_TIMEOUT')
495
- target.otelMetricsExportInterval = nonNegInt(OTEL_METRIC_EXPORT_INTERVAL, 'OTEL_METRIC_EXPORT_INTERVAL', false)
496
-
497
- // Parse temporality preference (default to DELTA for Datadog)
498
- if (OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE) {
499
- const temporalityPref = OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE.toUpperCase()
500
- if (['DELTA', 'CUMULATIVE', 'LOWMEMORY'].includes(temporalityPref)) {
501
- setString(target, 'otelMetricsTemporalityPreference', temporalityPref)
401
+
402
+ // TODO: Remove the experimental env vars as a major or deprecate the option?
403
+ if (this.experimental?.b3) {
404
+ if (!this.tracePropagationStyle.inject.includes('b3')) {
405
+ this.tracePropagationStyle.inject.push('b3')
502
406
  }
503
- }
504
- setBoolean(
505
- target,
506
- 'apmTracingEnabled',
507
- DD_APM_TRACING_ENABLED ??
508
- (DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED && isFalse(DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED))
509
- )
510
- setBoolean(target, 'propagateProcessTags.enabled', DD_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED)
511
- setString(target, 'appKey', DD_APP_KEY)
512
- setBoolean(target, 'appsec.apiSecurity.enabled', DD_API_SECURITY_ENABLED && isTrue(DD_API_SECURITY_ENABLED))
513
- target['appsec.apiSecurity.sampleDelay'] = maybeFloat(DD_API_SECURITY_SAMPLE_DELAY)
514
- setBoolean(target, 'appsec.apiSecurity.endpointCollectionEnabled',
515
- DD_API_SECURITY_ENDPOINT_COLLECTION_ENABLED)
516
- target['appsec.apiSecurity.endpointCollectionMessageLimit'] =
517
- maybeInt(DD_API_SECURITY_ENDPOINT_COLLECTION_MESSAGE_LIMIT)
518
- target['appsec.blockedTemplateGraphql'] = maybeFile(DD_APPSEC_GRAPHQL_BLOCKED_TEMPLATE_JSON)
519
- target['appsec.blockedTemplateHtml'] = maybeFile(DD_APPSEC_HTTP_BLOCKED_TEMPLATE_HTML)
520
- unprocessedTarget['appsec.blockedTemplateHtml'] = DD_APPSEC_HTTP_BLOCKED_TEMPLATE_HTML
521
- target['appsec.blockedTemplateJson'] = maybeFile(DD_APPSEC_HTTP_BLOCKED_TEMPLATE_JSON)
522
- unprocessedTarget['appsec.blockedTemplateJson'] = DD_APPSEC_HTTP_BLOCKED_TEMPLATE_JSON
523
- setBoolean(target, 'appsec.enabled', DD_APPSEC_ENABLED)
524
- setString(target, 'appsec.eventTracking.mode', DD_APPSEC_AUTO_USER_INSTRUMENTATION_MODE)
525
- // TODO appsec.extendedHeadersCollection are deprecated, to delete in a major
526
- setBoolean(target, 'appsec.extendedHeadersCollection.enabled', DD_APPSEC_COLLECT_ALL_HEADERS)
527
- setBoolean(
528
- target,
529
- 'appsec.extendedHeadersCollection.redaction',
530
- DD_APPSEC_HEADER_COLLECTION_REDACTION_ENABLED
531
- )
532
- target['appsec.extendedHeadersCollection.maxHeaders'] = maybeInt(DD_APPSEC_MAX_COLLECTED_HEADERS)
533
- unprocessedTarget['appsec.extendedHeadersCollection.maxHeaders'] = DD_APPSEC_MAX_COLLECTED_HEADERS
534
- setString(target, 'appsec.obfuscatorKeyRegex', DD_APPSEC_OBFUSCATION_PARAMETER_KEY_REGEXP)
535
- setString(target, 'appsec.obfuscatorValueRegex', DD_APPSEC_OBFUSCATION_PARAMETER_VALUE_REGEXP)
536
- setBoolean(target, 'appsec.rasp.enabled', DD_APPSEC_RASP_ENABLED)
537
- // TODO Deprecated, to delete in a major
538
- setBoolean(target, 'appsec.rasp.bodyCollection', DD_APPSEC_RASP_COLLECT_REQUEST_BODY)
539
- target['appsec.rateLimit'] = maybeInt(DD_APPSEC_TRACE_RATE_LIMIT)
540
- unprocessedTarget['appsec.rateLimit'] = DD_APPSEC_TRACE_RATE_LIMIT
541
- setString(target, 'appsec.rules', DD_APPSEC_RULES)
542
- // DD_APPSEC_SCA_ENABLED is never used locally, but only sent to the backend
543
- setBoolean(target, 'appsec.sca.enabled', DD_APPSEC_SCA_ENABLED)
544
- setBoolean(target, 'appsec.stackTrace.enabled', DD_APPSEC_STACK_TRACE_ENABLED)
545
- target['appsec.stackTrace.maxDepth'] = maybeInt(DD_APPSEC_MAX_STACK_TRACE_DEPTH)
546
- unprocessedTarget['appsec.stackTrace.maxDepth'] = DD_APPSEC_MAX_STACK_TRACE_DEPTH
547
- target['appsec.stackTrace.maxStackTraces'] = maybeInt(DD_APPSEC_MAX_STACK_TRACES)
548
- unprocessedTarget['appsec.stackTrace.maxStackTraces'] = DD_APPSEC_MAX_STACK_TRACES
549
- target['appsec.wafTimeout'] = maybeInt(DD_APPSEC_WAF_TIMEOUT)
550
- unprocessedTarget['appsec.wafTimeout'] = DD_APPSEC_WAF_TIMEOUT
551
- target['appsec.apiSecurity.downstreamBodyAnalysisSampleRate'] =
552
- maybeFloat(DD_API_SECURITY_DOWNSTREAM_BODY_ANALYSIS_SAMPLE_RATE)
553
- target['appsec.apiSecurity.maxDownstreamRequestBodyAnalysis'] =
554
- maybeInt(DD_API_SECURITY_MAX_DOWNSTREAM_REQUEST_BODY_ANALYSIS)
555
- target.baggageMaxBytes = DD_TRACE_BAGGAGE_MAX_BYTES
556
- target.baggageMaxItems = DD_TRACE_BAGGAGE_MAX_ITEMS
557
- setArray(target, 'baggageTagKeys', DD_TRACE_BAGGAGE_TAG_KEYS)
558
- setBoolean(target, 'clientIpEnabled', DD_TRACE_CLIENT_IP_ENABLED)
559
- setString(target, 'clientIpHeader', DD_TRACE_CLIENT_IP_HEADER?.toLowerCase())
560
- if (DD_TRACE_CLOUD_REQUEST_PAYLOAD_TAGGING || DD_TRACE_CLOUD_RESPONSE_PAYLOAD_TAGGING) {
561
- if (DD_TRACE_CLOUD_REQUEST_PAYLOAD_TAGGING) {
562
- setBoolean(target, 'cloudPayloadTagging.requestsEnabled', true)
407
+ if (!this.tracePropagationStyle.extract.includes('b3')) {
408
+ this.tracePropagationStyle.extract.push('b3')
563
409
  }
564
- if (DD_TRACE_CLOUD_RESPONSE_PAYLOAD_TAGGING) {
565
- setBoolean(target, 'cloudPayloadTagging.responsesEnabled', true)
410
+ if (!this.tracePropagationStyle.inject.includes('b3 single header')) {
411
+ this.tracePropagationStyle.inject.push('b3 single header')
566
412
  }
567
- target['cloudPayloadTagging.rules'] = appendRules(
568
- splitJSONPathRules(DD_TRACE_CLOUD_REQUEST_PAYLOAD_TAGGING),
569
- splitJSONPathRules(DD_TRACE_CLOUD_RESPONSE_PAYLOAD_TAGGING)
570
- )
571
- }
572
- if (DD_TRACE_CLOUD_PAYLOAD_TAGGING_MAX_DEPTH) {
573
- target['cloudPayloadTagging.maxDepth'] = maybeInt(DD_TRACE_CLOUD_PAYLOAD_TAGGING_MAX_DEPTH)
574
- }
575
- setBoolean(target, 'crashtracking.enabled', DD_CRASHTRACKING_ENABLED)
576
- setBoolean(target, 'codeOriginForSpans.enabled', DD_CODE_ORIGIN_FOR_SPANS_ENABLED)
577
- setBoolean(
578
- target,
579
- 'codeOriginForSpans.experimental.exit_spans.enabled',
580
- DD_CODE_ORIGIN_FOR_SPANS_EXPERIMENTAL_EXIT_SPANS_ENABLED
581
- )
582
- setString(target, 'dbmPropagationMode', DD_DBM_PROPAGATION_MODE)
583
- setBoolean(target, 'dbm.injectSqlBaseHash', DD_DBM_INJECT_SQL_BASEHASH)
584
- setString(target, 'dogstatsd.hostname', DD_DOGSTATSD_HOST)
585
- setString(target, 'dogstatsd.port', DD_DOGSTATSD_PORT)
586
- setBoolean(target, 'dsmEnabled', DD_DATA_STREAMS_ENABLED)
587
- target['dynamicInstrumentation.captureTimeoutMs'] = maybeInt(DD_DYNAMIC_INSTRUMENTATION_CAPTURE_TIMEOUT_MS)
588
- unprocessedTarget['dynamicInstrumentation.captureTimeoutMs'] = DD_DYNAMIC_INSTRUMENTATION_CAPTURE_TIMEOUT_MS
589
- setBoolean(target, 'dynamicInstrumentation.enabled', DD_DYNAMIC_INSTRUMENTATION_ENABLED)
590
- setString(target, 'dynamicInstrumentation.probeFile', DD_DYNAMIC_INSTRUMENTATION_PROBE_FILE)
591
- setArray(target, 'dynamicInstrumentation.redactedIdentifiers',
592
- DD_DYNAMIC_INSTRUMENTATION_REDACTED_IDENTIFIERS)
593
- setArray(
594
- target,
595
- 'dynamicInstrumentation.redactionExcludedIdentifiers',
596
- DD_DYNAMIC_INSTRUMENTATION_REDACTION_EXCLUDED_IDENTIFIERS
597
- )
598
- target['dynamicInstrumentation.uploadIntervalSeconds'] =
599
- maybeFloat(DD_DYNAMIC_INSTRUMENTATION_UPLOAD_INTERVAL_SECONDS)
600
- unprocessedTarget['dynamicInstrumentation.uploadInterval'] = DD_DYNAMIC_INSTRUMENTATION_UPLOAD_INTERVAL_SECONDS
601
- setString(target, 'env', DD_ENV || tags.env)
602
- setBoolean(
603
- target,
604
- 'experimental.flaggingProvider.enabled',
605
- DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED
606
- )
607
- if (DD_EXPERIMENTAL_FLAGGING_PROVIDER_INITIALIZATION_TIMEOUT_MS != null) {
608
- target['experimental.flaggingProvider.initializationTimeoutMs'] =
609
- maybeInt(DD_EXPERIMENTAL_FLAGGING_PROVIDER_INITIALIZATION_TIMEOUT_MS)
610
- }
611
- setBoolean(target, 'traceEnabled', DD_TRACE_ENABLED)
612
- setBoolean(target, 'experimental.aiguard.block', DD_AI_GUARD_BLOCK)
613
- setBoolean(target, 'experimental.aiguard.enabled', DD_AI_GUARD_ENABLED)
614
- setString(target, 'experimental.aiguard.endpoint', DD_AI_GUARD_ENDPOINT)
615
- target['experimental.aiguard.maxContentSize'] = maybeInt(DD_AI_GUARD_MAX_CONTENT_SIZE)
616
- unprocessedTarget['experimental.aiguard.maxContentSize'] = DD_AI_GUARD_MAX_CONTENT_SIZE
617
- target['experimental.aiguard.maxMessagesLength'] = maybeInt(DD_AI_GUARD_MAX_MESSAGES_LENGTH)
618
- unprocessedTarget['experimental.aiguard.maxMessagesLength'] = DD_AI_GUARD_MAX_MESSAGES_LENGTH
619
- target['experimental.aiguard.timeout'] = maybeInt(DD_AI_GUARD_TIMEOUT)
620
- unprocessedTarget['experimental.aiguard.timeout'] = DD_AI_GUARD_TIMEOUT
621
- setBoolean(target, 'experimental.enableGetRumData', DD_TRACE_EXPERIMENTAL_GET_RUM_DATA_ENABLED)
622
- setString(target, 'experimental.exporter', DD_TRACE_EXPERIMENTAL_EXPORTER)
623
- if (AWS_LAMBDA_FUNCTION_NAME && !fs.existsSync(DATADOG_MINI_AGENT_PATH)) {
624
- target.flushInterval = 0
625
- } else if (DD_TRACE_FLUSH_INTERVAL) {
626
- target.flushInterval = maybeInt(DD_TRACE_FLUSH_INTERVAL)
413
+ if (!this.tracePropagationStyle.extract.includes('b3 single header')) {
414
+ this.tracePropagationStyle.extract.push('b3 single header')
415
+ }
416
+ setAndTrack(this, 'tracePropagationStyle.inject', this.tracePropagationStyle.inject)
417
+ setAndTrack(this, 'tracePropagationStyle.extract', this.tracePropagationStyle.extract)
627
418
  }
628
- target.flushMinSpans = maybeInt(DD_TRACE_PARTIAL_FLUSH_MIN_SPANS)
629
- unprocessedTarget.flushMinSpans = DD_TRACE_PARTIAL_FLUSH_MIN_SPANS
630
- setBoolean(target, 'gitMetadataEnabled', DD_TRACE_GIT_METADATA_ENABLED)
631
- setIntegerRangeSet(target, 'grpc.client.error.statuses', DD_GRPC_CLIENT_ERROR_STATUSES)
632
- setIntegerRangeSet(target, 'grpc.server.error.statuses', DD_GRPC_SERVER_ERROR_STATUSES)
633
- setArray(target, 'headerTags', DD_TRACE_HEADER_TAGS)
634
- target['heapSnapshot.count'] = maybeInt(DD_HEAP_SNAPSHOT_COUNT)
635
- setString(target, 'heapSnapshot.destination', DD_HEAP_SNAPSHOT_DESTINATION)
636
- target['heapSnapshot.interval'] = maybeInt(DD_HEAP_SNAPSHOT_INTERVAL)
637
- setString(target, 'hostname', DD_AGENT_HOST)
638
- target['iast.dbRowsToTaint'] = maybeInt(DD_IAST_DB_ROWS_TO_TAINT)
639
- setBoolean(target, 'iast.deduplicationEnabled', DD_IAST_DEDUPLICATION_ENABLED)
640
- setBoolean(target, 'iast.enabled', DD_IAST_ENABLED)
641
- target['iast.maxConcurrentRequests'] = maybeInt(DD_IAST_MAX_CONCURRENT_REQUESTS)
642
- unprocessedTarget['iast.maxConcurrentRequests'] = DD_IAST_MAX_CONCURRENT_REQUESTS
643
- target['iast.maxContextOperations'] = maybeInt(DD_IAST_MAX_CONTEXT_OPERATIONS)
644
- unprocessedTarget['iast.maxContextOperations'] = DD_IAST_MAX_CONTEXT_OPERATIONS
645
- setBoolean(target, 'iast.redactionEnabled', DD_IAST_REDACTION_ENABLED && !isFalse(DD_IAST_REDACTION_ENABLED))
646
- setString(target, 'iast.redactionNamePattern', DD_IAST_REDACTION_NAME_PATTERN)
647
- setString(target, 'iast.redactionValuePattern', DD_IAST_REDACTION_VALUE_PATTERN)
648
- const iastRequestSampling = maybeInt(DD_IAST_REQUEST_SAMPLING)
649
- if (iastRequestSampling !== undefined && iastRequestSampling > -1 && iastRequestSampling < 101) {
650
- target['iast.requestSampling'] = iastRequestSampling
419
+
420
+ if (getEnvironmentVariable('AWS_LAMBDA_FUNCTION_NAME') && !fs.existsSync(DATADOG_MINI_AGENT_PATH)) {
421
+ setAndTrack(this, 'flushInterval', 0)
651
422
  }
652
- unprocessedTarget['iast.requestSampling'] = DD_IAST_REQUEST_SAMPLING
653
- setString(target, 'iast.securityControlsConfiguration', DD_IAST_SECURITY_CONTROLS_CONFIGURATION)
654
- setString(target, 'iast.telemetryVerbosity', DD_IAST_TELEMETRY_VERBOSITY)
655
- setBoolean(target, 'iast.stackTrace.enabled', DD_IAST_STACK_TRACE_ENABLED)
656
- setString(target, 'installSignature.id', DD_INSTRUMENTATION_INSTALL_ID)
657
- setString(target, 'installSignature.time', DD_INSTRUMENTATION_INSTALL_TIME)
658
- setString(target, 'installSignature.type', DD_INSTRUMENTATION_INSTALL_TYPE)
659
- // TODO: Why is DD_INJECTION_ENABLED a comma separated list?
660
- setArray(target, 'injectionEnabled', DD_INJECTION_ENABLED)
661
- if (DD_INJECTION_ENABLED !== undefined) {
662
- setString(target, 'instrumentationSource', DD_INJECTION_ENABLED ? 'ssi' : 'manual')
423
+
424
+ if (!trackedConfigOrigins.has('apmTracingEnabled') &&
425
+ trackedConfigOrigins.has('experimental.appsec.standalone.enabled')) {
426
+ setAndTrack(this, 'apmTracingEnabled', !this.experimental.appsec.standalone.enabled)
663
427
  }
664
- setBoolean(target, 'injectForce', DD_INJECT_FORCE)
665
- setBoolean(target, 'isAzureFunction', getIsAzureFunction())
666
- setBoolean(target, 'isGCPFunction', getIsGCPFunction())
667
- setBoolean(target, 'gcpPubSubPushSubscriptionEnabled', enableGCPPubSubPushSubscription())
668
- target['langchain.spanCharLimit'] = maybeInt(DD_LANGCHAIN_SPAN_CHAR_LIMIT)
669
- target['langchain.spanPromptCompletionSampleRate'] = maybeFloat(DD_LANGCHAIN_SPAN_PROMPT_COMPLETION_SAMPLE_RATE)
670
- setBoolean(target, 'legacyBaggageEnabled', DD_TRACE_LEGACY_BAGGAGE_ENABLED)
671
- setBoolean(target, 'llmobs.agentlessEnabled', DD_LLMOBS_AGENTLESS_ENABLED)
672
- setBoolean(target, 'llmobs.enabled', DD_LLMOBS_ENABLED)
673
- setString(target, 'llmobs.mlApp', DD_LLMOBS_ML_APP)
674
- setBoolean(target, 'logInjection', DD_LOGS_INJECTION)
675
- // Requires an accompanying DD_APM_OBFUSCATION_MEMCACHED_KEEP_COMMAND=true in the agent
676
- setBoolean(target, 'memcachedCommandEnabled', DD_TRACE_MEMCACHED_COMMAND_ENABLED)
677
- setBoolean(target, 'middlewareTracingEnabled', DD_TRACE_MIDDLEWARE_TRACING_ENABLED)
678
- setBoolean(target, 'openAiLogsEnabled', DD_OPENAI_LOGS_ENABLED)
679
- target['openai.spanCharLimit'] = maybeInt(DD_OPENAI_SPAN_CHAR_LIMIT)
680
- unprocessedTarget.openaiSpanCharLimit = DD_OPENAI_SPAN_CHAR_LIMIT
681
- if (DD_TRACE_PEER_SERVICE_MAPPING) {
682
- target.peerServiceMapping = Object.fromEntries(
683
- DD_TRACE_PEER_SERVICE_MAPPING.split(',').map(x => x.trim().split(':'))
684
- )
685
- unprocessedTarget.peerServiceMapping = DD_TRACE_PEER_SERVICE_MAPPING
428
+
429
+ if (this.cloudPayloadTagging?.request || this.cloudPayloadTagging?.response) {
430
+ setAndTrack(this, 'cloudPayloadTagging.rules', appendRules(
431
+ this.cloudPayloadTagging.request,
432
+ this.cloudPayloadTagging.response
433
+ ))
686
434
  }
687
- setString(target, 'port', DD_TRACE_AGENT_PORT)
688
- const profilingEnabled = normalizeProfilingEnabledValue(DD_PROFILING_ENABLED)
689
- setString(target, 'profiling.enabled', profilingEnabled)
690
- setString(target, 'profiling.exporters', DD_PROFILING_EXPORTERS)
691
- setBoolean(target, 'profiling.sourceMap', DD_PROFILING_SOURCE_MAP && !isFalse(DD_PROFILING_SOURCE_MAP))
692
- if (DD_INTERNAL_PROFILING_LONG_LIVED_THRESHOLD) {
693
- // This is only used in testing to not have to wait 30s
694
- target['profiling.longLivedThreshold'] = Number(DD_INTERNAL_PROFILING_LONG_LIVED_THRESHOLD)
435
+
436
+ if (this.injectionEnabled) {
437
+ setAndTrack(this, 'instrumentationSource', 'ssi')
695
438
  }
696
439
 
697
- setString(target, 'protocolVersion', DD_TRACE_AGENT_PROTOCOL_VERSION)
698
- setString(target, 'queryStringObfuscation', DD_TRACE_OBFUSCATION_QUERY_STRING_REGEXP)
699
- setBoolean(target, 'remoteConfig.enabled', DD_REMOTE_CONFIGURATION_ENABLED)
700
- target['remoteConfig.pollInterval'] = maybeFloat(DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS)
701
- unprocessedTarget['remoteConfig.pollInterval'] = DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS
702
- setBoolean(target, 'reportHostname', DD_TRACE_REPORT_HOSTNAME)
703
- if (DD_TRACE_RESOURCE_RENAMING_ENABLED !== undefined) {
704
- setBoolean(target, 'resourceRenamingEnabled', DD_TRACE_RESOURCE_RENAMING_ENABLED)
440
+ if (!trackedConfigOrigins.has('runtimeMetrics.enabled') && this.OTEL_METRICS_EXPORTER === 'none') {
441
+ setAndTrack(this, 'runtimeMetrics.enabled', false)
705
442
  }
706
- // only used to explicitly set runtimeMetrics to false
707
- const otelSetRuntimeMetrics = String(OTEL_METRICS_EXPORTER).toLowerCase() === 'none'
708
- ? false
709
- : undefined
710
- setBoolean(target, 'runtimeMetrics.enabled', DD_RUNTIME_METRICS_ENABLED ||
711
- otelSetRuntimeMetrics)
712
- setBoolean(target, 'runtimeMetrics.eventLoop', DD_RUNTIME_METRICS_EVENT_LOOP_ENABLED)
713
- setBoolean(target, 'runtimeMetrics.gc', DD_RUNTIME_METRICS_GC_ENABLED)
714
- setBoolean(target, 'runtimeMetricsRuntimeId', DD_RUNTIME_METRICS_RUNTIME_ID_ENABLED)
715
- setArray(target, 'sampler.spanSamplingRules', reformatSpanSamplingRules(
716
- maybeJsonFile(DD_SPAN_SAMPLING_RULES_FILE) ??
717
- safeJsonParse(DD_SPAN_SAMPLING_RULES)
718
- ))
719
- setUnit(
720
- target,
721
- 'sampleRate',
722
- DD_TRACE_SAMPLE_RATE || getFromOtelSamplerMap(OTEL_TRACES_SAMPLER, OTEL_TRACES_SAMPLER_ARG)
723
- )
724
- target['sampler.rateLimit'] = DD_TRACE_RATE_LIMIT
725
- setSamplingRule(target, 'sampler.rules', safeJsonParse(DD_TRACE_SAMPLING_RULES))
726
- unprocessedTarget['sampler.rules'] = DD_TRACE_SAMPLING_RULES
727
- setString(target, 'scope', DD_TRACE_SCOPE)
728
- // Priority:
729
- // DD_SERVICE > tags.service > OTEL_SERVICE_NAME > NX_TASK_TARGET_PROJECT (if DD_ENABLE_NX_SERVICE_NAME) > default
730
- let serviceName = DD_SERVICE || tags.service || OTEL_SERVICE_NAME
731
- let isServiceNameInferred
732
- if (!serviceName && NX_TASK_TARGET_PROJECT) {
733
- if (isTrue(DD_ENABLE_NX_SERVICE_NAME)) {
734
- isServiceNameInferred = true
735
- serviceName = NX_TASK_TARGET_PROJECT
736
- } else if (DD_MAJOR < 6) {
737
- // Warn about v6 behavior change for Nx projects
738
- log.warn(
739
- // eslint-disable-next-line @stylistic/max-len
740
- 'NX_TASK_TARGET_PROJECT is set but no service name was configured. In v6, NX_TASK_TARGET_PROJECT will be used as the default service name. Set DD_ENABLE_NX_SERVICE_NAME=true to opt-in to this behavior now, or set a service name explicitly.'
741
- )
443
+
444
+ if (!trackedConfigOrigins.has('sampleRate')) {
445
+ const effectiveSampler = (trackedConfigOrigins.has('OTEL_TRACES_EXPORTER') &&
446
+ this.OTEL_TRACES_EXPORTER === 'otlp' &&
447
+ !trackedConfigOrigins.has('OTEL_TRACES_SAMPLER'))
448
+ ? 'parentbased_always_on'
449
+ : this.OTEL_TRACES_SAMPLER
450
+ if (effectiveSampler && (trackedConfigOrigins.has('OTEL_TRACES_SAMPLER') ||
451
+ trackedConfigOrigins.has('OTEL_TRACES_EXPORTER'))) {
452
+ setAndTrack(this, 'sampleRate', getFromOtelSamplerMap(effectiveSampler, this.OTEL_TRACES_SAMPLER_ARG))
742
453
  }
743
454
  }
744
- setString(target, 'service', serviceName)
745
- if (serviceName) setBoolean(target, 'isServiceNameInferred', isServiceNameInferred ?? false)
746
- if (DD_SERVICE_MAPPING) {
747
- target.serviceMapping = Object.fromEntries(
748
- DD_SERVICE_MAPPING.split(',').map(x => x.trim().split(':'))
749
- )
750
- }
751
- setString(target, 'site', DD_SITE)
752
- if (DD_TRACE_SPAN_ATTRIBUTE_SCHEMA) {
753
- setString(target, 'spanAttributeSchema', validateNamingVersion(DD_TRACE_SPAN_ATTRIBUTE_SCHEMA))
754
- unprocessedTarget.spanAttributeSchema = DD_TRACE_SPAN_ATTRIBUTE_SCHEMA
755
- }
756
- // 0: disabled, 1: logging, 2: garbage collection + logging
757
- target.spanLeakDebug = maybeInt(DD_TRACE_SPAN_LEAK_DEBUG)
758
- setBoolean(target, 'spanRemoveIntegrationFromService', DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED)
759
- setBoolean(target, 'startupLogs', DD_TRACE_STARTUP_LOGS)
760
- setTags(target, 'tags', tags)
761
- target.tagsHeaderMaxLength = DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH
762
- setBoolean(target, 'telemetry.enabled', DD_INSTRUMENTATION_TELEMETRY_ENABLED)
763
- setString(target, 'instrumentation_config_id', DD_INSTRUMENTATION_CONFIG_ID)
764
- setBoolean(target, 'telemetry.debug', DD_TELEMETRY_DEBUG)
765
- setBoolean(target, 'telemetry.dependencyCollection', DD_TELEMETRY_DEPENDENCY_COLLECTION_ENABLED)
766
- target['telemetry.heartbeatInterval'] = maybeInt(Math.floor(DD_TELEMETRY_HEARTBEAT_INTERVAL * 1000))
767
- unprocessedTarget['telemetry.heartbeatInterval'] = DD_TELEMETRY_HEARTBEAT_INTERVAL
768
- setBoolean(target, 'telemetry.logCollection', DD_TELEMETRY_LOG_COLLECTION_ENABLED)
769
- setBoolean(target, 'telemetry.metrics', DD_TELEMETRY_METRICS_ENABLED)
770
- setBoolean(target, 'isKeepingCoverageConfiguration', DD_TEST_TIA_KEEP_COV_CONFIG)
771
- setBoolean(target, 'traceId128BitGenerationEnabled', DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED)
772
- setBoolean(target, 'traceId128BitLoggingEnabled', DD_TRACE_128_BIT_TRACEID_LOGGING_ENABLED)
773
- warnIfPropagationStyleConflict(
774
- DD_TRACE_PROPAGATION_STYLE,
775
- DD_TRACE_PROPAGATION_STYLE_INJECT,
776
- DD_TRACE_PROPAGATION_STYLE_EXTRACT
777
- )
778
- if (DD_TRACE_PROPAGATION_STYLE !== undefined) {
779
- setArray(target, 'tracePropagationStyle.inject', normalizePropagationStyle(DD_TRACE_PROPAGATION_STYLE))
780
- setArray(target, 'tracePropagationStyle.extract', normalizePropagationStyle(DD_TRACE_PROPAGATION_STYLE))
455
+
456
+ if (this.DD_SPAN_SAMPLING_RULES_FILE) {
457
+ try {
458
+ // TODO: Should we log a warning in case this is defined next to spanSamplingRules?
459
+ setAndTrack(this, 'spanSamplingRules', transformers.toCamelCase(JSON.parse(this.DD_SPAN_SAMPLING_RULES_FILE)))
460
+ } catch (error) {
461
+ log.warn('Error reading span sampling rules file %s; %o', this.DD_SPAN_SAMPLING_RULES_FILE, error)
462
+ }
781
463
  }
782
- if (DD_TRACE_PROPAGATION_STYLE_INJECT !== undefined) {
783
- setArray(target, 'tracePropagationStyle.inject',
784
- normalizePropagationStyle(DD_TRACE_PROPAGATION_STYLE_INJECT))
464
+
465
+ // All sampler options are tracked as individual values. No need to track the sampler object as a whole.
466
+ this.sampler = {
467
+ rules: this.samplingRules,
468
+ rateLimit: this.rateLimit,
469
+ sampleRate: this.sampleRate,
470
+ spanSamplingRules: this.spanSamplingRules,
785
471
  }
786
- if (DD_TRACE_PROPAGATION_STYLE_EXTRACT !== undefined) {
787
- setArray(target, 'tracePropagationStyle.extract',
788
- normalizePropagationStyle(DD_TRACE_PROPAGATION_STYLE_EXTRACT))
472
+
473
+ // For LLMObs, we want to auto enable it when other llmobs options are defined.
474
+ if (!this.llmobs.enabled &&
475
+ !trackedConfigOrigins.has('llmobs.enabled') &&
476
+ (trackedConfigOrigins.has('llmobs.agentlessEnabled') ||
477
+ trackedConfigOrigins.has('llmobs.mlApp'))) {
478
+ setAndTrack(this, 'llmobs.enabled', true)
789
479
  }
790
- setBoolean(target, 'tracePropagationExtractFirst', DD_TRACE_PROPAGATION_EXTRACT_FIRST)
791
- if (DD_TRACE_PROPAGATION_BEHAVIOR_EXTRACT !== undefined) {
792
- const stringPropagationBehaviorExtract = String(DD_TRACE_PROPAGATION_BEHAVIOR_EXTRACT)
793
- target.tracePropagationBehaviorExtract =
794
- VALID_PROPAGATION_BEHAVIOR_EXTRACT.has(stringPropagationBehaviorExtract)
795
- ? stringPropagationBehaviorExtract
796
- : 'continue'
480
+
481
+ if (this.OTEL_RESOURCE_ATTRIBUTES) {
482
+ for (const [key, value] of Object.entries(this.OTEL_RESOURCE_ATTRIBUTES)) {
483
+ // Not replacing existing tags keeps the order of the tags as before.
484
+ if (!this.tags[key]) {
485
+ this.tags[key] = value
486
+ }
487
+ }
797
488
  }
798
- if (DD_TRACE_PROPAGATION_STYLE !== undefined ||
799
- DD_TRACE_PROPAGATION_STYLE_INJECT !== undefined ||
800
- DD_TRACE_PROPAGATION_STYLE_EXTRACT !== undefined ||
801
- OTEL_PROPAGATORS !== undefined) {
802
- // At least one var is defined, calculate value using truthy logic
803
- const useDdStyle = DD_TRACE_PROPAGATION_STYLE ||
804
- DD_TRACE_PROPAGATION_STYLE_INJECT ||
805
- DD_TRACE_PROPAGATION_STYLE_EXTRACT
806
- setBoolean(target, 'tracePropagationStyle.otelPropagators',
807
- useDdStyle ? false : !!OTEL_PROPAGATORS)
808
-
809
- // Use OTEL_PROPAGATORS if no DD-specific vars are set
810
- if (!useDdStyle && OTEL_PROPAGATORS) {
811
- const otelStyles = normalizePropagationStyle(OTEL_PROPAGATORS)
812
- // Validate OTEL propagators
813
- for (const style of otelStyles || []) {
814
- if (!VALID_PROPAGATION_STYLES.has(style)) {
815
- log.warn('unexpected value %s for OTEL_PROPAGATORS environment variable', style)
816
- getCounter('otel.env.invalid', 'DD_TRACE_PROPAGATION_STYLE', 'OTEL_PROPAGATORS').inc()
489
+ if (this.DD_TRACE_TAGS) {
490
+ // TODO: This is a hack to keep the order of the tags as before.
491
+ // That hack is not sufficient, since it does not handle other cases where the tags are set by the user.
492
+ if (trackedConfigOrigins.get('tags') === 'code') {
493
+ for (const [key, value] of Object.entries(this.DD_TRACE_TAGS)) {
494
+ // Not replacing existing tags keeps the order of the tags as before.
495
+ if (!this.tags[key]) {
496
+ this.tags[key] = value
817
497
  }
818
498
  }
819
- // Set inject/extract from OTEL_PROPAGATORS
820
- if (otelStyles) {
821
- setArray(target, 'tracePropagationStyle.inject', otelStyles)
822
- setArray(target, 'tracePropagationStyle.extract', otelStyles)
823
- }
499
+ } else {
500
+ Object.assign(this.tags, this.DD_TRACE_TAGS)
824
501
  }
825
502
  }
826
- setBoolean(target, 'traceWebsocketMessagesEnabled', DD_TRACE_WEBSOCKET_MESSAGES_ENABLED)
827
- setBoolean(target, 'traceWebsocketMessagesInheritSampling', DD_TRACE_WEBSOCKET_MESSAGES_INHERIT_SAMPLING)
828
- setBoolean(target, 'traceWebsocketMessagesSeparateTraces', DD_TRACE_WEBSOCKET_MESSAGES_SEPARATE_TRACES)
829
- setBoolean(target, 'tracing', DD_TRACING_ENABLED)
830
- setString(target, 'version', DD_VERSION || tags.version)
831
- setBoolean(target, 'inferredProxyServicesEnabled', DD_TRACE_INFERRED_PROXY_SERVICES_ENABLED)
832
- setBoolean(target, 'trace.aws.addSpanPointers', DD_TRACE_AWS_ADD_SPAN_POINTERS)
833
- setString(target, 'trace.dynamoDb.tablePrimaryKeys', DD_TRACE_DYNAMODB_TABLE_PRIMARY_KEYS)
834
- setArray(target, 'graphqlErrorExtensions', DD_TRACE_GRAPHQL_ERROR_EXTENSIONS)
835
- setBoolean(target, 'trace.nativeSpanEvents', DD_TRACE_NATIVE_SPAN_EVENTS)
836
- target['vertexai.spanPromptCompletionSampleRate'] = maybeFloat(DD_VERTEXAI_SPAN_PROMPT_COMPLETION_SAMPLE_RATE)
837
- target['vertexai.spanCharLimit'] = maybeInt(DD_VERTEXAI_SPAN_CHAR_LIMIT)
838
- }
839
503
 
840
- #applyOptions (options) {
841
- const opts = this.#options
842
- const tags = {}
504
+ if (!this.#parsedDdTags) {
505
+ this.#parsedDdTags = rfdc(this.tags)
506
+ }
843
507
 
844
- options = this.#optionsArg = { ingestion: {}, ...options, ...opts }
508
+ if (!this.env && this.tags.env !== undefined) {
509
+ setAndTrack(this, 'env', this.tags.env)
510
+ }
845
511
 
846
- tagger.add(tags, options.tags)
512
+ if (!this.version) {
513
+ setAndTrack(this, 'version', this.tags.version || pkg.version)
514
+ this.tags.version ??= pkg.version
515
+ }
847
516
 
848
- setBoolean(opts, 'apmTracingEnabled', options.apmTracingEnabled ??
849
- (options.experimental?.appsec?.standalone && !options.experimental.appsec.standalone.enabled)
850
- )
851
- setBoolean(opts, 'appsec.apiSecurity.enabled', options.appsec?.apiSecurity?.enabled)
852
- setBoolean(opts, 'appsec.apiSecurity.endpointCollectionEnabled',
853
- options.appsec?.apiSecurity?.endpointCollectionEnabled)
854
- opts['appsec.apiSecurity.endpointCollectionMessageLimit'] =
855
- maybeInt(options.appsec?.apiSecurity?.endpointCollectionMessageLimit)
856
- opts['appsec.blockedTemplateGraphql'] = maybeFile(options.appsec?.blockedTemplateGraphql)
857
- opts['appsec.blockedTemplateHtml'] = maybeFile(options.appsec?.blockedTemplateHtml)
858
- this.#optsUnprocessed['appsec.blockedTemplateHtml'] = options.appsec?.blockedTemplateHtml
859
- opts['appsec.blockedTemplateJson'] = maybeFile(options.appsec?.blockedTemplateJson)
860
- this.#optsUnprocessed['appsec.blockedTemplateJson'] = options.appsec?.blockedTemplateJson
861
- setBoolean(opts, 'appsec.enabled', options.appsec?.enabled)
862
- setString(opts, 'appsec.eventTracking.mode', options.appsec?.eventTracking?.mode)
863
- setBoolean(
864
- opts,
865
- 'appsec.extendedHeadersCollection.enabled',
866
- options.appsec?.extendedHeadersCollection?.enabled
867
- )
868
- setBoolean(
869
- opts,
870
- 'appsec.extendedHeadersCollection.redaction',
871
- options.appsec?.extendedHeadersCollection?.redaction
872
- )
873
- opts['appsec.extendedHeadersCollection.maxHeaders'] = options.appsec?.extendedHeadersCollection?.maxHeaders
874
- setString(opts, 'appsec.obfuscatorKeyRegex', options.appsec?.obfuscatorKeyRegex)
875
- setString(opts, 'appsec.obfuscatorValueRegex', options.appsec?.obfuscatorValueRegex)
876
- setBoolean(opts, 'appsec.rasp.enabled', options.appsec?.rasp?.enabled)
877
- setBoolean(opts, 'appsec.rasp.bodyCollection', options.appsec?.rasp?.bodyCollection)
878
- opts['appsec.rateLimit'] = maybeInt(options.appsec?.rateLimit)
879
- this.#optsUnprocessed['appsec.rateLimit'] = options.appsec?.rateLimit
880
- setString(opts, 'appsec.rules', options.appsec?.rules)
881
- setBoolean(opts, 'appsec.stackTrace.enabled', options.appsec?.stackTrace?.enabled)
882
- opts['appsec.stackTrace.maxDepth'] = maybeInt(options.appsec?.stackTrace?.maxDepth)
883
- this.#optsUnprocessed['appsec.stackTrace.maxDepth'] = options.appsec?.stackTrace?.maxDepth
884
- opts['appsec.stackTrace.maxStackTraces'] = maybeInt(options.appsec?.stackTrace?.maxStackTraces)
885
- this.#optsUnprocessed['appsec.stackTrace.maxStackTraces'] = options.appsec?.stackTrace?.maxStackTraces
886
- opts['appsec.wafTimeout'] = maybeInt(options.appsec?.wafTimeout)
887
- this.#optsUnprocessed['appsec.wafTimeout'] = options.appsec?.wafTimeout
888
- setBoolean(opts, 'clientIpEnabled', options.clientIpEnabled)
889
- setString(opts, 'clientIpHeader', options.clientIpHeader?.toLowerCase())
890
- if (options.cloudPayloadTagging?.request || options.cloudPayloadTagging?.response) {
891
- if (options.cloudPayloadTagging.request) {
892
- setBoolean(opts, 'cloudPayloadTagging.requestsEnabled', true)
517
+ let isServiceNameInferred = false
518
+ if (!trackedConfigOrigins.has('service')) {
519
+ if (this.tags.service) {
520
+ setAndTrack(this, 'service', this.tags.service)
521
+ } else {
522
+ const NX_TASK_TARGET_PROJECT = getEnvironmentVariable('NX_TASK_TARGET_PROJECT')
523
+ if (NX_TASK_TARGET_PROJECT) {
524
+ if (this.DD_ENABLE_NX_SERVICE_NAME) {
525
+ setAndTrack(this, 'service', NX_TASK_TARGET_PROJECT)
526
+ isServiceNameInferred = true
527
+ } else if (DD_MAJOR < 6) {
528
+ log.warn(
529
+ // eslint-disable-next-line eslint-rules/eslint-log-printf-style
530
+ 'NX_TASK_TARGET_PROJECT is set but no service name was configured. In v6, NX_TASK_TARGET_PROJECT will ' +
531
+ 'be used as the default service name. Set DD_ENABLE_NX_SERVICE_NAME=true to opt-in to this behavior ' +
532
+ 'now, or set a service name explicitly.'
533
+ )
534
+ }
535
+ }
893
536
  }
894
- if (options.cloudPayloadTagging.response) {
895
- setBoolean(opts, 'cloudPayloadTagging.responsesEnabled', true)
537
+
538
+ if (!this.service) {
539
+ const serverlessName = IS_SERVERLESS
540
+ ? (
541
+ getEnvironmentVariable('AWS_LAMBDA_FUNCTION_NAME') ||
542
+ getEnvironmentVariable('FUNCTION_NAME') || // Google Cloud Function Name set by deprecated runtimes
543
+ getEnvironmentVariable('K_SERVICE') || // Google Cloud Function Name set by newer runtimes
544
+ getEnvironmentVariable('WEBSITE_SITE_NAME') // set by Azure Functions
545
+ )
546
+ : undefined
547
+
548
+ setAndTrack(this, 'service', serverlessName || pkg.name || 'node')
549
+ this.tags.service ??= /** @type {string} */ (this.service)
550
+ isServiceNameInferred = true
896
551
  }
897
- opts['cloudPayloadTagging.rules'] = appendRules(
898
- splitJSONPathRules(options.cloudPayloadTagging.request),
899
- splitJSONPathRules(options.cloudPayloadTagging.response)
900
- )
901
- }
902
- if (options.cloudPayloadTagging?.requestsEnabled !== undefined) {
903
- setBoolean(opts, 'cloudPayloadTagging.requestsEnabled', options.cloudPayloadTagging.requestsEnabled)
904
- }
905
- if (options.cloudPayloadTagging?.responsesEnabled !== undefined) {
906
- setBoolean(opts, 'cloudPayloadTagging.responsesEnabled', options.cloudPayloadTagging.responsesEnabled)
907
- }
908
- opts['cloudPayloadTagging.maxDepth'] = maybeInt(options.cloudPayloadTagging?.maxDepth)
909
- opts.baggageMaxBytes = options.baggageMaxBytes
910
- opts.baggageMaxItems = options.baggageMaxItems
911
- setArray(opts, 'baggageTagKeys', options.baggageTagKeys)
912
- setBoolean(opts, 'codeOriginForSpans.enabled', options.codeOriginForSpans?.enabled)
913
- setBoolean(
914
- opts,
915
- 'codeOriginForSpans.experimental.exit_spans.enabled',
916
- options.codeOriginForSpans?.experimental?.exit_spans?.enabled
917
- )
918
- setString(opts, 'dbmPropagationMode', options.dbmPropagationMode)
919
- setBoolean(opts, 'dbm.injectSqlBaseHash', options.dbm?.injectSqlBaseHash)
920
- if (options.dogstatsd) {
921
- setString(opts, 'dogstatsd.hostname', options.dogstatsd.hostname)
922
- setString(opts, 'dogstatsd.port', options.dogstatsd.port)
923
- }
924
- setBoolean(opts, 'dsmEnabled', options.dsmEnabled)
925
- opts['dynamicInstrumentation.captureTimeoutMs'] = maybeInt(options.dynamicInstrumentation?.captureTimeoutMs)
926
- this.#optsUnprocessed['dynamicInstrumentation.captureTimeoutMs'] = options.dynamicInstrumentation?.captureTimeoutMs
927
- setBoolean(opts, 'dynamicInstrumentation.enabled', options.dynamicInstrumentation?.enabled)
928
- setString(opts, 'dynamicInstrumentation.probeFile', options.dynamicInstrumentation?.probeFile)
929
- setArray(
930
- opts,
931
- 'dynamicInstrumentation.redactedIdentifiers',
932
- options.dynamicInstrumentation?.redactedIdentifiers
933
- )
934
- setArray(
935
- opts,
936
- 'dynamicInstrumentation.redactionExcludedIdentifiers',
937
- options.dynamicInstrumentation?.redactionExcludedIdentifiers
938
- )
939
- opts['dynamicInstrumentation.uploadIntervalSeconds'] =
940
- maybeFloat(options.dynamicInstrumentation?.uploadIntervalSeconds)
941
- this.#optsUnprocessed['dynamicInstrumentation.uploadIntervalSeconds'] =
942
- options.dynamicInstrumentation?.uploadIntervalSeconds
943
- setString(opts, 'env', options.env || tags.env)
944
- setBoolean(opts, 'experimental.aiguard.block', options.experimental?.aiguard?.block)
945
- setBoolean(opts, 'experimental.aiguard.enabled', options.experimental?.aiguard?.enabled)
946
- setString(opts, 'experimental.aiguard.endpoint', options.experimental?.aiguard?.endpoint)
947
- opts['experimental.aiguard.maxMessagesLength'] = maybeInt(options.experimental?.aiguard?.maxMessagesLength)
948
- this.#optsUnprocessed['experimental.aiguard.maxMessagesLength'] = options.experimental?.aiguard?.maxMessagesLength
949
- opts['experimental.aiguard.maxContentSize'] = maybeInt(options.experimental?.aiguard?.maxContentSize)
950
- this.#optsUnprocessed['experimental.aiguard.maxContentSize'] = options.experimental?.aiguard?.maxContentSize
951
- opts['experimental.aiguard.timeout'] = maybeInt(options.experimental?.aiguard?.timeout)
952
- this.#optsUnprocessed['experimental.aiguard.timeout'] = options.experimental?.aiguard?.timeout
953
- setBoolean(opts, 'experimental.enableGetRumData', options.experimental?.enableGetRumData)
954
- setString(opts, 'experimental.exporter', options.experimental?.exporter)
955
- setBoolean(opts, 'experimental.flaggingProvider.enabled', options.experimental?.flaggingProvider?.enabled)
956
- opts['experimental.flaggingProvider.initializationTimeoutMs'] = maybeInt(
957
- options.experimental?.flaggingProvider?.initializationTimeoutMs
958
- )
959
- this.#optsUnprocessed['experimental.flaggingProvider.initializationTimeoutMs'] =
960
- options.experimental?.flaggingProvider?.initializationTimeoutMs
961
- opts.flushInterval = maybeInt(options.flushInterval)
962
- this.#optsUnprocessed.flushInterval = options.flushInterval
963
- opts.flushMinSpans = maybeInt(options.flushMinSpans)
964
- this.#optsUnprocessed.flushMinSpans = options.flushMinSpans
965
- setArray(opts, 'headerTags', options.headerTags)
966
- setString(opts, 'hostname', options.hostname)
967
- opts['iast.dbRowsToTaint'] = maybeInt(options.iast?.dbRowsToTaint)
968
- setBoolean(opts, 'iast.deduplicationEnabled', options.iast && options.iast.deduplicationEnabled)
969
- setBoolean(opts, 'iast.enabled',
970
- options.iast && (options.iast === true || options.iast.enabled === true))
971
- opts['iast.maxConcurrentRequests'] = maybeInt(options.iast?.maxConcurrentRequests)
972
- this.#optsUnprocessed['iast.maxConcurrentRequests'] = options.iast?.maxConcurrentRequests
973
- opts['iast.maxContextOperations'] = maybeInt(options.iast?.maxContextOperations)
974
- this.#optsUnprocessed['iast.maxContextOperations'] = options.iast?.maxContextOperations
975
- setBoolean(opts, 'iast.redactionEnabled', options.iast?.redactionEnabled)
976
- setString(opts, 'iast.redactionNamePattern', options.iast?.redactionNamePattern)
977
- setString(opts, 'iast.redactionValuePattern', options.iast?.redactionValuePattern)
978
- const iastRequestSampling = maybeInt(options.iast?.requestSampling)
979
- if (iastRequestSampling !== undefined && iastRequestSampling > -1 && iastRequestSampling < 101) {
980
- opts['iast.requestSampling'] = iastRequestSampling
981
- this.#optsUnprocessed['iast.requestSampling'] = options.iast?.requestSampling
982
- }
983
- if (DD_MAJOR < 6) {
984
- opts['iast.securityControlsConfiguration'] = options.iast?.securityControlsConfiguration
985
- }
986
- setBoolean(opts, 'iast.stackTrace.enabled', options.iast?.stackTrace?.enabled)
987
- setString(opts, 'iast.telemetryVerbosity', options.iast && options.iast.telemetryVerbosity)
988
- setBoolean(opts, 'isCiVisibility', options.isCiVisibility)
989
- setBoolean(opts, 'legacyBaggageEnabled', options.legacyBaggageEnabled)
990
- setBoolean(opts, 'llmobs.agentlessEnabled', options.llmobs?.agentlessEnabled)
991
- setString(opts, 'llmobs.mlApp', options.llmobs?.mlApp)
992
- setBoolean(opts, 'logInjection', options.logInjection)
993
- opts.lookup = options.lookup
994
- setBoolean(opts, 'middlewareTracingEnabled', options.middlewareTracingEnabled)
995
- setBoolean(opts, 'openAiLogsEnabled', options.openAiLogsEnabled)
996
- opts.peerServiceMapping = options.peerServiceMapping
997
- setBoolean(opts, 'plugins', options.plugins)
998
- setString(opts, 'port', options.port)
999
- const strProfiling = String(options.profiling)
1000
- if (['true', 'false', 'auto'].includes(strProfiling)) {
1001
- setString(opts, 'profiling.enabled', strProfiling)
1002
552
  }
1003
- setString(opts, 'protocolVersion', options.protocolVersion)
1004
- if (options.remoteConfig) {
1005
- opts['remoteConfig.pollInterval'] = maybeFloat(options.remoteConfig.pollInterval)
1006
- this.#optsUnprocessed['remoteConfig.pollInterval'] = options.remoteConfig.pollInterval
1007
- }
1008
- setBoolean(opts, 'reportHostname', options.reportHostname)
1009
- setBoolean(opts, 'runtimeMetrics.enabled', options.runtimeMetrics?.enabled)
1010
- setBoolean(opts, 'runtimeMetrics.eventLoop', options.runtimeMetrics?.eventLoop)
1011
- setBoolean(opts, 'runtimeMetrics.gc', options.runtimeMetrics?.gc)
1012
- setBoolean(opts, 'runtimeMetricsRuntimeId', options.runtimeMetricsRuntimeId)
1013
- setArray(opts, 'sampler.spanSamplingRules', reformatSpanSamplingRules(options.spanSamplingRules))
1014
- setUnit(opts, 'sampleRate', options.sampleRate ?? options.ingestion.sampleRate)
1015
- opts['sampler.rateLimit'] = maybeInt(options.rateLimit ?? options.ingestion.rateLimit)
1016
- setSamplingRule(opts, 'sampler.rules', options.samplingRules)
1017
- const optService = options.service || tags.service
1018
- setString(opts, 'service', optService)
1019
- if (optService) {
1020
- setBoolean(opts, 'isServiceNameInferred', false)
553
+
554
+ // This should not be tracked.
555
+ // TODO: Consider moving this outside of the config.
556
+ set(this, 'isServiceNameInferred', isServiceNameInferred)
557
+
558
+ // Add missing tags, in case they are defined otherwise.
559
+ if (this.service) {
560
+ this.tags.service = this.service
1021
561
  }
1022
- opts.serviceMapping = options.serviceMapping
1023
- setString(opts, 'site', options.site)
1024
- if (options.spanAttributeSchema) {
1025
- setString(opts, 'spanAttributeSchema', validateNamingVersion(options.spanAttributeSchema))
1026
- this.#optsUnprocessed.spanAttributeSchema = options.spanAttributeSchema
562
+ if (this.env) {
563
+ this.tags.env = this.env
1027
564
  }
1028
- setBoolean(opts, 'spanRemoveIntegrationFromService', options.spanRemoveIntegrationFromService)
1029
- setBoolean(opts, 'startupLogs', options.startupLogs)
1030
- setTags(opts, 'tags', tags)
1031
- setBoolean(opts, 'traceId128BitGenerationEnabled', options.traceId128BitGenerationEnabled)
1032
- setBoolean(opts, 'traceId128BitLoggingEnabled', options.traceId128BitLoggingEnabled)
1033
- setBoolean(opts, 'traceWebsocketMessagesEnabled', options.traceWebsocketMessagesEnabled)
1034
- setBoolean(opts, 'traceWebsocketMessagesInheritSampling', options.traceWebsocketMessagesInheritSampling)
1035
- setBoolean(opts, 'traceWebsocketMessagesSeparateTraces', options.traceWebsocketMessagesSeparateTraces)
1036
- setString(opts, 'version', options.version || tags.version)
1037
- setBoolean(opts, 'inferredProxyServicesEnabled', options.inferredProxyServicesEnabled)
1038
- setBoolean(opts, 'graphqlErrorExtensions', options.graphqlErrorExtensions)
1039
- setBoolean(opts, 'trace.nativeSpanEvents', options.trace?.nativeSpanEvents)
1040
- if (options.tracePropagationStyle) {
1041
- setArray(opts, 'tracePropagationStyle.inject',
1042
- normalizePropagationStyle(options.tracePropagationStyle.inject ?? options.tracePropagationStyle))
1043
- setArray(opts, 'tracePropagationStyle.extract',
1044
- normalizePropagationStyle(options.tracePropagationStyle.extract ?? options.tracePropagationStyle))
565
+ if (this.version) {
566
+ this.tags.version = this.version
1045
567
  }
568
+ this.tags['runtime-id'] = RUNTIME_ID
1046
569
 
1047
- // For LLMObs, we want the environment variable to take precedence over the options.
1048
- // This is reliant on environment config being set before options.
1049
- // This is to make sure the origins of each value are tracked appropriately for telemetry.
1050
- // We'll only set `llmobs.enabled` on the opts when it's not set on the environment, and options.llmobs is provided.
1051
- if (this.#env['llmobs.enabled'] == null && options.llmobs) {
1052
- setBoolean(opts, 'llmobs.enabled', true)
570
+ if (IS_SERVERLESS) {
571
+ setAndTrack(this, 'telemetry.enabled', false)
572
+ setAndTrack(this, 'crashtracking.enabled', false)
573
+ setAndTrack(this, 'remoteConfig.enabled', false)
1053
574
  }
1054
- }
1055
575
 
1056
- #isCiVisibility () {
1057
- return this.#optionsArg.isCiVisibility ?? this.#defaults.isCiVisibility
1058
- }
1059
-
1060
- #getHostname () {
1061
- const DD_CIVISIBILITY_AGENTLESS_URL = getEnv('DD_CIVISIBILITY_AGENTLESS_URL')
1062
- const url = DD_CIVISIBILITY_AGENTLESS_URL
1063
- ? new URL(DD_CIVISIBILITY_AGENTLESS_URL)
1064
- : getAgentUrl(this.#getTraceAgentUrl(), this.#optionsArg)
1065
- const DD_AGENT_HOST = this.#optionsArg.hostname ??
1066
- getEnv('DD_AGENT_HOST') ??
1067
- defaults.hostname
1068
- return DD_AGENT_HOST || url?.hostname
1069
- }
1070
-
1071
- #getSpanComputePeerService () {
1072
- const DD_TRACE_SPAN_ATTRIBUTE_SCHEMA = validateNamingVersion(
1073
- this.#optionsArg.spanAttributeSchema ??
1074
- getEnv('DD_TRACE_SPAN_ATTRIBUTE_SCHEMA')
1075
- )
1076
-
1077
- const peerServiceSet = (
1078
- this.#optionsArg.hasOwnProperty('spanComputePeerService') ||
1079
- getEnv('DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED') !== undefined
1080
- )
1081
- const peerServiceValue = this.#optionsArg.spanComputePeerService ??
1082
- getEnv('DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED')
1083
-
1084
- const spanComputePeerService = (
1085
- DD_TRACE_SPAN_ATTRIBUTE_SCHEMA === 'v0'
1086
- // In v0, peer service is computed only if it is explicitly set to true
1087
- ? peerServiceSet && isTrue(peerServiceValue)
1088
- // In >v0, peer service is false only if it is explicitly set to false
1089
- : (peerServiceSet ? !isFalse(peerServiceValue) : true)
1090
- )
1091
-
1092
- return spanComputePeerService
1093
- }
1094
-
1095
- #isTraceStatsComputationEnabled () {
1096
- const apmTracingEnabled = this.#options.apmTracingEnabled !== false &&
1097
- this.#env.apmTracingEnabled !== false
1098
-
1099
- return apmTracingEnabled && (
1100
- this.#optionsArg.stats ??
1101
- getEnv('DD_TRACE_STATS_COMPUTATION_ENABLED') ??
1102
- (getIsGCPFunction() || getIsAzureFunction())
1103
- )
1104
- }
1105
-
1106
- #getTraceAgentUrl () {
1107
- return this.#optionsArg.url ??
1108
- getEnv('DD_TRACE_AGENT_URL') ??
1109
- null
1110
- }
1111
-
1112
- // handles values calculated from a mixture of options and env vars
1113
- #applyCalculated () {
1114
- const calc = this.#calculated
1115
-
1116
- const DD_CIVISIBILITY_AGENTLESS_URL = getEnv('DD_CIVISIBILITY_AGENTLESS_URL')
1117
-
1118
- calc.url = DD_CIVISIBILITY_AGENTLESS_URL
1119
- ? new URL(DD_CIVISIBILITY_AGENTLESS_URL)
1120
- : getAgentUrl(this.#getTraceAgentUrl(), this.#optionsArg)
576
+ // TODO: Should this unconditionally be disabled?
577
+ if (getEnvironmentVariable('JEST_WORKER_ID') && !trackedConfigOrigins.has('telemetry.enabled')) {
578
+ setAndTrack(this, 'telemetry.enabled', false)
579
+ }
1121
580
 
1122
581
  // Experimental agentless APM span intake
1123
582
  // When enabled, sends spans directly to Datadog intake without an agent
1124
- const agentlessEnabled = isTrue(getEnv('_DD_APM_TRACING_AGENTLESS_ENABLED'))
583
+ // TODO: Replace this with a proper configuration
584
+ const agentlessEnabled = isTrue(getEnvironmentVariable('_DD_APM_TRACING_AGENTLESS_ENABLED'))
1125
585
  if (agentlessEnabled) {
1126
- setString(calc, 'experimental.exporter', 'agentless')
1127
- // Disable rate limiting - server-side sampling will be used
1128
- calc['sampler.rateLimit'] = -1
586
+ setAndTrack(this, 'experimental.exporter', 'agentless')
1129
587
  // Disable client-side stats computation
1130
- setBoolean(calc, 'stats.enabled', false)
588
+ setAndTrack(this, 'stats.enabled', false)
1131
589
  // Enable hostname reporting
1132
- setBoolean(calc, 'reportHostname', true)
590
+ setAndTrack(this, 'reportHostname', true)
591
+ // Disable rate limiting - server-side sampling will be used
592
+ setAndTrack(this, 'sampler.rateLimit', -1)
1133
593
  // Clear sampling rules - server-side sampling handles this
1134
- calc['sampler.rules'] = []
594
+ setAndTrack(this, 'sampler.rules', [])
1135
595
  // Agentless intake only accepts 64-bit trace IDs; disable 128-bit generation
1136
- setBoolean(calc, 'traceId128BitGenerationEnabled', false)
1137
- }
1138
-
1139
- if (this.#isCiVisibility()) {
1140
- setBoolean(calc, 'isEarlyFlakeDetectionEnabled',
1141
- getEnv('DD_CIVISIBILITY_EARLY_FLAKE_DETECTION_ENABLED') ?? true)
1142
- setBoolean(calc, 'isFlakyTestRetriesEnabled', getEnv('DD_CIVISIBILITY_FLAKY_RETRY_ENABLED') ?? true)
1143
- calc.flakyTestRetriesCount = maybeInt(getEnv('DD_CIVISIBILITY_FLAKY_RETRY_COUNT')) ?? 5
1144
- setBoolean(calc, 'isIntelligentTestRunnerEnabled', isTrue(isCiVisibilityItrEnabled()))
1145
- setBoolean(calc, 'isManualApiEnabled', !isFalse(getEnv('DD_CIVISIBILITY_MANUAL_API_ENABLED')))
1146
- setString(calc, 'ciVisibilityTestSessionName', getEnv('DD_TEST_SESSION_NAME'))
1147
- setBoolean(calc, 'ciVisAgentlessLogSubmissionEnabled',
1148
- isTrue(getEnv('DD_AGENTLESS_LOG_SUBMISSION_ENABLED')))
1149
- setBoolean(calc, 'isTestDynamicInstrumentationEnabled',
1150
- !isFalse(getEnv('DD_TEST_FAILED_TEST_REPLAY_ENABLED')))
1151
- setBoolean(calc, 'isServiceUserProvided', !!this.#env.service)
1152
- setBoolean(calc, 'isTestManagementEnabled', !isFalse(getEnv('DD_TEST_MANAGEMENT_ENABLED')))
1153
- calc.testManagementAttemptToFixRetries = maybeInt(getEnv('DD_TEST_MANAGEMENT_ATTEMPT_TO_FIX_RETRIES')) ?? 20
1154
- setBoolean(calc, 'isImpactedTestsEnabled',
1155
- !isFalse(getEnv('DD_CIVISIBILITY_IMPACTED_TESTS_DETECTION_ENABLED')))
1156
- }
1157
-
1158
- // Disable log injection when OTEL logs are enabled
1159
- // OTEL logs and DD log injection are mutually exclusive
1160
- if (this.#env.otelLogsEnabled) {
1161
- setBoolean(calc, 'logInjection', false)
596
+ if (!trackedConfigOrigins.has('traceId128BitGenerationEnabled')) {
597
+ setAndTrack(this, 'traceId128BitGenerationEnabled', false)
598
+ }
1162
599
  }
1163
600
 
1164
- calc['dogstatsd.hostname'] = this.#getHostname()
1165
-
1166
- // Compute OTLP logs and metrics URLs to send payloads to the active Datadog Agent
1167
- const agentHostname = this.#getHostname()
1168
- calc.otelLogsUrl = `http://${agentHostname}:${DEFAULT_OTLP_PORT}`
1169
- calc.otelMetricsUrl = `http://${agentHostname}:${DEFAULT_OTLP_PORT}/v1/metrics`
1170
- calc.otelUrl = `http://${agentHostname}:${DEFAULT_OTLP_PORT}`
1171
- calc['telemetry.heartbeatInterval'] = maybeInt(Math.floor(this.#defaults['telemetry.heartbeatInterval'] * 1000))
1172
-
1173
- setBoolean(calc, 'isGitUploadEnabled',
1174
- calc.isIntelligentTestRunnerEnabled && !isFalse(getEnv('DD_CIVISIBILITY_GIT_UPLOAD_ENABLED')))
1175
-
1176
- // Enable resourceRenamingEnabled when appsec is enabled and only
1177
- // if DD_TRACE_RESOURCE_RENAMING_ENABLED is not explicitly set
1178
- if (this.#env.resourceRenamingEnabled === undefined) {
1179
- const appsecEnabled = this.#options['appsec.enabled'] ?? this.#env['appsec.enabled']
1180
- if (appsecEnabled) {
1181
- setBoolean(calc, 'resourceRenamingEnabled', true)
601
+ // Apply all fallbacks to the calculated config.
602
+ for (const [configName, alias] of fallbackConfigurations) {
603
+ if (!trackedConfigOrigins.has(configName) && trackedConfigOrigins.has(alias)) {
604
+ setAndTrack(this, configName, this[alias])
1182
605
  }
1183
606
  }
1184
607
 
1185
- setBoolean(calc, 'spanComputePeerService', this.#getSpanComputePeerService())
1186
- setBoolean(calc, 'stats.enabled', this.#isTraceStatsComputationEnabled())
1187
- const defaultPropagationStyle = getDefaultPropagationStyle(this.#optionsArg)
1188
- if (defaultPropagationStyle.length > 2) {
1189
- // b3 was added, so update defaults to include it
1190
- // This will only be used if no other source (options, env, stable config) set the value
1191
- calc['tracePropagationStyle.inject'] = defaultPropagationStyle
1192
- calc['tracePropagationStyle.extract'] = defaultPropagationStyle
608
+ const DEFAULT_OTLP_PORT = '4318'
609
+ if (!this.otelLogsUrl) {
610
+ setAndTrack(this, 'otelLogsUrl', `http://${agentHostname}:${DEFAULT_OTLP_PORT}`)
1193
611
  }
1194
- }
1195
-
1196
- /**
1197
- * Applies remote configuration options from APM_TRACING configs.
1198
- *
1199
- * @param {import('./remote_config').RemoteConfigOptions} options - Configurations received via Remote Config
1200
- */
1201
- #applyRemoteConfig (options) {
1202
- const opts = this.#remote
1203
-
1204
- setBoolean(opts, 'dynamicInstrumentation.enabled', options.dynamic_instrumentation_enabled)
1205
- setBoolean(opts, 'codeOriginForSpans.enabled', options.code_origin_enabled)
1206
- setUnit(opts, 'sampleRate', options.tracing_sampling_rate)
1207
- setBoolean(opts, 'logInjection', options.log_injection_enabled)
1208
- setBoolean(opts, 'tracing', options.tracing_enabled)
1209
- this.#remoteUnprocessed['sampler.rules'] = options.tracing_sampling_rules
1210
- setSamplingRule(opts, 'sampler.rules', reformatTagsFromRC(options.tracing_sampling_rules))
1211
-
1212
- opts.headerTags = options.tracing_header_tags?.map(tag => {
1213
- return tag.tag_name ? `${tag.header}:${tag.tag_name}` : tag.header
1214
- })
1215
-
1216
- const tags = {}
1217
- tagger.add(tags, options.tracing_tags)
1218
- if (Object.keys(tags).length) {
1219
- tags['runtime-id'] = RUNTIME_ID
612
+ if (!this.otelMetricsUrl) {
613
+ setAndTrack(this, 'otelMetricsUrl', `http://${agentHostname}:${DEFAULT_OTLP_PORT}/v1/metrics`)
1220
614
  }
1221
- setTags(opts, 'tags', tags)
1222
- }
1223
-
1224
- #setAndTrackChange ({ name, value, origin, unprocessedValue, changes }) {
1225
- set(this, name, value)
1226
-
1227
- if (!changeTracker[name]) {
1228
- changeTracker[name] = {}
615
+ if (!trackedConfigOrigins.has('otelTracesUrl') && this.OTEL_EXPORTER_OTLP_ENDPOINT) {
616
+ // Generic OTLP endpoint: per spec, append /v1/traces signal-specific subpath
617
+ setAndTrack(this, 'otelTracesUrl', this.OTEL_EXPORTER_OTLP_ENDPOINT.replace(/\/$/, '') + '/v1/traces')
618
+ } else if (!this.otelTracesUrl) {
619
+ const tracesHostname = agentHostname === '127.0.0.1' ? 'localhost' : agentHostname
620
+ setAndTrack(this, 'otelTracesUrl', `http://${tracesHostname}:${DEFAULT_OTLP_PORT}/v1/traces`)
1229
621
  }
1230
622
 
1231
- const originExists = origin in changeTracker[name]
1232
- const oldValue = changeTracker[name][origin]
1233
-
1234
- if (!originExists || oldValue !== value) {
1235
- changeTracker[name][origin] = value
1236
- changes.push({
1237
- name,
1238
- value: unprocessedValue || value,
1239
- origin,
1240
- })
623
+ if (process.platform === 'win32') {
624
+ // OOM monitoring does not work properly on Windows, so it will be disabled.
625
+ deactivateIfEnabledAndWarnOnWindows(this, 'DD_PROFILING_EXPERIMENTAL_OOM_MONITORING_ENABLED')
626
+ // Profiler sampling contexts are not available on Windows, so features
627
+ // depending on those (code hotspots and endpoint collection) need to be disabled on Windows.
628
+ deactivateIfEnabledAndWarnOnWindows(this, 'DD_PROFILING_CODEHOTSPOTS_ENABLED')
629
+ deactivateIfEnabledAndWarnOnWindows(this, 'DD_PROFILING_ENDPOINT_COLLECTION_ENABLED')
630
+ deactivateIfEnabledAndWarnOnWindows(this, 'DD_PROFILING_CPU_ENABLED')
631
+ deactivateIfEnabledAndWarnOnWindows(this, 'DD_PROFILING_TIMELINE_ENABLED')
632
+ deactivateIfEnabledAndWarnOnWindows(this, 'DD_PROFILING_ASYNC_CONTEXT_FRAME_ENABLED')
1241
633
  }
1242
- }
1243
634
 
1244
- // TODO: Report origin changes and errors to telemetry.
1245
- // TODO: Deeply merge configurations.
1246
- // TODO: Move change tracking to telemetry.
1247
- // for telemetry reporting, `name`s in `containers` need to be keys from:
1248
- // https://github.com/DataDog/dd-go/blob/prod/trace/apps/tracer-telemetry-intake/telemetry-payload/static/config_norm_rules.json
1249
- #merge () {
1250
- const changes = []
1251
- const sources = this.#getSourcesInOrder()
1252
-
1253
- for (const name of Object.keys(this.#defaults)) {
1254
- // Use reverse order for merge (lowest priority first)
1255
- for (let i = sources.length - 1; i >= 0; i--) {
1256
- const { container, origin, unprocessed } = sources[i]
1257
- const value = container[name]
1258
- if (value != null || container === this.#defaults) {
1259
- this.#setAndTrackChange({
1260
- name,
1261
- value,
1262
- origin,
1263
- unprocessedValue: unprocessed?.[name],
1264
- changes,
1265
- })
1266
- }
1267
- }
1268
- }
1269
- this.sampler.sampleRate = this.sampleRate
1270
- updateConfig(changes, this)
635
+ // Single tags update is tracked as a calculated value.
636
+ setAndTrack(this, 'tags', this.tags)
637
+
638
+ telemetry.updateConfig([...configWithOrigin.values()], this)
1271
639
  }
1272
640
 
641
+ // TODO: Move outside of config. This is unrelated to the config system.
1273
642
  #loadGitMetadata () {
1274
- // try to read Git metadata from the environment variables
1275
- this.repositoryUrl = removeUserSensitiveInfo(
1276
- getEnv('DD_GIT_REPOSITORY_URL') ?? this.tags[GIT_REPOSITORY_URL]
1277
- )
1278
- this.commitSHA = getEnv('DD_GIT_COMMIT_SHA') ?? this.tags[GIT_COMMIT_SHA]
643
+ // Try to read Git metadata from the environment variables
644
+ this.repositoryUrl = removeUserSensitiveInfo(this.DD_GIT_REPOSITORY_URL ?? this.tags[GIT_REPOSITORY_URL])
645
+ this.commitSHA = this.DD_GIT_COMMIT_SHA ?? this.tags[GIT_COMMIT_SHA]
1279
646
 
1280
- // otherwise, try to read Git metadata from the git.properties file
647
+ // Otherwise, try to read Git metadata from the git.properties file
1281
648
  if (!this.repositoryUrl || !this.commitSHA) {
1282
- const DD_GIT_PROPERTIES_FILE = getEnv('DD_GIT_PROPERTIES_FILE')
649
+ const DD_GIT_PROPERTIES_FILE = this.DD_GIT_PROPERTIES_FILE
1283
650
  const gitPropertiesFile = DD_GIT_PROPERTIES_FILE ?? `${process.cwd()}/git.properties`
1284
- let gitPropertiesString
1285
651
  try {
1286
- gitPropertiesString = fs.readFileSync(gitPropertiesFile, 'utf8')
1287
- } catch (e) {
652
+ const gitPropertiesString = fs.readFileSync(gitPropertiesFile, 'utf8')
653
+ const { commitSHA, repositoryUrl } = getGitMetadataFromGitProperties(gitPropertiesString)
654
+ this.commitSHA ??= commitSHA
655
+ this.repositoryUrl ??= repositoryUrl
656
+ } catch (error) {
1288
657
  // Only log error if the user has set a git.properties path
1289
658
  if (DD_GIT_PROPERTIES_FILE) {
1290
- log.error('Error reading DD_GIT_PROPERTIES_FILE: %s', gitPropertiesFile, e)
659
+ log.error('Error reading DD_GIT_PROPERTIES_FILE: %s', gitPropertiesFile, error)
1291
660
  }
1292
661
  }
1293
- if (gitPropertiesString) {
1294
- const { commitSHA, repositoryUrl } = getGitMetadataFromGitProperties(gitPropertiesString)
1295
- this.commitSHA = this.commitSHA || commitSHA
1296
- this.repositoryUrl = this.repositoryUrl || repositoryUrl
1297
- }
1298
662
  }
1299
- // otherwise, try to read Git metadata from the .git/ folder
1300
- if (!this.repositoryUrl || !this.commitSHA) {
1301
- const DD_GIT_FOLDER_PATH = getEnv('DD_GIT_FOLDER_PATH')
1302
- const gitFolderPath = DD_GIT_FOLDER_PATH ?? path.join(process.cwd(), '.git')
1303
- if (!this.repositoryUrl) {
1304
- // try to read git config (repository URL)
1305
- const gitConfigPath = path.join(gitFolderPath, 'config')
1306
- try {
1307
- const gitConfigContent = fs.readFileSync(gitConfigPath, 'utf8')
1308
- if (gitConfigContent) {
1309
- this.repositoryUrl = getRemoteOriginURL(gitConfigContent)
1310
- }
1311
- } catch (e) {
1312
- // Only log error if the user has set a .git/ path
1313
- if (DD_GIT_FOLDER_PATH) {
1314
- log.error('Error reading git config: %s', gitConfigPath, e)
1315
- }
663
+
664
+ // Otherwise, try to read Git metadata from the .git/ folder
665
+ const DD_GIT_FOLDER_PATH = this.DD_GIT_FOLDER_PATH
666
+ const gitFolderPath = DD_GIT_FOLDER_PATH ?? path.join(process.cwd(), '.git')
667
+
668
+ if (!this.repositoryUrl) {
669
+ // Try to read git config (repository URL)
670
+ const gitConfigPath = path.join(gitFolderPath, 'config')
671
+ try {
672
+ const gitConfigContent = fs.readFileSync(gitConfigPath, 'utf8')
673
+ if (gitConfigContent) {
674
+ this.repositoryUrl = getRemoteOriginURL(gitConfigContent)
1316
675
  }
1317
- }
1318
- if (!this.commitSHA) {
1319
- // try to read git HEAD (commit SHA)
1320
- const gitHeadSha = resolveGitHeadSHA(gitFolderPath)
1321
- if (gitHeadSha) {
1322
- this.commitSHA = gitHeadSha
676
+ } catch (error) {
677
+ // Only log error if the user has set a .git/ path
678
+ if (DD_GIT_FOLDER_PATH) {
679
+ log.error('Error reading git config: %s', gitConfigPath, error)
1323
680
  }
1324
681
  }
1325
682
  }
683
+ // Try to read git HEAD (commit SHA)
684
+ this.commitSHA ??= resolveGitHeadSHA(gitFolderPath)
1326
685
  }
1327
686
  }
1328
687
 
1329
- function getCounter (event, ddVar, otelVar) {
1330
- const counters = TELEMETRY_COUNTERS.get(event)
1331
- const tags = []
1332
- const ddVarPrefix = 'config_datadog:'
1333
- const otelVarPrefix = 'config_opentelemetry:'
1334
- if (ddVar) {
1335
- ddVar = ddVarPrefix + ddVar.toLowerCase()
1336
- tags.push(ddVar)
1337
- }
1338
- if (otelVar) {
1339
- otelVar = otelVarPrefix + otelVar.toLowerCase()
1340
- tags.push(otelVar)
1341
- }
1342
-
1343
- if (!(otelVar in counters)) counters[otelVar] = {}
1344
-
1345
- const counter = tracerMetrics.count(event, tags)
1346
- counters[otelVar][ddVar] = counter
1347
- return counter
1348
- }
1349
-
1350
- function getFromOtelSamplerMap (otelTracesSampler, otelTracesSamplerArg) {
1351
- const OTEL_TRACES_SAMPLER_MAPPING = {
1352
- always_on: '1.0',
1353
- always_off: '0.0',
1354
- traceidratio: otelTracesSamplerArg,
1355
- parentbased_always_on: '1.0',
1356
- parentbased_always_off: '0.0',
1357
- parentbased_traceidratio: otelTracesSamplerArg,
1358
- }
1359
- return OTEL_TRACES_SAMPLER_MAPPING[otelTracesSampler]
1360
- }
1361
-
1362
688
  /**
1363
- * Validate the type of an environment variable
1364
- * @param {string} envVar - The name of the environment variable
1365
- * @param {string} [value] - The value of the environment variable
1366
- * @returns {boolean} - True if the value is valid, false otherwise
689
+ * @param {Config} config
690
+ * @param {ConfigKey} envVar
1367
691
  */
1368
- function isInvalidOtelEnvironmentVariable (envVar, value) {
1369
- // Skip validation if the value is undefined (it was not set as environment variable)
1370
- if (value === undefined) return false
1371
-
1372
- switch (envVar) {
1373
- case 'OTEL_LOG_LEVEL':
1374
- return !VALID_LOG_LEVELS.has(value)
1375
- case 'OTEL_PROPAGATORS':
1376
- case 'OTEL_RESOURCE_ATTRIBUTES':
1377
- case 'OTEL_SERVICE_NAME':
1378
- return typeof value !== 'string'
1379
- case 'OTEL_TRACES_SAMPLER':
1380
- return getFromOtelSamplerMap(value, getEnv('OTEL_TRACES_SAMPLER_ARG')) === undefined
1381
- case 'OTEL_TRACES_SAMPLER_ARG':
1382
- return Number.isNaN(Number.parseFloat(value))
1383
- case 'OTEL_SDK_DISABLED':
1384
- return value.toLowerCase() !== 'true' && value.toLowerCase() !== 'false'
1385
- case 'OTEL_TRACES_EXPORTER':
1386
- case 'OTEL_METRICS_EXPORTER':
1387
- case 'OTEL_LOGS_EXPORTER':
1388
- return value.toLowerCase() !== 'none'
1389
- default:
1390
- return true
1391
- }
1392
- }
1393
-
1394
- function checkIfBothOtelAndDdEnvVarSet () {
1395
- for (const [otelEnvVar, ddEnvVar] of OTEL_DD_ENV_MAPPING) {
1396
- const otelValue = getEnv(otelEnvVar)
1397
-
1398
- if (ddEnvVar && getEnv(ddEnvVar) && otelValue) {
1399
- log.warn('both %s and %s environment variables are set', ddEnvVar, otelEnvVar)
1400
- getCounter('otel.env.hiding', ddEnvVar, otelEnvVar).inc()
1401
- }
1402
-
1403
- if (isInvalidOtelEnvironmentVariable(otelEnvVar, otelValue)) {
1404
- log.warn('unexpected value %s for %s environment variable', otelValue, otelEnvVar)
1405
- getCounter('otel.env.invalid', ddEnvVar, otelEnvVar).inc()
692
+ function deactivateIfEnabledAndWarnOnWindows (config, envVar) {
693
+ if (config[envVar]) {
694
+ const source = trackedConfigOrigins.get(envVar)
695
+ setAndTrack(config, envVar, false)
696
+ // TODO: Should we log even for default values?
697
+ if (source) {
698
+ log.warn('%s is not supported on Windows. Deactivating. (source: %s)', envVar, source)
1406
699
  }
1407
700
  }
1408
701
  }
1409
702
 
1410
- function maybeFile (filepath) {
1411
- if (!filepath) return
1412
- try {
1413
- return fs.readFileSync(filepath, 'utf8')
1414
- } catch (e) {
1415
- log.error('Error reading file %s', filepath, e)
1416
- }
1417
- }
1418
-
1419
- function maybeJsonFile (filepath) {
1420
- const file = maybeFile(filepath)
1421
- if (!file) return
1422
- try {
1423
- return JSON.parse(file)
1424
- } catch (e) {
1425
- log.error('Error parsing JSON file %s', filepath, e)
1426
- }
1427
- }
1428
-
1429
- function safeJsonParse (input) {
1430
- try {
1431
- return JSON.parse(input)
1432
- } catch {}
1433
- }
1434
-
1435
- function validateNamingVersion (versionString) {
1436
- if (!versionString) {
1437
- return DEFAULT_NAMING_VERSION
1438
- }
1439
- if (!NAMING_VERSIONS.has(versionString)) {
1440
- log.warn('Unexpected input for config.spanAttributeSchema, picked default', DEFAULT_NAMING_VERSION)
1441
- return DEFAULT_NAMING_VERSION
1442
- }
1443
- return versionString
1444
- }
1445
-
1446
- /**
1447
- * Given a string of comma-separated paths, return the array of paths.
1448
- * If a blank path is provided a null is returned to signal that the feature is disabled.
1449
- * An empty array means the feature is enabled but that no rules need to be applied.
1450
- *
1451
- * @param {string | string[]} input
1452
- */
1453
- function splitJSONPathRules (input) {
1454
- if (!input || input === '$') return
1455
- if (Array.isArray(input)) return input
1456
- if (input === 'all') return []
1457
- return input.split(',')
1458
- }
1459
-
1460
- // Shallow clone with property name remapping
1461
- function remapify (input, mappings) {
1462
- if (!input) return
1463
- const output = {}
1464
- for (const [key, value] of Object.entries(input)) {
1465
- output[key in mappings ? mappings[key] : key] = value
703
+ function increaseCounter (event, ddVar, otelVar) {
704
+ const tags = []
705
+ if (ddVar) {
706
+ tags.push(`config_datadog:${ddVar.toLowerCase()}`)
1466
707
  }
1467
- return output
708
+ tags.push(`config_opentelemetry:${otelVar.toLowerCase()}`)
709
+ tracerMetrics.count(event, tags).inc()
1468
710
  }
1469
711
 
1470
- /**
1471
- * Normalizes propagation style values to a lowercase array.
1472
- * Handles both string (comma-separated) and array inputs.
1473
- */
1474
- function normalizePropagationStyle (value) {
1475
- if (Array.isArray(value)) {
1476
- return value.map(v => v.toLowerCase())
1477
- }
1478
- if (typeof value === 'string') {
1479
- return value.split(',')
1480
- .filter(v => v !== '')
1481
- .map(v => v.trim().toLowerCase())
712
+ function getFromOtelSamplerMap (otelTracesSampler, otelTracesSamplerArg) {
713
+ const NON_PARENTBASED_TO_PARENTBASED = {
714
+ always_on: 'parentbased_always_on',
715
+ always_off: 'parentbased_always_off',
716
+ traceidratio: 'parentbased_traceidratio',
1482
717
  }
1483
- if (value !== undefined) {
1484
- log.warn('Unexpected input for config.tracePropagationStyle')
718
+ const OTEL_TRACES_SAMPLER_MAPPING = {
719
+ parentbased_always_on: 1,
720
+ parentbased_always_off: 0,
1485
721
  }
1486
- }
1487
722
 
1488
- /**
1489
- * Warns if both DD_TRACE_PROPAGATION_STYLE and specific inject/extract vars are set.
1490
- */
1491
- function warnIfPropagationStyleConflict (general, inject, extract) {
1492
- if (general && (inject || extract)) {
1493
- log.warn(
1494
- // eslint-disable-next-line @stylistic/max-len
1495
- 'Use either the DD_TRACE_PROPAGATION_STYLE environment variable or separate DD_TRACE_PROPAGATION_STYLE_INJECT and DD_TRACE_PROPAGATION_STYLE_EXTRACT environment variables'
723
+ const parentBasedEquivalent = NON_PARENTBASED_TO_PARENTBASED[otelTracesSampler]
724
+ if (parentBasedEquivalent) {
725
+ log.info(
726
+ 'OTEL_TRACES_SAMPLER=%s does not respect upstream sampling decisions; using parent-based equivalent %s instead',
727
+ otelTracesSampler, parentBasedEquivalent
1496
728
  )
729
+ otelTracesSampler = parentBasedEquivalent
1497
730
  }
1498
- }
1499
-
1500
- function reformatSpanSamplingRules (rules) {
1501
- if (!rules) return rules
1502
- return rules.map(rule => {
1503
- return remapify(rule, {
1504
- sample_rate: 'sampleRate',
1505
- max_per_second: 'maxPerSecond',
1506
- })
1507
- })
1508
- }
1509
731
 
1510
- function getDefaultPropagationStyle (options) {
1511
- // TODO: Remove the experimental env vars as a major?
1512
- const DD_TRACE_B3_ENABLED = options.experimental?.b3 ??
1513
- getEnv('DD_TRACE_EXPERIMENTAL_B3_ENABLED')
1514
- const defaultPropagationStyle = ['datadog', 'tracecontext']
1515
- if (isTrue(DD_TRACE_B3_ENABLED)) {
1516
- defaultPropagationStyle.push('b3', 'b3 single header')
732
+ const result = OTEL_TRACES_SAMPLER_MAPPING[otelTracesSampler] ?? otelTracesSamplerArg
733
+ if (result === undefined) {
734
+ increaseCounter('otel.env.invalid', 'DD_TRACE_SAMPLE_RATE', 'OTEL_TRACES_SAMPLER')
1517
735
  }
1518
- return defaultPropagationStyle
1519
- }
1520
-
1521
- function isCiVisibilityItrEnabled () {
1522
- return getEnv('DD_CIVISIBILITY_ITR_ENABLED') ?? true
736
+ return result
1523
737
  }
1524
738
 
1525
- function reformatTagsFromRC (samplingRules) {
1526
- for (const rule of (samplingRules || [])) {
1527
- if (rule.tags) {
1528
- const reformattedTags = {}
1529
- for (const tag of rule.tags) {
1530
- reformattedTags[tag.key] = tag.value_glob
739
+ function warnWrongOtelSettings () {
740
+ // This mostly works for non-aliased environment variables only.
741
+ // TODO: Adjust this to work across all sources.
742
+ for (const [otelEnvVar, ddEnvVar, key] of [
743
+ // eslint-disable-next-line eslint-rules/eslint-env-aliases
744
+ ['OTEL_LOG_LEVEL', 'DD_TRACE_LOG_LEVEL', 'logLevel'],
745
+ // eslint-disable-next-line eslint-rules/eslint-env-aliases
746
+ ['OTEL_PROPAGATORS', 'DD_TRACE_PROPAGATION_STYLE', 'DD_TRACE_PROPAGATION_STYLE'],
747
+ // eslint-disable-next-line eslint-rules/eslint-env-aliases
748
+ ['OTEL_SERVICE_NAME', 'DD_SERVICE', 'service'],
749
+ ['OTEL_TRACES_SAMPLER', 'DD_TRACE_SAMPLE_RATE'],
750
+ ['OTEL_TRACES_SAMPLER_ARG', 'DD_TRACE_SAMPLE_RATE'],
751
+ ['OTEL_TRACES_EXPORTER', 'DD_TRACE_ENABLED'],
752
+ ['OTEL_METRICS_EXPORTER', 'DD_RUNTIME_METRICS_ENABLED'],
753
+ ['OTEL_RESOURCE_ATTRIBUTES', 'DD_TAGS'],
754
+ ['OTEL_SDK_DISABLED', 'DD_TRACE_OTEL_ENABLED'],
755
+ ['OTEL_LOGS_EXPORTER'],
756
+ ]) {
757
+ // eslint-disable-next-line eslint-rules/eslint-process-env
758
+ const envs = process.env
759
+ const otelSource = trackedConfigOrigins.get(/** @type {ConfigPath} */ (key ?? otelEnvVar))
760
+ const otelEnvValue = envs[otelEnvVar]
761
+ if (otelEnvValue) {
762
+ if (envs[ddEnvVar]) {
763
+ log.warn('Conflicting %s and %s environment variables are set for %s', ddEnvVar, otelEnvVar, otelSource)
764
+ increaseCounter('otel.env.hiding', ddEnvVar, otelEnvVar)
1531
765
  }
1532
- rule.tags = reformattedTags
1533
- }
1534
- }
1535
- return samplingRules
1536
- }
1537
-
1538
- function setBoolean (obj, name, value) {
1539
- if (value === undefined || value === null) {
1540
- obj[name] = value
1541
- } else if (isTrue(value)) {
1542
- obj[name] = true
1543
- } else if (isFalse(value)) {
1544
- obj[name] = false
1545
- }
1546
- }
1547
-
1548
- function setUnit (obj, name, value) {
1549
- if (value === null || value === undefined) {
1550
- obj[name] = value
1551
- return
1552
- }
1553
-
1554
- value = Number.parseFloat(value)
1555
-
1556
- if (!Number.isNaN(value)) {
1557
- // TODO: Ignore out of range values instead of normalizing them.
1558
- obj[name] = Math.min(Math.max(value, 0), 1)
1559
- }
1560
- }
1561
-
1562
- function setArray (obj, name, value) {
1563
- if (value == null) {
1564
- obj[name] = null
1565
- return
1566
- }
1567
766
 
1568
- if (typeof value === 'string') {
1569
- value = value.split(',').map(item => {
1570
- // Trim each item and remove whitespace around the colon
1571
- const [key, val] = item.split(':').map(part => part.trim())
1572
- return val === undefined ? key : `${key}:${val}`
1573
- })
1574
- }
1575
-
1576
- if (Array.isArray(value)) {
1577
- obj[name] = value
1578
- }
1579
- }
1580
-
1581
- function setIntegerRangeSet (obj, name, value) {
1582
- if (value == null) {
1583
- obj[name] = null
1584
- return
1585
- }
1586
- value = value.split(',')
1587
- const result = []
1588
-
1589
- for (const val of value) {
1590
- if (val.includes('-')) {
1591
- const [start, end] = val.split('-').map(Number)
1592
- for (let i = start; i <= end; i++) {
1593
- result.push(i)
767
+ const invalidOtelValue = !otelSource
768
+ if (invalidOtelValue) {
769
+ increaseCounter('otel.env.invalid', ddEnvVar, otelEnvVar)
1594
770
  }
1595
- } else {
1596
- result.push(Number(val))
1597
771
  }
1598
772
  }
1599
- obj[name] = result
1600
- }
1601
-
1602
- function setSamplingRule (obj, name, value) {
1603
- if (value == null) {
1604
- obj[name] = null
1605
- return
1606
- }
1607
-
1608
- if (typeof value === 'string') {
1609
- value = value.split(',')
1610
- }
1611
-
1612
- if (Array.isArray(value)) {
1613
- value = value.map(rule => {
1614
- return remapify(rule, {
1615
- sample_rate: 'sampleRate',
1616
- })
1617
- })
1618
- obj[name] = value
1619
- }
1620
- }
1621
-
1622
- function setString (obj, name, value) {
1623
- obj[name] = value ? String(value) : undefined // unset for empty strings
1624
- }
1625
-
1626
- function setTags (obj, name, value) {
1627
- if (!value || Object.keys(value).length === 0) {
1628
- obj[name] = null
1629
- return
1630
- }
1631
-
1632
- obj[name] = value
1633
- }
1634
-
1635
- function handleOtel (tagString) {
1636
- return tagString
1637
- ?.replace(/(^|,)deployment\.environment=/, '$1env:')
1638
- .replace(/(^|,)service\.name=/, '$1service:')
1639
- .replace(/(^|,)service\.version=/, '$1version:')
1640
- .replaceAll('=', ':')
1641
- }
1642
-
1643
- function parseSpaceSeparatedTags (tagString) {
1644
- if (tagString && !tagString.includes(',')) {
1645
- tagString = tagString.replaceAll(/\s+/g, ',')
1646
- }
1647
- return tagString
1648
- }
1649
-
1650
- function maybeInt (number) {
1651
- const parsed = Number.parseInt(number)
1652
- return Number.isNaN(parsed) ? undefined : parsed
1653
- }
1654
-
1655
- function maybeFloat (number) {
1656
- const parsed = Number.parseFloat(number)
1657
- return Number.isNaN(parsed) ? undefined : parsed
1658
- }
1659
-
1660
- function nonNegInt (value, envVarName, allowZero = true) {
1661
- if (value === undefined) return
1662
- const parsed = Number.parseInt(value)
1663
- if (Number.isNaN(parsed) || parsed < 0 || (parsed === 0 && !allowZero)) {
1664
- log.warn('Invalid value %d for %s. Using default value.', parsed, envVarName)
1665
- return
1666
- }
1667
- return parsed
1668
- }
1669
-
1670
- function getAgentUrl (url, options) {
1671
- if (url) return new URL(url)
1672
-
1673
- if (os.type() === 'Windows_NT') return
1674
-
1675
- if (
1676
- !options.hostname &&
1677
- !options.port &&
1678
- !getEnv('DD_AGENT_HOST') &&
1679
- !getEnv('DD_TRACE_AGENT_PORT') &&
1680
- !isTrue(getEnv('DD_CIVISIBILITY_AGENTLESS_ENABLED')) &&
1681
- fs.existsSync('/var/run/datadog/apm.socket')
1682
- ) {
1683
- return new URL('unix:///var/run/datadog/apm.socket')
1684
- }
1685
773
  }
1686
774
 
775
+ /**
776
+ * @param {TracerOptions} [options]
777
+ */
1687
778
  function getConfig (options) {
1688
779
  if (!configInstance) {
1689
780
  configInstance = new Config(options)