dd-trace 5.81.0 → 5.82.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 (321) hide show
  1. package/index.d.ts +7 -0
  2. package/loader-hook.mjs +7 -2
  3. package/package.json +13 -18
  4. package/packages/datadog-core/src/utils/src/parse-tags.js +1 -1
  5. package/packages/datadog-esbuild/index.js +8 -7
  6. package/packages/datadog-esbuild/src/utils.js +14 -2
  7. package/packages/datadog-instrumentations/src/aerospike.js +3 -2
  8. package/packages/datadog-instrumentations/src/ai.js +2 -2
  9. package/packages/datadog-instrumentations/src/amqp10.js +1 -1
  10. package/packages/datadog-instrumentations/src/amqplib.js +4 -4
  11. package/packages/datadog-instrumentations/src/anthropic.js +2 -2
  12. package/packages/datadog-instrumentations/src/apollo-server-core.js +2 -2
  13. package/packages/datadog-instrumentations/src/apollo-server.js +1 -1
  14. package/packages/datadog-instrumentations/src/apollo.js +3 -2
  15. package/packages/datadog-instrumentations/src/avsc.js +1 -1
  16. package/packages/datadog-instrumentations/src/aws-sdk.js +1 -1
  17. package/packages/datadog-instrumentations/src/azure-event-hubs.js +4 -3
  18. package/packages/datadog-instrumentations/src/azure-functions.js +2 -2
  19. package/packages/datadog-instrumentations/src/azure-service-bus.js +3 -4
  20. package/packages/datadog-instrumentations/src/bluebird.js +1 -1
  21. package/packages/datadog-instrumentations/src/bullmq.js +11 -0
  22. package/packages/datadog-instrumentations/src/bunyan.js +1 -1
  23. package/packages/datadog-instrumentations/src/cassandra-driver.js +1 -1
  24. package/packages/datadog-instrumentations/src/child_process.js +2 -2
  25. package/packages/datadog-instrumentations/src/confluentinc-kafka-javascript.js +3 -3
  26. package/packages/datadog-instrumentations/src/couchbase.js +1 -1
  27. package/packages/datadog-instrumentations/src/crypto.js +1 -1
  28. package/packages/datadog-instrumentations/src/cucumber.js +12 -13
  29. package/packages/datadog-instrumentations/src/cypress.js +1 -1
  30. package/packages/datadog-instrumentations/src/dns.js +1 -1
  31. package/packages/datadog-instrumentations/src/elasticsearch.js +1 -1
  32. package/packages/datadog-instrumentations/src/express-mongo-sanitize.js +1 -1
  33. package/packages/datadog-instrumentations/src/express.js +1 -1
  34. package/packages/datadog-instrumentations/src/fs.js +1 -1
  35. package/packages/datadog-instrumentations/src/generic-pool.js +1 -1
  36. package/packages/datadog-instrumentations/src/google-cloud-pubsub.js +137 -15
  37. package/packages/datadog-instrumentations/src/google-cloud-vertexai.js +2 -3
  38. package/packages/datadog-instrumentations/src/google-genai.js +3 -3
  39. package/packages/datadog-instrumentations/src/graphql.js +1 -1
  40. package/packages/datadog-instrumentations/src/grpc/client.js +1 -1
  41. package/packages/datadog-instrumentations/src/grpc/server.js +1 -1
  42. package/packages/datadog-instrumentations/src/helpers/bundler-register.js +1 -1
  43. package/packages/datadog-instrumentations/src/helpers/hook.js +1 -1
  44. package/packages/datadog-instrumentations/src/helpers/hooks.js +4 -1
  45. package/packages/datadog-instrumentations/src/helpers/instrument.js +1 -1
  46. package/packages/datadog-instrumentations/src/helpers/register.js +6 -4
  47. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +2 -2
  48. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/bullmq.json +106 -0
  49. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +2 -1
  50. package/packages/datadog-instrumentations/src/helpers/router-helper.js +1 -1
  51. package/packages/datadog-instrumentations/src/helpers/shared-utils.js +9 -0
  52. package/packages/datadog-instrumentations/src/hono.js +55 -10
  53. package/packages/datadog-instrumentations/src/ioredis.js +1 -1
  54. package/packages/datadog-instrumentations/src/iovalkey.js +1 -1
  55. package/packages/datadog-instrumentations/src/jest.js +2 -2
  56. package/packages/datadog-instrumentations/src/kafkajs.js +3 -3
  57. package/packages/datadog-instrumentations/src/knex.js +1 -1
  58. package/packages/datadog-instrumentations/src/ldapjs.js +1 -1
  59. package/packages/datadog-instrumentations/src/light-my-request.js +93 -0
  60. package/packages/datadog-instrumentations/src/limitd-client.js +1 -1
  61. package/packages/datadog-instrumentations/src/lodash.js +1 -2
  62. package/packages/datadog-instrumentations/src/mariadb.js +1 -2
  63. package/packages/datadog-instrumentations/src/memcached.js +1 -1
  64. package/packages/datadog-instrumentations/src/mongodb-core.js +1 -1
  65. package/packages/datadog-instrumentations/src/mongodb.js +1 -1
  66. package/packages/datadog-instrumentations/src/mongoose.js +1 -1
  67. package/packages/datadog-instrumentations/src/mquery.js +1 -1
  68. package/packages/datadog-instrumentations/src/mysql.js +1 -1
  69. package/packages/datadog-instrumentations/src/mysql2.js +1 -1
  70. package/packages/datadog-instrumentations/src/net.js +1 -1
  71. package/packages/datadog-instrumentations/src/next.js +1 -1
  72. package/packages/datadog-instrumentations/src/nyc.js +1 -1
  73. package/packages/datadog-instrumentations/src/openai.js +2 -2
  74. package/packages/datadog-instrumentations/src/opensearch.js +1 -1
  75. package/packages/datadog-instrumentations/src/oracledb.js +1 -1
  76. package/packages/datadog-instrumentations/src/otel-sdk-trace.js +1 -1
  77. package/packages/datadog-instrumentations/src/pg.js +3 -3
  78. package/packages/datadog-instrumentations/src/pino.js +1 -1
  79. package/packages/datadog-instrumentations/src/playwright.js +1 -1
  80. package/packages/datadog-instrumentations/src/prisma.js +52 -37
  81. package/packages/datadog-instrumentations/src/process.js +1 -1
  82. package/packages/datadog-instrumentations/src/promise-js.js +1 -1
  83. package/packages/datadog-instrumentations/src/promise.js +1 -1
  84. package/packages/datadog-instrumentations/src/protobufjs.js +1 -1
  85. package/packages/datadog-instrumentations/src/q.js +1 -1
  86. package/packages/datadog-instrumentations/src/redis.js +1 -1
  87. package/packages/datadog-instrumentations/src/rhea.js +1 -1
  88. package/packages/datadog-instrumentations/src/selenium.js +1 -1
  89. package/packages/datadog-instrumentations/src/sequelize.js +1 -2
  90. package/packages/datadog-instrumentations/src/sharedb.js +1 -1
  91. package/packages/datadog-instrumentations/src/tedious.js +1 -1
  92. package/packages/datadog-instrumentations/src/undici.js +4 -4
  93. package/packages/datadog-instrumentations/src/url.js +1 -1
  94. package/packages/datadog-instrumentations/src/vitest.js +1 -1
  95. package/packages/datadog-instrumentations/src/vm.js +1 -1
  96. package/packages/datadog-instrumentations/src/when.js +1 -1
  97. package/packages/datadog-instrumentations/src/winston.js +1 -1
  98. package/packages/datadog-instrumentations/src/ws.js +3 -2
  99. package/packages/datadog-plugin-amqp10/src/index.js +1 -1
  100. package/packages/datadog-plugin-amqplib/src/index.js +1 -1
  101. package/packages/datadog-plugin-anthropic/src/index.js +1 -1
  102. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/index.js +1 -1
  103. package/packages/datadog-plugin-aws-sdk/src/services/dynamodb.js +4 -4
  104. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +2 -2
  105. package/packages/datadog-plugin-aws-sdk/src/util.js +3 -3
  106. package/packages/datadog-plugin-azure-event-hubs/src/index.js +1 -1
  107. package/packages/datadog-plugin-azure-event-hubs/src/producer.js +19 -5
  108. package/packages/datadog-plugin-azure-service-bus/src/index.js +1 -1
  109. package/packages/datadog-plugin-azure-service-bus/src/producer.js +4 -0
  110. package/packages/datadog-plugin-bullmq/src/consumer.js +60 -0
  111. package/packages/datadog-plugin-bullmq/src/index.js +18 -0
  112. package/packages/datadog-plugin-bullmq/src/producer.js +178 -0
  113. package/packages/datadog-plugin-confluentinc-kafka-javascript/src/index.js +1 -1
  114. package/packages/datadog-plugin-cypress/src/plugin.js +1 -1
  115. package/packages/datadog-plugin-express/src/index.js +1 -1
  116. package/packages/datadog-plugin-fastify/src/index.js +1 -1
  117. package/packages/datadog-plugin-google-cloud-pubsub/src/client.js +13 -3
  118. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +171 -12
  119. package/packages/datadog-plugin-google-cloud-pubsub/src/index.js +1 -2
  120. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +160 -13
  121. package/packages/datadog-plugin-google-cloud-pubsub/src/pubsub-push-subscription.js +217 -0
  122. package/packages/datadog-plugin-google-cloud-vertexai/src/index.js +1 -1
  123. package/packages/datadog-plugin-google-genai/src/index.js +1 -1
  124. package/packages/datadog-plugin-graphql/src/resolve.js +1 -1
  125. package/packages/datadog-plugin-grpc/src/index.js +1 -1
  126. package/packages/datadog-plugin-http/src/client.js +2 -1
  127. package/packages/datadog-plugin-http/src/index.js +25 -5
  128. package/packages/datadog-plugin-http2/src/client.js +2 -2
  129. package/packages/datadog-plugin-http2/src/index.js +1 -1
  130. package/packages/datadog-plugin-kafkajs/src/index.js +1 -1
  131. package/packages/datadog-plugin-langchain/src/index.js +1 -1
  132. package/packages/datadog-plugin-moleculer/src/index.js +1 -1
  133. package/packages/datadog-plugin-mongodb-core/src/index.js +6 -2
  134. package/packages/datadog-plugin-openai/src/index.js +1 -1
  135. package/packages/datadog-plugin-openai/src/stream-helpers.js +30 -10
  136. package/packages/datadog-plugin-openai/src/tracing.js +2 -2
  137. package/packages/datadog-plugin-rhea/src/index.js +1 -1
  138. package/packages/datadog-plugin-ws/src/close.js +56 -3
  139. package/packages/datadog-plugin-ws/src/index.js +4 -0
  140. package/packages/datadog-plugin-ws/src/producer.js +39 -4
  141. package/packages/datadog-plugin-ws/src/receiver.js +39 -3
  142. package/packages/datadog-plugin-ws/src/server.js +13 -1
  143. package/packages/datadog-plugin-ws/src/util.js +107 -0
  144. package/packages/datadog-shimmer/src/shimmer.js +2 -2
  145. package/packages/dd-trace/src/aiguard/sdk.js +3 -3
  146. package/packages/dd-trace/src/appsec/graphql.js +2 -2
  147. package/packages/dd-trace/src/appsec/iast/analyzers/code-injection-analyzer.js +1 -1
  148. package/packages/dd-trace/src/appsec/iast/analyzers/command-injection-analyzer.js +1 -1
  149. package/packages/dd-trace/src/appsec/iast/analyzers/cookie-analyzer.js +1 -1
  150. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-base-analyzer.js +1 -1
  151. package/packages/dd-trace/src/appsec/iast/analyzers/injection-analyzer.js +1 -1
  152. package/packages/dd-trace/src/appsec/iast/analyzers/ldap-injection-analyzer.js +1 -1
  153. package/packages/dd-trace/src/appsec/iast/analyzers/nosql-injection-mongodb-analyzer.js +3 -3
  154. package/packages/dd-trace/src/appsec/iast/analyzers/path-traversal-analyzer.js +1 -1
  155. package/packages/dd-trace/src/appsec/iast/analyzers/ssrf-analyzer.js +1 -1
  156. package/packages/dd-trace/src/appsec/iast/analyzers/untrusted-deserialization-analyzer.js +1 -1
  157. package/packages/dd-trace/src/appsec/iast/analyzers/unvalidated-redirect-analyzer.js +1 -1
  158. package/packages/dd-trace/src/appsec/iast/analyzers/weak-cipher-analyzer.js +1 -1
  159. package/packages/dd-trace/src/appsec/iast/analyzers/weak-hash-analyzer.js +3 -2
  160. package/packages/dd-trace/src/appsec/iast/analyzers/weak-randomness-analyzer.js +1 -1
  161. package/packages/dd-trace/src/appsec/iast/iast-plugin.js +3 -3
  162. package/packages/dd-trace/src/appsec/iast/index.js +5 -5
  163. package/packages/dd-trace/src/appsec/iast/security-controls/index.js +1 -1
  164. package/packages/dd-trace/src/appsec/iast/taint-tracking/index.js +1 -2
  165. package/packages/dd-trace/src/appsec/iast/taint-tracking/operations-taint-object.js +1 -1
  166. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +1 -1
  167. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +10 -14
  168. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +1 -1
  169. package/packages/dd-trace/src/appsec/iast/telemetry/namespaces.js +1 -1
  170. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +3 -3
  171. package/packages/dd-trace/src/appsec/index.js +8 -8
  172. package/packages/dd-trace/src/appsec/rasp/command_injection.js +1 -1
  173. package/packages/dd-trace/src/appsec/rasp/index.js +1 -1
  174. package/packages/dd-trace/src/appsec/rasp/lfi.js +1 -1
  175. package/packages/dd-trace/src/appsec/rc-products.js +10 -0
  176. package/packages/dd-trace/src/appsec/recommended.json +230 -3
  177. package/packages/dd-trace/src/appsec/remote_config.js +177 -0
  178. package/packages/dd-trace/src/appsec/reporter.js +3 -3
  179. package/packages/dd-trace/src/appsec/rule_manager.js +37 -20
  180. package/packages/dd-trace/src/appsec/sdk/index.js +1 -1
  181. package/packages/dd-trace/src/appsec/sdk/set_user.js +1 -1
  182. package/packages/dd-trace/src/appsec/sdk/track_event.js +2 -2
  183. package/packages/dd-trace/src/appsec/sdk/user_blocking.js +2 -2
  184. package/packages/dd-trace/src/appsec/user_tracking.js +2 -2
  185. package/packages/dd-trace/src/appsec/waf/index.js +17 -3
  186. package/packages/dd-trace/src/appsec/waf/waf_manager.js +11 -0
  187. package/packages/dd-trace/src/azure_metadata.js +8 -2
  188. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +6 -0
  189. package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +2 -2
  190. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +1 -1
  191. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +1 -1
  192. package/packages/dd-trace/src/config/remote_config.js +34 -0
  193. package/packages/dd-trace/src/config.js +29 -28
  194. package/packages/dd-trace/src/config_defaults.js +2 -1
  195. package/packages/dd-trace/src/constants.js +5 -0
  196. package/packages/dd-trace/src/crashtracking/crashtracker.js +10 -1
  197. package/packages/dd-trace/src/datastreams/checkpointer.js +2 -2
  198. package/packages/dd-trace/src/datastreams/index.js +1 -1
  199. package/packages/dd-trace/src/datastreams/pathway.js +7 -7
  200. package/packages/dd-trace/src/datastreams/processor.js +2 -2
  201. package/packages/dd-trace/src/datastreams/writer.js +2 -2
  202. package/packages/dd-trace/src/debugger/config.js +1 -0
  203. package/packages/dd-trace/src/debugger/devtools_client/config.js +1 -1
  204. package/packages/dd-trace/src/debugger/devtools_client/index.js +7 -2
  205. package/packages/dd-trace/src/debugger/devtools_client/send.js +3 -3
  206. package/packages/dd-trace/src/debugger/devtools_client/session.js +1 -1
  207. package/packages/dd-trace/src/debugger/devtools_client/snapshot/collector.js +5 -5
  208. package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +2 -2
  209. package/packages/dd-trace/src/debugger/devtools_client/state.js +1 -1
  210. package/packages/dd-trace/src/debugger/devtools_client/status.js +2 -2
  211. package/packages/dd-trace/src/debugger/index.js +1 -1
  212. package/packages/dd-trace/src/dogstatsd.js +3 -2
  213. package/packages/dd-trace/src/encode/0.4.js +1 -1
  214. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +2 -2
  215. package/packages/dd-trace/src/encode/coverage-ci-visibility.js +1 -1
  216. package/packages/dd-trace/src/encode/span-stats.js +6 -1
  217. package/packages/dd-trace/src/exporter.js +2 -2
  218. package/packages/dd-trace/src/exporters/agent/index.js +1 -1
  219. package/packages/dd-trace/src/exporters/common/agent-info-exporter.js +1 -1
  220. package/packages/dd-trace/src/exporters/common/request.js +2 -2
  221. package/packages/dd-trace/src/exporters/common/writer.js +1 -1
  222. package/packages/dd-trace/src/exporters/span-stats/index.js +1 -1
  223. package/packages/dd-trace/src/external-logger/src/index.js +1 -2
  224. package/packages/dd-trace/src/flare/index.js +1 -1
  225. package/packages/dd-trace/src/guardrails/index.js +6 -3
  226. package/packages/dd-trace/src/id.js +1 -1
  227. package/packages/dd-trace/src/index.js +1 -1
  228. package/packages/dd-trace/src/lambda/handler.js +4 -4
  229. package/packages/dd-trace/src/lambda/index.js +1 -1
  230. package/packages/dd-trace/src/lambda/runtime/patch.js +4 -4
  231. package/packages/dd-trace/src/lambda/runtime/ritm.js +1 -1
  232. package/packages/dd-trace/src/llmobs/constants/tags.js +7 -1
  233. package/packages/dd-trace/src/llmobs/index.js +8 -9
  234. package/packages/dd-trace/src/llmobs/plugins/ai/index.js +38 -7
  235. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +30 -9
  236. package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +3 -3
  237. package/packages/dd-trace/src/llmobs/plugins/genai/util.js +2 -2
  238. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/chain.js +1 -1
  239. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/chat_model.js +1 -1
  240. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/embedding.js +1 -1
  241. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/llm.js +1 -1
  242. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/vectorstore.js +1 -1
  243. package/packages/dd-trace/src/llmobs/plugins/openai/constants.js +16 -0
  244. package/packages/dd-trace/src/llmobs/plugins/openai/index.js +16 -1
  245. package/packages/dd-trace/src/llmobs/plugins/openai/utils.js +22 -10
  246. package/packages/dd-trace/src/llmobs/plugins/vertexai.js +1 -1
  247. package/packages/dd-trace/src/llmobs/sdk.js +15 -22
  248. package/packages/dd-trace/src/llmobs/span_processor.js +9 -13
  249. package/packages/dd-trace/src/llmobs/telemetry.js +3 -4
  250. package/packages/dd-trace/src/llmobs/writers/base.js +2 -2
  251. package/packages/dd-trace/src/llmobs/writers/spans.js +1 -2
  252. package/packages/dd-trace/src/log/index.js +1 -1
  253. package/packages/dd-trace/src/noop/proxy.js +2 -2
  254. package/packages/dd-trace/src/noop/span.js +1 -1
  255. package/packages/dd-trace/src/openfeature/index.js +2 -2
  256. package/packages/dd-trace/src/openfeature/noop.js +14 -14
  257. package/packages/dd-trace/src/openfeature/remote_config.js +31 -0
  258. package/packages/dd-trace/src/openfeature/writers/base.js +5 -5
  259. package/packages/dd-trace/src/openfeature/writers/exposures.js +9 -9
  260. package/packages/dd-trace/src/opentelemetry/context_manager.js +2 -2
  261. package/packages/dd-trace/src/opentelemetry/logs/logger.js +1 -1
  262. package/packages/dd-trace/src/opentelemetry/logs/logger_provider.js +4 -4
  263. package/packages/dd-trace/src/opentelemetry/logs/otlp_transformer.js +9 -8
  264. package/packages/dd-trace/src/opentelemetry/metrics/instruments.js +3 -3
  265. package/packages/dd-trace/src/opentelemetry/metrics/meter.js +2 -2
  266. package/packages/dd-trace/src/opentelemetry/metrics/otlp_transformer.js +4 -4
  267. package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +36 -11
  268. package/packages/dd-trace/src/opentelemetry/otlp/otlp_transformer_base.js +11 -10
  269. package/packages/dd-trace/src/opentelemetry/otlp/protobuf_loader.js +1 -1
  270. package/packages/dd-trace/src/opentelemetry/span.js +2 -2
  271. package/packages/dd-trace/src/opentelemetry/tracer.js +3 -3
  272. package/packages/dd-trace/src/opentracing/propagation/text_map.js +24 -8
  273. package/packages/dd-trace/src/opentracing/span.js +3 -3
  274. package/packages/dd-trace/src/opentracing/tracer.js +5 -5
  275. package/packages/dd-trace/src/payload-tagging/index.js +6 -2
  276. package/packages/dd-trace/src/plugin_manager.js +1 -1
  277. package/packages/dd-trace/src/plugins/apollo.js +1 -1
  278. package/packages/dd-trace/src/plugins/ci_plugin.js +27 -27
  279. package/packages/dd-trace/src/plugins/database.js +1 -1
  280. package/packages/dd-trace/src/plugins/index.js +5 -1
  281. package/packages/dd-trace/src/plugins/log_plugin.js +1 -1
  282. package/packages/dd-trace/src/plugins/outbound.js +1 -1
  283. package/packages/dd-trace/src/plugins/tracing.js +1 -1
  284. package/packages/dd-trace/src/plugins/util/ci.js +1 -1
  285. package/packages/dd-trace/src/plugins/util/git.js +8 -8
  286. package/packages/dd-trace/src/plugins/util/stacktrace.js +1 -1
  287. package/packages/dd-trace/src/plugins/util/test.js +24 -24
  288. package/packages/dd-trace/src/plugins/util/user-provided-git.js +1 -1
  289. package/packages/dd-trace/src/plugins/util/web.js +8 -5
  290. package/packages/dd-trace/src/priority_sampler.js +15 -16
  291. package/packages/dd-trace/src/process-tags/index.js +31 -29
  292. package/packages/dd-trace/src/profiling/config.js +32 -21
  293. package/packages/dd-trace/src/profiling/exporter_cli.js +4 -4
  294. package/packages/dd-trace/src/profiling/exporters/agent.js +5 -5
  295. package/packages/dd-trace/src/profiling/index.js +1 -1
  296. package/packages/dd-trace/src/profiling/libuv-size.js +1 -1
  297. package/packages/dd-trace/src/profiling/profiler.js +4 -5
  298. package/packages/dd-trace/src/profiling/profilers/event_plugins/event.js +1 -1
  299. package/packages/dd-trace/src/profiling/profilers/events.js +2 -2
  300. package/packages/dd-trace/src/profiling/profilers/wall.js +4 -4
  301. package/packages/dd-trace/src/proxy.js +12 -18
  302. package/packages/dd-trace/src/remote_config/index.js +541 -137
  303. package/packages/dd-trace/src/require-package-json.js +1 -1
  304. package/packages/dd-trace/src/ritm.js +50 -27
  305. package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +1 -1
  306. package/packages/dd-trace/src/serverless.js +16 -0
  307. package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +8 -0
  308. package/packages/dd-trace/src/service-naming/schemas/v1/messaging.js +8 -0
  309. package/packages/dd-trace/src/span_format.js +1 -1
  310. package/packages/dd-trace/src/span_processor.js +2 -2
  311. package/packages/dd-trace/src/span_stats.js +6 -4
  312. package/packages/dd-trace/src/standalone/index.js +1 -1
  313. package/packages/dd-trace/src/startup-log.js +3 -3
  314. package/packages/dd-trace/src/supported-configurations.json +3 -0
  315. package/packages/dd-trace/src/telemetry/dependencies.js +3 -3
  316. package/packages/dd-trace/src/telemetry/endpoints.js +8 -8
  317. package/packages/dd-trace/src/telemetry/logs/index.js +1 -1
  318. package/packages/dd-trace/src/telemetry/telemetry.js +11 -6
  319. package/packages/dd-trace/src/tracer.js +3 -3
  320. package/packages/dd-trace/src/tracer_metadata.js +19 -15
  321. package/packages/dd-trace/src/remote_config/manager.js +0 -368
