dd-trace 6.3.0 → 6.5.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 (207) hide show
  1. package/README.electron.md +7 -0
  2. package/README.md +17 -0
  3. package/ci/diagnose.js +2100 -0
  4. package/ci/init.js +23 -2
  5. package/ci/runbook.md +198 -0
  6. package/ci/test-optimization-validation/approval-artifacts.js +143 -0
  7. package/ci/test-optimization-validation/approval.js +299 -0
  8. package/ci/test-optimization-validation/artifact-id.js +20 -0
  9. package/ci/test-optimization-validation/bounded-json.js +121 -0
  10. package/ci/test-optimization-validation/ci-command-candidate.js +83 -0
  11. package/ci/test-optimization-validation/ci-discovery.js +181 -0
  12. package/ci/test-optimization-validation/ci-remediation.js +210 -0
  13. package/ci/test-optimization-validation/cli.js +903 -0
  14. package/ci/test-optimization-validation/command-blocker.js +81 -0
  15. package/ci/test-optimization-validation/command-output-policy.js +206 -0
  16. package/ci/test-optimization-validation/command-runner.js +707 -0
  17. package/ci/test-optimization-validation/command-suitability.js +471 -0
  18. package/ci/test-optimization-validation/executable-approval.js +48 -0
  19. package/ci/test-optimization-validation/executable.js +480 -0
  20. package/ci/test-optimization-validation/generated-file-policy.js +63 -0
  21. package/ci/test-optimization-validation/generated-files.js +351 -0
  22. package/ci/test-optimization-validation/generated-verifier.js +196 -0
  23. package/ci/test-optimization-validation/init-probe-preload.js +163 -0
  24. package/ci/test-optimization-validation/init-probe.js +246 -0
  25. package/ci/test-optimization-validation/late-initialization.js +63 -0
  26. package/ci/test-optimization-validation/local-command.js +163 -0
  27. package/ci/test-optimization-validation/manifest-loader.js +133 -0
  28. package/ci/test-optimization-validation/manifest-scaffold.js +738 -0
  29. package/ci/test-optimization-validation/manifest-schema.js +862 -0
  30. package/ci/test-optimization-validation/offline-fixtures.js +327 -0
  31. package/ci/test-optimization-validation/offline-output.js +406 -0
  32. package/ci/test-optimization-validation/payload-normalizer.js +72 -0
  33. package/ci/test-optimization-validation/plan-writer.js +1120 -0
  34. package/ci/test-optimization-validation/preflight-runner.js +114 -0
  35. package/ci/test-optimization-validation/redaction.js +331 -0
  36. package/ci/test-optimization-validation/report-writer.js +1508 -0
  37. package/ci/test-optimization-validation/safe-files.js +203 -0
  38. package/ci/test-optimization-validation/scenarios/auto-test-retries.js +159 -0
  39. package/ci/test-optimization-validation/scenarios/basic-reporting.js +657 -0
  40. package/ci/test-optimization-validation/scenarios/ci-wiring.js +780 -0
  41. package/ci/test-optimization-validation/scenarios/early-flake-detection.js +141 -0
  42. package/ci/test-optimization-validation/scenarios/helpers.js +539 -0
  43. package/ci/test-optimization-validation/scenarios/test-management.js +218 -0
  44. package/ci/test-optimization-validation/setup-runner.js +97 -0
  45. package/ci/test-optimization-validation/static-diagnosis.js +159 -0
  46. package/ci/test-optimization-validation/test-output.js +129 -0
  47. package/ci/test-optimization-validation-manifest.schema.json +1 -0
  48. package/ci/validate-test-optimization.js +3 -0
  49. package/ext/exporters.js +1 -0
  50. package/index.d.ts +121 -8
  51. package/index.electron.js +3 -0
  52. package/init.js +18 -0
  53. package/initialize.mjs +1 -1
  54. package/loader-hook.mjs +28 -18
  55. package/openfeature.d.ts +1 -0
  56. package/openfeature.js +4 -0
  57. package/package.json +15 -8
  58. package/packages/datadog-instrumentations/src/ai.js +37 -26
  59. package/packages/datadog-instrumentations/src/child_process.js +1 -1
  60. package/packages/datadog-instrumentations/src/claude-agent-sdk.js +1 -1
  61. package/packages/datadog-instrumentations/src/cucumber-worker-threads.js +9 -3
  62. package/packages/datadog-instrumentations/src/cucumber.js +24 -10
  63. package/packages/datadog-instrumentations/src/cypress-config.js +398 -52
  64. package/packages/datadog-instrumentations/src/express.js +20 -2
  65. package/packages/datadog-instrumentations/src/fastify.js +7 -11
  66. package/packages/datadog-instrumentations/src/grpc/server.js +18 -0
  67. package/packages/datadog-instrumentations/src/helpers/hook.js +27 -6
  68. package/packages/datadog-instrumentations/src/helpers/optional-peer-bundler.js +8 -8
  69. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +28 -2
  70. package/packages/datadog-instrumentations/src/helpers/router-helper.js +8 -8
  71. package/packages/datadog-instrumentations/src/http2/server.js +143 -17
  72. package/packages/datadog-instrumentations/src/jest.js +36 -4
  73. package/packages/datadog-instrumentations/src/mariadb.js +1 -1
  74. package/packages/datadog-instrumentations/src/mocha/main.js +0 -2
  75. package/packages/datadog-instrumentations/src/mocha/utils.js +0 -4
  76. package/packages/datadog-instrumentations/src/mongodb.js +3 -3
  77. package/packages/datadog-instrumentations/src/mongoose.js +3 -3
  78. package/packages/datadog-instrumentations/src/mquery.js +2 -2
  79. package/packages/datadog-instrumentations/src/mysql.js +1 -1
  80. package/packages/datadog-instrumentations/src/next.js +24 -0
  81. package/packages/datadog-instrumentations/src/nyc.js +0 -2
  82. package/packages/datadog-instrumentations/src/oracledb.js +2 -2
  83. package/packages/datadog-instrumentations/src/pg.js +2 -2
  84. package/packages/datadog-instrumentations/src/playwright.js +159 -22
  85. package/packages/datadog-instrumentations/src/process.js +3 -0
  86. package/packages/datadog-instrumentations/src/router.js +191 -106
  87. package/packages/datadog-instrumentations/src/selenium.js +52 -26
  88. package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +2 -2
  89. package/packages/datadog-instrumentations/src/vitest-main.js +0 -2
  90. package/packages/datadog-instrumentations/src/ws.js +2 -1
  91. package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/context.js +2 -2
  92. package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/util.js +2 -1
  93. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +41 -16
  94. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +21 -21
  95. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +14 -8
  96. package/packages/datadog-plugin-aws-sdk/src/util.js +2 -24
  97. package/packages/datadog-plugin-cucumber/src/index.js +1 -1
  98. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +24 -62
  99. package/packages/datadog-plugin-cypress/src/index.js +6 -1
  100. package/packages/datadog-plugin-cypress/src/support.js +92 -26
  101. package/packages/datadog-plugin-electron/src/ipc.js +1 -1
  102. package/packages/datadog-plugin-graphql/src/execute.js +177 -59
  103. package/packages/datadog-plugin-graphql/src/parse.js +22 -1
  104. package/packages/datadog-plugin-graphql/src/request.js +32 -1
  105. package/packages/datadog-plugin-graphql/src/utils.js +42 -0
  106. package/packages/datadog-plugin-graphql/src/validate.js +15 -3
  107. package/packages/datadog-plugin-http2/src/client.js +1 -1
  108. package/packages/datadog-plugin-http2/src/server.js +38 -6
  109. package/packages/datadog-plugin-jest/src/util.js +21 -6
  110. package/packages/datadog-plugin-langchain/src/handlers/embedding.js +2 -1
  111. package/packages/datadog-plugin-langchain/src/handlers/language_models.js +2 -1
  112. package/packages/datadog-plugin-langchain/src/tokens.js +2 -2
  113. package/packages/datadog-plugin-playwright/src/index.js +177 -64
  114. package/packages/datadog-plugin-router/src/index.js +11 -2
  115. package/packages/datadog-plugin-selenium/src/index.js +5 -36
  116. package/packages/datadog-plugin-vitest/src/index.js +4 -2
  117. package/packages/datadog-plugin-ws/src/close.js +2 -1
  118. package/packages/datadog-plugin-ws/src/producer.js +2 -1
  119. package/packages/datadog-plugin-ws/src/receiver.js +2 -1
  120. package/packages/datadog-plugin-ws/src/server.js +2 -1
  121. package/packages/dd-trace/index.electron.js +3 -0
  122. package/packages/dd-trace/index.js +2 -37
  123. package/packages/dd-trace/src/aiguard/sdk.js +1 -1
  124. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +2 -2
  125. package/packages/dd-trace/src/appsec/iast/telemetry/span-tags.js +3 -1
  126. package/packages/dd-trace/src/azure_metadata.js +2 -1
  127. package/packages/dd-trace/src/bootstrap.js +39 -0
  128. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +93 -28
  129. package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +1 -1
  130. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/index.js +160 -0
  131. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/msgpack-to-json.js +288 -0
  132. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/payload-projection.js +84 -0
  133. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/sink.js +369 -0
  134. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/writer.js +60 -0
  135. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +55 -5
  136. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +22 -6
  137. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +5 -0
  138. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +62 -7
  139. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +9 -2
  140. package/packages/dd-trace/src/ci-visibility/requests/upload-coverage-report.js +6 -2
  141. package/packages/dd-trace/src/ci-visibility/rum.js +7 -0
  142. package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +4 -0
  143. package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +1 -1
  144. package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +137 -9
  145. package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache.js +173 -9
  146. package/packages/dd-trace/src/ci-visibility/test-screenshot.js +90 -0
  147. package/packages/dd-trace/src/config/generated-config-types.d.ts +20 -0
  148. package/packages/dd-trace/src/config/helper.js +1 -0
  149. package/packages/dd-trace/src/config/index.js +10 -0
  150. package/packages/dd-trace/src/config/supported-configurations.json +83 -0
  151. package/packages/dd-trace/src/constants.js +7 -0
  152. package/packages/dd-trace/src/datastreams/pathway.js +6 -4
  153. package/packages/dd-trace/src/exporter.js +2 -0
  154. package/packages/dd-trace/src/exporters/common/client-library-headers.js +21 -0
  155. package/packages/dd-trace/src/exporters/common/request.js +59 -30
  156. package/packages/dd-trace/src/exporters/common/url.js +15 -1
  157. package/packages/dd-trace/src/feature-registry.js +29 -0
  158. package/packages/dd-trace/src/llmobs/constants/tags.js +1 -0
  159. package/packages/dd-trace/src/llmobs/experiments/client.js +113 -0
  160. package/packages/dd-trace/src/llmobs/experiments/dataset.js +154 -0
  161. package/packages/dd-trace/src/llmobs/experiments/experiment.js +283 -0
  162. package/packages/dd-trace/src/llmobs/experiments/index.js +152 -0
  163. package/packages/dd-trace/src/llmobs/experiments/noop.js +30 -0
  164. package/packages/dd-trace/src/llmobs/experiments/result.js +34 -0
  165. package/packages/dd-trace/src/llmobs/index.js +10 -2
  166. package/packages/dd-trace/src/llmobs/noop.js +6 -0
  167. package/packages/dd-trace/src/llmobs/plugins/ai/vercelTelemetry.js +20 -3
  168. package/packages/dd-trace/src/llmobs/plugins/anthropic/index.js +2 -2
  169. package/packages/dd-trace/src/llmobs/plugins/langgraph/index.js +1 -1
  170. package/packages/dd-trace/src/llmobs/plugins/openai/constants.js +8 -0
  171. package/packages/dd-trace/src/llmobs/plugins/openai/index.js +48 -14
  172. package/packages/dd-trace/src/llmobs/plugins/openai/utils.js +43 -0
  173. package/packages/dd-trace/src/llmobs/sdk.js +17 -0
  174. package/packages/dd-trace/src/llmobs/tagger.js +79 -7
  175. package/packages/dd-trace/src/llmobs/telemetry.js +2 -1
  176. package/packages/dd-trace/src/llmobs/util.js +32 -0
  177. package/packages/dd-trace/src/noop/proxy.js +5 -4
  178. package/packages/dd-trace/src/openfeature/agentless_configuration_source.js +322 -0
  179. package/packages/dd-trace/src/openfeature/configuration_source.js +90 -0
  180. package/packages/dd-trace/src/openfeature/flagging_provider.js +14 -23
  181. package/packages/dd-trace/src/openfeature/index.js +0 -2
  182. package/packages/dd-trace/src/openfeature/noop.js +1 -28
  183. package/packages/dd-trace/src/openfeature/register.js +35 -0
  184. package/packages/dd-trace/src/openfeature/remote_config.js +15 -18
  185. package/packages/dd-trace/src/openfeature/require-provider.js +18 -0
  186. package/packages/dd-trace/src/opentelemetry/span-ending-hook.js +10 -0
  187. package/packages/dd-trace/src/opentelemetry/span.js +5 -0
  188. package/packages/dd-trace/src/opentracing/propagation/log.js +11 -2
  189. package/packages/dd-trace/src/opentracing/propagation/text_map.js +80 -14
  190. package/packages/dd-trace/src/opentracing/propagation/text_map_dsm.js +10 -1
  191. package/packages/dd-trace/src/opentracing/tracer.js +7 -1
  192. package/packages/dd-trace/src/plugins/ci_plugin.js +20 -6
  193. package/packages/dd-trace/src/plugins/util/git.js +3 -2
  194. package/packages/dd-trace/src/plugins/util/inferred_proxy.js +29 -5
  195. package/packages/dd-trace/src/plugins/util/test.js +65 -8
  196. package/packages/dd-trace/src/plugins/util/web.js +12 -0
  197. package/packages/dd-trace/src/proxy.js +99 -10
  198. package/packages/dd-trace/src/span_processor.js +5 -0
  199. package/packages/dd-trace/src/standalone/index.js +0 -36
  200. package/packages/dd-trace/src/telemetry/send-data.js +2 -2
  201. package/packages/dd-trace/src/util.js +26 -0
  202. package/vendor/dist/@apm-js-collab/code-transformer/index.js +1 -1
  203. package/vendor/dist/@datadog/sketches-js/index.js +1 -1
  204. package/vendor/dist/protobufjs/index.js +1 -1
  205. package/vendor/dist/protobufjs/minimal/index.js +1 -1
  206. package/vendor/dist/shell-quote/index.js +1 -1
  207. package/packages/datadog-instrumentations/src/helpers/require-optional-peer.js +0 -17
