dd-trace 6.12.0 → 6.14.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 (251) hide show
  1. package/LICENSE-3rdparty.csv +3 -1
  2. package/ci/init.js +8 -3
  3. package/ci/test-optimization-validation/ci-package-scripts.js +2 -2
  4. package/ci/test-optimization-validation/ci-remediation.js +6 -6
  5. package/ci/test-optimization-validation/command-blocker.js +7 -5
  6. package/ci/test-optimization-validation/framework-adapters/cucumber.js +1 -1
  7. package/ci/test-optimization-validation/framework-adapters/cypress.js +9 -11
  8. package/ci/test-optimization-validation/framework-adapters/vitest.js +3 -3
  9. package/ci/test-optimization-validation/package-check.js +1 -1
  10. package/ci/test-optimization-validation/report-writer.js +7 -5
  11. package/ci/test-optimization-validation/scenarios/ci-wiring.js +5 -4
  12. package/ci/vitest-no-worker-init-runner-setup.mjs +8 -0
  13. package/ci/vitest-no-worker-init-setup.mjs +13 -13
  14. package/ci/vitest-no-worker-init-v5-setup.mjs +4 -0
  15. package/index.d.ts +127 -26
  16. package/package.json +22 -19
  17. package/packages/datadog-esbuild/index.js +3 -1
  18. package/packages/datadog-instrumentations/src/bunyan.js +4 -2
  19. package/packages/datadog-instrumentations/src/cypress-config.js +19 -17
  20. package/packages/datadog-instrumentations/src/fs.js +24 -20
  21. package/packages/datadog-instrumentations/src/google-cloud-vertexai.js +2 -2
  22. package/packages/datadog-instrumentations/src/graphql.js +16 -16
  23. package/packages/datadog-instrumentations/src/helpers/bunyan.js +12 -3
  24. package/packages/datadog-instrumentations/src/helpers/graphql-jit-runtime.js +504 -0
  25. package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
  26. package/packages/datadog-instrumentations/src/helpers/pool-acquire.js +266 -0
  27. package/packages/datadog-instrumentations/src/helpers/rewriter/compiler.js +1 -2
  28. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +95 -30
  29. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/ai.js +0 -25
  30. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/graphql-jit.js +83 -0
  31. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/graphql.js +85 -1
  32. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
  33. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/mercurius.js +30 -12
  34. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +13 -0
  35. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +279 -0
  36. package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +12 -1
  37. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +562 -27
  38. package/packages/datadog-instrumentations/src/jest.js +165 -38
  39. package/packages/datadog-instrumentations/src/knex.js +76 -0
  40. package/packages/datadog-instrumentations/src/mariadb-bundle.js +1597 -0
  41. package/packages/datadog-instrumentations/src/mariadb.js +13 -0
  42. package/packages/datadog-instrumentations/src/mocha/common.js +59 -2
  43. package/packages/datadog-instrumentations/src/mocha/main.js +25 -15
  44. package/packages/datadog-instrumentations/src/mocha/utils.js +2 -1
  45. package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +98 -0
  46. package/packages/datadog-instrumentations/src/mocha/worker.js +12 -8
  47. package/packages/datadog-instrumentations/src/net.js +14 -17
  48. package/packages/datadog-instrumentations/src/next.js +212 -62
  49. package/packages/datadog-instrumentations/src/openai.js +42 -40
  50. package/packages/datadog-instrumentations/src/pg.js +15 -0
  51. package/packages/datadog-instrumentations/src/pino.js +15 -4
  52. package/packages/datadog-instrumentations/src/playwright.js +137 -27
  53. package/packages/datadog-instrumentations/src/rum-browser-scripts.js +40 -0
  54. package/packages/datadog-instrumentations/src/sequelize.js +94 -2
  55. package/packages/datadog-instrumentations/src/undici.js +53 -4
  56. package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +44 -7
  57. package/packages/datadog-instrumentations/src/vitest-main.js +92 -9
  58. package/packages/datadog-instrumentations/src/vitest-worker.js +82 -14
  59. package/packages/datadog-instrumentations/src/webdriverio.js +986 -1
  60. package/packages/datadog-instrumentations/src/winston.js +6 -3
  61. package/packages/datadog-plugin-amqp10/src/consumer.js +3 -1
  62. package/packages/datadog-plugin-amqp10/src/producer.js +3 -1
  63. package/packages/datadog-plugin-amqp10/src/util.js +2 -1
  64. package/packages/datadog-plugin-avsc/src/schema_iterator.js +6 -1
  65. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +16 -5
  66. package/packages/datadog-plugin-cassandra-driver/src/index.js +8 -3
  67. package/packages/datadog-plugin-cucumber/src/index.js +0 -2
  68. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +262 -48
  69. package/packages/datadog-plugin-cypress/src/support.js +1 -0
  70. package/packages/datadog-plugin-google-cloud-pubsub/src/client.js +4 -1
  71. package/packages/datadog-plugin-graphql/src/execute.js +998 -196
  72. package/packages/datadog-plugin-graphql/src/index.js +27 -7
  73. package/packages/datadog-plugin-graphql/src/jit.js +136 -0
  74. package/packages/datadog-plugin-graphql/src/request.js +18 -27
  75. package/packages/datadog-plugin-graphql/src/resolve-error.js +108 -0
  76. package/packages/datadog-plugin-graphql/src/tools/signature.js +1 -2
  77. package/packages/datadog-plugin-graphql/src/tools/transforms.js +45 -3
  78. package/packages/datadog-plugin-graphql/src/utils.js +208 -120
  79. package/packages/datadog-plugin-graphql/src/validate.js +10 -23
  80. package/packages/datadog-plugin-http/src/client.js +2 -15
  81. package/packages/datadog-plugin-http2/src/client.js +2 -15
  82. package/packages/datadog-plugin-jest/src/index.js +0 -6
  83. package/packages/datadog-plugin-langchain/src/tracing.js +7 -0
  84. package/packages/datadog-plugin-mocha/src/index.js +403 -75
  85. package/packages/datadog-plugin-mongodb-core/src/query.js +6 -0
  86. package/packages/datadog-plugin-mysql/src/index.js +41 -15
  87. package/packages/datadog-plugin-net/src/tcp.js +3 -1
  88. package/packages/datadog-plugin-next/src/index.js +63 -29
  89. package/packages/datadog-plugin-openai-agents/src/integration.js +15 -11
  90. package/packages/datadog-plugin-playwright/src/index.js +176 -28
  91. package/packages/datadog-plugin-undici/src/index.js +29 -56
  92. package/packages/datadog-plugin-vitest/src/index.js +6 -12
  93. package/packages/dd-trace/src/aiguard/evaluation.js +96 -21
  94. package/packages/dd-trace/src/aiguard/integrations/vercel-ai.js +2 -3
  95. package/packages/dd-trace/src/aiguard/messages/anthropic.js +29 -10
  96. package/packages/dd-trace/src/aiguard/messages/openai.js +8 -1
  97. package/packages/dd-trace/src/aiguard/messages/vercel-ai.js +20 -6
  98. package/packages/dd-trace/src/aiguard/noop.js +9 -1
  99. package/packages/dd-trace/src/aiguard/redaction.js +183 -0
  100. package/packages/dd-trace/src/aiguard/sdk.js +7 -2
  101. package/packages/dd-trace/src/aiguard/tags.js +2 -0
  102. package/packages/dd-trace/src/appsec/api_security/index.js +23 -6
  103. package/packages/dd-trace/src/appsec/api_security/sampler.js +99 -40
  104. package/packages/dd-trace/src/appsec/graphql.js +6 -2
  105. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +3 -3
  106. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +2 -1
  107. package/packages/dd-trace/src/appsec/iast/telemetry/span-tags.js +8 -2
  108. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +11 -36
  109. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/url-sensitive-analyzer.js +1 -1
  110. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +10 -9
  111. package/packages/dd-trace/src/appsec/lambda.js +44 -26
  112. package/packages/dd-trace/src/appsec/rule_manager.js +2 -0
  113. package/packages/dd-trace/src/ci-visibility/encode/json-encoder.js +32 -2
  114. package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +8 -8
  115. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +6 -4
  116. package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +20 -4
  117. package/packages/dd-trace/src/ci-visibility/exporters/agentless/request-tracker.js +7 -150
  118. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +7 -6
  119. package/packages/dd-trace/src/ci-visibility/exporters/agents.js +54 -0
  120. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/writer.js +1 -2
  121. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +397 -234
  122. package/packages/dd-trace/src/ci-visibility/exporters/limits.js +9 -0
  123. package/packages/dd-trace/src/ci-visibility/exporters/request.js +323 -31
  124. package/packages/dd-trace/src/ci-visibility/exporters/settings-cache-key.js +42 -0
  125. package/packages/dd-trace/src/ci-visibility/final-flush.js +21 -0
  126. package/packages/dd-trace/src/ci-visibility/requests/fs-cache.js +57 -18
  127. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +0 -3
  128. package/packages/dd-trace/src/ci-visibility/requests/upload-test-screenshot.js +164 -71
  129. package/packages/dd-trace/src/ci-visibility/requests/video-request.js +176 -0
  130. package/packages/dd-trace/src/ci-visibility/telemetry.js +10 -7
  131. package/packages/dd-trace/src/ci-visibility/test-video.js +61 -0
  132. package/packages/dd-trace/src/config/generated-config-types.d.ts +10 -0
  133. package/packages/dd-trace/src/config/index.js +75 -14
  134. package/packages/dd-trace/src/config/parsers.js +11 -1
  135. package/packages/dd-trace/src/config/stable.js +3 -3
  136. package/packages/dd-trace/src/config/supported-configurations.json +47 -2
  137. package/packages/dd-trace/src/crashtracking/crashtracker.js +82 -18
  138. package/packages/dd-trace/src/debugger/config.js +12 -1
  139. package/packages/dd-trace/src/debugger/constants.js +1 -0
  140. package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +2 -1
  141. package/packages/dd-trace/src/debugger/devtools_client/request-options.js +33 -0
  142. package/packages/dd-trace/src/debugger/devtools_client/send.js +7 -39
  143. package/packages/dd-trace/src/debugger/devtools_client/status.js +11 -6
  144. package/packages/dd-trace/src/debugger/devtools_client/tags.js +41 -0
  145. package/packages/dd-trace/src/debugger/index.js +23 -3
  146. package/packages/dd-trace/src/dogstatsd.js +532 -71
  147. package/packages/dd-trace/src/encode/0.4-cross-payload.js +170 -0
  148. package/packages/dd-trace/src/encode/0.4.js +5 -5
  149. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +9 -8
  150. package/packages/dd-trace/src/evp_proxy/direct.js +27 -23
  151. package/packages/dd-trace/src/exporters/agent/index.js +24 -3
  152. package/packages/dd-trace/src/exporters/agent/writer.js +28 -11
  153. package/packages/dd-trace/src/exporters/agentless/index.js +7 -9
  154. package/packages/dd-trace/src/exporters/agentless/writer.js +100 -118
  155. package/packages/dd-trace/src/exporters/common/agents.js +28 -6
  156. package/packages/dd-trace/src/exporters/common/buffering-exporter.js +2 -2
  157. package/packages/dd-trace/src/exporters/common/final-flush-request-tracker.js +191 -0
  158. package/packages/dd-trace/src/exporters/common/request.js +31 -11
  159. package/packages/dd-trace/src/exporters/common/url.js +40 -1
  160. package/packages/dd-trace/src/exporters/common/writer.js +31 -7
  161. package/packages/dd-trace/src/exporters/span-stats/index.js +23 -4
  162. package/packages/dd-trace/src/external-logger/src/index.js +4 -3
  163. package/packages/dd-trace/src/flush.js +105 -0
  164. package/packages/dd-trace/src/id.js +14 -0
  165. package/packages/dd-trace/src/index.js +5 -2
  166. package/packages/dd-trace/src/llmobs/experiments/client.js +4 -0
  167. package/packages/dd-trace/src/llmobs/experiments/dataset.js +52 -2
  168. package/packages/dd-trace/src/llmobs/experiments/experiment.js +420 -105
  169. package/packages/dd-trace/src/llmobs/experiments/index.js +54 -42
  170. package/packages/dd-trace/src/llmobs/experiments/noop.js +39 -8
  171. package/packages/dd-trace/src/llmobs/experiments/result.js +1 -0
  172. package/packages/dd-trace/src/llmobs/experiments/util.js +21 -0
  173. package/packages/dd-trace/src/llmobs/index.js +111 -48
  174. package/packages/dd-trace/src/llmobs/noop.js +2 -1
  175. package/packages/dd-trace/src/llmobs/plugins/ai/ddTelemetry.js +22 -71
  176. package/packages/dd-trace/src/llmobs/plugins/ai/vercelTelemetry.js +23 -13
  177. package/packages/dd-trace/src/llmobs/plugins/anthropic/util.js +8 -4
  178. package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/index.js +6 -3
  179. package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +7 -0
  180. package/packages/dd-trace/src/llmobs/plugins/openai/utils.js +13 -6
  181. package/packages/dd-trace/src/llmobs/plugins/openai-agents/utils.js +5 -7
  182. package/packages/dd-trace/src/llmobs/util.js +0 -33
  183. package/packages/dd-trace/src/llmobs/writers/base.js +106 -53
  184. package/packages/dd-trace/src/log/index.js +7 -1
  185. package/packages/dd-trace/src/log-submission/log-submission-plugin.js +249 -0
  186. package/packages/dd-trace/src/noop/span.js +5 -0
  187. package/packages/dd-trace/src/openfeature/writers/base.js +14 -12
  188. package/packages/dd-trace/src/openfeature/writers/exposures.js +8 -1
  189. package/packages/dd-trace/src/openfeature/writers/util.js +1 -1
  190. package/packages/dd-trace/src/opentelemetry/logs/batch_log_processor.js +45 -3
  191. package/packages/dd-trace/src/opentelemetry/logs/index.js +9 -25
  192. package/packages/dd-trace/src/opentelemetry/logs/logger_provider.js +7 -4
  193. package/packages/dd-trace/src/opentelemetry/logs/otlp_http_log_exporter.js +14 -4
  194. package/packages/dd-trace/src/opentelemetry/metrics/index.js +18 -23
  195. package/packages/dd-trace/src/opentelemetry/metrics/meter_provider.js +8 -0
  196. package/packages/dd-trace/src/opentelemetry/metrics/otlp_http_metric_exporter.js +18 -6
  197. package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_exporter.js +14 -2
  198. package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +25 -5
  199. package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +61 -25
  200. package/packages/dd-trace/src/opentelemetry/otlp/otlp_transformer_base.js +19 -4
  201. package/packages/dd-trace/src/opentelemetry/resource-attributes.js +55 -0
  202. package/packages/dd-trace/src/opentelemetry/trace/index.js +6 -1
  203. package/packages/dd-trace/src/opentelemetry/trace/otlp_http_trace_exporter.js +10 -0
  204. package/packages/dd-trace/src/opentelemetry/tracer.js +26 -2
  205. package/packages/dd-trace/src/opentracing/propagation/text_map.js +494 -351
  206. package/packages/dd-trace/src/opentracing/span.js +28 -0
  207. package/packages/dd-trace/src/otel-thread-ctx.js +23 -5
  208. package/packages/dd-trace/src/payload-tagging/index.js +2 -1
  209. package/packages/dd-trace/src/plugin_manager.js +2 -0
  210. package/packages/dd-trace/src/plugins/ci_plugin.js +1 -6
  211. package/packages/dd-trace/src/plugins/tracing.js +12 -10
  212. package/packages/dd-trace/src/plugins/util/ci.js +3 -1
  213. package/packages/dd-trace/src/plugins/util/inferred_proxy.js +16 -15
  214. package/packages/dd-trace/src/plugins/util/status-validator.js +98 -0
  215. package/packages/dd-trace/src/plugins/util/test.js +157 -41
  216. package/packages/dd-trace/src/plugins/util/url.js +2 -2
  217. package/packages/dd-trace/src/plugins/util/web.js +6 -74
  218. package/packages/dd-trace/src/profiling/config.js +1 -0
  219. package/packages/dd-trace/src/profiling/oom.js +11 -5
  220. package/packages/dd-trace/src/profiling/profiler.js +30 -13
  221. package/packages/dd-trace/src/profiling/profilers/events.js +3 -3
  222. package/packages/dd-trace/src/profiling/profilers/space.js +38 -11
  223. package/packages/dd-trace/src/profiling/profilers/wall.js +14 -14
  224. package/packages/dd-trace/src/profiling/webspan-utils.js +7 -4
  225. package/packages/dd-trace/src/proxy.js +108 -10
  226. package/packages/dd-trace/src/remote_config/index.js +319 -101
  227. package/packages/dd-trace/src/remote_config/scheduler.js +37 -12
  228. package/packages/dd-trace/src/runtime_metrics/client.js +37 -8
  229. package/packages/dd-trace/src/runtime_metrics/index.js +5 -0
  230. package/packages/dd-trace/src/runtime_metrics/otlp_runtime_metrics.js +10 -1
  231. package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +22 -7
  232. package/packages/dd-trace/src/sampling_rule.js +36 -9
  233. package/packages/dd-trace/src/serverless/telemetry-delivery-tracker.js +51 -0
  234. package/packages/dd-trace/src/serverless/vercel.js +155 -0
  235. package/packages/dd-trace/src/serverless.js +45 -21
  236. package/packages/dd-trace/src/service-naming/schemas/util.js +1 -1
  237. package/packages/dd-trace/src/span_stats.js +64 -31
  238. package/packages/dd-trace/src/startup-log.js +3 -2
  239. package/packages/dd-trace/src/telemetry/agentless-url.js +28 -0
  240. package/packages/dd-trace/src/telemetry/send-data.js +18 -16
  241. package/packages/dd-trace/src/telemetry/session-propagation.js +3 -2
  242. package/packages/dd-trace/src/tracer.js +26 -5
  243. package/packages/dd-trace/src/tracer_metadata.js +11 -3
  244. package/packages/dd-trace/src/web-tags-cache.js +67 -13
  245. package/vendor/dist/@datadog/openfeature-node-server/index.js +1 -1
  246. package/vendor/dist/@datadog/sketches-js/index.js +1 -1
  247. package/vendor/dist/protobufjs/index.js +1 -1
  248. package/vendor/dist/protobufjs/minimal/index.js +1 -1
  249. package/packages/datadog-instrumentations/src/playwright-browser-scripts.js +0 -27
  250. package/packages/dd-trace/src/ci-visibility/log-submission/log-submission-plugin.js +0 -53
  251. package/packages/dd-trace/src/encode/agentless-json.js +0 -209