@@ -2,30 +2,188 @@
2
2
 
3
3
  const { getMessageSize } = require('../../dd-trace/src/datastreams')
4
4
  const ConsumerPlugin = require('../../dd-trace/src/plugins/consumer')
5
+ const SpanContext = require('../../dd-trace/src/opentracing/span_context')
6
+ const id = require('../../dd-trace/src/id')
7
+ const { storage } = require('../../datadog-core')
8
+
9
+ /**
10
+ * PULL SUBSCRIPTION: Service explicitly pulls messages from Pub/Sub and processes them.
11
+ * Async context storage for linking acknowledge() API calls back to original message spans.
12
+ *
13
+ * Problem: message.ack() is often called asynchronously outside the original handler,
14
+ * losing async context. The acknowledge() API only receives ackIds (strings), not Messages.
15
+ *
16
+ * Solution: Store context by Message (WeakMap), lookup by ackId (Map<ackId, WeakRef<Message>>).
17
+ * WeakRef allows Messages to be GC'd even if never acknowledged (network failures, crashes).
18
+ */
19
+ const messageToContext = new WeakMap() // Message -> context (auto-cleanup on GC)
20
+ const ackIdToMessage = new Map() // ackId -> WeakRef<Message> (needs cleanup)
21
+
22
+ const ackMapCleanup = new FinalizationRegistry((ackId) => {
23
+ ackIdToMessage.delete(ackId) // Remove orphaned ackId when Message is GC'd
24
+ })
5
25
 