@@ -1,8 +1,10 @@
1
1
  'use strict'
2
2
 
3
3
  const NoopProxy = require('./noop/proxy')
4
+ const { features } = require('./feature-registry')
4
5
  const DatadogTracer = require('./tracer')
5
6
  const getConfig = require('./config')
7
+ const { getEnvironmentVariable } = require('./config/helper')
6
8
  const runtimeMetrics = require('./runtime_metrics')
7
9
  const log = require('./log')
8
10
  const { setStartupLogPluginManager, startupLog } = require('./startup-log')
@@ -13,6 +15,7 @@ const PluginManager = require('./plugin_manager')
13
15
  const NoopDogStatsDClient = require('./noop/dogstatsd')
14
16
  const { IS_SERVERLESS } = require('./serverless')
15
17
  const processTags = require('./process-tags')
18
+ const { isTrue } = require('./util')
16
19
  const {
17
20
  setBaggageItem,
18
21
  getBaggageItem,
@@ -21,6 +24,24 @@ const {
21
24
  removeAllBaggageItems,
22
25
  } = require('./baggage')
23
26
 
27
+ const VALIDATION_MANIFEST_ENV = '_DD_TEST_OPTIMIZATION_VALIDATION_MANIFEST_FILE'
28
+ const VALIDATION_MODE_ENV = '_DD_TEST_OPTIMIZATION_VALIDATION_MODE'
29
+ const VALIDATION_OUTPUT_ENV = '_DD_TEST_OPTIMIZATION_VALIDATION_OUTPUT_DIR'
30
+ const ORDINARY_TRACING_DISABLED_MESSAGE =
31
+ 'Ordinary dd-trace application tracing initialization is disabled during offline Test Optimization validation. ' +
32
+ 'The CI test process must initialize through dd-trace/ci/init.'
33
+ const OFFLINE_VALIDATION_EXPORTERS = new Set([
34
+ 'ci_validation',
35
+ 'cucumber_worker',
36
+ 'jest_worker',
37
+ 'mocha_worker',
38
+ 'playwright_worker',
39
+ 'vitest_worker',
40
+ ])
41
+ const FEATURE_STATE_NOOP = 0
42
+ const FEATURE_STATE_LAZY = 1
43
+ const FEATURE_STATE_ACTIVE = 2
44
+
24
45
  class LazyModule {
25
46
  constructor (provider) {
26
47
  this.provider = provider
@@ -69,6 +90,9 @@ function defineLazily (obj, property, getClass, ...args) {
69
90
  }
70
91
 
71
92
  class Tracer extends NoopProxy {
93
+ /** @type {Record<string, number> | undefined} */
94
+ #featureStates
95
+
72
96
  constructor () {
73
97
  super()
74
98
 
@@ -91,7 +115,10 @@ class Tracer extends NoopProxy {
91
115
  iast: new LazyModule(() => require('./appsec/iast')),
92
116
  llmobs: new LazyModule(() => require('./llmobs')),
93
117
  rewriter: new LazyModule(() => require('./appsec/iast/taint-tracking/rewriter')),
94
- openfeature: new LazyModule(() => require('./openfeature')),
118
+ }
119
+
120
+ for (const feature of Object.values(features)) {
121
+ this._modules[feature.name] = new LazyModule(feature.factory)
95
122
  }
96
123
  }
97
124
 
@@ -103,6 +130,11 @@ class Tracer extends NoopProxy {
103
130
 
104
131
  this._initialized = true
105
132
 
133
+ if (isOfflineTestOptimizationValidation() && !isOfflineValidationExporter(options)) {
134
+ process.stderr.write(`${ORDINARY_TRACING_DISABLED_MESSAGE}\n`)
135
+ return this
136
+ }
137
+
106
138
  try {
107
139
  const config = getConfig(options) // TODO: support dynamic code config
108
140
 
@@ -114,7 +146,11 @@ class Tracer extends NoopProxy {
114
146
  propagationHash.configure(config)
115
147
 
116
148
  if (config.DD_CRASHTRACKING_ENABLED) {
117
- require('./crashtracking').start(config)
149
+ try {
150
+ require('./crashtracking').start(config)
151
+ } catch (e) {
152
+ log.warn('Crashtracking is not available in this environment', e)
153
+ }
118
154
  }
119
155
 
120
156
  if (config.DD_HEAP_SNAPSHOT_COUNT > 0) {
@@ -123,7 +159,7 @@ class Tracer extends NoopProxy {
123
159
 
124
160
  telemetry.start(config, this._pluginManager)
125
161
 
126
- if (config.dogstatsd) {
162
+ if (config.dogstatsd && !isOfflineTestOptimizationValidation()) {
127
163
  // Custom Metrics
128
164
  lazyProxy(this, 'dogstatsd', () => require('./dogstatsd').CustomMetrics, config)
129
165
  }
@@ -176,8 +212,9 @@ class Tracer extends NoopProxy {
176
212
  DynamicInstrumentation.start(config, rc)
177
213
  }
178
214
 
179
- const openfeatureRemoteConfig = require('./openfeature/remote_config')
180
- openfeatureRemoteConfig.enable(rc, config, () => this.openfeature)
215
+ for (const feature of Object.values(features)) {
216
+ feature.remoteConfig?.(rc, config, this)
217
+ }
181
218
  }
182
219
 
183
220
  if (config.profiling.DD_PROFILING_ENABLED === 'true') {
@@ -266,6 +303,36 @@ class Tracer extends NoopProxy {
266
303
  }
267
304
  }
268
305
 
306
+ /**
307
+ * @param {(typeof features)[string]} feature
308
+ * @param {import('./config/config-base')} config
309
+ */
310
+ #enableFeature (feature, config) {
311
+ const states = this.#featureStates ??= {}
312
+ const state = states[feature.name] ?? FEATURE_STATE_NOOP
313
+
314
+ if (state === FEATURE_STATE_ACTIVE || state === FEATURE_STATE_LAZY) return
315
+ states[feature.name] = FEATURE_STATE_LAZY
316
+
317
+ Reflect.defineProperty(this, feature.name, {
318
+ get: () => {
319
+ const Provider = feature.provider()
320
+ const provider = new Provider(this._tracer, config)
321
+
322
+ this._modules[feature.name].enable(config)
323
+ Reflect.defineProperty(this, feature.name, {
324
+ value: provider,
325
+ configurable: true,
326
+ enumerable: true,
327
+ })
328
+ states[feature.name] = FEATURE_STATE_ACTIVE
329
+ return provider
330
+ },
331
+ configurable: true,
332
+ enumerable: true,
333
+ })
334
+ }
335
+
269
336
  /**
270
337
  * @param {import('./config/config-base')} config - Tracer configuration
271
338
  */
@@ -287,14 +354,12 @@ class Tracer extends NoopProxy {
287
354
  lazyProxy(this, 'llmobs', () => require('./llmobs/sdk'), this._tracer, this._modules.llmobs, config)
288
355
 
289
356
  if (config.experimental?.aiguard?.enabled) {
290
- this._modules.aiguard.enable(this._tracer, config)
291
357
  lazyProxy(this, 'aiguard', () => require('./aiguard/sdk'), this._tracer, config)
292
358
  }
293
359
  this._tracingInitialized = true
294
360
  }
295
- if (config.experimental.flaggingProvider.enabled) {
296
- this._modules.openfeature.enable(config)
297
- lazyProxy(this, 'openfeature', () => require('./openfeature/flagging_provider'), this._tracer, config)
361
+ if (config.experimental?.aiguard?.enabled) {
362
+ this._modules.aiguard.enable(this._tracer, config)
298
363
  }
299
364
  if (config.iast.enabled) {
300
365
  this._modules.iast.enable(config, this._tracer)
@@ -305,7 +370,10 @@ class Tracer extends NoopProxy {
305
370
  this._modules.aiguard.disable()
306
371
  this._modules.iast.disable()
307
372
  this._modules.llmobs.disable()
308
- this._modules.openfeature.disable()
373
+ }
374
+
375
+ for (const feature of Object.values(features)) {
376
+ if (feature.isEnabled(config)) this.#enableFeature(feature, config)
309
377
  }
310
378
 
311
379
  if (this._tracingInitialized) {
@@ -388,4 +456,25 @@ class Tracer extends NoopProxy {
388
456
  }
389
457
  }
390
458
 
459
+ /**
460
+ * Checks the private filesystem-only Test Optimization validation mode.
461
+ *
462
+ * @returns {boolean} whether network-capable tracer side channels must stay disabled
463
+ */
464
+ function isOfflineTestOptimizationValidation () {
465
+ return isTrue(getEnvironmentVariable(VALIDATION_MODE_ENV)) &&
466
+ Boolean(getEnvironmentVariable(VALIDATION_MANIFEST_ENV)) &&
467
+ Boolean(getEnvironmentVariable(VALIDATION_OUTPUT_ENV))
468
+ }
469
+
470
+ /**
471
+ * Checks whether initialization selected a filesystem-only Test Optimization exporter.
472
+ *
473
+ * @param {import('../../../index').TracerOptions} [options] tracer initialization options
474
+ * @returns {boolean} whether the selected exporter is safe for offline validation
475
+ */
476
+ function isOfflineValidationExporter (options) {
477
+ return OFFLINE_VALIDATION_EXPORTERS.has(options?.experimental?.exporter)
478
+ }
479
+
391
480
  module.exports = Tracer
@@ -6,6 +6,7 @@ const SpanSampler = require('./span_sampler')
6
6
  const GitMetadataTagger = require('./git_metadata_tagger')
7
7
  const processTags = require('./process-tags')
8
8
  const { applyHttpOtelSemantics } = require('./plugins/util/http-otel-semantics')
9
+ const { APM_TRACING_ENABLED_KEY } = require('./constants')
9
10
 
10
11
  const startedSpans = new WeakSet()
11
12
  const finishedSpans = new WeakSet()
@@ -54,12 +55,16 @@ class SpanProcessor {
54
55
  this._gitMetadataTagger.tagGitMetadata(spanContext)
55
56
 
56
57
  let isFirstSpanInChunk = true
58
+ const stampApmDisabled = this._config.apmTracingEnabled === false
57
59
 
58
60
  for (const span of started) {
59
61
  if (span._duration === undefined) {
60
62
  active.push(span)
61
63
  } else {
62
64
  const formattedSpan = spanFormat(span, isFirstSpanInChunk, this._processTags)
65
+ if (isFirstSpanInChunk && stampApmDisabled) {
66
+ formattedSpan.metrics[APM_TRACING_ENABLED_KEY] = 0
67
+ }
63
68
  isFirstSpanInChunk = false
64
69
  // Span stats read Datadog HTTP tag names from the formatted span, so
65
70
  // record them before the OTel rename — an export-only transform.
@@ -2,60 +2,24 @@
2
2
 
3
3
  const { channel } = require('dc-polyfill')
4
4
  const { USER_KEEP } = require('../../../../ext/priority')
5
- const TraceState = require('../opentracing/propagation/tracestate')
6
- const { APM_TRACING_ENABLED_KEY } = require('../constants')
7
5
  const TraceSourcePrioritySampler = require('./tracesource_priority_sampler')
8
6
  const { hasTraceSourcePropagationTag } = require('./tracesource')
9
7
 
10
- const startCh = channel('dd-trace:span:start')
11
- const injectCh = channel('dd-trace:span:inject')
12
8
  const extractCh = channel('dd-trace:span:extract')
13
9
 
14
10
  /**
15
11
  * @param {import('../config/config-base')} config - Tracer configuration
16
12
  */
17
13
  function configure (config) {
18
- if (startCh.hasSubscribers) startCh.unsubscribe(onSpanStart)
19
- if (injectCh.hasSubscribers) injectCh.unsubscribe(onSpanInject)
20
14
  if (extractCh.hasSubscribers) extractCh.unsubscribe(onSpanExtract)
21
15
 
22
16
  if (config.apmTracingEnabled !== false) return
23
17
 
24
- startCh.subscribe(onSpanStart)
25
- injectCh.subscribe(onSpanInject)
26
18
  extractCh.subscribe(onSpanExtract)
27
19
 
28
20
  return new TraceSourcePrioritySampler(config.env)
29
21
  }
30
22
 
31
- function onSpanStart ({ span, fields }) {
32
- const context = span.context?.()
33
- if (!context) return
34
-
35
- const { parent } = fields
36
- if (!parent || parent._isRemote) {
37
- context.setTag(APM_TRACING_ENABLED_KEY, 0)
38
- }
39
- }
40
-
41
- function onSpanInject ({ spanContext, carrier }) {
42
- if (!spanContext?._trace?.tags || !carrier) return
43
-
44
- // do not inject trace and sampling if there is no _dd.p.ts
45
- if (!hasTraceSourcePropagationTag(spanContext._trace.tags)) {
46
- for (const key in carrier) {
47
- const lKey = key.toLowerCase()
48
- if (lKey.startsWith('x-datadog') || lKey.startsWith('x-b3') || lKey === 'traceparent') {
49
- delete carrier[key]
50
- } else if (lKey === 'tracestate') {
51
- const tracestate = TraceState.fromString(carrier[key])
52
- tracestate.forVendor('dd', state => state.clear())
53
- carrier[key] = tracestate.toString()
54
- }
55
- }
56
- }
57
- }
58
-
59
23
  function onSpanExtract ({ spanContext = {} }) {
60
24
  if (!spanContext._trace?.tags || !spanContext._sampling) return
61
25
 
@@ -77,11 +77,11 @@ let agentTelemetry = true
77
77
  */
78
78
  function getHeaders (config, application, reqType) {
79
79
  const headers = {
80
+ 'DD-Client-Library-Language': application.language_name,
81
+ 'DD-Client-Library-Version': application.tracer_version,
80
82
  'content-type': 'application/json',
81
83
  'dd-telemetry-api-version': 'v2',
82
84
  'dd-telemetry-request-type': reqType,
83
- 'dd-client-library-language': application.language_name,
84
- 'dd-client-library-version': application.tracer_version,
85
85
  'dd-session-id': config.tags['runtime-id'],
86
86
  }
87
87
  if (config.DD_ROOT_JS_SESSION_ID) {
@@ -77,6 +77,31 @@ function globMatch (pattern, subject) {
77
77
  return true
78
78
  }
79
79
 
80
+ /**
81
+ * Return the segment at {index} when splitting {string} on {separator}, without
82
+ * allocating the intermediate array. Equivalent to
83
+ * `string.split(separator, index + 1)[index]`, but `split` with a limit forces
84
+ * V8 off its constant-limit fast path (per-call ToUint32 plus an array
85
+ * allocation), making it 60-170% slower than this scan for the small inputs
86
+ * tracer code splits (paths, request lines, version strings).
87
+ *
88
+ * @param {string} string
89
+ * @param {string} separator
90
+ * @param {number} index
91
+ * @param {string} [fallback] returned when fewer than {index} + 1 segments exist
92
+ * @returns {string | undefined}
93
+ */
94
+ function getSegment (string, separator, index, fallback) {
95
+ let start = 0
96
+ for (let i = 0; i < index; i++) {
97
+ const next = string.indexOf(separator, start)
98
+ if (next === -1) return fallback
99
+ start = next + separator.length
100
+ }
101
+ const end = string.indexOf(separator, start)
102
+ return end === -1 ? string.slice(start) : string.slice(start, end)
103
+ }
104
+
80
105
  function calculateDDBasePath (dirname) {
81
106
  const dirSteps = dirname.split(path.sep)
82
107
  const packagesIndex = dirSteps.lastIndexOf('packages')
@@ -110,6 +135,7 @@ module.exports = {
110
135
  isFalse,
111
136
  isError,
112
137
  globMatch,
138
+ getSegment,
113
139
  ddBasePath: globalThis.__DD_ESBUILD_BASEPATH || calculateDDBasePath(__dirname),
114
140
  normalizePluginEnvName,
115
141
  formatKnuthRate,
@@ -1,4 +1,4 @@
1
- (()=>{var i={"./@apm-js-collab/code-transformer/index.js"(i,s,k){"use strict";i.exports=k("./@apm-js-collab/code-transformer/lib/index.js")},"./@apm-js-collab/code-transformer/lib/index.js"(i,s,k){"use strict";let{InstrumentationMatcher:S}=k("./@apm-js-collab/code-transformer/lib/matcher.js");i.exports={create:function(i,s){return new S(i,s)}}},"./@apm-js-collab/code-transformer/lib/matcher.js"(i,s,k){"use strict";let S=k("./semifies/index.js"),{Transformer:E}=k("./@apm-js-collab/code-transformer/lib/transformer.js");let InstrumentationMatcher=class InstrumentationMatcher{#e=[];#t=null;#r={};#n={};constructor(i,s){this.#e=i,this.#t=s||"diagnostics_channel"}free(){this.#r={}}addTransform(i,s){this.#n[i]=s}getTransformer(i,s,k){k=k.replace(/\\/g,"/");let w=`${i}/${k}@${s}`;if(this.#r[w])return this.#r[w];let C=this.#e.filter(({module:E})=>E.name===i&&E.filePath===k&&S(s,E.versionRange));if(0!==C.length)return this.#r[w]=new E(i,s,k,C,this.#t,this.#n),this.#r[w]}};i.exports={InstrumentationMatcher}},"./@apm-js-collab/code-transformer/lib/transformer.js"(i,s,k){"use strict";let S,E,w=k("./esquery/dist/esquery.min.js"),{parse:C}=k("./meriyah/dist/meriyah.cjs"),{generate:T}=k("./astring/dist/astring.js"),_=k("./@apm-js-collab/code-transformer/lib/transforms.js");let Transformer=class Transformer{#a=null;#o=null;#i=null;#e=[];#t=null;#n={};constructor(i,s,k,S,E,w={}){this.#a=i,this.#o=s,this.#i=k,this.#e=S,this.#t=E,this.#n=w}free(){}get moduleName(){return this.#a}get filePath(){return this.#i}transform(i,s,_){let O;if(Buffer.isBuffer(i)&&(i=i.toString()),!i)return{code:i};let N={},D=0;for(let k of this.#e){let{astQuery:S,functionQuery:E={}}=k;if(!O){let k={loc:!0,ranges:!0,raw:!0,module:"esm"===s};try{O=C(i,k)}catch{O=C(i,{...k,module:!k.module})}"esm"===s&&(N=this.#s(O))}let T=this.#l(E,N),_=S||this.#c(T),q={...k,dcModule:this.#t,moduleType:s,moduleVersion:this.#o,functionQuery:T};q.operator=this.#u(q),w.traverse(O,w.parse(_),(...i)=>{D++,this.#p(q,...i)})}if(0===D&&this.#e.length>0){let i=this.#e.map(({functionQuery:i={}})=>{let s=this.#l(i,N),k=i.methodName||i.privateMethodName||i.functionName||i.expressionName||"constructor",S=i.className||i.functionName||i.expressionName,E=s.className||s.functionName||s.expressionName;return S&&S!==E?`${S} (local name: ${E})`:k});throw Error(`Failed to find injection points for: ${JSON.stringify(i)}`)}if(O){let i;S??=k("./@apm-js-collab/code-transformer/node_modules/source-map/source-map.js").SourceMapConsumer,E??=k("./@apm-js-collab/code-transformer/node_modules/source-map/source-map.js").SourceMapGenerator;let s=`${this.#a}/${this.#i}`;if(_){let k=new S(_);k.file=s,i=E.fromSourceMap(k)}else i=new E({file:s});return{code:T(O,{sourceMap:i}),map:i.toString()}}return{code:i}}#p(i,...s){let k=this.#n[i.operator]??_[i.operator],{index:S=0}=i.functionQuery,[E]=s,w=E.init?.type||E.type;if("ClassDeclaration"===w||"ClassExpression"===w||"VariableDeclarator"!==E.type&&(i.functionIndex=++i.functionIndex||0,null===S||S===i.functionIndex))k(i,...s)}#u({transform:i,functionQuery:{kind:s}}){if(i)return i;switch(s){case"Async":return"tracePromise";case"Auto":return"traceAuto";case"Callback":return"traceCallback";default:return"traceSync"}}#s(i){let s={};for(let k of i.body)if("ExportNamedDeclaration"===k.type&&!k.source){for(let i of k.specifiers)if(i.exported&&i.local){let k=i.exported.name??i.exported.value,S=i.local.name??i.local.value;k&&S&&(s[k]=S)}}return s}#l(i,s){if(!i.isExportAlias)return i;let{functionName:k,expressionName:S,className:E}=i;return k&&s[k]?{...i,functionName:s[k]}:S&&s[S]?{...i,expressionName:s[S]}:E&&s[E]?{...i,className:s[E]}:i}#c(i){let{functionName:s,expressionName:k,className:S,objectName:E,propertyName:w}=i,C=i.privateMethodName?"PrivateIdentifier":"Identifier",T=[],_=i.methodName||i.privateMethodName;if(S?(_??="constructor",T.push(`[id.name="${S}"]`,`[id.name="${S}"] > ClassExpression`,`[id.name="${S}"] > ClassBody > [key.name="${_}"][key.type=${C}] > [async]`,`[id.name="${S}"] > ClassExpression > ClassBody > [key.name="${_}"][key.type=${C}] > [async]`)):_&&T.push(`ClassBody > [key.name="${_}"][key.type=${C}] > [async]`,`Property[key.name="${_}"][key.type=${C}] > [async]`),s?T.push(`FunctionDeclaration[id.name="${s}"][async]`):k&&T.push(`FunctionExpression[id.name="${k}"][async]`,`ArrowFunctionExpression[id.name="${k}"][async]`,`VariableDeclarator[id.name="${k}"] > FunctionExpression[async]`,`VariableDeclarator[id.name="${k}"] > ArrowFunctionExpression[async]`,`AssignmentExpression[left.property.name="${k}"] > FunctionExpression[async]`,`AssignmentExpression[left.property.name="${k}"] > ArrowFunctionExpression[async]`,`AssignmentExpression[left.name="${k}"] > FunctionExpression[async]`,`AssignmentExpression[left.name="${k}"] > ArrowFunctionExpression[async]`),E||w){if(!E||!w)throw Error(`functionQuery: 'objectName' and 'propertyName' must be used together (got objectName=${E}, propertyName=${w})`);let i="this"===E?"left.object.type=ThisExpression":`left.object.name="${E}"`;T.push(`AssignmentExpression[${i}][left.property.name="${w}"] > [async]`)}return T.join(", ")}};i.exports={Transformer}},"./@apm-js-collab/code-transformer/lib/transforms.js"(i,s,k){"use strict";let S=k("./esquery/dist/esquery.min.js"),{parse:E}=k("./meriyah/dist/meriyah.cjs"),tracingChannelPredicate=i=>i.declarations?.[0]?.id?.properties?.[0]?.value?.name==="tr_ch_apm_tracingChannel",w=/[^\w]/g,formatChannelVariable=i=>`tr_ch_apm$${i.replace(w,"_")}`,C=i.exports={tracingChannelImport({dcModule:i,moduleType:s},k){if(k.body.some(tracingChannelPredicate))return;let S={module:"esm"===s},w=k.body.findIndex(i=>"use strict"===i.directive),C="esm"===s?`import tr_ch_apm_dc from "${i}"`:`const tr_ch_apm_dc = require("${i}")`,T=`const tr_ch_apm_hasSubscribers = ch => ch.start.hasSubscribers
1
+ (()=>{var i={"./@apm-js-collab/code-transformer/index.js"(i,s,k){"use strict";i.exports=k("./@apm-js-collab/code-transformer/lib/index.js")},"./@apm-js-collab/code-transformer/lib/index.js"(i,s,k){"use strict";let{InstrumentationMatcher:S}=k("./@apm-js-collab/code-transformer/lib/matcher.js");i.exports={create:function(i,s){return new S(i,s)}}},"./@apm-js-collab/code-transformer/lib/matcher.js"(i,s,k){"use strict";let S=k("./semifies/index.js"),{Transformer:E}=k("./@apm-js-collab/code-transformer/lib/transformer.js");let InstrumentationMatcher=class InstrumentationMatcher{#e=[];#t=null;#r={};#n={};constructor(i,s){this.#e=i,this.#t=s||"diagnostics_channel"}free(){this.#r={}}addTransform(i,s){this.#n[i]=s}getTransformer(i,s,k){k=k.replace(/\\/g,"/");let w=`${i}/${k}@${s}`;if(this.#r[w])return this.#r[w];let C=this.#e.filter(({module:E})=>E.name===i&&("string"==typeof E.filePath?E.filePath===k:E.filePath.test(k))&&S(s,E.versionRange));if(0!==C.length)return this.#r[w]=new E(i,s,k,C,this.#t,this.#n),this.#r[w]}};i.exports={InstrumentationMatcher}},"./@apm-js-collab/code-transformer/lib/transformer.js"(i,s,k){"use strict";let S,E,w=k("./esquery/dist/esquery.min.js"),{parse:C}=k("./meriyah/dist/meriyah.cjs"),{generate:T}=k("./astring/dist/astring.js"),_=k("./@apm-js-collab/code-transformer/lib/transforms.js");let Transformer=class Transformer{#a=null;#o=null;#i=null;#e=[];#t=null;#n={};constructor(i,s,k,S,E,w={}){this.#a=i,this.#o=s,this.#i=k,this.#e=S,this.#t=E,this.#n=w}free(){}get moduleName(){return this.#a}get filePath(){return this.#i}transform(i,s,_){let O;if(Buffer.isBuffer(i)&&(i=i.toString()),!i)return{code:i};let N={},D=0;for(let k of this.#e){let{astQuery:S,functionQuery:E={}}=k;if(!O){let k={loc:!0,ranges:!0,raw:!0,module:"esm"===s};try{O=C(i,k)}catch{O=C(i,{...k,module:!k.module})}"esm"===s&&(N=this.#s(O))}let T=this.#l(E,N),_=S||this.#c(T),q={...k,dcModule:this.#t,moduleType:s,moduleVersion:this.#o,functionQuery:T};q.operator=this.#u(q),w.traverse(O,w.parse(_),(...i)=>{D++,this.#p(q,...i)})}if(0===D&&this.#e.length>0){let i=this.#e.map(({astQuery:i,functionQuery:s={}})=>{if(i)return i;let k=this.#l(s,N),S=s.methodName||s.privateMethodName||s.functionName||s.expressionName||"constructor",E=s.className||s.functionName||s.expressionName,w=k.className||k.functionName||k.expressionName;return E&&E!==w?`${E} (local name: ${w})`:S});throw Error(`Failed to find injection points for: ${JSON.stringify(i)}`)}if(O){let i;S??=k("./@apm-js-collab/code-transformer/node_modules/source-map/source-map.js").SourceMapConsumer,E??=k("./@apm-js-collab/code-transformer/node_modules/source-map/source-map.js").SourceMapGenerator;let s=`${this.#a}/${this.#i}`;if(_){let k=new S(_);k.file=s,i=E.fromSourceMap(k)}else i=new E({file:s});return{code:T(O,{sourceMap:i}),map:i.toString()}}return{code:i}}#p(i,...s){let k=this.#n[i.operator]??_[i.operator],{index:S=0}=i.functionQuery,[E]=s,w=E.init?.type||E.type;if("ClassDeclaration"===w||"ClassExpression"===w||"VariableDeclarator"!==E.type&&(i.functionIndex=++i.functionIndex||0,null===S||S===i.functionIndex))k(i,...s)}#u({transform:i,functionQuery:{kind:s}}){if(i)return i;switch(s){case"Async":return"tracePromise";case"Auto":return"traceAuto";case"Callback":return"traceCallback";default:return"traceSync"}}#s(i){let s={};for(let k of i.body)if("ExportNamedDeclaration"===k.type&&!k.source){for(let i of k.specifiers)if(i.exported&&i.local){let k=i.exported.name??i.exported.value,S=i.local.name??i.local.value;k&&S&&(s[k]=S)}}return s}#l(i,s){if(!i.isExportAlias)return i;let{functionName:k,expressionName:S,className:E}=i;return k&&s[k]?{...i,functionName:s[k]}:S&&s[S]?{...i,expressionName:s[S]}:E&&s[E]?{...i,className:s[E]}:i}#c(i){let{functionName:s,expressionName:k,className:S,objectName:E,propertyName:w}=i,C=i.privateMethodName?"PrivateIdentifier":"Identifier",T=[],_=i.methodName||i.privateMethodName;if(S?(_??="constructor",T.push(`[id.name="${S}"]`,`[id.name="${S}"] > ClassExpression`,`[id.name="${S}"] > ClassBody > [key.name="${_}"][key.type=${C}] > [async]`,`[id.name="${S}"] > ClassExpression > ClassBody > [key.name="${_}"][key.type=${C}] > [async]`)):_&&T.push(`ClassBody > [key.name="${_}"][key.type=${C}] > [async]`,`Property[key.name="${_}"][key.type=${C}] > [async]`),s?T.push(`FunctionDeclaration[id.name="${s}"][async]`):k&&T.push(`FunctionExpression[id.name="${k}"][async]`,`ArrowFunctionExpression[id.name="${k}"][async]`,`VariableDeclarator[id.name="${k}"] > FunctionExpression[async]`,`VariableDeclarator[id.name="${k}"] > ArrowFunctionExpression[async]`,`AssignmentExpression[left.property.name="${k}"] > FunctionExpression[async]`,`AssignmentExpression[left.property.name="${k}"] > ArrowFunctionExpression[async]`,`AssignmentExpression[left.name="${k}"] > FunctionExpression[async]`,`AssignmentExpression[left.name="${k}"] > ArrowFunctionExpression[async]`),E||w){if(!E||!w)throw Error(`functionQuery: 'objectName' and 'propertyName' must be used together (got objectName=${E}, propertyName=${w})`);let i="this"===E?"left.object.type=ThisExpression":`left.object.name="${E}"`;T.push(`AssignmentExpression[${i}][left.property.name="${w}"] > [async]`)}return T.join(", ")}};i.exports={Transformer}},"./@apm-js-collab/code-transformer/lib/transforms.js"(i,s,k){"use strict";let S=k("./esquery/dist/esquery.min.js"),{parse:E}=k("./meriyah/dist/meriyah.cjs"),tracingChannelPredicate=i=>i.declarations?.[0]?.id?.properties?.[0]?.value?.name==="tr_ch_apm_tracingChannel",w=/[^\w]/g,formatChannelVariable=i=>`tr_ch_apm$${i.replace(w,"_")}`,C=i.exports={tracingChannelImport({dcModule:i,moduleType:s},k){if(k.body.some(tracingChannelPredicate))return;let S={module:"esm"===s},w=k.body.findIndex(i=>"use strict"===i.directive),C="esm"===s?`import tr_ch_apm_dc from "${i}"`:`const tr_ch_apm_dc = require("${i}")`,T=`const tr_ch_apm_hasSubscribers = ch => ch.start.hasSubscribers
2
2
  || ch.end.hasSubscribers
3
3
  || ch.asyncStart.hasSubscribers
4
4
  || ch.asyncEnd.hasSubscribers