@@ -13,6 +13,7 @@ const { storage } = require('../../../../datadog-core')
13
13
  const legacyStorage = storage('legacy')
14
14
  const urlFilter = require('./urlfilter')
15
15
  const { createInferredProxySpan, finishInferredProxySpan } = require('./inferred_proxy')
16
+ const { getServerStatusValidator } = require('./status-validator')
16
17
  const { extractURL, obfuscateQs, getQsObfuscator, calculateHttpEndpoint } = require('./url')
17
18
  const { NETWORK_PEER_ADDRESS } = require('./http-otel-semantics')
18
19
 
@@ -34,12 +35,6 @@ const HTTP_CLIENT_IP = tags.HTTP_CLIENT_IP
34
35
  const MANUAL_DROP = tags.MANUAL_DROP
35
36
 
36
37
  const contexts = new WeakMap()
37
- const requests = new WeakMap()
38
- const statusCodeRangesPattern = /^[1-5]\d{2}(?:-[1-5]\d{2})?(?:,[1-5]\d{2}(?:-[1-5]\d{2})?)*$/
39
- const whitespacePattern = /\s/g
40
- const MAX_HTTP_STATUS_CODE = 599
41
-
42
- /** @typedef {(code: number) => boolean} StatusValidator */
43
38
 
44
39
  // TODO: change this to no longer rely on creating a dummy plugin to be able to access startSpan