6
26
  class GoogleCloudPubsubConsumerPlugin extends ConsumerPlugin {
7
27
  static id = 'google-cloud-pubsub'
8
28
  static operation = 'receive'
9
29
 
30
+ constructor (...args) {
31
+ super(...args)
32
+
33
+ /**
34
+ * Channel: message:ack-store
35
+ * When message.ack() is called, capture and store the current async context.
36
+ * Use WeakRef to allow Message GC even if never acknowledged.
37
+ */
38
+ this.addSub('apm:google-cloud-pubsub:message:ack-store', (ctx) => {
39
+ const { message, ackId } = ctx
40
+ const currentStore = storage('legacy').getStore()
41
+
42
+ if (currentStore) {
43
+ messageToContext.set(message, currentStore)
44
+ ackIdToMessage.set(ackId, new WeakRef(message))
45
+ ackMapCleanup.register(message, ackId, message)
46
+ }
47
+ })
48
+
49
+ /**
50
+ * Channel: message:ack-retrieve
51
+ * When acknowledge() API is called, retrieve stored context for the ackIds.
52
+ * Map: ackId -> WeakRef<Message> -> stored context.
53
+ * Clean up immediately after acknowledge (happy path), or via FinalizationRegistry (GC).
54
+ */
55
+ this.addSub('apm:google-cloud-pubsub:message:ack-retrieve', ({ ackIds, api, ctx }) => {
56
+ for (const ackId of ackIds) {
57
+ const weakRef = ackIdToMessage.get(ackId)
58
+ if (weakRef) {
59
+ const message = weakRef.deref()
60
+ if (message) {
61
+ const storedContext = messageToContext.get(message)
62
+ if (storedContext) {
63
+ ctx.storedContext = storedContext
64
+ break
65
+ }
66
+ }
67
+ }
68
+ }
69
+
70
+ if (api === 'acknowledge') {
71
+ ackIds.forEach(ackId => ackIdToMessage.delete(ackId))
72
+ }
73
+ })
74
+ }
75
+
76
+ #reconstructPubSubRequestContext (attrs) {
77
+ const traceIdLower = attrs['_dd.pubsub_request.trace_id']
78
+ const spanId = attrs['_dd.pubsub_request.span_id']
79
+ const traceIdUpper = attrs['_dd.pubsub_request.p.tid']
80
+
81
+ if (!traceIdLower || !spanId) return null
82
+
83
+ const traceId128 = traceIdUpper ? traceIdUpper + traceIdLower : traceIdLower.padStart(32, '0')
84
+ const traceId = id(traceId128, 16)
85
+ const parentId = id(spanId, 16)
86
+
87
+ const tags = {}
88
+ if (traceIdUpper) tags['_dd.p.tid'] = traceIdUpper
89
+
90
+ return new SpanContext({
91
+ traceId,
92
+ spanId: parentId,
93
+ tags
94
+ })
95
+ }
96
+
10
97
  bindStart (ctx) {
11
98
  const { message } = ctx
12
99
  const subscription = message._subscriber._subscription
13
- const topic = subscription.metadata && subscription.metadata.topic
14
- const childOf = this.tracer.extract('text_map', message.attributes) || null
100
+ const topic = subscription?.metadata?.topic || message.attributes?.['pubsub.topic']
101
+
102
+ const batchRequestTraceId = message.attributes?.['_dd.pubsub_request.trace_id']
103
+ const batchRequestSpanId = message.attributes?.['_dd.pubsub_request.span_id']
104
+
105
+ // Parse batch metadata once upfront for reuse
106
+ const batchSizeStr = message.attributes?.['_dd.batch.size']
107
+ const batchIndexStr = message.attributes?.['_dd.batch.index']
108
+ const batchSize = batchSizeStr ? Number(batchSizeStr) : undefined
109
+ const batchIndex = batchIndexStr ? Number(batchIndexStr) : undefined
110
+
111
+ let childOf = this.tracer.extract('text_map', message.attributes)
112
+
113
+ const isFirstMessage = batchIndex === 0
114
+ if (isFirstMessage && batchRequestSpanId) {
115
+ const pubsubRequestContext = this.#reconstructPubSubRequestContext(message.attributes)
116
+ if (pubsubRequestContext) {
117
+ childOf = pubsubRequestContext
118
+ }
119
+ }
120
+
121
+ const topicName = topic?.slice(topic.lastIndexOf('/') + 1) ??
122
+ subscription.name.slice(subscription.name.lastIndexOf('/') + 1)
123
+ const baseService = this.tracer._service || 'unknown'
124
+ const serviceName = this.config.service || `${baseService}-pubsub`
125
+ const meta = {
126
+ 'gcloud.project_id': subscription.pubsub.projectId,
127
+ 'pubsub.topic': topic,
128
+ 'span.kind': 'consumer',
129
+ 'pubsub.subscription_type': 'pull',
130
+ 'pubsub.span_type': 'message_processing',
131
+ 'messaging.operation': 'receive',
132
+ base_service: baseService,
133
+ service_override_type: 'custom'
134
+ }
135
+
136
+ if (batchRequestTraceId && batchRequestSpanId) {
137
+ meta['pubsub.batch.request_trace_id'] = batchRequestTraceId
138
+ // Use JSON format like producer for proper span link parsing
139
+ meta['_dd.span_links'] = JSON.stringify([{
140
+ trace_id: batchRequestTraceId,
141
+ span_id: batchRequestSpanId,
142
+ flags: 0
143
+ }])
144
+ }
145
+
146
+ const metrics = {
147
+ 'pubsub.ack': 0
148
+ }
149
+
150
+ if (batchSize) {
151
+ metrics['pubsub.batch.message_count'] = batchSize
152
+ metrics['pubsub.batch.size'] = batchSize
153
+ }
154
+ if (batchIndex !== undefined) {
155
+ metrics['pubsub.batch.message_index'] = batchIndex
156
+ metrics['pubsub.batch.index'] = batchIndex
157
+ }
158
+
159
+ if (batchSize && batchIndex !== undefined) {
160
+ meta['pubsub.batch.description'] = `Message ${batchIndex + 1} of ${batchSize}`
161
+ }
15
162
 
16
163
  const span = this.startSpan({
17
164
  childOf,
18
- resource: topic,
165
+ resource: `Message from ${topicName}`,
19
166
  type: 'worker',
20
- meta: {
21
- 'gcloud.project_id': subscription.pubsub.projectId,
22
- 'pubsub.topic': topic
23
- },
24
- metrics: {
25
- 'pubsub.ack': 0
26
- }
167
+ service: serviceName,
168
+ meta,
169
+ metrics
27
170
  }, ctx)
28
171
 
172
+ if (message.id) {
173
+ span.setTag('pubsub.message_id', message.id)
174
+ }
175
+ if (message.publishTime) {
176
+ span.setTag('pubsub.publish_time', message.publishTime.toISOString())
177
+ }
178
+
179
+ if (message.attributes) {
180
+ const publishStartTime = message.attributes['x-dd-publish-start-time']
181
+ if (publishStartTime) {
182
+ const deliveryDuration = Date.now() - Number(publishStartTime)
183
+ span.setTag('pubsub.delivery_duration_ms', deliveryDuration)
184
+ }
185
+ }
186
+
29
187
  if (this.config.dsmEnabled && message?.attributes) {
30
188
  const payloadSize = getMessageSize(message)
31
189
  this.tracer.decodeDataStreamsContext(message.attributes)
@@ -38,14 +196,15 @@ class GoogleCloudPubsubConsumerPlugin extends ConsumerPlugin {
38
196
 
39
197
  bindFinish (ctx) {
40
198
  const { message } = ctx
41
- const span = ctx.currentStore.span
199
+ const span = ctx.currentStore?.span
200
+
201
+ if (!span) return ctx.parentStore
42
202
 
43
203
  if (message?._handled) {
44
204
  span.setTag('pubsub.ack', 1)
45
205
  }
46
206
 
47
207
  super.finish()
48
-
49
208
  return ctx.parentStore
50
209
  }
51
210
  }
@@ -1,11 +1,10 @@
1
1
  'use strict'
2
2
 
3
+ const CompositePlugin = require('../../dd-trace/src/plugins/composite')
3
4
  const ProducerPlugin = require('./producer')
4
5
  const ConsumerPlugin = require('./consumer')
5
6
  const ClientPlugin = require('./client')
6
- const CompositePlugin = require('../../dd-trace/src/plugins/composite')
7
7
 
8
- // TODO: Consider splitting channels for publish/receive in the instrumentation.
9
8
  class GoogleCloudPubsubPlugin extends CompositePlugin {
10
9
  static id = 'google-cloud-pubsub'
11
10
  static get plugins () {
@@ -2,42 +2,189 @@
2
2
 
3
3
  const ProducerPlugin = require('../../dd-trace/src/plugins/producer')
4
4
  const { DsmPathwayCodec, getHeadersSize } = require('../../dd-trace/src/datastreams')
5
+ const id = require('../../dd-trace/src/id')
5
6
 
6
7
  class GoogleCloudPubsubProducerPlugin extends ProducerPlugin {
7
8
  static id = 'google-cloud-pubsub'
8
9
  static operation = 'request'
9
10
 
11
+ constructor (...args) {
12
+ super(...args)
13
+
14
+ /**
15
+ * Inject trace context into individual messages published via Topic.publish() or
16
+ * Topic.publishMessage(). This happens before the batch publish API call, allowing
17
+ * each message to propagate trace context to consumers.
18
+ */
19
+ this.addSub('apm:google-cloud-pubsub:message:publish', this.handleMessagePublish.bind(this))
20
+ }
21
+
22
+ handleMessagePublish ({ attributes, pubsub, topicName }) {
23
+ // Skip if message already has trace context from upstream
24
+ if (attributes['x-datadog-trace-id'] || attributes.traceparent) return
25
+
26
+ const activeSpan = this.tracer.scope().active()
27
+ if (!activeSpan) return
28
+
29
+ // Inject current span's trace context into message attributes
30
+ this.tracer.inject(activeSpan, 'text_map', attributes)
31
+
32
+ const traceIdUpperBits = activeSpan.context()._trace.tags['_dd.p.tid']
33
+ if (traceIdUpperBits) attributes['_dd.p.tid'] = traceIdUpperBits
34
+
35
+ if (pubsub) attributes['gcloud.project_id'] = pubsub.projectId
36
+ if (topicName) attributes['pubsub.topic'] = topicName
37
+ }
38
+
10
39
  bindStart (ctx) {
11
40
  const { request, api, projectId } = ctx
12
-
13
41
  if (api !== 'publish') return
14
42
 
15
43
  const messages = request.messages || []
16
44
  const topic = request.topic
17
- const span = this.startSpan({ // TODO: rename
18
- resource: `${api} ${topic}`,
45
+ const messageCount = messages.length
46
+ const hasTraceContext = messages[0]?.attributes?.['x-datadog-trace-id']
47
+
48
+ /**
49
+ * Batch Publishing Strategy:
50
+ * - Create one "batch span" representing the entire publish operation
51
+ * - If messages already have trace context (from upstream), use the first message's
52
+ * context as the parent, and create span links for messages 2-N
53
+ * - Otherwise, use the current active span as parent
54
+ * - Inject batch span context + metadata into all message attributes for downstream
55
+ * consumers to reconstruct the trace and understand batch relationships
56
+ */
57
+ const spanLinkData = hasTraceContext
58
+ ? messages.slice(1).map(msg => this.#extractSpanLink(msg.attributes)).filter(Boolean)
59
+ : []
60
+
61
+ const firstAttrs = messages[0]?.attributes
62
+ const parentData = firstAttrs?.['x-datadog-trace-id'] && firstAttrs['x-datadog-parent-id']
63
+ ? {
64
+ traceId: firstAttrs['x-datadog-trace-id'],
65
+ spanId: firstAttrs['x-datadog-parent-id'],
66
+ traceIdUpper: firstAttrs['_dd.p.tid'],
67
+ samplingPriority: firstAttrs['x-datadog-sampling-priority']
68
+ }
69
+ : null
70
+
71
+ const lastSlash = topic.lastIndexOf('/')
72
+ const topicName = lastSlash === -1 ? topic : topic.slice(lastSlash + 1)
73
+ const batchSpan = this.startSpan({
74
+ childOf: parentData ? this.#extractParentContext(parentData) : undefined,
75
+ resource: `${api} to Topic ${topicName}`,
19
76
  meta: {
20
77
  'gcloud.project_id': projectId,
21
- 'pubsub.method': api, // TODO: remove
22
- 'pubsub.topic': topic
78
+ 'pubsub.method': api,
79
+ 'pubsub.topic': topic,
80
+ 'span.kind': 'producer',
81
+ '_dd.base_service': this.tracer._service,
82
+ '_dd.serviceoverride.type': 'integration',
83
+ 'pubsub.linked_message_count': spanLinkData.length || undefined,
84
+ operation: messageCount > 1 ? 'batched.pubsub.request' : 'pubsub.request'
85
+ },
86
+ metrics: {
87
+ 'pubsub.batch.message_count': messageCount,
88
+ 'pubsub.batch': messageCount > 1 ? true : undefined
23
89
  }
24
90
  }, ctx)
25
91
 
26
- for (const msg of messages) {
27
- if (!msg.attributes) {
28
- msg.attributes = {}
92
+ const spanCtx = batchSpan.context()
93
+ // Get 128-bit trace ID and span ID as hex strings
94
+ const fullTraceIdHex = spanCtx.toTraceId(true)
95
+ const batchSpanIdHex = spanCtx.toSpanId(true)
96
+ // Extract lower 64 bits (last 16 hex chars) for trace ID
97
+ const batchTraceIdHex = fullTraceIdHex.slice(-16)
98
+ const batchTraceIdUpper = spanCtx._trace.tags['_dd.p.tid']
99
+
100
+ if (spanLinkData.length) {
101
+ batchSpan.setTag('_dd.span_links', JSON.stringify(
102
+ spanLinkData.map(link => ({
103
+ trace_id: link.traceId,
104
+ span_id: link.spanId,
105
+ flags: link.samplingPriority || 0
106
+ }))
107
+ ))
108
+ }
109
+
110
+ messages.forEach((msg, i) => {
111
+ msg.attributes ??= {}
112
+
113
+ if (!hasTraceContext) {
114
+ this.tracer.inject(batchSpan, 'text_map', msg.attributes)
115
+ }
116
+
117
+ Object.assign(msg.attributes, {
118
+ '_dd.pubsub_request.trace_id': batchTraceIdHex,
119
+ '_dd.pubsub_request.span_id': batchSpanIdHex,
120
+ '_dd.batch.size': String(messageCount),
121
+ '_dd.batch.index': String(i),
122
+ 'gcloud.project_id': projectId,
123
+ 'pubsub.topic': topic,
124
+ 'x-dd-publish-start-time': String(Math.floor(batchSpan._startTime))
125
+ })
126
+
127
+ if (batchTraceIdUpper) {
128
+ msg.attributes['_dd.pubsub_request.p.tid'] = batchTraceIdUpper
29
129
  }
30
- this.tracer.inject(span, 'text_map', msg.attributes)
130
+
31
131
  if (this.config.dsmEnabled) {
32
- const payloadSize = getHeadersSize(msg)
33
- const dataStreamsContext = this.tracer
34
- .setCheckpoint(['direction:out', `topic:${topic}`, 'type:google-pubsub'], span, payloadSize)
132
+ const dataStreamsContext = this.tracer.setCheckpoint(
133
+ ['direction:out', `topic:${topic}`, 'type:google-pubsub'],
134
+ batchSpan,
135
+ getHeadersSize(msg)
136
+ )
35
137
  DsmPathwayCodec.encode(dataStreamsContext, msg.attributes)
36
138
  }
37
- }
139
+ })
38
140
 
141
+ ctx.batchSpan = batchSpan
39
142
  return ctx.currentStore
40
143
  }
144
+
145
+ bindFinish (ctx) {
146
+ if (ctx.batchSpan && !ctx.batchSpan._duration) ctx.batchSpan.finish()
147
+ return super.bindFinish(ctx)
148
+ }
149
+
150
+ bindError (ctx) {
151
+ if (ctx.error && ctx.batchSpan) {
152
+ ctx.batchSpan.setTag('error', ctx.error)
153
+ }
154
+ return ctx.parentStore
155
+ }
156
+
157
+ #extractSpanLink (attrs) {
158
+ if (!attrs?.['x-datadog-trace-id'] || !attrs['x-datadog-parent-id']) return null
159
+
160
+ // Convert to hex strings
161
+ const lowerHex = id(attrs['x-datadog-trace-id']).toString(16)
162
+ const spanIdHex = id(attrs['x-datadog-parent-id']).toString(16)
163
+
164
+ // Build full 128-bit trace ID
165
+ const traceIdHex = attrs['_dd.p.tid']
166
+ ? attrs['_dd.p.tid'] + lowerHex
167
+ : lowerHex.padStart(32, '0')
168
+
169
+ return {
170
+ traceId: traceIdHex,
171
+ spanId: spanIdHex,
172
+ samplingPriority: attrs['x-datadog-sampling-priority']
173
+ ? Number.parseInt(attrs['x-datadog-sampling-priority'], 10)
174
+ : undefined
175
+ }
176
+ }
177
+
178
+ #extractParentContext (data) {
179
+ const carrier = {
180
+ 'x-datadog-trace-id': data.traceId,
181
+ 'x-datadog-parent-id': data.spanId
182
+ }
183
+ if (data.traceIdUpper) carrier['_dd.p.tid'] = data.traceIdUpper
184
+ if (data.samplingPriority) carrier['x-datadog-sampling-priority'] = String(data.samplingPriority)
185
+
186
+ return this.tracer.extract('text_map', carrier)
187
+ }
41
188
  }
42
189
 
43
190
  module.exports = GoogleCloudPubsubProducerPlugin
@@ -0,0 +1,217 @@
1
+ 'use strict'
2
+
3
+ const TracingPlugin = require('../../dd-trace/src/plugins/tracing')
4
+ const SpanContext = require('../../dd-trace/src/opentracing/span_context')
5
+ const id = require('../../dd-trace/src/id')
6
+ const log = require('../../dd-trace/src/log')
7
+
8
+ // WeakMap to track push receive spans by request
9
+ const pushReceiveSpans = new WeakMap()
10
+
11
+ class GoogleCloudPubsubPushSubscriptionPlugin extends TracingPlugin {
12
+ static get id () { return 'google-cloud-pubsub-push-subscription' }
13
+
14
+ constructor (...args) {
15
+ super(...args)
16
+
17
+ /**
18
+ * PUSH SUBSCRIPTION: GCP sends HTTP POST requests to our service with message data in headers.
19
+ * We intercept these requests to create a pubsub.push.receive span that wraps the HTTP request.
20
+ *
21
+ * Flow: Detect push request -> Extract trace context -> Create receive span -> Activate it
22
+ * Hierarchy: pubsub.push.receive (parent) -> http.request (child) -> express.middleware...
23
+ *
24
+ * Plugin load order (http/index.js) ensures we subscribe before HttpServerPlugin.
25
+ */
26
+ this.addSub('apm:http:server:request:start', (ctx) => {
27
+ this.#handlePubSubRequest(ctx)
28
+ })
29
+
30
+ this.addSub('apm:http:server:request:finish', ({ req }) => {
31
+ this.#finishPushReceiveSpan(req)
32
+ })
33
+ }
34
+
35
+ #finishPushReceiveSpan (req) {
36
+ const pushReceiveSpan = pushReceiveSpans.get(req)
37
+ if (pushReceiveSpan && !pushReceiveSpan._duration) {
38
+ pushReceiveSpan.finish()
39
+ pushReceiveSpans.delete(req)
40
+ }
41
+ }
42
+
43
+ #handlePubSubRequest (ctx) {
44
+ const { req } = ctx
45
+ const userAgent = req.headers['user-agent'] || ''
46
+ if (req.method !== 'POST' || !userAgent.includes('APIs-Google')) {
47
+ return false
48
+ }
49
+
50
+ if (req.headers['x-goog-pubsub-message-id']) {
51
+ this.#createPushReceiveSpanAndActivate(ctx)
52
+ return true
53
+ }
54
+
55
+ log.warn(
56
+ '[PubSub] No x-goog-pubsub-* headers detected. pubsub.push.receive spans will not be created. ' +
57
+ 'Add --push-no-wrapper-write-metadata to your subscription.'
58
+ )
59
+ return false
60
+ }
61
+
62
+ #createPushReceiveSpanAndActivate (ctx) {
63
+ const { req, res } = ctx
64
+ const messageData = this.#parseMessage(req)
65
+ if (!messageData) {
66
+ return
67
+ }
68
+
69
+ const originalContext = this.#extractContext(messageData)
70
+ const pubsubRequestContext = this.#reconstructPubSubContext(messageData.attrs) || originalContext
71
+ const isSameTrace = pubsubRequestContext &&
72
+ originalContext?.toTraceId() === pubsubRequestContext.toTraceId()
73
+
74
+ /**
75
+ * Create receive span, choosing parent context:
76
+ * - Same trace: use batch context (message is part of the batch trace)
77
+ * - Different trace: use message context as parent, link to batch for observability
78
+ *
79
+ * this.enter() activates the span so the HTTP request span becomes its child.
80
+ */
81
+ const pushReceiveSpan = this.#createPushReceiveSpan(
82
+ messageData,
83
+ isSameTrace ? pubsubRequestContext : originalContext,
84
+ isSameTrace ? null : pubsubRequestContext
85
+ )
86
+
87
+ if (!pushReceiveSpan) {
88
+ return
89
+ }
90
+
91
+ this.enter(pushReceiveSpan, { req, res })
92
+ pushReceiveSpans.set(req, pushReceiveSpan)
93
+ }
94
+
95
+ #parseMessage (req) {
96
+ const subscription = req.headers['x-goog-pubsub-subscription-name']
97
+ const message = {
98
+ messageId: req.headers['x-goog-pubsub-message-id'],
99
+ publishTime: req.headers['x-goog-pubsub-publish-time']
100
+ }
101
+
102
+ const topicName = req.headers['pubsub.topic'] || 'push-subscription-topic'
103
+ return { message, subscription, attrs: req.headers, topicName }
104
+ }
105
+
106
+ #extractContext (messageData) {
107
+ return this.tracer.extract('text_map', messageData.attrs)
108
+ }
109
+
110
+ #reconstructPubSubContext (attrs) {
111
+ /**
112
+ * Reconstruct the batch publish span context from message attributes.
113
+ *
114
+ * When a batch is published, the producer injects:
115
+ * - _dd.pubsub_request.trace_id: lower 64 bits of the batch span's trace ID (hex)
116
+ * - _dd.pubsub_request.span_id: the batch span's span ID (hex)
117
+ * - _dd.pubsub_request.p.tid: upper 64 bits of trace ID (hex, optional for 128-bit traces)
118
+ *
119
+ * This context represents the "pubsub.request" span on the producer side.
120
+ * We use it to create span links, connecting each pubsub.push.receive span back to the original batch.
121
+ */
122
+ const traceIdLower = attrs['_dd.pubsub_request.trace_id']
123
+ const spanId = attrs['_dd.pubsub_request.span_id']
124
+ const traceIdUpper = attrs['_dd.pubsub_request.p.tid']
125
+
126
+ if (!traceIdLower || !spanId) return null
127
+
128
+ // Reconstruct full 128-bit trace ID (or pad 64-bit to 128-bit)
129
+ const traceId128 = traceIdUpper ? traceIdUpper + traceIdLower : traceIdLower.padStart(32, '0')
130
+ const traceId = id(traceId128, 16)
131
+ const parentId = id(spanId, 16)
132
+
133
+ const tags = {}
134
+ if (traceIdUpper) tags['_dd.p.tid'] = traceIdUpper
135
+
136
+ return new SpanContext({
137
+ traceId,
138
+ spanId: parentId,
139
+ tags
140
+ })
141
+ }
142
+
143
+ #createPushReceiveSpan (messageData, parentContext, linkContext) {
144
+ const { message, subscription, topicName, attrs } = messageData
145
+ const subscriptionName = subscription?.slice(subscription.lastIndexOf('/') + 1) ?? subscription
146
+ const publishStartTime = attrs['x-dd-publish-start-time']
147
+ const startTime = publishStartTime ? Number.parseInt(publishStartTime, 10) : undefined
148
+
149
+ // Get the base service name and construct the pubsub service override
150
+ const baseService = this.tracer._service
151
+ const serviceOverride = this.config.service ?? `${baseService}-pubsub`
152
+
153
+ // Use this.startSpan() which automatically activates the span
154
+ const span = this.startSpan('pubsub.push.receive', {
155
+ childOf: parentContext,
156
+ startTime,
157
+ kind: 'consumer',
158
+ service: serviceOverride,
159
+ meta: {
160
+ component: 'google-cloud-pubsub',
161
+ 'pubsub.method': 'receive',
162
+ 'pubsub.subscription': subscription,
163
+ 'pubsub.message_id': message.messageId,
164
+ 'pubsub.subscription_type': 'push',
165
+ 'pubsub.topic': topicName,
166
+ '_dd.base_service': baseService,
167
+ '_dd.serviceoverride.type': 'integration',
168
+ 'resource.name': `Push Subscription ${subscriptionName}`
169
+ }
170
+ })
171
+
172
+ if (!span) {
173
+ return null
174
+ }
175
+
176
+ span._integrationName = 'google-cloud-pubsub'
177
+ // Calculate delivery latency (queue time from publish to delivery)
178
+ if (publishStartTime) {
179
+ const deliveryDuration = Date.now() - Number(publishStartTime)
180
+ span.setTag('pubsub.delivery_duration_ms', deliveryDuration)
181
+ }
182
+
183
+ this.#addBatchMetadata(span, attrs)
184
+
185
+ if (linkContext) {
186
+ if (span.addLink) {
187
+ span.addLink(linkContext, {})
188
+ } else {
189
+ span._links ??= []
190
+ span._links.push({ context: linkContext, attributes: {} })
191
+ }
192
+ }
193
+
194
+ return span
195
+ }
196
+
197
+ #addBatchMetadata (span, attrs) {
198
+ const batchSizeStr = attrs['_dd.batch.size']
199
+ const batchIndexStr = attrs['_dd.batch.index']
200
+
201
+ if (!batchSizeStr || batchIndexStr === undefined) return
202
+
203
+ const size = Number(batchSizeStr)
204
+ const index = Number(batchIndexStr)
205
+
206
+ span.setTag('pubsub.batch.message_count', size)
207
+ span.setTag('pubsub.batch.message_index', index)
208
+ span.setTag('pubsub.batch.description', `Message ${index + 1} of ${size}`)
209
+
210
+ const requestTraceId = attrs['_dd.pubsub_request.trace_id']
211
+ if (requestTraceId) {
212
+ span.setTag('pubsub.batch.request_trace_id', requestTraceId)
213
+ }
214
+ }
215
+ }
216
+
217
+ module.exports = GoogleCloudPubsubPushSubscriptionPlugin
@@ -1,8 +1,8 @@
1
1
  'use strict'
