dd-trace 5.104.0 → 5.106.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 (159) hide show
  1. package/LICENSE-3rdparty.csv +90 -102
  2. package/index.d.ts +82 -3
  3. package/package.json +15 -15
  4. package/packages/datadog-core/src/storage.js +1 -1
  5. package/packages/datadog-instrumentations/src/aerospike.js +1 -1
  6. package/packages/datadog-instrumentations/src/ai.js +8 -7
  7. package/packages/datadog-instrumentations/src/aws-sdk.js +16 -2
  8. package/packages/datadog-instrumentations/src/azure-cosmos.js +7 -0
  9. package/packages/datadog-instrumentations/src/azure-functions.js +3 -0
  10. package/packages/datadog-instrumentations/src/cucumber-worker-threads.js +19 -0
  11. package/packages/datadog-instrumentations/src/cucumber.js +390 -157
  12. package/packages/datadog-instrumentations/src/dns.js +54 -18
  13. package/packages/datadog-instrumentations/src/fastify.js +142 -82
  14. package/packages/datadog-instrumentations/src/graphql.js +188 -62
  15. package/packages/datadog-instrumentations/src/helpers/ai-messages.js +322 -14
  16. package/packages/datadog-instrumentations/src/helpers/hooks.js +4 -0
  17. package/packages/datadog-instrumentations/src/helpers/instrument.js +2 -1
  18. package/packages/datadog-instrumentations/src/helpers/openai-ai-guard.js +269 -0
  19. package/packages/datadog-instrumentations/src/helpers/promise-instrumentor.js +42 -0
  20. package/packages/datadog-instrumentations/src/helpers/register.js +1 -1
  21. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +2 -3
  22. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/azure-cosmos.js +50 -0
  23. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +2 -0
  24. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/langgraph.js +4 -2
  25. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +85 -0
  26. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +37 -236
  27. package/packages/datadog-instrumentations/src/hono.js +54 -3
  28. package/packages/datadog-instrumentations/src/http/server.js +9 -4
  29. package/packages/datadog-instrumentations/src/jest/coverage-backfill.js +163 -0
  30. package/packages/datadog-instrumentations/src/jest.js +360 -150
  31. package/packages/datadog-instrumentations/src/kafkajs.js +120 -16
  32. package/packages/datadog-instrumentations/src/mocha/main.js +128 -17
  33. package/packages/datadog-instrumentations/src/nats.js +182 -0
  34. package/packages/datadog-instrumentations/src/nyc.js +38 -1
  35. package/packages/datadog-instrumentations/src/openai.js +33 -18
  36. package/packages/datadog-instrumentations/src/oracledb.js +6 -1
  37. package/packages/datadog-instrumentations/src/pino.js +17 -5
  38. package/packages/datadog-instrumentations/src/playwright.js +515 -292
  39. package/packages/datadog-instrumentations/src/router.js +76 -32
  40. package/packages/datadog-instrumentations/src/stripe.js +1 -1
  41. package/packages/datadog-plugin-avsc/src/schema_iterator.js +1 -1
  42. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/tracing.js +1 -1
  43. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +218 -4
  44. package/packages/datadog-plugin-azure-cosmos/src/index.js +144 -0
  45. package/packages/datadog-plugin-azure-event-hubs/src/producer.js +1 -1
  46. package/packages/datadog-plugin-azure-functions/src/index.js +5 -2
  47. package/packages/datadog-plugin-azure-service-bus/src/producer.js +1 -1
  48. package/packages/datadog-plugin-bunyan/src/index.js +28 -0
  49. package/packages/datadog-plugin-cucumber/src/index.js +17 -3
  50. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +199 -28
  51. package/packages/datadog-plugin-cypress/src/support.js +69 -1
  52. package/packages/datadog-plugin-dns/src/lookup.js +8 -6
  53. package/packages/datadog-plugin-google-cloud-pubsub/src/pubsub-push-subscription.js +1 -1
  54. package/packages/datadog-plugin-graphql/src/execute.js +2 -0
  55. package/packages/datadog-plugin-graphql/src/resolve.js +64 -67
  56. package/packages/datadog-plugin-http/src/server.js +40 -15
  57. package/packages/datadog-plugin-jest/src/index.js +11 -3
  58. package/packages/datadog-plugin-jest/src/util.js +15 -8
  59. package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +1 -1
  60. package/packages/datadog-plugin-kafkajs/src/producer.js +3 -0
  61. package/packages/datadog-plugin-langgraph/src/stream.js +1 -1
  62. package/packages/datadog-plugin-mocha/src/index.js +19 -4
  63. package/packages/datadog-plugin-mongodb-core/src/index.js +281 -40
  64. package/packages/datadog-plugin-nats/src/consumer.js +43 -0
  65. package/packages/datadog-plugin-nats/src/index.js +20 -0
  66. package/packages/datadog-plugin-nats/src/producer.js +62 -0
  67. package/packages/datadog-plugin-nats/src/util.js +33 -0
  68. package/packages/datadog-plugin-next/src/index.js +5 -3
  69. package/packages/datadog-plugin-openai/src/tracing.js +15 -2
  70. package/packages/datadog-plugin-oracledb/src/index.js +13 -2
  71. package/packages/datadog-plugin-pino/src/index.js +42 -0
  72. package/packages/datadog-plugin-playwright/src/index.js +4 -4
  73. package/packages/datadog-plugin-protobufjs/src/schema_iterator.js +1 -1
  74. package/packages/datadog-plugin-rhea/src/producer.js +1 -1
  75. package/packages/datadog-plugin-router/src/index.js +33 -44
  76. package/packages/datadog-plugin-selenium/src/index.js +1 -1
  77. package/packages/datadog-plugin-vitest/src/index.js +5 -13
  78. package/packages/datadog-plugin-winston/src/index.js +30 -0
  79. package/packages/datadog-shimmer/src/shimmer.js +33 -40
  80. package/packages/dd-trace/src/aiguard/index.js +1 -1
  81. package/packages/dd-trace/src/aiguard/sdk.js +1 -1
  82. package/packages/dd-trace/src/appsec/api_security_sampler.js +1 -1
  83. package/packages/dd-trace/src/appsec/index.js +1 -1
  84. package/packages/dd-trace/src/appsec/reporter.js +5 -6
  85. package/packages/dd-trace/src/appsec/sdk/user_blocking.js +1 -1
  86. package/packages/dd-trace/src/appsec/sdk/utils.js +1 -1
  87. package/packages/dd-trace/src/appsec/user_tracking.js +5 -4
  88. package/packages/dd-trace/src/baggage.js +7 -1
  89. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +0 -1
  90. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +25 -13
  91. package/packages/dd-trace/src/ci-visibility/test-optimization-cache.js +70 -6
  92. package/packages/dd-trace/src/config/generated-config-types.d.ts +6 -2
  93. package/packages/dd-trace/src/config/supported-configurations.json +27 -8
  94. package/packages/dd-trace/src/datastreams/writer.js +2 -4
  95. package/packages/dd-trace/src/debugger/devtools_client/condition.js +5 -8
  96. package/packages/dd-trace/src/encode/0.4.js +124 -108
  97. package/packages/dd-trace/src/encode/0.5.js +114 -26
  98. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +31 -23
  99. package/packages/dd-trace/src/encode/agentless-json.js +4 -2
  100. package/packages/dd-trace/src/encode/coverage-ci-visibility.js +32 -13
  101. package/packages/dd-trace/src/encode/span-stats.js +16 -16
  102. package/packages/dd-trace/src/encode/tags-processors.js +16 -0
  103. package/packages/dd-trace/src/id.js +15 -0
  104. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +92 -6
  105. package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +43 -21
  106. package/packages/dd-trace/src/llmobs/plugins/genai/index.js +1 -1
  107. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +1 -1
  108. package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +9 -7
  109. package/packages/dd-trace/src/llmobs/plugins/langgraph/index.js +1 -1
  110. package/packages/dd-trace/src/llmobs/plugins/openai/index.js +1 -1
  111. package/packages/dd-trace/src/llmobs/sdk.js +0 -16
  112. package/packages/dd-trace/src/llmobs/span_processor.js +3 -3
  113. package/packages/dd-trace/src/llmobs/tagger.js +9 -1
  114. package/packages/dd-trace/src/llmobs/telemetry.js +1 -1
  115. package/packages/dd-trace/src/llmobs/util.js +66 -3
  116. package/packages/dd-trace/src/log/index.js +1 -1
  117. package/packages/dd-trace/src/msgpack/chunk.js +394 -10
  118. package/packages/dd-trace/src/msgpack/index.js +96 -2
  119. package/packages/dd-trace/src/openfeature/encoding.js +70 -0
  120. package/packages/dd-trace/src/openfeature/flagging_provider.js +20 -0
  121. package/packages/dd-trace/src/openfeature/span-enrichment-hook.js +143 -0
  122. package/packages/dd-trace/src/openfeature/span-enrichment.js +149 -0
  123. package/packages/dd-trace/src/opentelemetry/span-helpers.js +4 -3
  124. package/packages/dd-trace/src/opentelemetry/span.js +1 -1
  125. package/packages/dd-trace/src/opentelemetry/trace/otlp_transformer.js +22 -3
  126. package/packages/dd-trace/src/opentracing/propagation/log.js +18 -7
  127. package/packages/dd-trace/src/opentracing/propagation/text_map.js +64 -77
  128. package/packages/dd-trace/src/opentracing/span.js +59 -19
  129. package/packages/dd-trace/src/opentracing/span_context.js +50 -3
  130. package/packages/dd-trace/src/plugins/ci_plugin.js +20 -20
  131. package/packages/dd-trace/src/plugins/database.js +7 -6
  132. package/packages/dd-trace/src/plugins/index.js +4 -0
  133. package/packages/dd-trace/src/plugins/log_injection.js +56 -0
  134. package/packages/dd-trace/src/plugins/log_plugin.js +3 -48
  135. package/packages/dd-trace/src/plugins/outbound.js +1 -1
  136. package/packages/dd-trace/src/plugins/plugin.js +15 -17
  137. package/packages/dd-trace/src/plugins/tracing.js +43 -5
  138. package/packages/dd-trace/src/plugins/util/test.js +236 -13
  139. package/packages/dd-trace/src/plugins/util/web.js +79 -65
  140. package/packages/dd-trace/src/priority_sampler.js +2 -2
  141. package/packages/dd-trace/src/profiling/config.js +10 -23
  142. package/packages/dd-trace/src/profiling/exporters/agent.js +11 -10
  143. package/packages/dd-trace/src/profiling/profiler.js +21 -11
  144. package/packages/dd-trace/src/profiling/profilers/wall.js +12 -7
  145. package/packages/dd-trace/src/sampling_rule.js +7 -7
  146. package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +10 -0
  147. package/packages/dd-trace/src/service-naming/schemas/v1/messaging.js +8 -0
  148. package/packages/dd-trace/src/service-naming/source-resolver.js +46 -0
  149. package/packages/dd-trace/src/span_format.js +190 -58
  150. package/packages/dd-trace/src/spanleak.js +1 -1
  151. package/packages/dd-trace/src/standalone/index.js +3 -3
  152. package/packages/dd-trace/src/tagger.js +0 -2
  153. package/vendor/dist/@apm-js-collab/code-transformer/index.js +70 -39
  154. package/vendor/dist/@datadog/sketches-js/LICENSE +10 -36
  155. package/vendor/dist/@datadog/sketches-js/index.js +1 -1
  156. package/vendor/dist/protobufjs/index.js +1 -1
  157. package/vendor/dist/protobufjs/minimal/index.js +1 -1
  158. package/packages/dd-trace/src/msgpack/encoder.js +0 -308
  159. package/packages/dd-trace/src/plugins/structured_log_plugin.js +0 -9