45
40
  function createWebPlugin (tracer, config = {}) {
@@ -65,7 +60,7 @@ const web = {
65
60
  // Ensure the configuration has the correct structure and defaults.
66
61
  normalizeConfig (config) {
67
62
  const headers = getHeadersToRecord(config)
68
- const validateStatus = getStatusValidator(config)
63
+ const validateStatus = getServerStatusValidator(config)
69
64
  const hooks = getHooks(config)
70
65
  const filter = urlFilter.getFilter(config)
71
66
  const middleware = getMiddlewareSetting(config)
@@ -133,7 +128,6 @@ const web = {
133
128
  context.tracer = tracer
134
129
  context.span = span
135
130
  context.res = res
136
- requests.set(span, req)
137
131
 
138
132
  this.setConfig(req, config)
139
133
  addRequestTags(context, this.TYPE)
@@ -318,7 +312,6 @@ const web = {
318
312
  web.finishMiddleware(context)
319
313
 
320
314
  web.finishSpan(context, spanType)
321
- requests.delete(context.span)
322
315
 
323
316
  finishInferredProxySpan(context)
324
317
  },
@@ -348,9 +341,6 @@ const web = {
348
341
  getContext (req) {
349
342
  return contexts.get(req)
350
343
  },
351
- getRequest (span) {
352
- return requests.get(span)
353
- },
354
344
  setRouteOrEndpointTag (req) {
355
345
  const context = contexts.get(req)
356
346
 
@@ -515,9 +505,10 @@ function addResourceTag (context) {
515
505
 
516
506
  if (spanContext.getTag(RESOURCE_NAME)) return
517
507
 
518
- const resource = [req.method, spanContext.getTag(HTTP_ROUTE)]
519
- .filter(Boolean)
520
- .join(' ')
508
+ let resource = req.method
509
+ const route = spanContext.getTag(HTTP_ROUTE)
510
+
511
+ if (route) resource += ` ${route}`
521
512
 
522
513
  span.setTag(RESOURCE_NAME, resource)
523
514
  }
@@ -563,65 +554,6 @@ function getHeadersToRecord (config) {
563
554
  return []
564
555
  }
565
556
 
566
- function isNot500ErrorCode (code) {
567
- return code < 500
568
- }
569
-
570
- /**
571
- * @param {{ validateStatus?: unknown, DD_TRACE_HTTP_SERVER_ERROR_STATUSES?: unknown }} config
572
- * @returns {StatusValidator}
573
- */
574
- function getStatusValidator (config) {
575
- if (typeof config.validateStatus === 'function') {
576
- return /** @type {StatusValidator} */ (config.validateStatus)
577
- } else if (config.hasOwnProperty('validateStatus')) {
578
- log.error('Expected `validateStatus` to be a function.')
579
- }
580
-
581
- const { DD_TRACE_HTTP_SERVER_ERROR_STATUSES } = config
582
- if (DD_TRACE_HTTP_SERVER_ERROR_STATUSES === undefined) return isNot500ErrorCode
583
- if (typeof DD_TRACE_HTTP_SERVER_ERROR_STATUSES !== 'string') {
584
- log.error('Expected `DD_TRACE_HTTP_SERVER_ERROR_STATUSES` to be a string.')
585
- return isNot500ErrorCode
586
- }
587
- if (DD_TRACE_HTTP_SERVER_ERROR_STATUSES === '500-599') return isNot500ErrorCode
588
-
589
- const normalized = DD_TRACE_HTTP_SERVER_ERROR_STATUSES.replaceAll(whitespacePattern, '')
590
- if (normalized === '500-599') return isNot500ErrorCode
591
- if (!statusCodeRangesPattern.test(normalized)) {
592
- log.error(
593
- '`DD_TRACE_HTTP_SERVER_ERROR_STATUSES` must contain comma-separated status codes or ranges from 100 to 599.'
594
- )
595
- return isNot500ErrorCode
596
- }
597
-
598
- const errorStatusCodes = new Uint8Array(MAX_HTTP_STATUS_CODE + 1)
599
- const ranges = normalized.split(',')
600
- for (const range of ranges) {
601
- const separator = range.indexOf('-')
602
- if (separator === -1) {
603
- errorStatusCodes[Number(range)] = 1
604
- continue
605
- }
606
-
607
- const first = Number(range.slice(0, separator))
608
- const second = Number(range.slice(separator + 1))
609
- const start = Math.min(first, second)
610
- const end = Math.max(first, second)
611
- errorStatusCodes.fill(1, start, end + 1)
612
- }
613
-
614
- /**
615
- * @param {number} code
616
- * @returns {boolean}
617
- */
618
- function isValidStatusCode (code) {
619
- return errorStatusCodes[code] !== 1
620
- }
621
-
622
- return isValidStatusCode
623
- }
624
-
625
557
  const noop = () => {}
626
558
 
627
559
  function getHooks (config) {
@@ -222,4 +222,5 @@ function buildProfilingRuntime (config) {
222
222
 
223
223
  module.exports = {
224
224
  buildProfilingRuntime,
225
+ getProfilingTags,
225
226
  }
@@ -54,18 +54,24 @@ function strategiesToCallbackMode (strategies, callbackMode) {
54
54
  * @returns {string[]}
55
55
  */
56
56
  function buildExportCommand (exporters, tags) {
57
- const tagString = [...Object.entries(tags),
58
- ['snapshot', snapshotKinds.ON_OUT_OF_MEMORY]].map(([key, value]) => `${key}:${value}`).join(',')
59
- const urls = []
57
+ let tagString = ''
58
+ for (const [key, value] of Object.entries(tags)) {
59
+ if (tagString) tagString += ','
60
+ tagString += `${key}:${value}`
61
+ }
62
+ if (tagString) tagString += ','
63
+ tagString += `snapshot:${snapshotKinds.ON_OUT_OF_MEMORY}`
64
+ let urls = ''
60
65
  for (const exporter of exporters) {
61
66
  const url = exporter.getExportUrl()
62
67
  if (url !== undefined) {
63
- urls.push(url.toString())
68
+ if (urls) urls += ','
69
+ urls += url.toString()
64
70
  }
65
71
  }
66
72
  return [process.execPath,
67
73
  path.join(__dirname, 'exporter_cli.js'),
68
- urls.join(','), tagString, 'space']
74
+ urls, tagString, 'space']
69
75
  }
70
76
 
71
77
  module.exports = { oomExportStrategies, ensureOOMExportStrategies, strategiesToCallbackMode, buildExportCommand }
@@ -4,7 +4,7 @@ const { EventEmitter } = require('events')
4
4
  const dc = require('dc-polyfill')
5
5
  const crashtracker = require('../crashtracking')
6
6
  const log = require('../log')
7
- const { buildProfilingRuntime } = require('./config')
7
+ const { buildProfilingRuntime, getProfilingTags } = require('./config')
8
8
  const { snapshotKinds } = require('./constants')
9
9
  const { threadNamePrefix } = require('./profilers/shared')
10
10
  const { isWebServerSpan, endpointNameFromTags, getStartedSpans } = require('./webspan-utils')
@@ -54,6 +54,7 @@ class Profiler extends EventEmitter {
54
54
  #compressionFn
55
55
  #compressionFnInitialized = false
56
56
  #compressionOptions
57
+ #config
57
58
  #customLabelKeys = new Set()
58
59
  #enabled = false
59
60
  #endpointCounts = new Map()
@@ -64,7 +65,7 @@ class Profiler extends EventEmitter {
64
65
  #profilers
65
66
  #spanFinishListener
66
67
  #systemInfoReport
67
- #tags
68
+ #currentSnapshotTags
68
69
  #timer
69
70
  #uploadCompression
70
71
 
@@ -95,6 +96,10 @@ class Profiler extends EventEmitter {
95
96
  for (const key of keys) {
96
97
  this.#customLabelKeys.add(key)
97
98
  }
99
+ this.#applyCustomLabelKeys()
100
+ }
101
+
102
+ #applyCustomLabelKeys () {
98
103
  if (this.#profilers) {
99
104
  for (const profiler of this.#profilers) {
100
105
  profiler.setCustomLabelKeys?.(this.#customLabelKeys)
@@ -152,7 +157,7 @@ class Profiler extends EventEmitter {
152
157
  }
153
158
  }
154
159
  } else {
155
- const zstdCompress = require('@datadog/libdatadog').load('datadog-js-zstd').zstd_compress
160
+ const { zstd_compress: zstdCompress } = require('@datadog/libdatadog')
156
161
  const level = clevel ?? 0 // 0 is zstd default compression level
157
162
  this.#compressionFn = (buffer) => Promise.resolve(Buffer.from(zstdCompress(buffer, level)))
158
163
  }
@@ -172,14 +177,18 @@ class Profiler extends EventEmitter {
172
177
  if (this.enabled) return true
173
178
  this.#enabled = true
174
179
 
175
- const { tags, exporters, flushInterval, profilers, uploadCompression, systemInfoReport } =
180
+ const { tags: snapshotTags, exporters, flushInterval, profilers, uploadCompression, systemInfoReport } =
176
181
  buildProfilingRuntime(config)
177
- this.#tags = tags
182
+ this.#config = config
178
183
  this.#exporters = exporters
179
184
  this.#flushInterval = flushInterval
180
185
  this.#profilers = profilers
186
+ this.#currentSnapshotTags = snapshotTags
181
187
  this.#uploadCompression = uploadCompression
182
188
  this.#systemInfoReport = systemInfoReport
189
+ if (this.#customLabelKeys.size > 0) {
190
+ this.#applyCustomLabelKeys()
191
+ }
183
192
 
184
193
  this._setInterval()
185
194
  // Log errors if the source map finder fails, but don't prevent the rest
@@ -241,7 +250,7 @@ class Profiler extends EventEmitter {
241
250
  processInfo(infos, info, profileType)
242
251
  this.#submit({
243
252
  [profileType]: encodedProfile,
244
- }, infos, start, end, snapshotKinds.ON_OUT_OF_MEMORY)
253
+ }, infos, start, end, this.#currentSnapshotTags, snapshotKinds.ON_OUT_OF_MEMORY)
245
254
  }
246
255
 
247
256
  _setInterval () {
@@ -325,6 +334,7 @@ class Profiler extends EventEmitter {
325
334
 
326
335
  const startDate = this.#lastStart
327
336
  const endDate = new Date()
337
+ const snapshotTags = this.#currentSnapshotTags
328
338
  const profiles = []
329
339
 
330
340
  crashtracker.withProfilerSerializing(() => {
@@ -341,6 +351,7 @@ class Profiler extends EventEmitter {
341
351
  })
342
352
 
343
353
  if (restart) {
354
+ this.#currentSnapshotTags = getProfilingTags(this.#config)
344
355
  this._capture(this._timeoutInterval, endDate)
345
356
  }
346
357
 
@@ -378,7 +389,7 @@ class Profiler extends EventEmitter {
378
389
  }))
379
390
 
380
391
  if (hasEncoded) {
381
- await this.#submit(encodedProfiles, infos, startDate, endDate, snapshotKind)
392
+ await this.#submit(encodedProfiles, infos, startDate, endDate, snapshotTags, snapshotKind)
382
393
  profileSubmittedChannel.publish()
383
394
  log.debug('Submitted profiles')
384
395
  }
@@ -388,9 +399,15 @@ class Profiler extends EventEmitter {
388
399
  }
389
400
  }
390
401
 
391
- #submit (profiles, infos, start, end, snapshotKind) {
392
- const tags = this.#tags
393
-
402
+ /**
403
+ * @param {Record<string, Buffer|string>} profiles
404
+ * @param {Record<string, unknown>} infos
405
+ * @param {Date} start
406
+ * @param {Date} end
407
+ * @param {Record<string, string|number|boolean|undefined>} snapshotTags
408
+ * @param {string} snapshotKind
409
+ */
410
+ #submit (profiles, infos, start, end, snapshotTags, snapshotKind) {
394
411
  // Flatten endpoint counts
395
412
  const endpointCounts = {}
396
413
  for (const [endpoint, { count }] of this.#endpointCounts) {
@@ -398,12 +415,12 @@ class Profiler extends EventEmitter {
398
415
  }
399
416
  this.#endpointCounts.clear()
400
417
 
401
- tags.snapshot = snapshotKind
402
- tags.profile_seq = this.#profileSeq++
418
+ snapshotTags.snapshot = snapshotKind
419
+ snapshotTags.profile_seq = this.#profileSeq++
403
420
  const customAttributes = this.#customLabelKeys.size > 0
404
421
  ? [...this.#customLabelKeys]
405
422
  : undefined
406
- const exportSpec = { profiles, infos, start, end, tags, endpointCounts, customAttributes }
423
+ const exportSpec = { profiles, infos, start, end, tags: snapshotTags, endpointCounts, customAttributes }
407
424
  const tasks = this.#exporters.map(exporter =>
408
425
  exporter.export(exportSpec).catch(error => {
409
426
  log.warn(error)
@@ -124,13 +124,13 @@ class GCDecorator {
124
124
  }
125
125
  let reasonLabel = this.reasonLabels[flags]
126
126
  if (!reasonLabel) {
127
- const reasons = []
127
+ let reasonStr = ''
128
128
  for (const [key, value] of Object.entries(this.flagObj)) {
129
129
  if (value & flags) {
130
- reasons.push(key)
130
+ if (reasonStr) reasonStr += ','
131
+ reasonStr += key
131
132
  }
132
133
  }
133
- const reasonStr = reasons.join(',')
134
134
  reasonLabel = labelFromStr(this.stringTable, this.reasonLabelKey, reasonStr)
135
135
  this.reasonLabels[flags] = reasonLabel
136
136
  }
@@ -1,5 +1,8 @@
1
1
  'use strict'
2
2
 
3
+ const { channel } = require('dc-polyfill')
4
+
5
+ const log = require('../../log')
3
6
  const { oomExportStrategies, ensureOOMExportStrategies, strategiesToCallbackMode, buildExportCommand } =
4
7
  require('../oom')
5
8
  const { encodeProfileAsync, getThreadLabels } = require('./shared')
@@ -11,10 +14,12 @@ const { encodeProfileAsync, getThreadLabels } = require('./shared')
11
14
  */
12
15
 
13
16
  const STACK_DEPTH = 64
17
+ const identityRefreshChannel = channel('datadog:identity:refresh')
14
18
 
15
19
  class NativeSpaceProfiler {
16
20
  #config
17
21
  #exporters
22
+ #identityRefreshListener
18
23
  #mapper
19
24
  #pprof
20
25
  #samplingInterval
@@ -39,20 +44,36 @@ class NativeSpaceProfiler {
39
44
  start ({ mapper, nearOOMCallback } = {}) {
40
45
  if (this.#started) return
41
46
 
42
- const config = this.#config
43
47
  this.#mapper = mapper
44
48
  this.#pprof = require('@datadog/pprof')
45
- this.#pprof.heap.start(this.#samplingInterval, STACK_DEPTH, config.DD_PROFILING_ALLOCATION_ENABLED)
46
- if (config.DD_PROFILING_EXPERIMENTAL_OOM_MONITORING_ENABLED) {
49
+ this.#pprof.heap.start(this.#samplingInterval, STACK_DEPTH, this.#config.DD_PROFILING_ALLOCATION_ENABLED)
50
+
51
+ if (this.#config.DD_PROFILING_EXPERIMENTAL_OOM_MONITORING_ENABLED) {
52
+ const config = this.#config
47
53
  const strategies = ensureOOMExportStrategies(config.DD_PROFILING_EXPERIMENTAL_OOM_EXPORT_STRATEGIES)
48
- this.#pprof.heap.monitorOutOfMemory(
49
- config.DD_PROFILING_EXPERIMENTAL_OOM_HEAP_LIMIT_EXTENSION_SIZE,
50
- config.DD_PROFILING_EXPERIMENTAL_OOM_MAX_HEAP_EXTENSION_COUNT,
51
- strategies.includes(oomExportStrategies.LOGS),
52
- strategies.includes(oomExportStrategies.PROCESS) ? buildExportCommand(this.#exporters, this.#tags) : [],
53
- (profile) => nearOOMCallback(this.type, this.#pprof.encodeSync(profile), this.getInfo()),
54
- strategiesToCallbackMode(strategies, this.#pprof.heap.CallbackMode)
55
- )
54
+ const monitorOutOfMemory = () => {
55
+ this.#pprof.heap.monitorOutOfMemory(
56
+ config.DD_PROFILING_EXPERIMENTAL_OOM_HEAP_LIMIT_EXTENSION_SIZE,
57
+ config.DD_PROFILING_EXPERIMENTAL_OOM_MAX_HEAP_EXTENSION_COUNT,
58
+ strategies.includes(oomExportStrategies.LOGS),
59
+ strategies.includes(oomExportStrategies.PROCESS) ? buildExportCommand(this.#exporters, this.#tags) : [],
60
+ (profile) => nearOOMCallback(this.type, this.#pprof.encodeSync(profile), this.getInfo()),
61
+ strategiesToCallbackMode(strategies, this.#pprof.heap.CallbackMode)
62
+ )
63
+ }
64
+ monitorOutOfMemory()
65
+
66
+ if (strategies.includes(oomExportStrategies.PROCESS)) {
67
+ this.#identityRefreshListener = () => {
68
+ try {
69
+ Object.assign(this.#tags, config.tags)
70
+ monitorOutOfMemory()
71
+ } catch (error) {
72
+ log.error(error)
73
+ }
74
+ }
75
+ identityRefreshChannel.subscribe(this.#identityRefreshListener)
76
+ }
56
77
  }
57
78
 
58
79
  this.#started = true
@@ -74,6 +95,12 @@ class NativeSpaceProfiler {
74
95
 
75
96
  stop () {
76
97
  if (!this.#started) return
98
+
99
+ if (this.#identityRefreshListener !== undefined) {
100
+ identityRefreshChannel.unsubscribe(this.#identityRefreshListener)
101
+ this.#identityRefreshListener = undefined
102
+ }
103
+
77
104
  this.#pprof.heap.stop()
78
105
  this.#started = false
79
106
  }
@@ -138,7 +138,7 @@ class NativeWallProfiler {
138
138
 
139
139
  this.#pprof.time.start({
140
140
  collectCpuTime: this.#cpuProfilingEnabled,
141
- columnNumbers: 'pack',
141
+ columnNumbers: 'emit',
142
142
  durationMillis: this.#flushIntervalMillis,
143
143
  intervalMicros: this.#samplingIntervalMicros,
144
144
  lineNumbers: false,
@@ -168,8 +168,8 @@ class NativeWallProfiler {
168
168
  spanFinishCh.subscribe(this.#boundSpanFinished)
169
169
  if (this.#endpointCollectionEnabled) {
170
170
  // Web-tags cache publishes once per span at the moment its
171
- // walk-result transitions from undefined to a real value
172
- // exactly when we need to refresh the ProfilingContext snapshot.
171
+ // walk-result changes exactly when we need to refresh the
172
+ // ProfilingContext snapshot.
173
173
  webTagsCache.resolvedCh.subscribe(this.#boundSpanTagsUpdated)
174
174
  // Turn on the cache's own tagsUpdate subscription — it's
175
175
  // ref-counted, so this composes with any other active consumer.
@@ -229,13 +229,12 @@ class NativeWallProfiler {
229
229
  } else if (current !== sampleContext) {
230
230
  this.#pprof.time.setContext(sampleContext)
231
231
  }
232
- // Every setContext() call in ACF mode allocates a fresh contextHolder
233
- // (a node::ObjectWrap with its own v8::Global<v8::Value>) in the native
234
- // profiler. Skip the call if the CPED already holds this sampleContext,
235
- // which is the common case when the same span is repeatedly activated:
236
- // #getProfilingContext caches profilingContext on span[ProfilingContext],
237
- // so identity comparison short-circuits.
238
232
  } else if (current !== sampleContext) {
233
+ // Every setContext() call in ACF mode allocates a fresh contextHolder
234
+ // (a node::ObjectWrap with its own v8::Global<v8::Value>) in the native
235
+ // profiler. We're only incurring the cost when current !== sampleContext
236
+ // and skip it when current === sampleContext, which is the common case
237
+ // when the same span is repeatedly activated.
239
238
  this.#pprof.time.setContext(sampleContext)
240
239
  }
241
240
  } else {
@@ -266,8 +265,8 @@ class NativeWallProfiler {
266
265
  }
267
266
 
268
267
  // webTags is snapshotted into the sample context at getProfilingContext
269
- // time; if the answer turns out to be undefined and the span later gets
270
- // web-server tags, #spanTagsUpdated refreshes this field via the shared
268
+ // time; if the answer changes later the span or an ancestor becomes a
269
+ // web-server span #spanTagsUpdated refreshes this field via the shared
271
270
  // cache (see web-tags-cache.js).
272
271
  const webTags = this.#endpointCollectionEnabled ? webTagsCache.getCachedWebTags(span) : undefined
273
272
 
@@ -291,9 +290,10 @@ class NativeWallProfiler {
291
290
  }
292
291
 
293
292
  // Invoked (via webTagsCache.resolvedCh) once per span at the moment the
294
- // shared cache promotes a previously-undefined webTags answer into a
295
- // real value. Refresh the ProfilingContext snapshot so future samples
296
- // pick it up.
293
+ // shared cache changes its webTags answer: an empty one promoted into a real
294
+ // value, or an outer request's tag bag replaced by a nearer one. Refresh the
295
+ // ProfilingContext snapshot in place so samples already holding it — including
296
+ // those of a span that stays active across the promotion — pick it up.
297
297
  #spanTagsUpdated (span) {
298
298
  if (!this.#started) return
299
299
  const profilingContext = span[ProfilingContext]
@@ -8,10 +8,13 @@ function isWebServerSpan (tags) {
8
8
  }
9
9
 
10
10
  function endpointNameFromTags (tags) {
11
- return tags[RESOURCE_NAME] || [
12
- tags[HTTP_METHOD],
13
- tags[HTTP_ROUTE],
14
- ].filter(Boolean).join(' ')
11
+ const resource = tags[RESOURCE_NAME]
12
+ if (resource) return resource
13
+
14
+ let endpoint = tags[HTTP_METHOD] || ''
15
+ const route = tags[HTTP_ROUTE]
16
+ if (route) endpoint += endpoint ? ` ${route}` : route
17
+ return endpoint
15
18
  }
16
19
 
17
20
  // The endpoint name a web-server span's tag bag yields changes over the span's