dd-trace 5.100.0 → 5.102.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 (189) hide show
  1. package/index.d.ts +14 -0
  2. package/package.json +11 -9
  3. package/packages/datadog-instrumentations/src/aerospike.js +2 -2
  4. package/packages/datadog-instrumentations/src/ai.js +8 -8
  5. package/packages/datadog-instrumentations/src/amqplib.js +6 -7
  6. package/packages/datadog-instrumentations/src/anthropic.js +10 -10
  7. package/packages/datadog-instrumentations/src/apollo-server-core.js +3 -3
  8. package/packages/datadog-instrumentations/src/apollo-server.js +5 -5
  9. package/packages/datadog-instrumentations/src/avsc.js +6 -6
  10. package/packages/datadog-instrumentations/src/aws-sdk.js +151 -67
  11. package/packages/datadog-instrumentations/src/azure-durable-functions.js +8 -8
  12. package/packages/datadog-instrumentations/src/bluebird.js +2 -2
  13. package/packages/datadog-instrumentations/src/body-parser.js +2 -2
  14. package/packages/datadog-instrumentations/src/cassandra-driver.js +7 -7
  15. package/packages/datadog-instrumentations/src/child_process.js +12 -12
  16. package/packages/datadog-instrumentations/src/confluentinc-kafka-javascript.js +9 -9
  17. package/packages/datadog-instrumentations/src/connect.js +7 -7
  18. package/packages/datadog-instrumentations/src/cookie-parser.js +4 -4
  19. package/packages/datadog-instrumentations/src/cookie.js +2 -2
  20. package/packages/datadog-instrumentations/src/couchbase.js +16 -30
  21. package/packages/datadog-instrumentations/src/crypto.js +4 -4
  22. package/packages/datadog-instrumentations/src/cucumber.js +77 -16
  23. package/packages/datadog-instrumentations/src/cypress.js +5 -3
  24. package/packages/datadog-instrumentations/src/dns.js +0 -3
  25. package/packages/datadog-instrumentations/src/elasticsearch.js +8 -11
  26. package/packages/datadog-instrumentations/src/express-mongo-sanitize.js +6 -6
  27. package/packages/datadog-instrumentations/src/express-session.js +4 -4
  28. package/packages/datadog-instrumentations/src/express.js +10 -11
  29. package/packages/datadog-instrumentations/src/fastify.js +2 -2
  30. package/packages/datadog-instrumentations/src/fs.js +14 -14
  31. package/packages/datadog-instrumentations/src/google-cloud-pubsub.js +5 -7
  32. package/packages/datadog-instrumentations/src/google-genai.js +4 -4
  33. package/packages/datadog-instrumentations/src/grpc/server.js +2 -2
  34. package/packages/datadog-instrumentations/src/hapi.js +2 -2
  35. package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +8 -8
  36. package/packages/datadog-instrumentations/src/helpers/promise.js +2 -2
  37. package/packages/datadog-instrumentations/src/hono.js +2 -2
  38. package/packages/datadog-instrumentations/src/http/client.js +26 -9
  39. package/packages/datadog-instrumentations/src/http/server.js +9 -9
  40. package/packages/datadog-instrumentations/src/jest.js +93 -63
  41. package/packages/datadog-instrumentations/src/kafkajs.js +9 -9
  42. package/packages/datadog-instrumentations/src/knex.js +17 -17
  43. package/packages/datadog-instrumentations/src/koa.js +12 -12
  44. package/packages/datadog-instrumentations/src/ldapjs.js +5 -5
  45. package/packages/datadog-instrumentations/src/light-my-request.js +2 -2
  46. package/packages/datadog-instrumentations/src/limitd-client.js +4 -4
  47. package/packages/datadog-instrumentations/src/lodash.js +4 -4
  48. package/packages/datadog-instrumentations/src/mariadb.js +13 -13
  49. package/packages/datadog-instrumentations/src/memcached.js +2 -2
  50. package/packages/datadog-instrumentations/src/microgateway-core.js +2 -2
  51. package/packages/datadog-instrumentations/src/mocha/common.js +7 -4
  52. package/packages/datadog-instrumentations/src/mocha/main.js +37 -14
  53. package/packages/datadog-instrumentations/src/mocha/utils.js +133 -16
  54. package/packages/datadog-instrumentations/src/mocha/worker.js +12 -7
  55. package/packages/datadog-instrumentations/src/mongodb-core.js +9 -22
  56. package/packages/datadog-instrumentations/src/mongodb.js +5 -5
  57. package/packages/datadog-instrumentations/src/mongoose.js +21 -21
  58. package/packages/datadog-instrumentations/src/mquery.js +5 -5
  59. package/packages/datadog-instrumentations/src/multer.js +4 -4
  60. package/packages/datadog-instrumentations/src/mysql.js +16 -16
  61. package/packages/datadog-instrumentations/src/mysql2.js +4 -4
  62. package/packages/datadog-instrumentations/src/net.js +14 -8
  63. package/packages/datadog-instrumentations/src/nyc.js +5 -5
  64. package/packages/datadog-instrumentations/src/openai.js +19 -19
  65. package/packages/datadog-instrumentations/src/oracledb.js +6 -6
  66. package/packages/datadog-instrumentations/src/otel-sdk-trace.js +11 -6
  67. package/packages/datadog-instrumentations/src/passport-utils.js +5 -5
  68. package/packages/datadog-instrumentations/src/pg.js +15 -15
  69. package/packages/datadog-instrumentations/src/pino.js +6 -10
  70. package/packages/datadog-instrumentations/src/playwright.js +20 -15
  71. package/packages/datadog-instrumentations/src/protobufjs.js +16 -16
  72. package/packages/datadog-instrumentations/src/redis.js +1 -2
  73. package/packages/datadog-instrumentations/src/restify.js +2 -2
  74. package/packages/datadog-instrumentations/src/router.js +12 -12
  75. package/packages/datadog-instrumentations/src/stripe.js +12 -12
  76. package/packages/datadog-instrumentations/src/vitest.js +107 -26
  77. package/packages/datadog-instrumentations/src/winston.js +4 -4
  78. package/packages/datadog-instrumentations/src/ws.js +7 -7
  79. package/packages/datadog-plugin-aws-sdk/src/base.js +52 -4
  80. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +19 -12
  81. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +45 -35
  82. package/packages/datadog-plugin-aws-sdk/src/services/lambda.js +33 -22
  83. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +12 -13
  84. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +73 -54
  85. package/packages/datadog-plugin-aws-sdk/src/services/stepfunctions.js +19 -17
  86. package/packages/datadog-plugin-aws-sdk/src/util.js +22 -0
  87. package/packages/datadog-plugin-bullmq/src/consumer.js +2 -2
  88. package/packages/datadog-plugin-bullmq/src/producer.js +14 -20
  89. package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +6 -6
  90. package/packages/datadog-plugin-cucumber/src/index.js +4 -0
  91. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +18 -4
  92. package/packages/datadog-plugin-cypress/src/plugin.js +5 -14
  93. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +1 -5
  94. package/packages/datadog-plugin-google-cloud-pubsub/src/pubsub-push-subscription.js +3 -1
  95. package/packages/datadog-plugin-http/src/client.js +1 -5
  96. package/packages/datadog-plugin-jest/src/util.js +1 -2
  97. package/packages/datadog-plugin-kafkajs/src/consumer.js +2 -9
  98. package/packages/datadog-plugin-kafkajs/src/producer.js +2 -8
  99. package/packages/datadog-plugin-mocha/src/index.js +4 -0
  100. package/packages/datadog-plugin-mongodb-core/src/index.js +2 -1
  101. package/packages/datadog-plugin-openai/src/tracing.js +12 -23
  102. package/packages/datadog-plugin-playwright/src/index.js +1 -1
  103. package/packages/datadog-plugin-vitest/src/index.js +8 -1
  104. package/packages/datadog-shimmer/src/shimmer.js +7 -1
  105. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-password-rules.js +1 -1
  106. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secret-rules.js +81 -81
  107. package/packages/dd-trace/src/appsec/iast/security-controls/index.js +2 -2
  108. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugins/kafka.js +2 -2
  109. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +2 -2
  110. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +2 -2
  111. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +2 -0
  112. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/index.js +1 -3
  113. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +83 -48
  114. package/packages/dd-trace/src/appsec/index.js +21 -24
  115. package/packages/dd-trace/src/appsec/reporter.js +7 -2
  116. package/packages/dd-trace/src/appsec/rule_manager.js +4 -2
  117. package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +31 -16
  118. package/packages/dd-trace/src/ci-visibility/lage.js +2 -1
  119. package/packages/dd-trace/src/ci-visibility/requests/request.js +11 -33
  120. package/packages/dd-trace/src/config/config-types.d.ts +0 -2
  121. package/packages/dd-trace/src/config/git_properties.js +2 -2
  122. package/packages/dd-trace/src/config/index.js +1 -55
  123. package/packages/dd-trace/src/datastreams/checkpointer.js +4 -10
  124. package/packages/dd-trace/src/datastreams/encoding.js +39 -28
  125. package/packages/dd-trace/src/datastreams/index.js +2 -1
  126. package/packages/dd-trace/src/datastreams/pathway.js +29 -26
  127. package/packages/dd-trace/src/datastreams/processor.js +18 -17
  128. package/packages/dd-trace/src/datastreams/size.js +6 -2
  129. package/packages/dd-trace/src/debugger/config.js +5 -2
  130. package/packages/dd-trace/src/debugger/devtools_client/index.js +2 -5
  131. package/packages/dd-trace/src/debugger/devtools_client/send.js +2 -1
  132. package/packages/dd-trace/src/debugger/devtools_client/snapshot-pruner.js +1 -0
  133. package/packages/dd-trace/src/dogstatsd.js +10 -7
  134. package/packages/dd-trace/src/encode/0.4.js +759 -234
  135. package/packages/dd-trace/src/encode/0.5.js +15 -9
  136. package/packages/dd-trace/src/encode/agentless-json.js +2 -2
  137. package/packages/dd-trace/src/encode/tags-processors.js +2 -27
  138. package/packages/dd-trace/src/exporters/common/request.js +22 -11
  139. package/packages/dd-trace/src/exporters/common/retry.js +104 -0
  140. package/packages/dd-trace/src/git_metadata.js +66 -0
  141. package/packages/dd-trace/src/git_metadata_tagger.js +13 -5
  142. package/packages/dd-trace/src/id.js +15 -26
  143. package/packages/dd-trace/src/llmobs/constants/tags.js +2 -0
  144. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +1 -2
  145. package/packages/dd-trace/src/llmobs/plugins/anthropic/index.js +27 -16
  146. package/packages/dd-trace/src/llmobs/plugins/anthropic/util.js +3 -0
  147. package/packages/dd-trace/src/llmobs/plugins/genai/util.js +33 -13
  148. package/packages/dd-trace/src/llmobs/plugins/openai/index.js +20 -50
  149. package/packages/dd-trace/src/llmobs/sdk.js +29 -27
  150. package/packages/dd-trace/src/llmobs/span_processor.js +52 -6
  151. package/packages/dd-trace/src/llmobs/tagger.js +42 -0
  152. package/packages/dd-trace/src/llmobs/telemetry.js +29 -0
  153. package/packages/dd-trace/src/llmobs/util.js +81 -5
  154. package/packages/dd-trace/src/msgpack/chunk.js +6 -3
  155. package/packages/dd-trace/src/openfeature/noop.js +40 -36
  156. package/packages/dd-trace/src/openfeature/writers/exposures.js +33 -52
  157. package/packages/dd-trace/src/opentelemetry/active-span-proxy.js +42 -0
  158. package/packages/dd-trace/src/opentelemetry/bridge-span-base.js +106 -0
  159. package/packages/dd-trace/src/opentelemetry/context_manager.js +11 -2
  160. package/packages/dd-trace/src/opentelemetry/otlp/otlp_transformer_base.js +1 -2
  161. package/packages/dd-trace/src/opentelemetry/span-helpers.js +188 -50
  162. package/packages/dd-trace/src/opentelemetry/span.js +42 -80
  163. package/packages/dd-trace/src/opentelemetry/tracer.js +0 -22
  164. package/packages/dd-trace/src/opentracing/propagation/text_map.js +65 -27
  165. package/packages/dd-trace/src/opentracing/propagation/text_map_dsm.js +2 -11
  166. package/packages/dd-trace/src/opentracing/propagation/tracestate.js +58 -22
  167. package/packages/dd-trace/src/opentracing/span.js +56 -48
  168. package/packages/dd-trace/src/opentracing/span_context.js +1 -0
  169. package/packages/dd-trace/src/plugins/util/ci.js +1 -1
  170. package/packages/dd-trace/src/plugins/util/git-cache.js +3 -5
  171. package/packages/dd-trace/src/plugins/util/test.js +19 -7
  172. package/packages/dd-trace/src/plugins/util/url.js +1 -3
  173. package/packages/dd-trace/src/plugins/util/user-provided-git.js +1 -1
  174. package/packages/dd-trace/src/plugins/util/web.js +5 -7
  175. package/packages/dd-trace/src/priority_sampler.js +6 -4
  176. package/packages/dd-trace/src/profiling/config.js +5 -4
  177. package/packages/dd-trace/src/profiling/profilers/events.js +3 -23
  178. package/packages/dd-trace/src/profiling/profilers/wall.js +4 -5
  179. package/packages/dd-trace/src/remote_config/index.js +5 -3
  180. package/packages/dd-trace/src/runtime_metrics/index.js +2 -2
  181. package/packages/dd-trace/src/scope.js +3 -10
  182. package/packages/dd-trace/src/serverless.js +1 -4
  183. package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +7 -1
  184. package/packages/dd-trace/src/service-naming/schemas/v1/messaging.js +4 -0
  185. package/packages/dd-trace/src/span_format.js +52 -5
  186. package/packages/dd-trace/src/span_processor.js +0 -4
  187. package/packages/dd-trace/src/spanleak.js +0 -1
  188. package/packages/dd-trace/src/tracer.js +7 -7
  189. package/packages/dd-trace/src/util.js +17 -0