@@ -6,10 +6,18 @@ const { AgentEncoder: BaseEncoder, stringifySpanEvents } = require('./0.4')
6
6
  const ARRAY_OF_TWO = 0x92
7
7
  const ARRAY_OF_TWELVE = 0x9C
8
8
 
9
+ // Per-span fused head: `[0x9C, service-idx, name-idx, resource-idx,
10
+ // trace-id, span-id, parent-id]` — three uint32 indexes (5 bytes each) +
11
+ // three uint64 IDs (9 bytes each) + the array marker. Replaces seven
12
+ // separate reserves (`writeByte` + 3 × `writeInteger` + 3 × `_encodeId`)
13
+ // with one block-sized reserve per span.
14
+ const HEAD_BLOCK_SIZE = 1 + 5 * 3 + 9 * 3
15
+
9
16
  function formatSpan (span) {
10
17
  span = normalizeSpan(span)
11
18
  // v0.5 has no native span_events slot; always serialize as a meta tag.
12
19
  if (span.span_events) {
20
+ // TODO: this is a costly operation. Consolidate this with the formatter
13
21
  span.meta.events = stringifySpanEvents(span.span_events)
14
22
  // `= undefined` over `delete` to keep the span's hidden class.
15
23
  span.span_events = undefined
@@ -35,20 +43,36 @@ class AgentEncoder extends BaseEncoder {
35
43
  }
36
44
 
37
45
  _encode (bytes, trace) {
38
- this._encodeArrayPrefix(bytes, trace)
46
+ bytes.writeArrayPrefix(trace)
47
+
48
+ const stringMap = this._stringMap
39
49
 
40
50
  for (let span of trace) {
41
51
  span = formatSpan(span)
42
- this._encodeByte(bytes, ARRAY_OF_TWELVE)
43
- this._encodeString(bytes, span.service)
44
- this._encodeString(bytes, span.name)
45
- this._encodeString(bytes, span.resource)
46
- this._encodeId(bytes, span.trace_id)
47
- this._encodeId(bytes, span.span_id)
48
- this._encodeId(bytes, span.parent_id)
49
- this._encodeIntOrFloat(bytes, span.start || 0)
50
- this._encodeIntOrFloat(bytes, span.duration || 0)
51
- this._encodeIntOrFloat(bytes, span.error)
52
+
53
+ // Resolve the three head string indices up front. `_cacheString`
54
+ // writes into `_stringBytes`, an independent chunk, so the side
55
+ // effect is safe to interleave with the `_traceBytes` reserve
56
+ // below.
57
+ const serviceIndex = stringMap[span.service] ?? this._cacheString(span.service)
58
+ const nameIndex = stringMap[span.name] ?? this._cacheString(span.name)
59
+ const resourceIndex = stringMap[span.resource] ?? this._cacheString(span.resource)
60
+
61
+ const blockOffset = bytes.length
62
+ bytes.reserve(HEAD_BLOCK_SIZE)
63
+ const target = bytes.buffer
64
+
65
+ target[blockOffset] = ARRAY_OF_TWELVE
66
+ let cursor = this.#writeIndexAt(target, blockOffset + 1, serviceIndex)
67
+ cursor = this.#writeIndexAt(target, cursor, nameIndex)
68
+ cursor = this.#writeIndexAt(target, cursor, resourceIndex)
69
+ cursor = this.#writeIdAt(target, cursor, span.trace_id)
70
+ cursor = this.#writeIdAt(target, cursor, span.span_id)
71
+ this.#writeIdAt(target, cursor, span.parent_id)
72
+
73
+ bytes.writeIntOrFloat(span.start || 0)
74
+ bytes.writeIntOrFloat(span.duration || 0)
75
+ bytes.writeIntOrFloat(span.error)
52
76
  this._encodeMap(bytes, span.meta || {})
53
77
  this._encodeMap(bytes, span.metrics || {})
54
78
  this._encodeString(bytes, span.type)
@@ -65,18 +89,41 @@ class AgentEncoder extends BaseEncoder {
65
89
  bytes.reserve(5)
66
90
  bytes.buffer[offset] = 0xDF
67
91
 
92
+ const stringMap = this._stringMap
68
93
  let count = 0
69
94
  for (const key of Object.keys(value)) {
70
95
  const entryValue = value[key]
96
+ if (typeof entryValue !== 'string' && typeof entryValue !== 'number') continue
97
+
98
+ const keyIndex = stringMap[key] ?? this._cacheString(key)
99
+ const writeOffset = bytes.length
100
+
71
101
  if (typeof entryValue === 'string') {
72
- this._encodeString(bytes, key)
73
- this._encodeString(bytes, entryValue)
74
- count++
75
- } else if (typeof entryValue === 'number') {
76
- this._encodeString(bytes, key)
77
- this._encodeIntOrFloat(bytes, entryValue)
78
- count++
102
+ // Both halves are uint32 indices on the v0.5 wire — known
103
+ // size, so the key and value pair fuses into one reserve.
104
+ const valueIndex = stringMap[entryValue] ?? this._cacheString(entryValue)
105
+ bytes.reserve(10)
106
+ const target = bytes.buffer
107
+ this.#writeIndexAt(target, writeOffset, keyIndex)
108
+ this.#writeIndexAt(target, writeOffset + 5, valueIndex)
109
+ } else {
110
+ // Speculate that the value is a positive fixint (0..127). The
111
+ // metrics map is mostly small unsigned integers (sample priority,
112
+ // `_dd.measured`, attribute counts), so one reserve covers the
113
+ // key (5 bytes) and the value (1 byte). Misses rewind the
114
+ // speculative value byte and route the value through the full
115
+ // encoder so the wire still picks the shortest valid encoding.
116
+ bytes.reserve(6)
117
+ const target = bytes.buffer
118
+ this.#writeIndexAt(target, writeOffset, keyIndex)
119
+ if (entryValue === (entryValue & 0x7F)) {
120
+ target[writeOffset + 5] = entryValue
121
+ } else {
122
+ bytes.length = writeOffset + 5
123
+ bytes.writeIntOrFloat(entryValue)
124
+ }
79
125
  }
126
+ count++
80
127
  }
81
128
 
82
129
  const target = bytes.buffer
@@ -87,20 +134,18 @@ class AgentEncoder extends BaseEncoder {
87
134
  }
88
135
 
89
136
  _encodeString (bytes, value = '') {
137
+ const index = this._stringMap[value] ?? this._cacheString(value)
138
+ bytes.writeInteger(index)
139
+ }
140
+
141
+ _cacheString (value) {
90
142
  let index = this._stringMap[value]
91
143
  if (index === undefined) {
92
144
  index = this._stringCount++
93
145
  this._stringMap[value] = index
94
146
  this._stringBytes.write(value)
95
147
  }
96
- this._encodeInteger(bytes, index)
97
- }
98
-
99
- _cacheString (value) {
100
- if (this._stringMap[value] === undefined) {
101
- this._stringMap[value] = this._stringCount++
102
- this._stringBytes.write(value)
103
- }
148
+ return index
104
149
  }
105
150
 
106
151
  _writeStrings (buffer, offset) {
@@ -109,6 +154,49 @@ class AgentEncoder extends BaseEncoder {
109
154
 
110
155
  return offset
111
156
  }
157
+
158
+ /**
159
+ * Write `[0xCE, uint32(index)]` into `target` at `offset` and return the
160
+ * new cursor. Caller is responsible for having reserved enough room.
161
+ *
162
+ * @param {Uint8Array} target
163
+ * @param {number} offset
164
+ * @param {number} index
165
+ * @returns {number}
166
+ */
167
+ #writeIndexAt (target, offset, index) {
168
+ target[offset] = 0xCE
169
+ target[offset + 1] = index >> 24
170
+ target[offset + 2] = index >> 16
171
+ target[offset + 3] = index >> 8
172
+ target[offset + 4] = index
173
+ return offset + 5
174
+ }
175
+
176
+ /**
177
+ * Write `[0xCF, uint64(id)]` into `target` at `offset` and return the
178
+ * new cursor. The id is truncated to the low 8 bytes, matching the
179
+ * inherited `_encodeId` behavior.
180
+ *
181
+ * @param {Uint8Array} target
182
+ * @param {number} offset
183
+ * @param {{ toBuffer: () => Uint8Array | number[] }} identifier
184
+ * @returns {number}
185
+ */
186
+ #writeIdAt (target, offset, identifier) {
187
+ target[offset] = 0xCF
188
+ const idBuffer = identifier.toBuffer()
189
+ const start = idBuffer.length - 8
190
+ target[offset + 1] = idBuffer[start]
191
+ target[offset + 2] = idBuffer[start + 1]
192
+ target[offset + 3] = idBuffer[start + 2]
193
+ target[offset + 4] = idBuffer[start + 3]
194
+ target[offset + 5] = idBuffer[start + 4]
195
+ target[offset + 6] = idBuffer[start + 5]
196
+ target[offset + 7] = idBuffer[start + 6]
197
+ target[offset + 8] = idBuffer[start + 7]
198
+ return offset + 9
199
+ }
112
200
  }
113
201
 
114
202
  module.exports = { AgentEncoder }
@@ -9,7 +9,7 @@ const {
9
9
  } = require('../ci-visibility/telemetry')
10
10
  const { MsgpackChunk } = require('../msgpack')
11
11
  const { AgentEncoder } = require('./0.4')
12
- const { truncateSpan, normalizeSpan } = require('./tags-processors')
12
+ const { truncateSpanTestOpt, normalizeSpan } = require('./tags-processors')
13
13
 
14
14
  const ENCODING_VERSION = 1
15
15
  const ALLOWED_CONTENT_TYPES = new Set(['test_session_end', 'test_module_end', 'test_suite_end', 'test'])
@@ -32,7 +32,7 @@ function formatSpan (span) {
32
32
  return {
33
33
  type: ALLOWED_CONTENT_TYPES.has(span.type) ? span.type : 'span',
34
34
  version: encodingVersion,
35
- content: normalizeSpan(truncateSpan(span)),
35
+ content: normalizeSpan(truncateSpanTestOpt(span)),
36
36
  }
37
37
  }
38
38
 
@@ -48,11 +48,18 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
48
48
  this._eventCount = 0
49
49
 
50
50
  this.metadataTags = {}
51
+ this.wildcardMetadataTags = {}
51
52
 
52
53
  this.reset()
53
54
  }
54
55
 
55
56
  addMetadataTags (tags) {
57
+ if (tags['*']) {
58
+ this.wildcardMetadataTags = {
59
+ ...this.wildcardMetadataTags,
60
+ ...tags['*'],
61
+ }
62
+ }
56
63
  for (const type of ALLOWED_CONTENT_TYPES) {
57
64
  if (tags[type]) {
58
65
  this.metadataTags[type] = {
@@ -70,7 +77,7 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
70
77
  keysLength++
71
78
  }
72
79
 
73
- this._encodeMapPrefix(bytes, keysLength)
80
+ bytes.writeMapPrefix(keysLength)
74
81
  this._encodeString(bytes, 'type')
75
82
  this._encodeString(bytes, content.type)
76
83
 
@@ -90,7 +97,7 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
90
97
  }
91
98
 
92
99
  this._encodeString(bytes, 'error')
93
- this._encodeNumber(bytes, content.error)
100
+ bytes.writeNumber(content.error)
94
101
  this._encodeString(bytes, 'name')
95
102
  this._encodeString(bytes, content.name)
96
103
  this._encodeString(bytes, 'service')
@@ -98,9 +105,9 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
98
105
  this._encodeString(bytes, 'resource')
99
106
  this._encodeString(bytes, content.resource)
100
107
  this._encodeString(bytes, 'start')
101
- this._encodeNumber(bytes, content.start)
108
+ bytes.writeNumber(content.start)
102
109
  this._encodeString(bytes, 'duration')
103
- this._encodeNumber(bytes, content.duration)
110
+ bytes.writeNumber(content.duration)
104
111
  this._encodeString(bytes, 'meta')
105
112
  this._encodeMap(bytes, content.meta)
106
113
  this._encodeString(bytes, 'metrics')
@@ -108,7 +115,7 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
108
115
  }
109
116
 
110
117
  _encodeTestModule (bytes, content) {
111
- this._encodeMapPrefix(bytes, TEST_MODULE_KEYS_LENGTH)
118
+ bytes.writeMapPrefix(TEST_MODULE_KEYS_LENGTH)
112
119
  this._encodeString(bytes, 'type')
113
120
  this._encodeString(bytes, content.type)
114
121
 
@@ -119,7 +126,7 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
119
126
  this._encodeId(bytes, content.span_id)
120
127
 
121
128
  this._encodeString(bytes, 'error')
122
- this._encodeNumber(bytes, content.error)
129
+ bytes.writeNumber(content.error)
123
130
  this._encodeString(bytes, 'name')
124
131
  this._encodeString(bytes, content.name)
125
132
  this._encodeString(bytes, 'service')
@@ -127,9 +134,9 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
127
134
  this._encodeString(bytes, 'resource')
128
135
  this._encodeString(bytes, content.resource)
129
136
  this._encodeString(bytes, 'start')
130
- this._encodeNumber(bytes, content.start)
137
+ bytes.writeNumber(content.start)
131
138
  this._encodeString(bytes, 'duration')
132
- this._encodeNumber(bytes, content.duration)
139
+ bytes.writeNumber(content.duration)
133
140
  this._encodeString(bytes, 'meta')
134
141
  this._encodeMap(bytes, content.meta)
135
142
  this._encodeString(bytes, 'metrics')
@@ -137,7 +144,7 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
137
144
  }
138
145
 
139
146
  _encodeTestSession (bytes, content) {
140
- this._encodeMapPrefix(bytes, TEST_SESSION_KEYS_LENGTH)
147
+ bytes.writeMapPrefix(TEST_SESSION_KEYS_LENGTH)
141
148
  this._encodeString(bytes, 'type')
142
149
  this._encodeString(bytes, content.type)
143
150
 
@@ -145,7 +152,7 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
145
152
  this._encodeId(bytes, content.trace_id)
146
153
 
147
154
  this._encodeString(bytes, 'error')
148
- this._encodeNumber(bytes, content.error)
155
+ bytes.writeNumber(content.error)
149
156
  this._encodeString(bytes, 'name')
150
157
  this._encodeString(bytes, content.name)
151
158
  this._encodeString(bytes, 'service')
@@ -153,9 +160,9 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
153
160
  this._encodeString(bytes, 'resource')
154
161
  this._encodeString(bytes, content.resource)
155
162
  this._encodeString(bytes, 'start')
156
- this._encodeNumber(bytes, content.start)
163
+ bytes.writeNumber(content.start)
157
164
  this._encodeString(bytes, 'duration')
158
- this._encodeNumber(bytes, content.duration)
165
+ bytes.writeNumber(content.duration)
159
166
  this._encodeString(bytes, 'meta')
160
167
  this._encodeMap(bytes, content.meta)
161
168
  this._encodeString(bytes, 'metrics')
@@ -180,7 +187,7 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
180
187
  if (content.type) {
181
188
  totalKeysLength += 1
182
189
  }
183
- this._encodeMapPrefix(bytes, totalKeysLength)
190
+ bytes.writeMapPrefix(totalKeysLength)
184
191
  if (content.type) {
185
192
  this._encodeString(bytes, 'type')
186
193
  this._encodeString(bytes, content.type)
@@ -198,11 +205,11 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
198
205
  this._encodeString(bytes, 'service')
199
206
  this._encodeString(bytes, content.service)
200
207
  this._encodeString(bytes, 'error')
201
- this._encodeNumber(bytes, content.error)
208
+ bytes.writeNumber(content.error)
202
209
  this._encodeString(bytes, 'start')
203
- this._encodeNumber(bytes, content.start)
210
+ bytes.writeNumber(content.start)
204
211
  this._encodeString(bytes, 'duration')
205
- this._encodeNumber(bytes, content.duration)
212
+ bytes.writeNumber(content.duration)
206
213
  /**
207
214
  * We include `test_session_id` and `test_suite_id`
208
215
  * in the root of the event by passing them via the `meta` dict.
@@ -243,12 +250,12 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
243
250
  }
244
251
 
245
252
  _encodeEvent (bytes, event) {
246
- this._encodeMapPrefix(bytes, Object.keys(event).length)
253
+ bytes.writeMapPrefix(Object.keys(event).length)
247
254
  this._encodeString(bytes, 'type')
248
255
  this._encodeString(bytes, event.type)
249
256
 
250
257
  this._encodeString(bytes, 'version')
251
- this._encodeNumber(bytes, event.version)
258
+ bytes.writeNumber(event.version)
252
259
 
253
260
  this._encodeString(bytes, 'content')
254
261
  if (event.type === 'span' || event.type === 'test') {
@@ -318,6 +325,7 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
318
325
  '*': {
319
326
  language: 'javascript',
320
327
  library_version: ddTraceVersion,
328
+ ...this.wildcardMetadataTags,
321
329
  },
322
330
  ...this.metadataTags,
323
331
  },
@@ -331,11 +339,11 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
331
339
  payload.metadata['*']['runtime-id'] = this.runtimeId
332
340
  }
333
341
 
334
- this._encodeMapPrefix(bytes, Object.keys(payload).length)
342
+ bytes.writeMapPrefix(Object.keys(payload).length)
335
343
  this._encodeString(bytes, 'version')
336
- this._encodeNumber(bytes, payload.version)
344
+ bytes.writeNumber(payload.version)
337
345
  this._encodeString(bytes, 'metadata')
338
- this._encodeMapPrefix(bytes, Object.keys(payload.metadata).length)
346
+ bytes.writeMapPrefix(Object.keys(payload.metadata).length)
339
347
  this._encodeString(bytes, '*')
340
348
  this._encodeMap(bytes, payload.metadata['*'])
341
349
  if (payload.metadata.test) {
@@ -86,10 +86,12 @@ class AgentlessJSONEncoder {
86
86
  /**
87
87
  * @param {object} writer - Writer instance with a flush() method, called when the buffer exceeds the soft limit
88
88
  * @param {object} [metadata] - Shared metadata spread into each trace object (hostname, env, tracerVersion, etc.)
89
+ * @param {number} [softLimit] - Estimated payload-size threshold that triggers an early flush. Defaults to 8 MiB.
89
90
  */
90
- constructor (writer, metadata = {}) {
91
+ constructor (writer, metadata = {}, softLimit = SOFT_LIMIT) {
91
92
  this._writer = writer
92
93
  this._metadata = metadata
94
+ this._softLimit = softLimit
93
95
  this._reset()
94
96
  }
95
97
 
@@ -134,7 +136,7 @@ class AgentlessJSONEncoder {
134
136
  log.error('All %d span(s) in trace failed to encode. Entire trace dropped.', trace.length)
135
137
  }
136
138
 
137
- if (this._estimatedSize > SOFT_LIMIT) {
139
+ if (this._estimatedSize > this._softLimit) {
138
140
  log.debug('Buffer went over soft limit, flushing')
139
141
  try {
140
142
  this._writer.flush()
@@ -12,6 +12,17 @@ const { AgentEncoder } = require('./0.4')
12
12
  const COVERAGE_PAYLOAD_VERSION = 2
13
13
  const COVERAGE_KEYS_LENGTH = 2
14
14
 
15
+ function getBitmapBuffer (bitmap) {
16
+ if (!bitmap) return
17
+ if (Buffer.isBuffer(bitmap)) return bitmap
18
+ if (ArrayBuffer.isView(bitmap)) {
19
+ return Buffer.from(bitmap.buffer, bitmap.byteOffset, bitmap.byteLength)
20
+ }
21
+ if (bitmap.type === 'Buffer' && Array.isArray(bitmap.data)) {
22
+ return Buffer.from(bitmap.data)
23
+ }
24
+ }
25
+
15
26
  class CoverageCIVisibilityEncoder extends AgentEncoder {
16
27
  constructor () {
17
28
  super(...arguments)
@@ -39,32 +50,40 @@ class CoverageCIVisibilityEncoder extends AgentEncoder {
39
50
  }
40
51
 
41
52
  encodeCodeCoverage (bytes, coverage) {
42
- if (coverage.testId) {
43
- this._encodeMapPrefix(bytes, 4)
44
- } else {
45
- this._encodeMapPrefix(bytes, 3)
46
- }
53
+ let keysLength = 2
54
+ if (coverage.suiteId) keysLength++
55
+ if (coverage.testId) keysLength++
56
+
57
+ bytes.writeMapPrefix(keysLength)
47
58
  this._encodeString(bytes, 'test_session_id')
48
59
  this._encodeId(bytes, coverage.sessionId)
49
- this._encodeString(bytes, 'test_suite_id')
50
- this._encodeId(bytes, coverage.suiteId)
60
+ if (coverage.suiteId) {
61
+ this._encodeString(bytes, 'test_suite_id')
62
+ this._encodeId(bytes, coverage.suiteId)
63
+ }
51
64
  if (coverage.testId) {
52
65
  this._encodeString(bytes, 'span_id')
53
66
  this._encodeId(bytes, coverage.testId)
54
67
  }
55
68
  this._encodeString(bytes, 'files')
56
- this._encodeArrayPrefix(bytes, coverage.files)
57
- for (const filename of coverage.files) {
58
- this._encodeMapPrefix(bytes, 1)
69
+ bytes.writeArrayPrefix(coverage.files)
70
+ for (const file of coverage.files) {
71
+ const filename = typeof file === 'string' ? file : file.filename
72
+ const bitmap = getBitmapBuffer(file.bitmap)
73
+ bytes.writeMapPrefix(bitmap ? 2 : 1)
59
74
  this._encodeString(bytes, 'filename')
60
75
  this._encodeString(bytes, filename)
76
+ if (bitmap) {
77
+ this._encodeString(bytes, 'bitmap')
78
+ bytes.writeBin(bitmap)
79
+ }
61
80
  }
62
81
  }
63
82
 
64
83
  reset () {
65
84
  this._reset()
66
85
  if (this._coverageBytes) {
67
- this._coverageBytes.length = 0
86
+ this._coverageBytes.reset()
68
87
  }
69
88
  this._coveragesCount = 0
70
89
  this._encodePayloadStart(this._coverageBytes)
@@ -75,9 +94,9 @@ class CoverageCIVisibilityEncoder extends AgentEncoder {
75
94
  version: COVERAGE_PAYLOAD_VERSION,
76
95
  coverages: [],
77
96
  }
78
- this._encodeMapPrefix(bytes, COVERAGE_KEYS_LENGTH)
97
+ bytes.writeMapPrefix(COVERAGE_KEYS_LENGTH)
79
98
  this._encodeString(bytes, 'version')
80
- this._encodeInteger(bytes, payload.version)
99
+ bytes.writeInteger(payload.version)
81
100
  this._encodeString(bytes, 'coverages')
82
101
  // Get offset of the coverages list to update the length of the array when calling `makePayload`
83
102
  this._coveragesOffset = bytes.length
@@ -31,7 +31,7 @@ class SpanStatsEncoder extends AgentEncoder {
31
31
  }
32
32
 
33
33
  _encodeStat (bytes, stat) {
34
- this._encodeMapPrefix(bytes, 15)
34
+ bytes.writeMapPrefix(15)
35
35
 
36
36
  this._encodeString(bytes, 'Service')
37
37
  const service = stat.Service || DEFAULT_SERVICE_NAME
@@ -45,31 +45,31 @@ class SpanStatsEncoder extends AgentEncoder {
45
45
  this._encodeString(bytes, truncate(stat.Resource, MAX_RESOURCE_NAME_LENGTH, '...'))
46
46
 
47
47
  this._encodeString(bytes, 'HTTPStatusCode')
48
- this._encodeInteger(bytes, stat.HTTPStatusCode)
48
+ bytes.writeInteger(stat.HTTPStatusCode)
49
49
 
50
50
  this._encodeString(bytes, 'Type')
51
51
  this._encodeString(bytes, truncate(stat.Type, MAX_TYPE_LENGTH))
52
52
 
53
53
  this._encodeString(bytes, 'Hits')
54
- this._encodeLong(bytes, stat.Hits)
54
+ bytes.writeLong(stat.Hits)
55
55
 
56
56
  this._encodeString(bytes, 'Errors')
57
- this._encodeLong(bytes, stat.Errors)
57
+ bytes.writeLong(stat.Errors)
58
58
 
59
59
  this._encodeString(bytes, 'Duration')
60
- this._encodeLong(bytes, stat.Duration)
60
+ bytes.writeLong(stat.Duration)
61
61
 
62
62
  this._encodeString(bytes, 'OkSummary')
63
- this._encodeBuffer(bytes, stat.OkSummary)
63
+ bytes.writeBin(stat.OkSummary)
64
64
 
65
65
  this._encodeString(bytes, 'ErrorSummary')
66
- this._encodeBuffer(bytes, stat.ErrorSummary)
66
+ bytes.writeBin(stat.ErrorSummary)
67
67
 
68
68
  this._encodeString(bytes, 'Synthetics')
69
- this._encodeBool(bytes, stat.Synthetics)
69
+ bytes.writeBoolean(stat.Synthetics)
70
70
 
71
71
  this._encodeString(bytes, 'TopLevelHits')
72
- this._encodeLong(bytes, stat.TopLevelHits)
72
+ bytes.writeLong(stat.TopLevelHits)
73
73
 
74
74
  this._encodeString(bytes, 'HTTPMethod')
75
75
  this._encodeString(bytes, stat.HTTPMethod)
@@ -82,23 +82,23 @@ class SpanStatsEncoder extends AgentEncoder {
82
82
  }
83
83
 
84
84
  _encodeBucket (bytes, bucket) {
85
- this._encodeMapPrefix(bytes, 3)
85
+ bytes.writeMapPrefix(3)
86
86
 
87
87
  this._encodeString(bytes, 'Start')
88
- this._encodeLong(bytes, bucket.Start)
88
+ bytes.writeLong(bucket.Start)
89
89
 
90
90
  this._encodeString(bytes, 'Duration')
91
- this._encodeLong(bytes, bucket.Duration)
91
+ bytes.writeLong(bucket.Duration)
92
92
 
93
93
  this._encodeString(bytes, 'Stats')
94
- this._encodeArrayPrefix(bytes, bucket.Stats)
94
+ bytes.writeArrayPrefix(bucket.Stats)
95
95
  for (const stat of bucket.Stats) {
96
96
  this._encodeStat(bytes, stat)
97
97
  }
98
98
  }
99
99
 
100
100
  _encode (bytes, stats) {
101
- this._encodeMapPrefix(bytes, stats.ProcessTags ? 9 : 8)
101
+ bytes.writeMapPrefix(stats.ProcessTags ? 9 : 8)
102
102
 
103
103
  this._encodeString(bytes, 'Hostname')
104
104
  this._encodeString(bytes, stats.Hostname)
@@ -110,7 +110,7 @@ class SpanStatsEncoder extends AgentEncoder {
110
110
  this._encodeString(bytes, stats.Version)
111
111
 
112
112
  this._encodeString(bytes, 'Stats')
113
- this._encodeArrayPrefix(bytes, stats.Stats)
113
+ bytes.writeArrayPrefix(stats.Stats)
114
114
  for (const bucket of stats.Stats) {
115
115
  this._encodeBucket(bytes, bucket)
116
116
  }
@@ -125,7 +125,7 @@ class SpanStatsEncoder extends AgentEncoder {
125
125
  this._encodeString(bytes, stats.RuntimeID)
126
126
 
127
127
  this._encodeString(bytes, 'Sequence')
128
- this._encodeLong(bytes, stats.Sequence)
128
+ bytes.writeLong(stats.Sequence)
129
129
 
130
130
  if (stats.ProcessTags) {
131
131
  this._encodeString(bytes, 'ProcessTags')
@@ -9,6 +9,8 @@ const MAX_RESOURCE_NAME_LENGTH = 5000
9
9
  const MAX_META_KEY_LENGTH = 200
10
10
  // MAX_META_VALUE_LENGTH the maximum length of metadata value
11
11
  const MAX_META_VALUE_LENGTH = 25_000
12
+ // MAX_META_VALUE_LENGTH_TEST_OPTIMIZATION the maximum length of metadata value for Test Optimization
13
+ const MAX_META_VALUE_LENGTH_TEST_OPTIMIZATION = 5000
12
14
  // MAX_METRIC_KEY_LENGTH the maximum length of a metric name key
13
15
  const MAX_METRIC_KEY_LENGTH = MAX_META_KEY_LENGTH
14
16
 
@@ -32,6 +34,18 @@ function truncateSpan (span) {
32
34
  return span
33
35
  }
34
36
 
37
+ function truncateSpanTestOpt (span) {
38
+ truncateSpan(span)
39
+ if (span.meta) {
40
+ for (const key of Object.keys(span.meta)) {
41
+ if (span.meta[key].length > MAX_META_VALUE_LENGTH_TEST_OPTIMIZATION) {
42
+ span.meta[key] = `${span.meta[key].slice(0, MAX_META_VALUE_LENGTH_TEST_OPTIMIZATION)}...`
43
+ }
44
+ }
45
+ }
46
+ return span
47
+ }
48
+
35
49
  function normalizeSpan (span) {
36
50
  span.service = span.service || DEFAULT_SERVICE_NAME
37
51
  if (span.service.length > MAX_SERVICE_LENGTH) {
@@ -53,9 +67,11 @@ function normalizeSpan (span) {
53
67
 
54
68
  module.exports = {
55
69
  truncateSpan,
70
+ truncateSpanTestOpt,
56
71
  normalizeSpan,
57
72
  MAX_META_KEY_LENGTH,
58
73
  MAX_META_VALUE_LENGTH,
74
+ MAX_META_VALUE_LENGTH_TEST_OPTIMIZATION,
59
75
  MAX_METRIC_KEY_LENGTH,
60
76
  MAX_NAME_LENGTH,
61
77
  MAX_SERVICE_LENGTH,
@@ -78,6 +78,21 @@ class Identifier {
78
78
  return this.toString()
79
79
  }
80
80
 
81
+ /**
82
+ * Returns the full hex trace ID. When this is a 64-bit identifier and `traceIdHigh`
83
+ * is provided, prepends it to form the 128-bit trace ID. Otherwise returns
84
+ * only this identifier's hex representation.
85
+ *
86
+ * @param {string | undefined} traceIdHigh - 16-char hex of the upper 64 bits, or undefined
87
+ * @returns {string}
88
+ */
89
+ toTraceIdHex (traceIdHigh) {
90
+ if (traceIdHigh && this.#buffer.length <= 8) {
91
+ return traceIdHigh + this.toString(16)
92
+ }
93
+ return this.toString(16)
94
+ }
95
+
81
96
  /**
82
97
  * @param {Identifier} other
83
98
  * @returns {boolean}