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
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const os = require('os')
3
+ const { buildResourceAttributes, registerResourceAttributeRefresh } = require('../resource-attributes')
4
4
 
5
5
  /**
6
6
  * @typedef {import('../../config')} Config
@@ -27,6 +27,7 @@ const os = require('os')
27
27
  * @package
28
28
  */
29
29
 
30
+ const { registerTelemetryFlusher } = require('../../flush')
30
31
  const LoggerProvider = require('./logger_provider')
31
32
  const BatchLogRecordProcessor = require('./batch_log_processor')
32
33
  const OtlpHttpLogExporter = require('./otlp_http_log_exporter')
@@ -36,35 +37,13 @@ const OtlpHttpLogExporter = require('./otlp_http_log_exporter')
36
37
  * @param {import('../../config/config-base')} config - Tracer configuration instance
37
38
  */
38
39
  function initializeOpenTelemetryLogs (config) {
39
- // Build resource attributes
40
- const resourceAttributes = {
41
- 'service.name': config.service,
42
- 'service.version': config.version,
43
- 'deployment.environment': config.env,
44
- }
45
-
46
- // Add all tracer tags (includes DD_TAGS, OTEL_RESOURCE_ATTRIBUTES, DD_TRACE_TAGS, etc.)
47
- // Exclude Datadog-style keys that duplicate OpenTelemetry standard keys
48
- if (config.tags) {
49
- const filteredTags = { ...config.tags }
50
- delete filteredTags.service
51
- delete filteredTags.version
52
- delete filteredTags.env
53
- Object.assign(resourceAttributes, filteredTags)
54
- }
55
-
56
- // Add host.name if reportHostname is enabled
57
- if (config.reportHostname) {
58
- resourceAttributes['host.name'] = os.hostname()
59
- }
60
-
61
40
  // Create OTLP exporter using resolved config values
62
41
  const exporter = new OtlpHttpLogExporter(
63
42
  config.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT,
64
43
  config.OTEL_EXPORTER_OTLP_LOGS_HEADERS,
65
44
  config.OTEL_EXPORTER_OTLP_LOGS_TIMEOUT,
66
45
  config.OTEL_EXPORTER_OTLP_LOGS_PROTOCOL,
67
- resourceAttributes
46
+ buildResourceAttributes(config)
68
47
  )
69
48
 
70
49
  // Create batch processor for exporting logs to Datadog Agent
@@ -77,8 +56,13 @@ function initializeOpenTelemetryLogs (config) {
77
56
  // Create logger provider with processor for Datadog Agent export
78
57
  const loggerProvider = new LoggerProvider({ processor })
79
58
 
80
- // Register the logger provider globally with OpenTelemetry API
59
+ // Expose this provider to application calls through the OpenTelemetry Logs API.
81
60
  loggerProvider.register()
61
+
62
+ // Include final log batches in lifecycle retention with trace delivery.
63
+ registerTelemetryFlusher(done => loggerProvider.forceFlush(done))
64
+
65
+ registerResourceAttributeRefresh(exporter, () => buildResourceAttributes(config))
82
66
  }
83
67
 
84
68
  module.exports = {
@@ -84,12 +84,15 @@ class LoggerProvider {
84
84
 
85
85
  /**
86
86
  * Forces a flush of all pending log records.
87
- * @returns {undefined} Promise that resolves when flush is n ssue cncomplete
87
+ * @param {Function} [done] Called after all pending log exports complete
88
88
  */
89
- forceFlush () {
90
- if (!this.isShutdown) {
91
- return this.processor?.forceFlush()
89
+ forceFlush (done) {
90
+ if (this.isShutdown || !this.processor) {
91
+ done?.()
92
+ return
92
93
  }
94
+
95
+ this.processor.forceFlush(done)
93
96
  }
94
97
 
95
98
  /**
@@ -4,7 +4,7 @@ const OtlpHttpExporterBase = require('../otlp/otlp_http_exporter_base')
4
4
  const OtlpTransformer = require('./otlp_transformer')
5
5
 
6
6
  /**
7
- * @typedef {import('@opentelemetry/resources').Resource} Resource
7
+ * @typedef {import('@opentelemetry/api').Attributes} Attributes
8
8
  * @typedef {import('@opentelemetry/api-logs').LogRecord} LogRecord
9
9
  */
10
10
 
@@ -26,11 +26,21 @@ class OtlpHttpLogExporter extends OtlpHttpExporterBase {
26
26
  * corresponding `OTEL_EXPORTER_OTLP_*_HEADERS` env by the MAP parser.
27
27
  * @param {number} timeout - Request timeout in milliseconds
28
28
  * @param {string} protocol - OTLP protocol (http/protobuf or http/json)
29
- * @param {Resource} resource - Resource attributes
29
+ * @param {Attributes} resourceAttributes - Resource attributes
30
30
  */
31
- constructor (url, headers, timeout, protocol, resource) {
31
+ constructor (url, headers, timeout, protocol, resourceAttributes) {
32
32
  super(url, headers, timeout, protocol, 'logs')
33
- this.transformer = new OtlpTransformer(resource, protocol)
33
+ this.transformer = new OtlpTransformer(resourceAttributes, protocol)
34
+ }
35
+
36
+ /**
37
+ * Recomputes the resource attributes baked into the transformer (e.g. after a MicroVM clone
38
+ * resume regenerates `runtime-id`).
39
+ *
40
+ * @param {Attributes} resourceAttributes - Resource attributes
41
+ */
42
+ updateResourceAttributes (resourceAttributes) {
43
+ this.transformer.updateResourceAttributes(resourceAttributes)
34
44
  }
35
45
 
36
46
  /**
@@ -6,12 +6,16 @@ const { metrics } = require('@opentelemetry/api')
6
6
 
7
7
  const { VERSION } = require('../../../../../version')
8
8
  const processTags = require('../../process-tags')
9
+ const { registerTelemetryFlusher } = require('../../flush')
10
+ const {
11
+ buildResourceAttributes: buildGeneralResourceAttributes,
12
+ registerResourceAttributeRefresh,
13
+ } = require('../resource-attributes')
9
14
  const MeterProvider = require('./meter_provider')
10
15
  const PeriodicMetricReader = require('./periodic_metric_reader')
11
16
  const OtlpHttpMetricExporter = require('./otlp_http_metric_exporter')
12
17
 
13
18
  const RESERVED_TRACER_TAGS = new Set(['service', 'env', 'version', 'runtime_id', 'runtime-id'])
14
-
15
19
  /**
16
20
  * @typedef {import('../../config')} Config
17
21
  */
@@ -43,30 +47,12 @@ const RESERVED_TRACER_TAGS = new Set(['service', 'env', 'version', 'runtime_id',
43
47
  * @param {import('../../config/config-base')} config - Tracer configuration instance
44
48
  */
45
49
  function initializeOpenTelemetryMetrics (config) {
46
- const resourceAttributes = {
47
- 'service.name': config.service,
48
- 'service.version': config.version,
49
- 'deployment.environment': config.env,
50
- }
51
-
52
- if (config.tags) {
53
- const filteredTags = { ...config.tags }
54
- delete filteredTags.service
55
- delete filteredTags.version
56
- delete filteredTags.env
57
- Object.assign(resourceAttributes, filteredTags)
58
- }
59
-
60
- if (config.reportHostname) {
61
- resourceAttributes['host.name'] = os.hostname()
62
- }
63
-
64
50
  const exporter = new OtlpHttpMetricExporter(
65
51
  config.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT,
66
52
  config.OTEL_EXPORTER_OTLP_METRICS_HEADERS,
67
53
  config.OTEL_EXPORTER_OTLP_METRICS_TIMEOUT,
68
54
  config.OTEL_EXPORTER_OTLP_METRICS_PROTOCOL,
69
- resourceAttributes
55
+ buildGeneralResourceAttributes(config)
70
56
  )
71
57
 
72
58
  const reader = new PeriodicMetricReader(
@@ -78,6 +64,11 @@ function initializeOpenTelemetryMetrics (config) {
78
64
 
79
65
  const meterProvider = new MeterProvider({ reader })
80
66
  metrics.setGlobalMeterProvider(meterProvider)
67
+
68
+ // Include the final metric collection and export in lifecycle retention.
69
+ registerTelemetryFlusher(done => meterProvider.forceFlush(done))
70
+
71
+ registerResourceAttributeRefresh(exporter, () => buildGeneralResourceAttributes(config))
81
72
  }
82
73
 
83
74
  /**
@@ -120,19 +111,23 @@ function buildResourceAttributes (tags, { reportHostname, service, env, serviceV
120
111
  function createOtlpSpanStatsExporter (config) {
121
112
  const { OtlpStatsExporter } = require('./otlp_span_stats_exporter')
122
113
  const protocol = config.OTEL_EXPORTER_OTLP_METRICS_PROTOCOL || 'http/json'
123
- const resourceAttributes = buildResourceAttributes(config.tags, {
114
+ const buildSpanStatsResourceAttributes = () => buildResourceAttributes(config.tags, {
124
115
  reportHostname: config.reportHostname,
125
116
  service: config.service,
126
117
  env: config.env,
127
118
  serviceVersion: config.version,
128
119
  })
129
- return new OtlpStatsExporter(
120
+ const exporter = new OtlpStatsExporter(
130
121
  config.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT,
131
122
  protocol,
132
- resourceAttributes,
123
+ buildSpanStatsResourceAttributes(),
133
124
  config.OTEL_EXPORTER_OTLP_METRICS_HEADERS,
134
125
  config.OTEL_EXPORTER_OTLP_METRICS_TIMEOUT
135
126
  )
127
+
128
+ registerResourceAttributeRefresh(exporter, buildSpanStatsResourceAttributes)
129
+
130
+ return exporter
136
131
  }
137
132
 
138
133
  module.exports = {
@@ -49,6 +49,14 @@ class MeterProvider {
49
49
  }
50
50
  return meter
51
51
  }
52
+
53
+ /**
54
+ * @param {Function} [done] Called after the metric export completes
55
+ */
56
+ forceFlush (done) {
57
+ if (this.reader) this.reader.forceFlush(done)
58
+ else done?.()
59
+ }
52
60
  }
53
61
 
54
62
  module.exports = MeterProvider
@@ -4,7 +4,7 @@ const OtlpHttpExporterBase = require('../otlp/otlp_http_exporter_base')
4
4
  const OtlpTransformer = require('./otlp_transformer')
5
5
 
6
6
  /**
7
- * @typedef {import('@opentelemetry/resources').Resource} Resource
7
+ * @typedef {import('@opentelemetry/api').Attributes} Attributes
8
8
  * @typedef {import('./periodic_metric_reader').AggregatedMetric} AggregatedMetric
9
9
  */
10
10
 
@@ -22,11 +22,21 @@ class OtlpHttpMetricExporter extends OtlpHttpExporterBase {
22
22
  * corresponding `OTEL_EXPORTER_OTLP_*_HEADERS` env by the MAP parser.
23
23
  * @param {number} timeout - Request timeout in milliseconds
24
24
  * @param {string} protocol - OTLP protocol (http/protobuf or http/json)
25
- * @param {Resource} resource - Resource attributes
25
+ * @param {Attributes} resourceAttributes - Resource attributes
26
26
  */
27
- constructor (url, headers, timeout, protocol, resource) {
27
+ constructor (url, headers, timeout, protocol, resourceAttributes) {
28
28
  super(url, headers, timeout, protocol, 'metrics')
29
- this.transformer = new OtlpTransformer(resource, protocol)
29
+ this.transformer = new OtlpTransformer(resourceAttributes, protocol)
30
+ }
31
+
32
+ /**
33
+ * Recomputes the resource attributes baked into the transformer (e.g. after a MicroVM clone
34
+ * resume regenerates `runtime-id`). Leaves the reader's export interval untouched.
35
+ *
36
+ * @param {Attributes} resourceAttributes - Resource attributes
37
+ */
38
+ updateResourceAttributes (resourceAttributes) {
39
+ this.transformer.updateResourceAttributes(resourceAttributes)
30
40
  }
31
41
 
32
42
  /**
@@ -34,10 +44,11 @@ class OtlpHttpMetricExporter extends OtlpHttpExporterBase {
34
44
  *
35
45
  * @param {Map<string, AggregatedMetric>} metrics - Map of metric data to export
36
46
  *
37
- * @returns {void}
47
+ * @param {Function} [done] Called after the HTTP export completes
38
48
  */
39
- export (metrics) {
49
+ export (metrics, done) {
40
50
  if (metrics.size === 0) {
51
+ done?.({ code: 0 })
41
52
  return
42
53
  }
43
54
 
@@ -56,6 +67,7 @@ class OtlpHttpMetricExporter extends OtlpHttpExporterBase {
56
67
  if (result.code === 0) {
57
68
  this.recordTelemetry('otel.metrics_export_successes', 1, additionalTags)
58
69
  }
70
+ done?.(result)
59
71
  })
60
72
  }
61
73
  }
@@ -19,17 +19,29 @@ class OtlpStatsExporter extends OtlpHttpExporterBase {
19
19
  this.#transformer = new OtlpStatsTransformer(resourceAttributes, protocol)
20
20
  }
21
21
 
22
+ /**
23
+ * Recomputes the resource attributes baked into the transformer (e.g. after a MicroVM clone
24
+ * resume regenerates `runtime-id`).
25
+ *
26
+ * @param {import('@opentelemetry/api').Attributes} resourceAttributes
27
+ */
28
+ updateResourceAttributes (resourceAttributes) {
29
+ this.#transformer.updateResourceAttributes(resourceAttributes)
30
+ }
31
+
22
32
  /**
23
33
  * @param {Array<{timeNs: number, bucket: import('../../span_stats').SpanBuckets}>} drained
24
34
  * @param {number} bucketSizeNs
35
+ * @param {Function} [done] Called after the HTTP export completes
25
36
  */
26
- export (drained, bucketSizeNs) {
27
- if (drained.length === 0) return
37
+ export (drained, bucketSizeNs, done) {
38
+ if (drained.length === 0) return done?.()
28
39
  const payload = this.#transformer.transform(drained, bucketSizeNs)
29
40
  this.sendPayload(payload, (result) => {
30
41
  if (result.code !== 0) {
31
42
  log.error('Failed to export span stats: %s', result.error?.message)
32
43
  }
44
+ done?.()
33
45
  })
34
46
  }
35
47
  }
@@ -197,14 +197,33 @@ class PeriodicMetricReader {
197
197
 
198
198
  /**
199
199
  * Forces an immediate collection and export of all metrics.
200
- * @returns {void}
200
+ * @param {Function} [done] Called after the metric export completes
201
201
  */
202
- forceFlush () {
202
+ forceFlush (done) {
203
203
  if (this.#isShutdown) {
204
204
  log.warn('PeriodicMetricReader is shutdown. %d measurement(s) were dropped', this.#droppedCount)
205
+ done?.()
205
206
  return
206
207
  }
207
- this.#collectAndExport()
208
+ let pending = 2
209
+ const complete = () => {
210
+ if (--pending === 0) done?.()
211
+ }
212
+
213
+ // Snapshot requests already active before starting this flush's export.
214
+ try {
215
+ if (typeof this.exporter.flush === 'function') this.exporter.flush(complete)
216
+ else complete()
217
+ } catch (error) {
218
+ log.error('Error flushing OTLP metrics:', error)
219
+ complete()
220
+ }
221
+ try {
222
+ this.#collectAndExport(complete)
223
+ } catch (error) {
224
+ log.error('Error exporting OTLP metrics:', error)
225
+ complete()
226
+ }
208
227
  }
209
228
 
210
229
  /**
@@ -250,7 +269,8 @@ class PeriodicMetricReader {
250
269
  *
251
270
  * @param {Function} [callback] - Called after export completes
252
271
  */
253
- #collectAndExport (callback = () => {}) {
272
+ #collectAndExport (callback) {
273
+ // Observable instruments must be collected even without synchronous measurements.
254
274
  // Atomically drain measurements for export. New measurements can be recorded
255
275
  // during export without interfering with this batch.
256
276
  const allMeasurements = this.#measurements
@@ -292,7 +312,7 @@ class PeriodicMetricReader {
292
312
  }
293
313
 
294
314
  if (allMeasurements.length === 0) {
295
- callback()
315
+ callback?.()
296
316
  return
297
317
  }
298
318
 
@@ -5,6 +5,7 @@ const https = require('node:https')
5
5
  const { URL } = require('node:url')
6
6
  const { storage } = require('../../../../datadog-core')
7
7
  const log = require('../../log')
8
+ const { createServerlessDeliveryTracker } = require('../../serverless')
8
9
  const telemetryMetrics = require('../../telemetry/metrics')
9
10
 
10
11
  const tracerMetrics = telemetryMetrics.manager.namespace('tracers')
@@ -20,6 +21,7 @@ const legacyStorage = storage('legacy')
20
21
  */
21
22
  class OtlpHttpExporterBase {
22
23
  #transport = https
24
+ #serverlessDeliveryTracker
23
25
 
24
26
  /**
25
27
  * Creates a new OtlpHttpExporterBase instance.
@@ -32,6 +34,7 @@ class OtlpHttpExporterBase {
32
34
  * @param {string} signalType - Signal type for error messages (e.g., 'logs', 'metrics')
33
35
  */
34
36
  constructor (url, headers, timeout, protocol, signalType) {
37
+ this.#serverlessDeliveryTracker = createServerlessDeliveryTracker()
35
38
  this.protocol = protocol
36
39
  this.signalType = signalType
37
40
 
@@ -80,6 +83,13 @@ class OtlpHttpExporterBase {
80
83
  * @protected
81
84
  */
82
85
  sendPayload (payload, resultCallback) {
86
+ if (this.#serverlessDeliveryTracker) {
87
+ return this.#serverlessDeliveryTracker.track(done => this.#sendPayload(payload, resultCallback, done))
88
+ }
89
+ this.#sendPayload(payload, resultCallback)
90
+ }
91
+
92
+ #sendPayload (payload, resultCallback, done) {
83
93
  const options = {
84
94
  ...this.options,
85
95
  headers: {
@@ -88,39 +98,65 @@ class OtlpHttpExporterBase {
88
98
  },
89
99
  }
90
100
 
91
- legacyStorage.run({ noop: true }, () => {
92
- const req = this.#transport.request(options, (res) => {
93
- let data = ''
101
+ let completed = false
102
+ const complete = result => {
103
+ if (completed) return
104
+ completed = true
105
+ resultCallback(result)
106
+ done?.()
107
+ }
94
108
 
95
- res.on('data', (chunk) => {
96
- data += chunk
109
+ try {
110
+ legacyStorage.run({ noop: true }, () => {
111
+ const req = this.#transport.request(options, (res) => {
112
+ let data = ''
113
+
114
+ res.on('data', (chunk) => {
115
+ data += chunk
116
+ })
117
+
118
+ res.once('error', (error) => {
119
+ complete({ code: 1, error })
120
+ })
121
+
122
+ res.once('end', () => {
123
+ // @ts-expect-error - res.statusCode can be undefined
124
+ if (res.statusCode >= 200 && res.statusCode < 300) {
125
+ complete({ code: 0 })
126
+ } else {
127
+ const error = new Error(`HTTP ${res.statusCode}: ${data}`)
128
+ complete({ code: 1, error })
129
+ }
130
+ })
97
131
  })
98
132
 
99
- res.once('end', () => {
100
- // @ts-expect-error - res.statusCode can be undefined
101
- if (res.statusCode >= 200 && res.statusCode < 300) {
102
- resultCallback({ code: 0 })
103
- } else {
104
- const error = new Error(`HTTP ${res.statusCode}: ${data}`)
105
- resultCallback({ code: 1, error })
106
- }
133
+ req.on('error', (error) => {
134
+ log.error('Error sending OTLP %s:', this.signalType, error)
135
+ complete({ code: 1, error })
107
136
  })
108
- })
109
137
 
110
- req.on('error', (error) => {
111
- log.error('Error sending OTLP %s:', this.signalType, error)
112
- resultCallback({ code: 1, error })
113
- })
138
+ req.once('timeout', () => {
139
+ req.destroy()
140
+ const error = new Error('Request timeout')
141
+ complete({ code: 1, error })
142
+ })
114
143
 
115
- req.once('timeout', () => {
116
- req.destroy()
117
- const error = new Error('Request timeout')
118
- resultCallback({ code: 1, error })
144
+ req.write(payload)
145
+ req.end()
119
146
  })
147
+ } catch (error) {
148
+ log.error('Error sending OTLP %s:', this.signalType, error)
149
+ complete({ code: 1, error })
150
+ }
151
+ }
120
152
 
121
- req.write(payload)
122
- req.end()
123
- })
153
+ /**
154
+ * Calls back once Vercel-tracked requests active at the flush boundary complete.
155
+ * @param {Function} [done]
156
+ */
157
+ flush (done) {
158
+ if (this.#serverlessDeliveryTracker) return this.#serverlessDeliveryTracker.waitForIdle(done)
159
+ done?.()
124
160
  }
125
161
 
126
162
  /**
@@ -75,6 +75,16 @@ class OtlpTransformerBase {
75
75
  }
76
76
  }
77
77
 
78
+ /**
79
+ * Recomputes the cached OTLP resource attributes (e.g. after `config.tags` changes post-
80
+ * construction, such as a MicroVM clone resume regenerating its runtime-id). Leaves the
81
+ * reader/exporter/protocol otherwise untouched.
82
+ * @param {Attributes} resourceAttributes - Resource attributes
83
+ */
84
+ updateResourceAttributes (resourceAttributes) {
85
+ this.#resourceAttributes = this.transformAttributes(resourceAttributes)
86
+ }
87
+
78
88
  /**
79
89
  * Transforms attributes to OTLP KeyValue format.
80
90
  * @param {Attributes} attributes - Attributes to transform
@@ -170,10 +180,15 @@ function stableStringify (attributes) {
170
180
  // Attributes are sorted by key to ensure consistent serialization regardless of key order.
171
181
  // Keys are always strings and values are always strings, numbers, booleans,
172
182
  // or arrays of strings, numbers, or booleans.
173
- return Object.keys(attributes)
174
- .sort()
175
- .map(key => `${key}:${JSON.stringify(attributes[key])}`)
176
- .join(',')
183
+ const keys = Object.keys(attributes).sort()
184
+ let serialized = ''
185
+ let isFirstKey = true
186
+ for (const key of keys) {
187
+ if (!isFirstKey) serialized += ','
188
+ serialized += `${key}:${JSON.stringify(attributes[key])}`
189
+ isFirstKey = false
190
+ }
191
+ return serialized
177
192
  }
178
193
 
179
194
  module.exports = OtlpTransformerBase
@@ -0,0 +1,55 @@
1
+ 'use strict'
2
+
3
+ const os = require('node:os')
4
+
5
+ const { channel } = require('dc-polyfill')
6
+
7
+ const identityRefreshChannel = channel('datadog:identity:refresh')
8
+ const resourceAttributeRefreshers = new Map()
9
+
10
+ function refreshActiveResourceAttributes () {
11
+ for (const refreshResourceAttributes of resourceAttributeRefreshers.values()) {
12
+ refreshResourceAttributes()
13
+ }
14
+ }
15
+
16
+ /**
17
+ * @typedef {import('@opentelemetry/api').Attributes} Attributes
18
+ * @typedef {{
19
+ * signalType: string,
20
+ * updateResourceAttributes: (resourceAttributes: Attributes) => void
21
+ * }} ResourceAttributeExporter
22
+ */
23
+
24
+ /**
25
+ * @param {import('../config/config-base')} config
26
+ * @returns {Attributes}
27
+ */
28
+ function buildResourceAttributes (config) {
29
+ const { service, version, env, ...tags } = config.tags
30
+ const resourceAttributes = {
31
+ 'service.name': config.service,
32
+ 'service.version': config.version,
33
+ 'deployment.environment': config.env,
34
+ ...tags,
35
+ }
36
+
37
+ if (config.reportHostname) resourceAttributes['host.name'] = os.hostname()
38
+
39
+ return resourceAttributes
40
+ }
41
+
42
+ /**
43
+ * @param {ResourceAttributeExporter} exporter
44
+ * @param {() => Attributes} buildResourceAttributes
45
+ */
46
+ function registerResourceAttributeRefresh (exporter, buildResourceAttributes) {
47
+ if (resourceAttributeRefreshers.size === 0) {
48
+ identityRefreshChannel.subscribe(refreshActiveResourceAttributes)
49
+ }
50
+ resourceAttributeRefreshers.set(exporter.signalType, () => {
51
+ exporter.updateResourceAttributes(buildResourceAttributes())
52
+ })
53
+ }
54
+
55
+ module.exports = { buildResourceAttributes, registerResourceAttributeRefresh }
@@ -1,6 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  const { VERSION } = require('../../../../../version')
4
+ const { registerResourceAttributeRefresh } = require('../resource-attributes')
4
5
  const OtlpHttpTraceExporter = require('./otlp_http_trace_exporter')
5
6
 
6
7
  /**
@@ -59,13 +60,17 @@ function buildResourceAttributes (config) {
59
60
  * @returns {OtlpHttpTraceExporter} The OTLP HTTP/JSON exporter
60
61
  */
61
62
  function createOtlpTraceExporter (config) {
62
- return new OtlpHttpTraceExporter(
63
+ const exporter = new OtlpHttpTraceExporter(
63
64
  config.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT,
64
65
  config.OTEL_EXPORTER_OTLP_TRACES_HEADERS,
65
66
  config.OTEL_EXPORTER_OTLP_TRACES_TIMEOUT,
66
67
  buildResourceAttributes(config),
67
68
  config.DD_TRACE_OTEL_SEMANTICS_ENABLED
68
69
  )
70
+
71
+ registerResourceAttributeRefresh(exporter, () => buildResourceAttributes(config))
72
+
73
+ return exporter
69
74
  }
70
75
 
71
76
  module.exports = {
@@ -43,6 +43,16 @@ class OtlpHttpTraceExporter extends OtlpHttpExporterBase {
43
43
  this.#transformer = new OtlpTraceTransformer(resourceAttributes, otelTraceSemanticsEnabled)
44
44
  }
45
45
 
46
+ /**
47
+ * Recomputes the resource attributes baked into the transformer (e.g. after a MicroVM clone
48
+ * resume regenerates `runtime-id`).
49
+ *
50
+ * @param {import('@opentelemetry/api').Attributes} resourceAttributes - Resource attributes
51
+ */
52
+ updateResourceAttributes (resourceAttributes) {
53
+ this.#transformer.updateResourceAttributes(resourceAttributes)
54
+ }
55
+
46
56
  /**
47
57
  * Exports DD-formatted spans via OTLP over HTTP.
48
58
  *