@@ -19,10 +19,9 @@ class DataStreamsCheckpointer {
19
19
  if (!this.config.dsmEnabled) return
20
20
 
21
21
  const ctx = this.dsmProcessor.setCheckpoint(
22
- ['type:' + type, 'topic:' + target, 'direction:out', 'manual_checkpoint:true'],
22
+ ['direction:out', 'type:' + type, 'topic:' + target, 'manual_checkpoint:true'],
23
23
  null,
24
- DataStreamsContext.getDataStreamsContext(),
25
- null
24
+ DataStreamsContext.getDataStreamsContext()
26
25
  )
27
26
  DataStreamsContext.setDataStreamsContext(ctx)
28
27
 
@@ -45,17 +44,12 @@ class DataStreamsCheckpointer {
45
44
  const parentCtx = this.tracer.extract('text_map_dsm', carrier)
46
45
  DataStreamsContext.setDataStreamsContext(parentCtx)
47
46
 
48
- const tags = ['type:' + type, 'topic:' + source, 'direction:in']
47
+ const tags = ['direction:in', 'type:' + type, 'topic:' + source]
49
48
  if (manualCheckpoint) {
50
49
  tags.push('manual_checkpoint:true')
51
50
  }
52
51
 
53
- const ctx = this.dsmProcessor.setCheckpoint(
54
- tags,
55
- null,
56
- parentCtx,
57
- null
58
- )
52
+ const ctx = this.dsmProcessor.setCheckpoint(tags, null, parentCtx)
59
53
  DataStreamsContext.setDataStreamsContext(ctx)
60
54
 
61
55
  return ctx
@@ -1,5 +1,7 @@
1
1
  'use strict'
2
2
 
3
+ const maxVarLen64 = 9
4
+
3
5
  /**
4
6
  * Encodes positive and negative numbers, using zig zag encoding to reduce the size of the variable length encoding.
5
7
  * Uses high and low part to ensure those parts are under the limit for byte operations in javascript (32 bits)
@@ -8,15 +10,45 @@
8
10
  * @returns {Uint8Array|undefined}
9
11
  */
10
12
  function encodeVarint (v) {
11
- const sign = v >= 0 ? 0 : 1
13
+ const result = new Uint8Array(maxVarLen64)
14
+ const written = encodeVarintInto(result, 0, v)
15
+ if (written === 0) {
16
+ return
17
+ }
18
+ return result.slice(0, written)
19
+ }
20
+
21
+ /**
22
+ * Writes a zig-zag varint at `target[offset..]` and returns the offset just past the last
23
+ * byte written. Returns `offset` unchanged when the value exceeds MAX_SAFE_INTEGER/2, mirroring
24
+ * the `encodeVarint` overflow contract. Used on the DSM checkpoint hot path to avoid
25
+ * per-call Uint8Array / Buffer allocations.
26
+ * @param {Uint8Array | Buffer} target
27
+ * @param {number} offset
28
+ * @param {number} value
29
+ * @returns {number}
30
+ */
31
+ function encodeVarintInto (target, offset, value) {
32
+ const sign = value >= 0 ? 0 : 1
12
33
  // We leave the least significant bit for the sign.
13
- const double = Math.abs(v) * 2
34
+ const double = Math.abs(value) * 2
14
35
  if (double > Number.MAX_SAFE_INTEGER) {
15
- return
36
+ return offset
16
37
  }
17
- const high = Math.floor(double / 0x1_00_00_00_00)
18
- const low = (double & 0xFF_FF_FF_FF) | sign
19
- return encodeUvarint64(low, high)
38
+ let high = Math.floor(double / 0x1_00_00_00_00)
39
+ let low = (double & 0xFF_FF_FF_FF) | sign
40
+ let i = offset
41
+ const limit = offset + maxVarLen64 - 1
42
+ // if first byte is 1, the number is negative in javascript, but we want to interpret it as positive
43
+ while ((high !== 0 || low < 0 || low > 0x80) && i < limit) {
44
+ target[i] = (low & 0x7F) | 0x80
45
+ low >>>= 7
46
+ low |= (high & 0x7F) << 25
47
+ high >>>= 7
48
+ i++
49
+ }
50
+ target[i] = low & 0x7F
51
+ return i + 1
20
52
  }
21
53
 
22
54
  /**
@@ -35,28 +67,6 @@ function decodeVarint (b) {
35
67
  return [positive ? abs : -abs, bytes]
36
68
  }
37
69
 
38
- const maxVarLen64 = 9
39
-
40
- /**
41
- * @param {number} low
42
- * @param {number} high
43
- * @returns {Uint8Array}
44
- */
45
- function encodeUvarint64 (low, high) {
46
- const result = new Uint8Array(maxVarLen64)
47
- let i = 0
48
- // if first byte is 1, the number is negative in javascript, but we want to interpret it as positive
49
- while ((high !== 0 || low < 0 || low > 0x80) && i < maxVarLen64 - 1) {
50
- result[i] = (low & 0x7F) | 0x80
51
- low >>>= 7
52
- low |= (high & 0x7F) << 25
53
- high >>>= 7
54
- i++
55
- }
56
- result[i] = low & 0x7F
57
- return result.slice(0, i + 1)
58
- }
59
-
60
70
  /**
61
71
  * @param {Uint8Array} bytes
62
72
  * @returns {[number|undefined, number|undefined, Uint8Array]}
@@ -95,5 +105,6 @@ function decodeUvarint64 (
95
105
 
96
106
  module.exports = {
97
107
  encodeVarint,
108
+ encodeVarintInto,
98
109
  decodeVarint,
99
110
  }
@@ -28,7 +28,8 @@ function lazyClass (classGetter, methods = [], staticMethods = []) {
28
28
  }
29
29
 
30
30
  const activate = () => {
31
- return (ActiveClass = ActiveClass || classGetter())
31
+ ActiveClass ??= classGetter()
32
+ return ActiveClass
32
33
  }
33
34
 
34
35
  for (const method of methods) {
@@ -7,18 +7,24 @@ const crypto = require('crypto')
7
7
  const { LRUCache } = require('../../../../vendor/dist/lru-cache')
8
8
  const log = require('../log')
9
9
  const pick = require('../../../datadog-core/src/utils/src/pick')
10
- const { encodeVarint, decodeVarint } = require('./encoding')
10
+ const { encodeVarintInto, decodeVarint } = require('./encoding')
11
11
 
12
12
  const cache = new LRUCache({ max: 500 })
13
13
 
14
14
  const CONTEXT_PROPAGATION_KEY = 'dd-pathway-ctx'
15
15
  const CONTEXT_PROPAGATION_KEY_BASE64 = 'dd-pathway-ctx-base64'
16
16
 
17
+ const PATHWAY_CONTEXT_BYTES = 20
18
+
19
+ // Reused across `encodePathwayContext` calls; the buffer is fully rewritten before each
20
+ // `Buffer.from(...)` copy-out so callers never observe mutation between checkpoints.
21
+ const pathwayScratch = Buffer.allocUnsafe(PATHWAY_CONTEXT_BYTES)
22
+
17
23
  const logKeys = [CONTEXT_PROPAGATION_KEY, CONTEXT_PROPAGATION_KEY_BASE64]
18
24
 
19
25
  function shaHash (checkpointString) {
20
- const hash = crypto.createHash('sha256').update(checkpointString).digest('hex').slice(0, 16)
21
- return Buffer.from(hash, 'hex')
26
+ // Copy out of the 32-byte digest so the LRU cache doesn't retain it.
27
+ return Buffer.from(crypto.createHash('sha256').update(checkpointString).digest().subarray(0, 8))
22
28
  }
23
29
 
24
30
  /**
@@ -30,30 +36,25 @@ function shaHash (checkpointString) {
30
36
  */
31
37
  function computeHash (service, env, edgeTags, parentHash, propagationHashBigInt = null) {
32
38
  edgeTags.sort()
33
- const hashableEdgeTags = edgeTags.filter(item => item !== 'manual_checkpoint:true')
34
-
35
- // Cache key includes parentHash to handle fan-in/fan-out scenarios where the same
36
- // service+env+tags+propagationHash can have different parents. This ensures we cache
37
- // the complete pathway context, not just the current node's identity.
38
- const propagationPart = propagationHashBigInt ? `:${propagationHashBigInt.toString(16)}` : ''
39
- const key = `${service}${env}${hashableEdgeTags.join('')}${parentHash}${propagationPart}`
39
+ const hashableEdgeTags = edgeTags.includes('manual_checkpoint:true')
40
+ ? edgeTags.filter(item => item !== 'manual_checkpoint:true')
41
+ : edgeTags
42
+
43
+ // The cache key includes parentHash so a fan-in node with different parents
44
+ // gets distinct cache entries; the hash input below excludes parentHash and
45
+ // gets combined with it via a second sha pass to produce the final hash.
46
+ const joinedEdgeTags = hashableEdgeTags.join('')
47
+ const propagationHex = propagationHashBigInt ? propagationHashBigInt.toString(16) : ''
48
+ const propagationPart = propagationHex ? `:${propagationHex}` : ''
49
+ const key = `${service}${env}${joinedEdgeTags}${parentHash}${propagationPart}`
40
50
 
41
51
  let value = cache.get(key)
42
52
  if (value) {
43
53
  return value
44
54
  }
45
55
 
46
- // Key vs hashInput distinction:
47
- // - 'key' (above) is used for caching and includes parentHash to differentiate pathways
48
- // with the same node but different parents (e.g., multiple queues feeding one consumer)
49
- // - 'hashInput' (below) excludes parentHash to compute only the current node's identity hash,
50
- // which is then XORed with parentHash (line 54) to build the complete pathway hash
51
- // This two-step approach (hash current node independently, then combine with parent) is
52
- // required for proper pathway construction in the DSM protocol.
53
- const baseString = `${service}${env}` + hashableEdgeTags.join('')
54
- const hashInput = propagationHashBigInt
55
- ? `${baseString}:${propagationHashBigInt.toString(16)}`
56
- : baseString
56
+ const baseString = `${service}${env}${joinedEdgeTags}`
57
+ const hashInput = propagationHex ? `${baseString}:${propagationHex}` : baseString
57
58
 
58
59
  const currentHash = shaHash(hashInput)
59
60
  const buf = Buffer.concat([currentHash, parentHash], 16)
@@ -70,11 +71,12 @@ function computeHash (service, env, edgeTags, parentHash, propagationHashBigInt
70
71
  * @returns {Buffer}
71
72
  */
72
73
  function encodePathwayContext (dataStreamsContext) {
73
- return Buffer.concat([
74
- dataStreamsContext.hash,
75
- Buffer.from(encodeVarint(Math.round(dataStreamsContext.pathwayStartNs / 1e6))),
76
- Buffer.from(encodeVarint(Math.round(dataStreamsContext.edgeStartNs / 1e6))),
77
- ], 20)
74
+ let offset = dataStreamsContext.hash.copy(pathwayScratch, 0)
75
+ offset = encodeVarintInto(pathwayScratch, offset, Math.round(dataStreamsContext.pathwayStartNs / 1e6))
76
+ offset = encodeVarintInto(pathwayScratch, offset, Math.round(dataStreamsContext.edgeStartNs / 1e6))
77
+ // No-op when offset >= PATHWAY_CONTEXT_BYTES; otherwise pads stale bytes from a previous call.
78
+ pathwayScratch.fill(0, offset, PATHWAY_CONTEXT_BYTES)
79
+ return Buffer.from(pathwayScratch.subarray(0, PATHWAY_CONTEXT_BYTES))
78
80
  }
79
81
 
80
82
  /**
@@ -178,6 +180,7 @@ const DsmPathwayCodec = {
178
180
  }
179
181
 
180
182
  module.exports = {
183
+ CONTEXT_PROPAGATION_KEY_BASE64,
181
184
  computePathwayHash: computeHash,
182
185
  encodePathwayContext,
183
186
  decodePathwayContext,
@@ -8,15 +8,21 @@ const { PATHWAY_HASH, DSM_TRANSACTION_ID, DSM_TRANSACTION_CHECKPOINT } = require
8
8
  const log = require('../log')
9
9
  const processTags = require('../process-tags')
10
10
  const propagationHash = require('../propagation-hash')
11
- const { DsmPathwayCodec } = require('./pathway')
11
+ const { CONTEXT_PROPAGATION_KEY_BASE64, computePathwayHash } = require('./pathway')
12
12
  const { DataStreamsWriter } = require('./writer')
13
- const { computePathwayHash } = require('./pathway')
14
13
  const { getAmqpMessageSize, getHeadersSize, getMessageSize, getSizeOrZero } = require('./size')
15
14
  const { SchemaBuilder } = require('./schemas/schema_builder')
16
15
  const { SchemaSampler } = require('./schemas/schema_sampler')
17
16
 
18
17
  const ENTRY_PARENT_HASH = Buffer.from('0000000000000000', 'hex')
19
18
 
19
+ // A direction:out checkpoint estimates the size cost of the header the
20
+ // producer plugin will inject. The pathway context is always 20 binary
21
+ // bytes, encoded as 28 base64 chars; together with the header key and
22
+ // JSON framing (matching the prior `JSON.stringify({key: value})` byte
23
+ // count minus 1), this is a fixed value.
24
+ const PATHWAY_HEADER_BYTES = CONTEXT_PROPAGATION_KEY_BASE64.length + 28 + 6
25
+
20
26
  class StatsPoint {
21
27
  constructor (hash, parentHash, edgeTags) {
22
28
  this.hash = hash.readBigUInt64LE()
@@ -265,25 +271,24 @@ class DataStreamsProcessor {
265
271
  */
266
272
  bucketFromTimestamp (timestamp) {
267
273
  const bucketTime = Math.round(timestamp - (timestamp % this.bucketSizeNs))
268
- const bucket = this.buckets.forTime(bucketTime)
269
- return bucket
274
+ return this.buckets.forTime(bucketTime)
270
275
  }
271
276
 
272
277
  recordCheckpoint (checkpoint, span = null) {
273
278
  if (!this.enabled) return
274
- this.bucketFromTimestamp(checkpoint.currentTimestamp)
275
- .forCheckpoint(checkpoint)
276
- .addLatencies(checkpoint)
277
- // set DSM pathway hash on span to enable related traces feature on DSM tab, convert from buffer to uint64
279
+ const statsPoint = this.bucketFromTimestamp(checkpoint.currentTimestamp).forCheckpoint(checkpoint)
280
+ statsPoint.addLatencies(checkpoint)
278
281
  if (span) {
279
- span.setTag(PATHWAY_HASH, checkpoint.hash.readBigUInt64LE(0).toString())
282
+ // StatsPoint already converted the 8-byte Buffer hash to a uint64 BigInt.
283
+ span.setTag(PATHWAY_HASH, statsPoint.hash.toString())
280
284
  }
281
285
  }
282
286
 
283
- setCheckpoint (edgeTags, span, ctx = null, payloadSize = 0) {
284
- if (!this.enabled) return null
287
+ setCheckpoint (edgeTags, span, ctx, payloadSize = 0) {
288
+ if (!this.enabled) return
285
289
  const nowNs = Date.now() * 1e6
286
- const direction = edgeTags.find(t => t.startsWith('direction:'))
290
+ // Callers must place the direction tag at index 0.
291
+ const direction = edgeTags[0]
287
292
  let pathwayStartNs = nowNs
288
293
  let edgeStartNs = nowNs
289
294
  let parentHash = ENTRY_PARENT_HASH
@@ -334,11 +339,7 @@ class DataStreamsProcessor {
334
339
  closestOppositeDirectionEdgeStart,
335
340
  }
336
341
  if (direction === 'direction:out') {
337
- // Add the header for this now, as the callee doesn't have access to context when producing
338
- // - 1 to account for extra byte for {
339
- const ddInfoContinued = {}
340
- DsmPathwayCodec.encode(dataStreamsContext, ddInfoContinued)
341
- payloadSize += getSizeOrZero(JSON.stringify(ddInfoContinued)) - 1
342
+ payloadSize += PATHWAY_HEADER_BYTES
342
343
  }
343
344
  const checkpoint = {
344
345
  currentTimestamp: nowNs,
@@ -4,7 +4,7 @@ const { types } = require('util')
4
4
 
5
5
  function getSizeOrZero (obj) {
6
6
  if (typeof obj === 'string') {
7
- return Buffer.from(obj, 'utf8').length
7
+ return Buffer.byteLength(obj, 'utf8')
8
8
  }
9
9
  if (types.isArrayBuffer(obj)) {
10
10
  return obj.byteLength
@@ -32,7 +32,11 @@ function getSizeOrZero (obj) {
32
32
 
33
33
  function getHeadersSize (headers) {
34
34
  if (headers === undefined) return 0
35
- return Object.entries(headers).reduce((prev, [key, val]) => getSizeOrZero(key) + getSizeOrZero(val) + prev, 0)
35
+ let size = 0
36
+ for (const key of Object.keys(headers)) {
37
+ size += Buffer.byteLength(key, 'utf8') + getSizeOrZero(headers[key])
38
+ }
39
+ return size
36
40
  }
37
41
 
38
42
  function getMessageSize (message) {
@@ -1,8 +1,11 @@
1
1
  'use strict'
2
2
 
3
+ const getGitMetadata = require('../git_metadata')
4
+
3
5
  module.exports = function getDebuggerConfig (config, inputPath) {
6
+ const { commitSHA, repositoryUrl } = getGitMetadata(config)
4
7
  return {
5
- commitSHA: config.commitSHA,
8
+ commitSHA,
6
9
  debug: config.debug,
7
10
  dynamicInstrumentation: config.dynamicInstrumentation,
8
11
  env: config.env,
@@ -10,7 +13,7 @@ module.exports = function getDebuggerConfig (config, inputPath) {
10
13
  logLevel: config.logLevel,
11
14
  port: config.port,
12
15
  propagateProcessTags: { enabled: config.DD_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED },
13
- repositoryUrl: config.repositoryUrl,
16
+ repositoryUrl,
14
17
  runtimeId: config.tags['runtime-id'],
15
18
  service: config.service,
16
19
  url: config.url?.toString(),
@@ -247,10 +247,6 @@ session.on('Debugger.paused', async ({ params }) => {
247
247
  language: 'javascript',
248
248
  }
249
249
 
250
- if (config.propagateProcessTags.enabled) {
251
- snapshot[processTags.DYNAMIC_INSTRUMENTATION_FIELD_NAME] = processTags.tagsObject
252
- }
253
-
254
250
  if (probe.captureSnapshot) {
255
251
  if (fatalSnapshotErrors && fatalSnapshotErrors.length > 0) {
256
252
  // There was an error collecting the snapshot for this probe, let's not try again
@@ -327,7 +323,8 @@ session.on('Debugger.paused', async ({ params }) => {
327
323
 
328
324
  ackEmitting(probe)
329
325
 
330
- send(message, logger, dd, snapshot)
326
+ send(message, logger, dd, snapshot,
327
+ config.propagateProcessTags.enabled ? processTags.serialized : undefined)
331
328
  }
332
329
  })
333
330
 
@@ -40,7 +40,7 @@ const jsonBuffer = new JSONBuffer({
40
40
  onFlush,
41
41
  })
42
42
 
43
- function send (message, logger, dd, snapshot) {
43
+ function send (message, logger, dd, snapshot, processTags) {
44
44
  const payload = {
45
45
  ddsource,
46
46
  hostname,
@@ -50,6 +50,7 @@ function send (message, logger, dd, snapshot) {
50
50
  : message,
51
51
  logger,
52
52
  dd,
53
+ process_tags: processTags,
53
54
  debugger: { snapshot },
54
55
  }
55
56
 
@@ -175,6 +175,7 @@ function parseJsonToTree (json) {
175
175
  switch (json.charCodeAt(index)) {
176
176
  case 34: { // 34: double quote
177
177
  const stringStart = index + 1
178
+ // eslint-disable-next-line sonarjs/updated-loop-counter -- skip past the string token
178
179
  index = skipString(json, index)
179
180
  const stringLength = index - stringStart
180
181
 
@@ -22,6 +22,7 @@ const TYPE_HISTOGRAM = 'h'
22
22
  */
23
23
  class DogStatsDClient {
24
24
  #lookup
25
+ #tagsPrefix
25
26
  constructor (options) {
26
27
  this.#lookup = options.lookup
27
28
  if (options.metricsProxyUrl) {
@@ -36,6 +37,7 @@ class DogStatsDClient {
36
37
  this._family = isIP(this._host)
37
38
  this._port = options.port
38
39
  this._tags = options.tags
40
+ this.#tagsPrefix = this._tags?.length ? `|#${this._tags.join(',')}` : ''
39
41
  this._queue = []
40
42
  this._buffer = ''
41
43
  this._offset = 0
@@ -66,9 +68,9 @@ class DogStatsDClient {
66
68
  flush () {
67
69
  const queue = this._enqueue()
68
70
 
69
- log.debug('Flushing %s metrics via', queue.length, this._httpOptions ? 'HTTP' : 'UDP')
71
+ if (queue.length === 0) return
70
72
 
71
- if (this._queue.length === 0) return
73
+ log.debug('Flushing %s metrics via %s', queue.length, this._httpOptions ? 'HTTP' : 'UDP')
72
74
 
73
75
  this._queue = []
74
76
 
@@ -119,11 +121,12 @@ class DogStatsDClient {
119
121
  _add (stat, value, type, tags) {
120
122
  let message = `${stat}:${value}|${type}`
121
123
 
122
- // Don't manipulate this._tags as it is still used
123
- tags = tags ? [...this._tags, ...tags] : this._tags
124
-
125
- if (tags.length > 0) {
126
- message += `|#${tags.join(',')}`
124
+ if (tags?.length) {
125
+ message += this.#tagsPrefix
126
+ ? `${this.#tagsPrefix},${tags.join(',')}`
127
+ : `|#${tags.join(',')}`
128
+ } else {
129
+ message += this.#tagsPrefix
127
130
  }
128
131
 
129
132
  if (entityId) {