dd-trace 5.80.0 → 5.81.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 (213) hide show
  1. package/LICENSE-3rdparty.csv +79 -88
  2. package/ext/tags.d.ts +1 -0
  3. package/ext/tags.js +1 -0
  4. package/index.d.ts +35 -35
  5. package/loader-hook.mjs +10 -3
  6. package/package.json +22 -40
  7. package/packages/datadog-esbuild/index.js +36 -19
  8. package/packages/datadog-instrumentations/index.js +1 -0
  9. package/packages/datadog-instrumentations/src/anthropic.js +12 -0
  10. package/packages/datadog-instrumentations/src/aws-sdk.js +5 -1
  11. package/packages/datadog-instrumentations/src/cucumber.js +2 -2
  12. package/packages/datadog-instrumentations/src/find-my-way.js +6 -5
  13. package/packages/datadog-instrumentations/src/google-genai.js +120 -0
  14. package/packages/datadog-instrumentations/src/graphql.js +20 -0
  15. package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
  16. package/packages/datadog-instrumentations/src/helpers/instrument.js +10 -0
  17. package/packages/datadog-instrumentations/src/helpers/register.js +6 -1
  18. package/packages/datadog-instrumentations/src/helpers/rewriter/compiler.js +27 -0
  19. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +152 -0
  20. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +5 -0
  21. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/langchain.js +237 -0
  22. package/packages/datadog-instrumentations/src/helpers/rewriter/loader.js +9 -0
  23. package/packages/datadog-instrumentations/src/helpers/rewriter/loader.mjs +11 -0
  24. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +139 -0
  25. package/packages/datadog-instrumentations/src/langchain.js +3 -109
  26. package/packages/datadog-instrumentations/src/mocha/main.js +1 -1
  27. package/packages/datadog-instrumentations/src/mysql2.js +1 -1
  28. package/packages/datadog-instrumentations/src/playwright.js +45 -16
  29. package/packages/datadog-instrumentations/src/router.js +1 -1
  30. package/packages/datadog-instrumentations/src/selenium.js +3 -1
  31. package/packages/datadog-instrumentations/src/ws.js +35 -17
  32. package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +1 -1
  33. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +23 -2
  34. package/packages/datadog-plugin-cypress/src/plugin.js +1 -1
  35. package/packages/datadog-plugin-cypress/src/support.js +73 -31
  36. package/packages/datadog-plugin-google-genai/src/index.js +17 -0
  37. package/packages/datadog-plugin-google-genai/src/tracing.js +41 -0
  38. package/packages/datadog-plugin-graphql/src/tools/transforms.js +5 -4
  39. package/packages/datadog-plugin-jest/src/util.js +1 -1
  40. package/packages/datadog-plugin-langchain/src/tracing.js +7 -3
  41. package/packages/datadog-plugin-next/src/index.js +11 -3
  42. package/packages/dd-trace/src/aiguard/sdk.js +18 -10
  43. package/packages/dd-trace/src/appsec/api_security_sampler.js +1 -1
  44. package/packages/dd-trace/src/appsec/iast/overhead-controller.js +1 -1
  45. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter-esm.mjs +1 -1
  46. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +1 -2
  47. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +1 -1
  48. package/packages/dd-trace/src/appsec/reporter.js +0 -4
  49. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +4 -8
  50. package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +4 -2
  51. package/packages/dd-trace/src/config.js +81 -7
  52. package/packages/dd-trace/src/config_defaults.js +14 -2
  53. package/packages/dd-trace/src/datastreams/encoding.js +23 -6
  54. package/packages/dd-trace/src/datastreams/pathway.js +40 -1
  55. package/packages/dd-trace/src/datastreams/processor.js +1 -1
  56. package/packages/dd-trace/src/datastreams/schemas/schema_builder.js +1 -1
  57. package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +15 -5
  58. package/packages/dd-trace/src/debugger/devtools_client/condition.js +1 -1
  59. package/packages/dd-trace/src/debugger/devtools_client/config.js +2 -0
  60. package/packages/dd-trace/src/debugger/devtools_client/index.js +30 -15
  61. package/packages/dd-trace/src/debugger/devtools_client/inspector_promises_polyfill.js +2 -0
  62. package/packages/dd-trace/src/debugger/devtools_client/json-buffer.js +24 -18
  63. package/packages/dd-trace/src/debugger/devtools_client/send.js +18 -8
  64. package/packages/dd-trace/src/debugger/devtools_client/snapshot/collector.js +103 -15
  65. package/packages/dd-trace/src/debugger/devtools_client/snapshot/constants.js +25 -0
  66. package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +56 -25
  67. package/packages/dd-trace/src/debugger/devtools_client/snapshot/processor.js +64 -23
  68. package/packages/dd-trace/src/debugger/devtools_client/snapshot/symbols.js +3 -1
  69. package/packages/dd-trace/src/debugger/devtools_client/snapshot-pruner.js +404 -0
  70. package/packages/dd-trace/src/debugger/devtools_client/source-maps.js +1 -1
  71. package/packages/dd-trace/src/debugger/devtools_client/state.js +7 -2
  72. package/packages/dd-trace/src/debugger/devtools_client/status.js +1 -1
  73. package/packages/dd-trace/src/debugger/index.js +1 -1
  74. package/packages/dd-trace/src/encode/span-stats.js +7 -1
  75. package/packages/dd-trace/src/histogram.js +1 -1
  76. package/packages/dd-trace/src/id.js +60 -0
  77. package/packages/dd-trace/src/lambda/runtime/ritm.js +1 -1
  78. package/packages/dd-trace/src/llmobs/constants/tags.js +1 -0
  79. package/packages/dd-trace/src/llmobs/plugins/genai/index.js +104 -0
  80. package/packages/dd-trace/src/llmobs/plugins/genai/util.js +486 -0
  81. package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +2 -2
  82. package/packages/dd-trace/src/llmobs/plugins/{openai.js → openai/index.js} +48 -6
  83. package/packages/dd-trace/src/llmobs/plugins/openai/utils.js +114 -0
  84. package/packages/dd-trace/src/llmobs/sdk.js +5 -0
  85. package/packages/dd-trace/src/llmobs/span_processor.js +6 -1
  86. package/packages/dd-trace/src/llmobs/tagger.js +4 -0
  87. package/packages/dd-trace/src/opentelemetry/logs/index.js +2 -2
  88. package/packages/dd-trace/src/opentelemetry/logs/logger.js +3 -2
  89. package/packages/dd-trace/src/opentelemetry/logs/otlp_http_log_exporter.js +5 -3
  90. package/packages/dd-trace/src/opentelemetry/logs/otlp_transformer.js +8 -8
  91. package/packages/dd-trace/src/opentelemetry/metrics/constants.js +34 -0
  92. package/packages/dd-trace/src/opentelemetry/metrics/index.js +81 -0
  93. package/packages/dd-trace/src/opentelemetry/metrics/instruments.js +225 -0
  94. package/packages/dd-trace/src/opentelemetry/metrics/meter.js +171 -0
  95. package/packages/dd-trace/src/opentelemetry/metrics/meter_provider.js +54 -0
  96. package/packages/dd-trace/src/opentelemetry/metrics/otlp_http_metric_exporter.js +62 -0
  97. package/packages/dd-trace/src/opentelemetry/metrics/otlp_transformer.js +251 -0
  98. package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +532 -0
  99. package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +10 -18
  100. package/packages/dd-trace/src/opentelemetry/otlp/otlp_transformer_base.js +36 -22
  101. package/packages/dd-trace/src/opentelemetry/otlp/protobuf_loader.js +1 -1
  102. package/packages/dd-trace/src/opentelemetry/span.js +1 -1
  103. package/packages/dd-trace/src/opentelemetry/tracer.js +1 -1
  104. package/packages/dd-trace/src/opentelemetry/tracer_provider.js +1 -1
  105. package/packages/dd-trace/src/payload-tagging/index.js +2 -2
  106. package/packages/dd-trace/src/plugin_manager.js +4 -2
  107. package/packages/dd-trace/src/plugins/index.js +1 -0
  108. package/packages/dd-trace/src/plugins/util/test.js +3 -3
  109. package/packages/dd-trace/src/plugins/util/url.js +119 -1
  110. package/packages/dd-trace/src/plugins/util/web.js +10 -41
  111. package/packages/dd-trace/src/process-tags/index.js +81 -0
  112. package/packages/dd-trace/src/profiling/config.js +1 -1
  113. package/packages/dd-trace/src/profiling/exporters/agent.js +1 -1
  114. package/packages/dd-trace/src/profiling/profilers/events.js +10 -1
  115. package/packages/dd-trace/src/proxy.js +5 -0
  116. package/packages/dd-trace/src/rate_limiter.js +1 -1
  117. package/packages/dd-trace/src/remote_config/manager.js +1 -1
  118. package/packages/dd-trace/src/ritm.js +1 -1
  119. package/packages/dd-trace/src/service-naming/schemas/v0/web.js +4 -0
  120. package/packages/dd-trace/src/service-naming/schemas/v1/web.js +4 -0
  121. package/packages/dd-trace/src/span_format.js +9 -4
  122. package/packages/dd-trace/src/span_processor.js +8 -3
  123. package/packages/dd-trace/src/span_stats.js +15 -4
  124. package/packages/dd-trace/src/spanleak.js +1 -1
  125. package/packages/dd-trace/src/supported-configurations.json +13 -0
  126. package/packages/dd-trace/src/telemetry/dependencies.js +1 -1
  127. package/packages/dd-trace/src/telemetry/telemetry.js +11 -2
  128. package/vendor/dist/@datadog/sketches-js/LICENSE +39 -0
  129. package/vendor/dist/@datadog/sketches-js/index.js +1 -0
  130. package/vendor/dist/@datadog/source-map/LICENSE +28 -0
  131. package/vendor/dist/@datadog/source-map/index.js +1 -0
  132. package/vendor/dist/@isaacs/ttlcache/LICENSE +55 -0
  133. package/vendor/dist/@isaacs/ttlcache/index.js +1 -0
  134. package/vendor/dist/@opentelemetry/core/LICENSE +201 -0
  135. package/vendor/dist/@opentelemetry/core/index.js +1 -0
  136. package/vendor/dist/@opentelemetry/resources/LICENSE +201 -0
  137. package/vendor/dist/@opentelemetry/resources/index.js +1 -0
  138. package/vendor/dist/astring/LICENSE +19 -0
  139. package/vendor/dist/astring/index.js +1 -0
  140. package/vendor/dist/crypto-randomuuid/index.js +1 -0
  141. package/vendor/dist/escape-string-regexp/LICENSE +9 -0
  142. package/vendor/dist/escape-string-regexp/index.js +1 -0
  143. package/vendor/dist/esquery/LICENSE +24 -0
  144. package/vendor/dist/esquery/index.js +1 -0
  145. package/vendor/dist/ignore/LICENSE +21 -0
  146. package/vendor/dist/ignore/index.js +1 -0
  147. package/vendor/dist/istanbul-lib-coverage/LICENSE +24 -0
  148. package/vendor/dist/istanbul-lib-coverage/index.js +1 -0
  149. package/vendor/dist/jest-docblock/LICENSE +21 -0
  150. package/vendor/dist/jest-docblock/index.js +1 -0
  151. package/vendor/dist/jsonpath-plus/LICENSE +22 -0
  152. package/vendor/dist/jsonpath-plus/index.js +1 -0
  153. package/vendor/dist/limiter/LICENSE +19 -0
  154. package/vendor/dist/limiter/index.js +1 -0
  155. package/vendor/dist/lodash.sortby/LICENSE +47 -0
  156. package/vendor/dist/lodash.sortby/index.js +1 -0
  157. package/vendor/dist/lru-cache/LICENSE +15 -0
  158. package/vendor/dist/lru-cache/index.js +1 -0
  159. package/vendor/dist/meriyah/LICENSE +7 -0
  160. package/vendor/dist/meriyah/index.js +1 -0
  161. package/vendor/dist/module-details-from-path/LICENSE +21 -0
  162. package/vendor/dist/module-details-from-path/index.js +1 -0
  163. package/vendor/dist/mutexify/promise/LICENSE +21 -0
  164. package/vendor/dist/mutexify/promise/index.js +1 -0
  165. package/vendor/dist/opentracing/LICENSE +201 -0
  166. package/vendor/dist/opentracing/binary_carrier.d.ts +11 -0
  167. package/vendor/dist/opentracing/constants.d.ts +61 -0
  168. package/vendor/dist/opentracing/examples/demo/demo.d.ts +2 -0
  169. package/vendor/dist/opentracing/ext/tags.d.ts +90 -0
  170. package/vendor/dist/opentracing/functions.d.ts +20 -0
  171. package/vendor/dist/opentracing/global_tracer.d.ts +14 -0
  172. package/vendor/dist/opentracing/index.d.ts +12 -0
  173. package/vendor/dist/opentracing/index.js +1 -0
  174. package/vendor/dist/opentracing/mock_tracer/index.d.ts +5 -0
  175. package/vendor/dist/opentracing/mock_tracer/mock_context.d.ts +13 -0
  176. package/vendor/dist/opentracing/mock_tracer/mock_report.d.ts +16 -0
  177. package/vendor/dist/opentracing/mock_tracer/mock_span.d.ts +50 -0
  178. package/vendor/dist/opentracing/mock_tracer/mock_tracer.d.ts +26 -0
  179. package/vendor/dist/opentracing/noop.d.ts +8 -0
  180. package/vendor/dist/opentracing/reference.d.ts +33 -0
  181. package/vendor/dist/opentracing/span.d.ts +147 -0
  182. package/vendor/dist/opentracing/span_context.d.ts +26 -0
  183. package/vendor/dist/opentracing/test/api_compatibility.d.ts +16 -0
  184. package/vendor/dist/opentracing/test/mocktracer_implemenation.d.ts +3 -0
  185. package/vendor/dist/opentracing/test/noop_implementation.d.ts +4 -0
  186. package/vendor/dist/opentracing/test/opentracing_api.d.ts +3 -0
  187. package/vendor/dist/opentracing/test/unittest.d.ts +2 -0
  188. package/vendor/dist/opentracing/tracer.d.ts +127 -0
  189. package/vendor/dist/path-to-regexp/LICENSE +21 -0
  190. package/vendor/dist/path-to-regexp/index.js +1 -0
  191. package/vendor/dist/pprof-format/LICENSE +8 -0
  192. package/vendor/dist/pprof-format/index.js +1 -0
  193. package/vendor/dist/protobufjs/LICENSE +39 -0
  194. package/vendor/dist/protobufjs/index.js +1 -0
  195. package/vendor/dist/protobufjs/minimal/LICENSE +39 -0
  196. package/vendor/dist/protobufjs/minimal/index.js +1 -0
  197. package/vendor/dist/retry/LICENSE +21 -0
  198. package/vendor/dist/retry/index.js +1 -0
  199. package/vendor/dist/rfdc/LICENSE +15 -0
  200. package/vendor/dist/rfdc/index.js +1 -0
  201. package/vendor/dist/semifies/LICENSE +201 -0
  202. package/vendor/dist/semifies/index.js +1 -0
  203. package/vendor/dist/shell-quote/LICENSE +24 -0
  204. package/vendor/dist/shell-quote/index.js +1 -0
  205. package/vendor/dist/source-map/LICENSE +28 -0
  206. package/vendor/dist/source-map/index.js +1 -0
  207. package/vendor/dist/source-map/lib/util/LICENSE +28 -0
  208. package/vendor/dist/source-map/lib/util/index.js +1 -0
  209. package/vendor/dist/source-map/mappings.wasm +0 -0
  210. package/vendor/dist/tlhunter-sorted-set/LICENSE +21 -0
  211. package/vendor/dist/tlhunter-sorted-set/index.js +1 -0
  212. package/vendor/dist/ttl-set/LICENSE +21 -0
  213. package/vendor/dist/ttl-set/index.js +1 -0