2
2
 
3
3
  const CompositePlugin = require('../../dd-trace/src/plugins/composite')
4
- const GoogleVertexAITracingPlugin = require('./tracing')
5
4
  const VertexAILLMObsPlugin = require('../../dd-trace/src/llmobs/plugins/vertexai')
5
+ const GoogleVertexAITracingPlugin = require('./tracing')
6
6
 
7
7
  class GoogleCloudVertexAIPlugin extends CompositePlugin {
8
8
  static id = 'google-cloud-vertexai'
@@ -1,8 +1,8 @@
1
1
  'use strict'
2
2
 
3
3
  const CompositePlugin = require('../../dd-trace/src/plugins/composite')
4
- const GenAiTracingPlugin = require('./tracing')
5
4
  const GenAiLLMObsPlugin = require('../../dd-trace/src/llmobs/plugins/genai')
5
+ const GenAiTracingPlugin = require('./tracing')
6
6
 
7
7
  class GenAiPlugin extends CompositePlugin {
8
8
  static id = 'google-genai'
@@ -1,7 +1,7 @@
1
1
  'use strict'
2
2
 
3
- const TracingPlugin = require('../../dd-trace/src/plugins/tracing')
4
3
  const dc = require('dc-polyfill')
4
+ const TracingPlugin = require('../../dd-trace/src/plugins/tracing')
5
5
 
6
6
  const collapsedPathSym = Symbol('collapsedPaths')
7
7
 
@@ -1,8 +1,8 @@
1
1
  'use strict'
2
2
 
3
+ const CompositePlugin = require('../../dd-trace/src/plugins/composite')
3
4
  const GrpcServerPlugin = require('./server')
4
5
  const GrpcClientPlugin = require('./client')
5
- const CompositePlugin = require('../../dd-trace/src/plugins/composite')
6
6
 
7
7
  class GrpcPlugin extends CompositePlugin {
8
8
  static id = 'grpc'