@@ -2,7 +2,7 @@
2
2
 
3
3
  const fs = require('fs')
4
4
  const os = require('os')
5
- const uuid = require('crypto-randomuuid') // we need to keep the old uuid dep because of cypress
5
+ const uuid = require('../../../vendor/dist/crypto-randomuuid') // we need to keep the old uuid dep because of cypress
6
6
  const { URL } = require('url')
7
7
 
8
8
  const log = require('./log')
@@ -446,6 +446,7 @@ class Config {
446
446
  DD_DBM_PROPAGATION_MODE,
447
447
  DD_DOGSTATSD_HOST,
448
448
  DD_DOGSTATSD_PORT,
449
+ DD_DYNAMIC_INSTRUMENTATION_CAPTURE_TIMEOUT_MS,
449
450
  DD_DYNAMIC_INSTRUMENTATION_ENABLED,
450
451
  DD_DYNAMIC_INSTRUMENTATION_PROBE_FILE,
451
452
  DD_DYNAMIC_INSTRUMENTATION_REDACTED_IDENTIFIERS,
@@ -453,6 +454,7 @@ class Config {
453
454
  DD_DYNAMIC_INSTRUMENTATION_UPLOAD_INTERVAL_SECONDS,
454
455
  DD_ENV,
455
456
  DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED,
457
+ DD_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED,
456
458
  DD_PROFILING_ENABLED,
457
459
  DD_GRPC_CLIENT_ERROR_STATUSES,
458
460
  DD_GRPC_SERVER_ERROR_STATUSES,
@@ -477,6 +479,7 @@ class Config {
477
479
  DD_INSTRUMENTATION_CONFIG_ID,
478
480
  DD_LOGS_INJECTION,
479
481
  DD_LOGS_OTEL_ENABLED,
482
+ DD_METRICS_OTEL_ENABLED,
480
483
  DD_LANGCHAIN_SPAN_CHAR_LIMIT,
481
484
  DD_LANGCHAIN_SPAN_PROMPT_COMPLETION_SAMPLE_RATE,
482
485
  DD_LLMOBS_AGENTLESS_ENABLED,
@@ -543,6 +546,7 @@ class Config {
543
546
  DD_TRACE_RATE_LIMIT,
544
547
  DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED,
545
548
  DD_TRACE_REPORT_HOSTNAME,
549
+ DD_TRACE_RESOURCE_RENAMING_ENABLED,
546
550
  DD_TRACE_SAMPLE_RATE,
547
551
  DD_TRACE_SAMPLING_RULES,
548
552
  DD_TRACE_SCOPE,
@@ -571,12 +575,20 @@ class Config {
571
575
  OTEL_EXPORTER_OTLP_LOGS_HEADERS,
572
576
  OTEL_EXPORTER_OTLP_LOGS_PROTOCOL,
573
577
  OTEL_EXPORTER_OTLP_LOGS_TIMEOUT,
578
+ OTEL_EXPORTER_OTLP_METRICS_ENDPOINT,
579
+ OTEL_EXPORTER_OTLP_METRICS_HEADERS,
580
+ OTEL_EXPORTER_OTLP_METRICS_PROTOCOL,
581
+ OTEL_EXPORTER_OTLP_METRICS_TIMEOUT,
582
+ OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE,
583
+ OTEL_METRIC_EXPORT_TIMEOUT,
574
584
  OTEL_EXPORTER_OTLP_PROTOCOL,
575
585
  OTEL_EXPORTER_OTLP_ENDPOINT,
576
586
  OTEL_EXPORTER_OTLP_HEADERS,
577
587
  OTEL_EXPORTER_OTLP_TIMEOUT,
578
588
  OTEL_BSP_SCHEDULE_DELAY,
579
- OTEL_BSP_MAX_EXPORT_BATCH_SIZE
589
+ OTEL_BSP_MAX_EXPORT_BATCH_SIZE,
590
+ OTEL_BSP_MAX_QUEUE_SIZE,
591
+ OTEL_METRIC_EXPORT_INTERVAL
580
592
  } = source
581
593
 
582
594
  const tags = {}
@@ -603,16 +615,51 @@ class Config {
603
615
  this.#setString(target, 'otelLogsHeaders', OTEL_EXPORTER_OTLP_LOGS_HEADERS || target.otelHeaders)
604
616
  this.#setString(target, 'otelProtocol', OTEL_EXPORTER_OTLP_PROTOCOL)
605
617
  this.#setString(target, 'otelLogsProtocol', OTEL_EXPORTER_OTLP_LOGS_PROTOCOL || target.otelProtocol)
606
- target.otelTimeout = maybeInt(OTEL_EXPORTER_OTLP_TIMEOUT)
607
- target.otelLogsTimeout = maybeInt(OTEL_EXPORTER_OTLP_LOGS_TIMEOUT) || target.otelTimeout
608
- target.otelLogsBatchTimeout = maybeInt(OTEL_BSP_SCHEDULE_DELAY)
609
- target.otelLogsMaxExportBatchSize = maybeInt(OTEL_BSP_MAX_EXPORT_BATCH_SIZE)
618
+ const otelTimeout = nonNegInt(OTEL_EXPORTER_OTLP_TIMEOUT, 'OTEL_EXPORTER_OTLP_TIMEOUT')
619
+ if (otelTimeout !== undefined) {
620
+ target.otelTimeout = otelTimeout
621
+ }
622
+ const otelLogsTimeout = nonNegInt(OTEL_EXPORTER_OTLP_LOGS_TIMEOUT, 'OTEL_EXPORTER_OTLP_LOGS_TIMEOUT')
623
+ target.otelLogsTimeout = otelLogsTimeout === undefined ? target.otelTimeout : otelLogsTimeout
624
+ const otelBatchTimeout = nonNegInt(OTEL_BSP_SCHEDULE_DELAY, 'OTEL_BSP_SCHEDULE_DELAY', false)
625
+ if (otelBatchTimeout !== undefined) {
626
+ target.otelBatchTimeout = otelBatchTimeout
627
+ }
628
+ target.otelMaxExportBatchSize = nonNegInt(OTEL_BSP_MAX_EXPORT_BATCH_SIZE, 'OTEL_BSP_MAX_EXPORT_BATCH_SIZE', false)
629
+ target.otelMaxQueueSize = nonNegInt(OTEL_BSP_MAX_QUEUE_SIZE, 'OTEL_BSP_MAX_QUEUE_SIZE', false)
630
+
631
+ const otelMetricsExporterEnabled = OTEL_METRICS_EXPORTER?.toLowerCase() !== 'none'
632
+ this.#setBoolean(
633
+ target,
634
+ 'otelMetricsEnabled',
635
+ DD_METRICS_OTEL_ENABLED && isTrue(DD_METRICS_OTEL_ENABLED) && otelMetricsExporterEnabled
636
+ )
637
+ // Set OpenTelemetry metrics configuration with specific _METRICS_ vars
638
+ // taking precedence over generic _EXPORTERS_ vars
639
+ if (OTEL_EXPORTER_OTLP_ENDPOINT || OTEL_EXPORTER_OTLP_METRICS_ENDPOINT) {
640
+ this.#setString(target, 'otelMetricsUrl', OTEL_EXPORTER_OTLP_METRICS_ENDPOINT || target.otelUrl)
641
+ }
642
+ this.#setString(target, 'otelMetricsHeaders', OTEL_EXPORTER_OTLP_METRICS_HEADERS || target.otelHeaders)
643
+ this.#setString(target, 'otelMetricsProtocol', OTEL_EXPORTER_OTLP_METRICS_PROTOCOL || target.otelProtocol)
644
+ const otelMetricsTimeout = nonNegInt(OTEL_EXPORTER_OTLP_METRICS_TIMEOUT, 'OTEL_EXPORTER_OTLP_METRICS_TIMEOUT')
645
+ target.otelMetricsTimeout = otelMetricsTimeout === undefined ? target.otelTimeout : otelMetricsTimeout
646
+ target.otelMetricsExportTimeout = nonNegInt(OTEL_METRIC_EXPORT_TIMEOUT, 'OTEL_METRIC_EXPORT_TIMEOUT')
647
+ target.otelMetricsExportInterval = nonNegInt(OTEL_METRIC_EXPORT_INTERVAL, 'OTEL_METRIC_EXPORT_INTERVAL', false)
648
+
649
+ // Parse temporality preference (default to DELTA for Datadog)
650
+ if (OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE) {
651
+ const temporalityPref = OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE.toUpperCase()
652
+ if (['DELTA', 'CUMULATIVE', 'LOWMEMORY'].includes(temporalityPref)) {
653
+ this.#setString(target, 'otelMetricsTemporalityPreference', temporalityPref)
654
+ }
655
+ }
610
656
  this.#setBoolean(
611
657
  target,
612
658
  'apmTracingEnabled',
613
659
  DD_APM_TRACING_ENABLED ??
614
660
  (DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED && isFalse(DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED))
615
661
  )
662
+ this.#setBoolean(target, 'propagateProcessTags.enabled', DD_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED)
616
663
  this.#setString(target, 'appKey', DD_APP_KEY)
617
664
  this.#setBoolean(target, 'appsec.apiSecurity.enabled', DD_API_SECURITY_ENABLED && isTrue(DD_API_SECURITY_ENABLED))
618
665
  target['appsec.apiSecurity.sampleDelay'] = maybeFloat(DD_API_SECURITY_SAMPLE_DELAY)
@@ -684,6 +731,8 @@ class Config {
684
731
  this.#setString(target, 'dogstatsd.hostname', DD_DOGSTATSD_HOST)
685
732
  this.#setString(target, 'dogstatsd.port', DD_DOGSTATSD_PORT)
686
733
  this.#setBoolean(target, 'dsmEnabled', DD_DATA_STREAMS_ENABLED)
734
+ target['dynamicInstrumentation.captureTimeoutMs'] = maybeInt(DD_DYNAMIC_INSTRUMENTATION_CAPTURE_TIMEOUT_MS)
735
+ unprocessedTarget['dynamicInstrumentation.captureTimeoutMs'] = DD_DYNAMIC_INSTRUMENTATION_CAPTURE_TIMEOUT_MS
687
736
  this.#setBoolean(target, 'dynamicInstrumentation.enabled', DD_DYNAMIC_INSTRUMENTATION_ENABLED)
688
737
  this.#setString(target, 'dynamicInstrumentation.probeFile', DD_DYNAMIC_INSTRUMENTATION_PROBE_FILE)
689
738
  this.#setArray(target, 'dynamicInstrumentation.redactedIdentifiers',
@@ -787,6 +836,9 @@ class Config {
787
836
  target['remoteConfig.pollInterval'] = maybeFloat(DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS)
788
837
  unprocessedTarget['remoteConfig.pollInterval'] = DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS
789
838
  this.#setBoolean(target, 'reportHostname', DD_TRACE_REPORT_HOSTNAME)
839
+ if (DD_TRACE_RESOURCE_RENAMING_ENABLED !== undefined) {
840
+ this.#setBoolean(target, 'resourceRenamingEnabled', DD_TRACE_RESOURCE_RENAMING_ENABLED)
841
+ }
790
842
  // only used to explicitly set runtimeMetrics to false
791
843
  const otelSetRuntimeMetrics = String(OTEL_METRICS_EXPORTER).toLowerCase() === 'none'
792
844
  ? false
@@ -984,6 +1036,8 @@ class Config {
984
1036
  this.#setString(opts, 'dogstatsd.port', options.dogstatsd.port)
985
1037
  }
986
1038
  this.#setBoolean(opts, 'dsmEnabled', options.dsmEnabled)
1039
+ opts['dynamicInstrumentation.captureTimeoutMs'] = maybeInt(options.dynamicInstrumentation?.captureTimeoutMs)
1040
+ this.#optsUnprocessed['dynamicInstrumentation.captureTimeoutMs'] = options.dynamicInstrumentation?.captureTimeoutMs
987
1041
  this.#setBoolean(opts, 'dynamicInstrumentation.enabled', options.dynamicInstrumentation?.enabled)
988
1042
  this.#setString(opts, 'dynamicInstrumentation.probeFile', options.dynamicInstrumentation?.probeFile)
989
1043
  this.#setArray(
@@ -1201,14 +1255,24 @@ class Config {
1201
1255
 
1202
1256
  calc['dogstatsd.hostname'] = this.#getHostname()
1203
1257
 
1204
- // Compute OTLP logs URL to send payloads to the active Datadog Agent
1258
+ // Compute OTLP logs and metrics URLs to send payloads to the active Datadog Agent
1205
1259
  const agentHostname = this.#getHostname()
1206
1260
  calc.otelLogsUrl = `http://${agentHostname}:${DEFAULT_OTLP_PORT}`
1261
+ calc.otelMetricsUrl = `http://${agentHostname}:${DEFAULT_OTLP_PORT}/v1/metrics`
1207
1262
  calc.otelUrl = `http://${agentHostname}:${DEFAULT_OTLP_PORT}`
1208
1263
 
1209
1264
  this.#setBoolean(calc, 'isGitUploadEnabled',
1210
1265
  calc.isIntelligentTestRunnerEnabled && !isFalse(getEnv('DD_CIVISIBILITY_GIT_UPLOAD_ENABLED')))
1211
1266
 
1267
+ // Enable resourceRenamingEnabled when appsec is enabled and only
1268
+ // if DD_TRACE_RESOURCE_RENAMING_ENABLED is not explicitly set
1269
+ if (this.#env.resourceRenamingEnabled === undefined) {
1270
+ const appsecEnabled = this.#options['appsec.enabled'] ?? this.#env['appsec.enabled']
1271
+ if (appsecEnabled) {
1272
+ this.#setBoolean(calc, 'resourceRenamingEnabled', true)
1273
+ }
1274
+ }
1275
+
1212
1276
  this.#setBoolean(calc, 'spanComputePeerService', this.#getSpanComputePeerService())
1213
1277
  this.#setBoolean(calc, 'stats.enabled', this.#isTraceStatsComputationEnabled())
1214
1278
  const defaultPropagationStyle = this.#getDefaultPropagationStyle(this.#optionsArg)
@@ -1492,6 +1556,16 @@ function maybeFloat (number) {
1492
1556
  return Number.isNaN(parsed) ? undefined : parsed
1493
1557
  }
1494
1558
 
1559
+ function nonNegInt (value, envVarName, allowZero = true) {
1560
+ if (value === undefined) return
1561
+ const parsed = Number.parseInt(value)
1562
+ if (Number.isNaN(parsed) || parsed < 0 || (parsed === 0 && !allowZero)) {
1563
+ log.warn(`Invalid value ${parsed} for ${envVarName}. Using default value.`)
1564
+ return
1565
+ }
1566
+ return parsed
1567
+ }
1568
+
1495
1569
  function getAgentUrl (url, options) {
1496
1570
  if (url) return new URL(url)
1497
1571
 
@@ -63,6 +63,7 @@ module.exports = {
63
63
  'dogstatsd.hostname': '127.0.0.1',
64
64
  'dogstatsd.port': '8125',
65
65
  dsmEnabled: false,
66
+ 'dynamicInstrumentation.captureTimeoutMs': 15,
66
67
  'dynamicInstrumentation.enabled': false,
67
68
  'dynamicInstrumentation.probeFile': undefined,
68
69
  'dynamicInstrumentation.redactedIdentifiers': [],
@@ -139,8 +140,17 @@ module.exports = {
139
140
  otelLogsProtocol: 'http/protobuf',
140
141
  otelLogsTimeout: 10_000,
141
142
  otelTimeout: 10_000,
142
- otelLogsBatchTimeout: 5000,
143
- otelLogsMaxExportBatchSize: 512,
143
+ otelBatchTimeout: 5000,
144
+ otelMaxExportBatchSize: 512,
145
+ otelMaxQueueSize: 2048,
146
+ otelMetricsEnabled: false,
147
+ otelMetricsUrl: undefined, // Will be computed using agent host
148
+ otelMetricsHeaders: '',
149
+ otelMetricsProtocol: 'http/protobuf',
150
+ otelMetricsTimeout: 10_000,
151
+ otelMetricsExportTimeout: 7500,
152
+ otelMetricsExportInterval: 10_000,
153
+ otelMetricsTemporalityPreference: 'DELTA', // DELTA, CUMULATIVE, or LOWMEMORY
144
154
  lookup: undefined,
145
155
  inferredProxyServicesEnabled: false,
146
156
  memcachedCommandEnabled: false,
@@ -151,6 +161,7 @@ module.exports = {
151
161
  plugins: true,
152
162
  port: '8126',
153
163
  'profiling.enabled': undefined,
164
+ 'propagateProcessTags.enabled': undefined,
154
165
  'profiling.exporters': 'agent',
155
166
  'profiling.sourceMap': true,
156
167
  'profiling.longLivedThreshold': undefined,
@@ -159,6 +170,7 @@ module.exports = {
159
170
  'remoteConfig.enabled': true,
160
171
  'remoteConfig.pollInterval': 5, // seconds
161
172
  reportHostname: false,
173
+ resourceRenamingEnabled: false,
162
174
  'runtimeMetrics.enabled': false,
163
175
  'runtimeMetrics.eventLoop': true,
164
176
  'runtimeMetrics.gc': true,
@@ -1,11 +1,15 @@
1
1
  'use strict'
2
2
 
3
- // encodes positive and negative numbers, using zig zag encoding to reduce the size of the variable length encoding.
4
- // uses high and low part to ensure those parts are under the limit for byte operations in javascript (32 bits)
5
- // maximum number possible to encode is MAX_SAFE_INTEGER/2 (using zig zag shifts the bits by 1 to the left)
3
+ /**
4
+ * Encodes positive and negative numbers, using zig zag encoding to reduce the size of the variable length encoding.
5
+ * Uses high and low part to ensure those parts are under the limit for byte operations in javascript (32 bits)
6
+ * Maximum number possible to encode is MAX_SAFE_INTEGER/2 (using zig zag shifts the bits by 1 to the left)
7
+ * @param {number} v
8
+ * @returns {Uint8Array|undefined}
9
+ */
6
10
  function encodeVarint (v) {
7
11
  const sign = v >= 0 ? 0 : 1
8
- // we leave the least significant bit for the sign.
12
+ // We leave the least significant bit for the sign.
9
13
  const double = Math.abs(v) * 2
10
14
  if (double > Number.MAX_SAFE_INTEGER) {
11
15
  return
@@ -15,8 +19,12 @@ function encodeVarint (v) {
15
19
  return encodeUvarint64(low, high)
16
20
  }
17
21
 
18
- // decodes positive and negative numbers, using zig zag encoding to reduce the size of the variable length encoding.
19
- // uses high and low part to ensure those parts are under the limit for byte operations in javascript (32 bits)
22
+ /**
23
+ * Decodes positive and negative numbers, using zig zag encoding to reduce the size of the variable length encoding.
24
+ * Uses high and low part to ensure those parts are under the limit for byte operations in javascript (32 bits)
25
+ * @param {Uint8Array} b
26
+ * @returns {[number|undefined, Uint8Array]}
27
+ */
20
28
  function decodeVarint (b) {
21
29
  const [low, high, bytes] = decodeUvarint64(b)
22
30
  if (low === undefined || high === undefined) {
@@ -29,6 +37,11 @@ function decodeVarint (b) {
29
37
 
30
38
  const maxVarLen64 = 9
31
39
 
40
+ /**
41
+ * @param {number} low
42
+ * @param {number} high
43
+ * @returns {Uint8Array}
44
+ */
32
45
  function encodeUvarint64 (low, high) {
33
46
  const result = new Uint8Array(maxVarLen64)
34
47
  let i = 0
@@ -44,6 +57,10 @@ function encodeUvarint64 (low, high) {
44
57
  return result.slice(0, i + 1)
45
58
  }
46
59
 
60
+ /**
61
+ * @param {Uint8Array} bytes
62
+ * @returns {[number|undefined, number|undefined, Uint8Array]}
63
+ */
47
64
  function decodeUvarint64 (
48
65
  bytes
49
66
  ) {
@@ -5,7 +5,7 @@
5
5
  // this inconsistency is ok because hashes do not need to be consistent across services
6
6
  const crypto = require('crypto')
7
7
  const { encodeVarint, decodeVarint } = require('./encoding')
8
- const { LRUCache } = require('lru-cache')
8
+ const { LRUCache } = require('../../../../vendor/dist/lru-cache')
9
9
  const log = require('../log')
10
10
  const pick = require('../../../datadog-core/src/utils/src/pick')
11
11
 
@@ -21,6 +21,12 @@ function shaHash (checkpointString) {
21
21
  return Buffer.from(hash, 'hex')
22
22
  }
23
23
 
24
+ /**
25
+ * @param {string} service
26
+ * @param {string} env
27
+ * @param {string[]} edgeTags
28
+ * @param {Buffer} parentHash
29
+ */
24
30
  function computeHash (service, env, edgeTags, parentHash) {
25
31
  edgeTags.sort()
26
32
  const hashableEdgeTags = edgeTags.filter(item => item !== 'manual_checkpoint:true')
@@ -37,6 +43,13 @@ function computeHash (service, env, edgeTags, parentHash) {
37
43
  return value
38
44
  }
39
45
 
46
+ /**
47
+ * @param {Object} dataStreamsContext
48
+ * @param {Buffer} dataStreamsContext.hash
49
+ * @param {number} dataStreamsContext.pathwayStartNs
50
+ * @param {number} dataStreamsContext.edgeStartNs
51
+ * @returns {Buffer}
52
+ */
40
53
  function encodePathwayContext (dataStreamsContext) {
41
54
  return Buffer.concat([
42
55
  dataStreamsContext.hash,
@@ -45,11 +58,22 @@ function encodePathwayContext (dataStreamsContext) {
45
58
  ], 20)
46
59
  }
47
60
 
61
+ /**
62
+ * @param {Object} dataStreamsContext
63
+ * @param {Buffer} dataStreamsContext.hash
64
+ * @param {number} dataStreamsContext.pathwayStartNs
65
+ * @param {number} dataStreamsContext.edgeStartNs
66
+ * @returns {string}
67
+ */
48
68
  function encodePathwayContextBase64 (dataStreamsContext) {
49
69
  const encodedPathway = encodePathwayContext(dataStreamsContext)
50
70
  return encodedPathway.toString('base64')
51
71
  }
52
72
 
73
+ /**
74
+ * @param {Buffer} pathwayContext
75
+ * @returns {Object}
76
+ */
53
77
  function decodePathwayContext (pathwayContext) {
54
78
  if (pathwayContext == null || pathwayContext.length < 8) {
55
79
  return null
@@ -68,6 +92,10 @@ function decodePathwayContext (pathwayContext) {
68
92
  return { hash: pathwayHash, pathwayStartNs: pathwayStartMs * 1e6, edgeStartNs: edgeStartMs * 1e6 }
69
93
  }
70
94
 
95
+ /**
96
+ * @param {string} pathwayContext
97
+ * @returns {ReturnType<typeof decodePathwayContext>|undefined}
98
+ */
71
99
  function decodePathwayContextBase64 (pathwayContext) {
72
100
  if (pathwayContext == null || pathwayContext.length < 8) {
73
101
  return
@@ -82,6 +110,13 @@ function decodePathwayContextBase64 (pathwayContext) {
82
110
  const DsmPathwayCodec = {
83
111
  // we use a class for encoding / decoding in case we update our encoding/decoding. A class will make updates easier
84
112
  // instead of using individual functions.
113
+ /**
114
+ * @param {Object} dataStreamsContext
115
+ * @param {Buffer} dataStreamsContext.hash
116
+ * @param {number} dataStreamsContext.pathwayStartNs
117
+ * @param {number} dataStreamsContext.edgeStartNs
118
+ * @param {Object} carrier
119
+ */
85
120
  encode (dataStreamsContext, carrier) {
86
121
  if (!dataStreamsContext || !dataStreamsContext.hash) {
87
122
  return
@@ -91,6 +126,10 @@ const DsmPathwayCodec = {
91
126
  log.debug(() => `Injected into DSM carrier: ${JSON.stringify(pick(carrier, logKeys))}.`)
92
127
  },
93
128
 
129
+ /**
130
+ * @param {Object} carrier
131
+ * @returns {ReturnType<typeof decodePathwayContext>|undefined}
132
+ */
94
133
  decode (carrier) {
95
134
  log.debug(() => `Attempting extract from DSM carrier: ${JSON.stringify(pick(carrier, logKeys))}.`)
96
135
 
@@ -3,7 +3,7 @@
3
3
  const os = require('os')
4
4
  const pkg = require('../../../../package.json')
5
5
 
6
- const { LogCollapsingLowestDenseDDSketch } = require('@datadog/sketches-js')
6
+ const { LogCollapsingLowestDenseDDSketch } = require('../../../../vendor/dist/@datadog/sketches-js')
7
7
  const { DsmPathwayCodec } = require('./pathway')
8
8
  const { DataStreamsWriter } = require('./writer')
9
9
  const { computePathwayHash } = require('./pathway')
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const { LRUCache } = require('lru-cache')
3
+ const { LRUCache } = require('../../../../../vendor/dist/lru-cache')
4
4
  const { fnv64 } = require('../fnv')
5
5
  const { Schema } = require('./schema')
6
6
 
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const mutex = require('mutexify/promise')()
3
+ const mutex = require('../../../../../vendor/dist/mutexify/promise')()
4
4
  const { getGeneratedPosition } = require('./source-maps')
5
5
  const session = require('./session')
6
6
  const { compile: compileCondition, compileSegments, templateRequiresEvaluation } = require('./condition')
@@ -64,8 +64,9 @@ async function addBreakpoint (probe) {
64
64
  const snapshotsPerSecond = probe.sampling?.snapshotsPerSecond ?? (probe.captureSnapshot
65
65
  ? MAX_SNAPSHOTS_PER_SECOND_PER_PROBE
66
66
  : MAX_NON_SNAPSHOTS_PER_SECOND_PER_PROBE)
67
- probe.nsBetweenSampling = BigInt(1 / snapshotsPerSecond * 1e9)
68
- probe.lastCaptureNs = 0n
67
+ probe.nsBetweenSampling = BigInt(Math.trunc(1 / snapshotsPerSecond * 1e9))
68
+ // Initialize to a large negative value to ensure first probe hit is always captured
69
+ probe.lastCaptureNs = BigInt(Number.MIN_SAFE_INTEGER)
69
70
 
70
71
  // Warning: The code below relies on undocumented behavior of the inspector!
71
72
  // It expects that `await session.post('Debugger.enable')` will wait for all loaded scripts to be emitted as
@@ -80,8 +81,17 @@ async function addBreakpoint (probe) {
80
81
  log.debug(
81
82
  '[debugger:devtools_client] Translating location using source map for %s:%d:%d (probe: %s, version: %d)',
82
83
  file, lineNumber, columnNumber, probe.id, probe.version
83
- );
84
- ({ line: lineNumber, column: columnNumber } = await getGeneratedPosition(url, source, lineNumber, sourceMapURL))
84
+ )
85
+ const position = await getGeneratedPosition(url, source, lineNumber, sourceMapURL)
86
+ if (position.line !== null && position.column !== null) {
87
+ lineNumber = position.line
88
+ columnNumber = position.column
89
+ } else {
90
+ throw new Error(
91
+ // eslint-disable-next-line @stylistic/max-len
92
+ `Could not find generated position for ${url}:${lineNumber}:${columnNumber} (probe: ${probe.id}, version: ${probe.version})`
93
+ )
94
+ }
85
95
  }
86
96
 
87
97
  try {
@@ -33,7 +33,7 @@ const reservedWords = new Set([
33
33
  // Future reserved words in strict mode
34
34
  'implements', 'interface', 'package', 'private', 'protected', 'public',
35
35
 
36
- // Litterals
36
+ // Literals
37
37
  'NaN'
38
38
  ])
39
39
 
@@ -24,4 +24,6 @@ function updateUrl (updates) {
24
24
  hostname: updates.hostname || defaults.hostname,
25
25
  port: updates.port
26
26
  })
27
+
28
+ config.dynamicInstrumentation.captureTimeoutNs = BigInt(updates.dynamicInstrumentation.captureTimeoutMs) * 1_000_000n
27
29
  }
@@ -7,7 +7,7 @@ const { getLocalStateForCallFrame } = require('./snapshot')
7
7
  const send = require('./send')
8
8
  const { getStackFromCallFrames } = require('./state')
9
9
  const { ackEmitting } = require('./status')
10
- const { parentThreadId } = require('./config')
10
+ const config = require('./config')
11
11
  const { MAX_SNAPSHOTS_PER_SECOND_GLOBALLY } = require('./defaults')
12
12
  const log = require('./log')
13
13
  const { version } = require('../../../../../package.json')
@@ -33,8 +33,8 @@ const getDDTagsExpression = `(() => {
33
33
 
34
34
  // There doesn't seem to be an official standard for the content of these fields, so we're just populating them with
35
35
  // something that should be useful to a Node.js developer.
36
- const threadId = parentThreadId === 0 ? `pid:${process.pid}` : `pid:${process.pid};tid:${parentThreadId}`
37
- const threadName = parentThreadId === 0 ? 'MainThread' : `WorkerThread:${parentThreadId}`
36
+ const threadId = config.parentThreadId === 0 ? `pid:${process.pid}` : `pid:${process.pid};tid:${config.parentThreadId}`
37
+ const threadName = config.parentThreadId === 0 ? 'MainThread' : `WorkerThread:${config.parentThreadId}`
38
38
 
39
39
  const SUPPORT_ARRAY_BUFFER_RESIZE = NODE_MAJOR >= 20
40
40
  const oneSecondNs = 1_000_000_000n
@@ -46,6 +46,7 @@ let snapshotProbeIndexBuffer, snapshotProbeIndex
46
46
 
47
47
  if (SUPPORT_ARRAY_BUFFER_RESIZE) {
48
48
  // TODO: Is a limit of 256 snapshots ever going to be a problem?
49
+ // @ts-ignore - ArrayBuffer constructor with maxByteLength is available in Node.js 20+ but not in @types/node@18
49
50
  // eslint-disable-next-line n/no-unsupported-features/es-syntax
50
51
  snapshotProbeIndexBuffer = new ArrayBuffer(1, { maxByteLength: 256 })
51
52
  // TODO: Is a limit of 256 probes ever going to be a problem?
@@ -165,13 +166,20 @@ session.on('Debugger.paused', async ({ params }) => {
165
166
  }
166
167
 
167
168
  // TODO: Create unique states for each affected probe based on that probes unique `capture` settings (DEBUG-2863)
168
- const processLocalState = numberOfProbesWithSnapshots !== 0 && await getLocalStateForCallFrame(
169
- params.callFrames[0],
170
- { maxReferenceDepth, maxCollectionSize, maxFieldCount, maxLength }
171
- )
169
+ let processLocalState, captureErrors
170
+ if (numberOfProbesWithSnapshots !== 0) {
171
+ const opts = {
172
+ maxReferenceDepth,
173
+ maxCollectionSize,
174
+ maxFieldCount,
175
+ maxLength,
176
+ deadlineNs: start + config.dynamicInstrumentation.captureTimeoutNs
177
+ }
178
+ ;({ processLocalState, captureErrors } = await getLocalStateForCallFrame(params.callFrames[0], opts))
179
+ }
172
180
 
173
181
  await session.post('Debugger.resume')
174
- const diff = process.hrtime.bigint() - start // TODO: Recored as telemetry (DEBUG-2858)
182
+ const diff = process.hrtime.bigint() - start // TODO: Recorded as telemetry (DEBUG-2858)
175
183
 
176
184
  // This doesn't measure the overhead of the CDP protocol. The actual pause time is slightly larger.
177
185
  // On my machine I'm seeing around 1.7ms of overhead.
@@ -208,14 +216,21 @@ session.on('Debugger.paused', async ({ params }) => {
208
216
  }
209
217
 
210
218
  if (probe.captureSnapshot) {
211
- const state = processLocalState()
212
- if (state instanceof Error) {
213
- snapshot.captureError = state.message
214
- } else if (state) {
215
- snapshot.captures = {
216
- lines: { [probe.location.lines[0]]: { locals: state } }
217
- }
219
+ if (captureErrors?.length > 0) {
220
+ // There was an error collecting the snapshot for this probe, let's not try again
221
+ probe.captureSnapshot = false
222
+ probe.permanentEvaluationErrors = captureErrors.map(error => ({
223
+ expr: '',
224
+ message: error.message
225
+ }))
218
226
  }
227
+ snapshot.captures = {
228
+ lines: { [probe.location.lines[0]]: { locals: processLocalState() } }
229
+ }
230
+ }
231
+
232
+ if (probe.permanentEvaluationErrors !== undefined) {
233
+ snapshot.evaluationErrors = [...probe.permanentEvaluationErrors]
219
234
  }
220
235
 
221
236
  let message = ''
@@ -5,6 +5,7 @@
5
5
  const { builtinModules } = require('node:module')
6
6
 
7
7
  if (builtinModules.includes('inspector/promises')) {
8
+ // @ts-ignore - inspector/promises is available in Node.js 20+ but not in @types/node@18
8
9
  module.exports = require('node:inspector/promises')
9
10
  } else {
10
11
  const inspector = require('node:inspector')
@@ -12,6 +13,7 @@ if (builtinModules.includes('inspector/promises')) {
12
13
 
13
14
  // The rest of the code in this file is lifted from:
14
15
  // https://github.com/nodejs/node/blob/1d4d76ff3fb08f9a0c55a1d5530b46c4d5d550c7/lib/inspector/promises.js
16
+ // @ts-expect-error - We intentionally override 'post' with a promisified version, changing its signature
15
17
  class Session extends inspector.Session {
16
18
  constructor () { super() } // eslint-disable-line no-useless-constructor
17
19
  }
@@ -1,34 +1,40 @@
1
1
  'use strict'
2
2
 
3
3
  class JSONBuffer {
4
+ #maxSize
5
+ #timeout
6
+ #onFlush
7
+ #timer
8
+ #partialJson
9
+
4
10
  constructor ({ size, timeout, onFlush }) {
5
- this._maxSize = size
6
- this._timeout = timeout
7
- this._onFlush = onFlush
8
- this._reset()
11
+ this.#maxSize = size
12
+ this.#timeout = timeout
13
+ this.#onFlush = onFlush
14
+ this.#reset()
9
15
  }
10
16
 
11
- _reset () {
12
- clearTimeout(this._timer)
13
- this._timer = null
14
- this._partialJson = null
17
+ #reset () {
18
+ clearTimeout(this.#timer)
19
+ this.#timer = undefined
20
+ this.#partialJson = undefined
15
21
  }
16
22
 
17
- _flush () {
18
- const json = `${this._partialJson}]`
19
- this._reset()
20
- this._onFlush(json)
23
+ #flush () {
24
+ const json = `${this.#partialJson}]`
25
+ this.#reset()
26
+ this.#onFlush(json)
21
27
  }
22
28
 
23
29
  write (str, size = Buffer.byteLength(str)) {
24
- if (this._timer === null) {
25
- this._partialJson = `[${str}`
26
- this._timer = setTimeout(() => this._flush(), this._timeout)
27
- } else if (Buffer.byteLength(this._partialJson) + size + 2 > this._maxSize) {
28
- this._flush()
30
+ if (this.#timer === undefined) {
31
+ this.#partialJson = `[${str}`
32
+ this.#timer = setTimeout(() => this.#flush(), this.#timeout)
33
+ } else if (Buffer.byteLength(/** @type {string} */ (this.#partialJson)) + size + 2 > this.#maxSize) {
34
+ this.#flush()
29
35
  this.write(str, size)
30
36
  } else {
31
- this._partialJson += `,${str}`
37
+ this.#partialJson += `,${str}`
32
38
  }
33
39
  }
34
40
  }
@@ -10,6 +10,7 @@ const { GIT_COMMIT_SHA, GIT_REPOSITORY_URL } = require('../../plugins/util/tags'
10
10
  const log = require('./log')
11
11
  const { version } = require('../../../../../package.json')
12
12
  const { getEnvironmentVariable } = require('../../config-helper')
13
+ const { pruneSnapshot } = require('./snapshot-pruner')
13
14
 
14
15
  module.exports = send
15
16
 
@@ -55,14 +56,23 @@ function send (message, logger, dd, snapshot) {
55
56
  let size = Buffer.byteLength(json)
56
57
 
57
58
  if (size > MAX_LOG_PAYLOAD_SIZE_BYTES) {
58
- // TODO: This is a very crude way to handle large payloads. Proper pruning will be implemented later (DEBUG-2624)
59
- delete payload.debugger.snapshot.captures
60
- payload.debugger.snapshot.captureError =
61
- `Snapshot was too large (max allowed size is ${MAX_LOG_PAYLOAD_SIZE_MB} MiB). ` +
62
- 'Consider reducing the capture depth or turn off "Capture Variables" completely, ' +
63
- 'and instead include the variables of interest directly in the message template.'
64
- json = JSON.stringify(payload)
65
- size = Buffer.byteLength(json)
59
+ let pruned
60
+ try {
61
+ pruned = pruneSnapshot(json, size, MAX_LOG_PAYLOAD_SIZE_BYTES)
62
+ } catch (err) {
63
+ log.error('[debugger:devtools_client] Error pruning snapshot', err)
64
+ }
65
+
66
+ if (pruned) {
67
+ json = pruned
68
+ size = Buffer.byteLength(json)
69
+ } else {
70
+ // Fallback if pruning fails
71
+ const line = Object.keys(snapshot.captures.lines)[0]
72
+ snapshot.captures.lines[line] = { pruned: true }
73
+ json = JSON.stringify(payload)
74
+ size = Buffer.byteLength(json)
75
+ }
66
76
  }
67
77
 
68
78
  jsonBuffer.write(json, size)