dd-trace 5.101.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 (140) hide show
  1. package/package.json +9 -7
  2. package/packages/datadog-instrumentations/src/aerospike.js +2 -2
  3. package/packages/datadog-instrumentations/src/ai.js +8 -8
  4. package/packages/datadog-instrumentations/src/amqplib.js +6 -7
  5. package/packages/datadog-instrumentations/src/anthropic.js +10 -10
  6. package/packages/datadog-instrumentations/src/apollo-server-core.js +3 -3
  7. package/packages/datadog-instrumentations/src/apollo-server.js +5 -5
  8. package/packages/datadog-instrumentations/src/avsc.js +6 -6
  9. package/packages/datadog-instrumentations/src/aws-sdk.js +151 -67
  10. package/packages/datadog-instrumentations/src/azure-durable-functions.js +8 -8
  11. package/packages/datadog-instrumentations/src/bluebird.js +2 -2
  12. package/packages/datadog-instrumentations/src/body-parser.js +2 -2
  13. package/packages/datadog-instrumentations/src/cassandra-driver.js +7 -7
  14. package/packages/datadog-instrumentations/src/child_process.js +12 -12
  15. package/packages/datadog-instrumentations/src/confluentinc-kafka-javascript.js +9 -9
  16. package/packages/datadog-instrumentations/src/connect.js +7 -7
  17. package/packages/datadog-instrumentations/src/cookie-parser.js +4 -4
  18. package/packages/datadog-instrumentations/src/cookie.js +2 -2
  19. package/packages/datadog-instrumentations/src/couchbase.js +16 -30
  20. package/packages/datadog-instrumentations/src/crypto.js +4 -4
  21. package/packages/datadog-instrumentations/src/cucumber.js +77 -16
  22. package/packages/datadog-instrumentations/src/dns.js +0 -3
  23. package/packages/datadog-instrumentations/src/elasticsearch.js +8 -11
  24. package/packages/datadog-instrumentations/src/express-mongo-sanitize.js +6 -6
  25. package/packages/datadog-instrumentations/src/express-session.js +4 -4
  26. package/packages/datadog-instrumentations/src/express.js +10 -11
  27. package/packages/datadog-instrumentations/src/fastify.js +2 -2
  28. package/packages/datadog-instrumentations/src/fs.js +14 -14
  29. package/packages/datadog-instrumentations/src/google-cloud-pubsub.js +5 -7
  30. package/packages/datadog-instrumentations/src/google-genai.js +4 -4
  31. package/packages/datadog-instrumentations/src/grpc/server.js +2 -2
  32. package/packages/datadog-instrumentations/src/hapi.js +2 -2
  33. package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +8 -8
  34. package/packages/datadog-instrumentations/src/helpers/promise.js +2 -2
  35. package/packages/datadog-instrumentations/src/hono.js +2 -2
  36. package/packages/datadog-instrumentations/src/http/client.js +6 -6
  37. package/packages/datadog-instrumentations/src/http/server.js +9 -9
  38. package/packages/datadog-instrumentations/src/jest.js +31 -31
  39. package/packages/datadog-instrumentations/src/kafkajs.js +9 -9
  40. package/packages/datadog-instrumentations/src/knex.js +17 -17
  41. package/packages/datadog-instrumentations/src/koa.js +12 -12
  42. package/packages/datadog-instrumentations/src/ldapjs.js +5 -5
  43. package/packages/datadog-instrumentations/src/light-my-request.js +2 -2
  44. package/packages/datadog-instrumentations/src/limitd-client.js +4 -4
  45. package/packages/datadog-instrumentations/src/lodash.js +4 -4
  46. package/packages/datadog-instrumentations/src/mariadb.js +13 -13
  47. package/packages/datadog-instrumentations/src/memcached.js +2 -2
  48. package/packages/datadog-instrumentations/src/microgateway-core.js +2 -2
  49. package/packages/datadog-instrumentations/src/mocha/common.js +3 -3
  50. package/packages/datadog-instrumentations/src/mocha/main.js +12 -10
  51. package/packages/datadog-instrumentations/src/mocha/utils.js +133 -16
  52. package/packages/datadog-instrumentations/src/mocha/worker.js +7 -5
  53. package/packages/datadog-instrumentations/src/mongodb-core.js +9 -22
  54. package/packages/datadog-instrumentations/src/mongodb.js +5 -5
  55. package/packages/datadog-instrumentations/src/mongoose.js +21 -21
  56. package/packages/datadog-instrumentations/src/mquery.js +5 -5
  57. package/packages/datadog-instrumentations/src/multer.js +4 -4
  58. package/packages/datadog-instrumentations/src/mysql.js +16 -16
  59. package/packages/datadog-instrumentations/src/mysql2.js +4 -4
  60. package/packages/datadog-instrumentations/src/net.js +14 -8
  61. package/packages/datadog-instrumentations/src/nyc.js +5 -5
  62. package/packages/datadog-instrumentations/src/openai.js +19 -19
  63. package/packages/datadog-instrumentations/src/oracledb.js +6 -6
  64. package/packages/datadog-instrumentations/src/passport-utils.js +5 -5
  65. package/packages/datadog-instrumentations/src/pg.js +15 -15
  66. package/packages/datadog-instrumentations/src/pino.js +6 -10
  67. package/packages/datadog-instrumentations/src/playwright.js +20 -15
  68. package/packages/datadog-instrumentations/src/protobufjs.js +16 -16
  69. package/packages/datadog-instrumentations/src/redis.js +1 -2
  70. package/packages/datadog-instrumentations/src/restify.js +2 -2
  71. package/packages/datadog-instrumentations/src/router.js +12 -12
  72. package/packages/datadog-instrumentations/src/stripe.js +12 -12
  73. package/packages/datadog-instrumentations/src/vitest.js +107 -26
  74. package/packages/datadog-instrumentations/src/winston.js +4 -4
  75. package/packages/datadog-instrumentations/src/ws.js +7 -7
  76. package/packages/datadog-plugin-aws-sdk/src/base.js +52 -4
  77. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +19 -12
  78. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +45 -35
  79. package/packages/datadog-plugin-aws-sdk/src/services/lambda.js +33 -22
  80. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +12 -13
  81. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +73 -54
  82. package/packages/datadog-plugin-aws-sdk/src/services/stepfunctions.js +19 -17
  83. package/packages/datadog-plugin-aws-sdk/src/util.js +22 -0
  84. package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +6 -6
  85. package/packages/datadog-plugin-cucumber/src/index.js +4 -0
  86. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +1 -4
  87. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +1 -5
  88. package/packages/datadog-plugin-google-cloud-pubsub/src/pubsub-push-subscription.js +3 -1
  89. package/packages/datadog-plugin-http/src/client.js +1 -5
  90. package/packages/datadog-plugin-jest/src/util.js +1 -2
  91. package/packages/datadog-plugin-mocha/src/index.js +4 -0
  92. package/packages/datadog-plugin-mongodb-core/src/index.js +2 -1
  93. package/packages/datadog-plugin-openai/src/tracing.js +12 -23
  94. package/packages/datadog-plugin-playwright/src/index.js +1 -1
  95. package/packages/datadog-plugin-vitest/src/index.js +8 -1
  96. package/packages/datadog-shimmer/src/shimmer.js +7 -1
  97. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-password-rules.js +1 -1
  98. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secret-rules.js +81 -81
  99. package/packages/dd-trace/src/appsec/iast/security-controls/index.js +2 -2
  100. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugins/kafka.js +2 -2
  101. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +2 -2
  102. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +2 -2
  103. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +2 -0
  104. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/index.js +1 -3
  105. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +83 -48
  106. package/packages/dd-trace/src/appsec/index.js +21 -24
  107. package/packages/dd-trace/src/appsec/reporter.js +3 -1
  108. package/packages/dd-trace/src/appsec/rule_manager.js +4 -2
  109. package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +31 -16
  110. package/packages/dd-trace/src/config/git_properties.js +2 -2
  111. package/packages/dd-trace/src/datastreams/index.js +2 -1
  112. package/packages/dd-trace/src/datastreams/processor.js +1 -2
  113. package/packages/dd-trace/src/debugger/devtools_client/snapshot-pruner.js +1 -0
  114. package/packages/dd-trace/src/encode/0.4.js +757 -232
  115. package/packages/dd-trace/src/encode/0.5.js +13 -7
  116. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +1 -2
  117. package/packages/dd-trace/src/llmobs/plugins/genai/util.js +6 -3
  118. package/packages/dd-trace/src/llmobs/sdk.js +24 -26
  119. package/packages/dd-trace/src/llmobs/span_processor.js +25 -5
  120. package/packages/dd-trace/src/llmobs/util.js +1 -0
  121. package/packages/dd-trace/src/msgpack/chunk.js +6 -3
  122. package/packages/dd-trace/src/openfeature/noop.js +40 -36
  123. package/packages/dd-trace/src/openfeature/writers/exposures.js +33 -52
  124. package/packages/dd-trace/src/opentelemetry/otlp/otlp_transformer_base.js +1 -2
  125. package/packages/dd-trace/src/opentelemetry/tracer.js +0 -22
  126. package/packages/dd-trace/src/opentracing/propagation/text_map_dsm.js +2 -11
  127. package/packages/dd-trace/src/plugins/util/ci.js +1 -1
  128. package/packages/dd-trace/src/plugins/util/git-cache.js +3 -5
  129. package/packages/dd-trace/src/plugins/util/test.js +19 -7
  130. package/packages/dd-trace/src/plugins/util/url.js +1 -3
  131. package/packages/dd-trace/src/plugins/util/user-provided-git.js +1 -1
  132. package/packages/dd-trace/src/plugins/util/web.js +5 -7
  133. package/packages/dd-trace/src/profiling/profilers/events.js +3 -23
  134. package/packages/dd-trace/src/profiling/profilers/wall.js +4 -5
  135. package/packages/dd-trace/src/runtime_metrics/index.js +2 -2
  136. package/packages/dd-trace/src/scope.js +3 -10
  137. package/packages/dd-trace/src/serverless.js +1 -4
  138. package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +7 -1
  139. package/packages/dd-trace/src/service-naming/schemas/v1/messaging.js +4 -0
  140. package/packages/dd-trace/src/tracer.js +7 -7
@@ -1,17 +1,18 @@
1
1
  'use strict'
2
2
 
3
3
  const { normalizeSpan } = require('./tags-processors')
4
- const { AgentEncoder: BaseEncoder } = require('./0.4')
4
+ const { AgentEncoder: BaseEncoder, stringifySpanEvents } = require('./0.4')
5
5
 
6
6
  const ARRAY_OF_TWO = 0x92
7
7
  const ARRAY_OF_TWELVE = 0x9C
8
8
 
9
9
  function formatSpan (span) {
10
10
  span = normalizeSpan(span)
11
- // ensure span events are encoded as tags
11
+ // v0.5 has no native span_events slot; always serialize as a meta tag.
12
12
  if (span.span_events) {
13
- span.meta.events = JSON.stringify(span.span_events)
14
- delete span.span_events
13
+ span.meta.events = stringifySpanEvents(span.span_events)
14
+ // `= undefined` over `delete` to keep the span's hidden class.
15
+ span.span_events = undefined
15
16
  }
16
17
  return span
17
18
  }
@@ -55,12 +56,17 @@ class AgentEncoder extends BaseEncoder {
55
56
  }
56
57
 
57
58
  _encodeString (bytes, value = '') {
58
- this._cacheString(value)
59
- this._encodeInteger(bytes, this._stringMap[value])
59
+ let index = this._stringMap[value]
60
+ if (index === undefined) {
61
+ index = this._stringCount++
62
+ this._stringMap[value] = index
63
+ this._stringBytes.write(value)
64
+ }
65
+ this._encodeInteger(bytes, index)
60
66
  }
61
67
 
62
68
  _cacheString (value) {
63
- if (!(value in this._stringMap)) {
69
+ if (this._stringMap[value] === undefined) {
64
70
  this._stringMap[value] = this._stringCount++
65
71
  this._stringBytes.write(value)
66
72
  }
@@ -41,8 +41,7 @@ const VERCEL_AI_GENERATION_METADATA_PREFIX = 'ai.settings.'
41
41
  */
42
42
  function getSpanTags (ctx) {
43
43
  const span = ctx.currentStore?.span
44
- const carrier = ctx.attributes ?? span?.context()._tags ?? {}
45
- return /** @type {SpanTags} */ (carrier)
44
+ return /** @type {SpanTags} */ (ctx.attributes ?? span?.context()._tags ?? {})
46
45
  }
47
46
 
48
47
  /**
@@ -243,9 +243,11 @@ function formatContentObject (content) {
243
243
  let functionResponses
244
244
  for (const part of parts) {
245
245
  if (part.functionCall) {
246
- (functionCalls ??= []).push(part)
246
+ functionCalls ??= []
247
+ functionCalls.push(part)
247
248
  } else if (part.functionResponse) {
248
- (functionResponses ??= []).push(part)
249
+ functionResponses ??= []
250
+ functionResponses.push(part)
249
251
  }
250
252
  }
251
253
 
@@ -341,7 +343,8 @@ function formatNonStreamingCandidate (candidate) {
341
343
  let codeExecutionResult
342
344
  for (const part of parts) {
343
345
  if (part.functionCall) {
344
- (functionCalls ??= []).push(part)
346
+ functionCalls ??= []
347
+ functionCalls.push(part)
345
348
  } else if (!executableCode && part.executableCode) {
346
349
  executableCode = part
347
350
  } else if (!codeExecutionResult && part.codeExecutionResult) {
@@ -112,16 +112,16 @@ class LLMObs extends NoopLLMObs {
112
112
  const {
113
113
  spanOptions,
114
114
  ...llmobsOptions
115
- } = this._extractOptions(options)
115
+ } = this.#extractOptions(options)
116
116
 
117
117
  if (fn.length > 1) {
118
118
  return this._tracer.trace(name, spanOptions, (span, cb) =>
119
- this._activate(span, { kind, ...llmobsOptions }, () => fn(span, cb))
119
+ this.#activate(span, { kind, ...llmobsOptions }, () => fn(span, cb))
120
120
  )
121
121
  }
122
122
 
123
123
  return this._tracer.trace(name, spanOptions, span =>
124
- this._activate(span, { kind, ...llmobsOptions }, () => fn(span))
124
+ this.#activate(span, { kind, ...llmobsOptions }, () => fn(span))
125
125
  )
126
126
  }
127
127
 
@@ -142,53 +142,53 @@ class LLMObs extends NoopLLMObs {
142
142
  const {
143
143
  spanOptions,
144
144
  ...llmobsOptions
145
- } = this._extractOptions(options)
145
+ } = this.#extractOptions(options)
146
146
 
147
147
  const llmobs = this
148
148
 
149
- function wrapped () {
149
+ function wrapped (...args) {
150
150
  telemetry.incrementLLMObsSpanStartCount({ autoinstrumented: false, kind })
151
151
 
152
152
  const span = llmobs._tracer.scope().active()
153
- const fnArgs = arguments
153
+ const fnArgs = args
154
154
 
155
155
  const lastArgId = fnArgs.length - 1
156
156
  const cb = fnArgs[lastArgId]
157
157
  const hasCallback = typeof cb === 'function'
158
158
 
159
159
  if (hasCallback) {
160
- const scopeBoundCb = llmobs._bind(cb)
161
- fnArgs[lastArgId] = function () {
160
+ const scopeBoundCb = llmobs.#bind(cb)
161
+ fnArgs[lastArgId] = function (...args) {
162
162
  // it is standard practice to follow the callback signature (err, result)
163
163
  // however, we try to parse the arguments to determine if the first argument is an error
164
164
  // if it is not, and is not undefined, we will use that for the output value
165
- const maybeError = arguments[0]
166
- const maybeResult = arguments[1]
165
+ const maybeError = args[0]
166
+ const maybeResult = args[1]
167
167
 
168
- llmobs._autoAnnotate(
168
+ llmobs.#autoAnnotate(
169
169
  span,
170
170
  kind,
171
171
  getFunctionArguments(fn, fnArgs),
172
172
  isError(maybeError) || maybeError == null ? maybeResult : maybeError
173
173
  )
174
174
 
175
- return scopeBoundCb.apply(this, arguments)
175
+ return scopeBoundCb.apply(this, args)
176
176
  }
177
177
  }
178
178
 
179
179
  try {
180
- const result = llmobs._activate(span, { kind, ...llmobsOptions }, () => fn.apply(this, fnArgs))
180
+ const result = llmobs.#activate(span, { kind, ...llmobsOptions }, () => fn.apply(this, fnArgs))
181
181
 
182
182
  if (result && typeof result.then === 'function') {
183
183
  return result.then(
184
184
  value => {
185
185
  if (!hasCallback) {
186
- llmobs._autoAnnotate(span, kind, getFunctionArguments(fn, fnArgs), value)
186
+ llmobs.#autoAnnotate(span, kind, getFunctionArguments(fn, fnArgs), value)
187
187
  }
188
188
  return value
189
189
  },
190
190
  err => {
191
- llmobs._autoAnnotate(span, kind, getFunctionArguments(fn, fnArgs))
191
+ llmobs.#autoAnnotate(span, kind, getFunctionArguments(fn, fnArgs))
192
192
  throw err
193
193
  }
194
194
  )
@@ -199,12 +199,12 @@ class LLMObs extends NoopLLMObs {
199
199
  // the callback is called before the function returns (although unlikely)
200
200
  // we do not want to throw for "annotating a finished span" in this case
201
201
  if (!hasCallback) {
202
- llmobs._autoAnnotate(span, kind, getFunctionArguments(fn, fnArgs), result)
202
+ llmobs.#autoAnnotate(span, kind, getFunctionArguments(fn, fnArgs), result)
203
203
  }
204
204
 
205
205
  return result
206
206
  } catch (e) {
207
- llmobs._autoAnnotate(span, kind, getFunctionArguments(fn, fnArgs))
207
+ llmobs.#autoAnnotate(span, kind, getFunctionArguments(fn, fnArgs))
208
208
  throw e
209
209
  }
210
210
  }
@@ -516,7 +516,7 @@ class LLMObs extends NoopLLMObs {
516
516
  flushCh.publish()
517
517
  }
518
518
 
519
- _autoAnnotate (span, kind, input, output) {
519
+ #autoAnnotate (span, kind, input, output) {
520
520
  const annotations = {}
521
521
  if (input && !['llm', 'embedding'].includes(kind) && !LLMObsTagger.tagMap.get(span)?.[INPUT_VALUE]) {
522
522
  annotations.inputData = input
@@ -534,7 +534,7 @@ class LLMObs extends NoopLLMObs {
534
534
  return store?.span
535
535
  }
536
536
 
537
- _activate (span, options, fn) {
537
+ #activate (span, options, fn) {
538
538
  const parentStore = storage.getStore()
539
539
  if (this.enabled) storage.enterWith({ ...parentStore, span })
540
540
 
@@ -567,22 +567,20 @@ class LLMObs extends NoopLLMObs {
567
567
  }
568
568
 
569
569
  // bind function to active LLMObs span
570
- _bind (fn) {
570
+ #bind (fn) {
571
571
  if (typeof fn !== 'function') return fn
572
572
 
573
573
  const llmobs = this
574
574
  const activeSpan = llmobs._active()
575
575
 
576
- const bound = function () {
577
- return llmobs._activate(activeSpan, null, () => {
578
- return fn.apply(this, arguments)
576
+ return function (...args) {
577
+ return llmobs.#activate(activeSpan, null, () => {
578
+ return fn.apply(this, args)
579
579
  })
580
580
  }
581
-
582
- return bound
583
581
  }
584
582
 
585
- _extractOptions (options) {
583
+ #extractOptions (options) {
586
584
  const {
587
585
  modelName,
588
586
  modelProvider,
@@ -39,10 +39,16 @@ const telemetry = require('./telemetry')
39
39
  const LLMObsTagger = require('./tagger')
40
40
 
41
41
  class LLMObservabilitySpan {
42
- constructor () {
42
+ /**
43
+ * @param {string} kind span kind
44
+ */
45
+ constructor (kind) {
43
46
  this.input = []
44
47
  this.output = []
45
48
 
49
+ /** @type {string} */
50
+ this.kind = kind
51
+
46
52
  this._tags = {}
47
53
  }
48
54
 
@@ -115,7 +121,6 @@ class LLMObsSpanProcessor {
115
121
  }
116
122
 
117
123
  format (span) {
118
- const llmObsSpan = new LLMObservabilitySpan()
119
124
  let inputType, outputType
120
125
 
121
126
  const spanTags = span.context()._tags
@@ -145,14 +150,18 @@ class LLMObsSpanProcessor {
145
150
  }
146
151
 
147
152
  if (mlObsTags[TOOL_DEFINITIONS]) {
148
- this.#addObject(mlObsTags[TOOL_DEFINITIONS], meta.tool_definitions = [])
153
+ meta.tool_definitions = []
154
+ this.#addObject(mlObsTags[TOOL_DEFINITIONS], meta.tool_definitions)
149
155
  }
150
156
 
157
+ const llmObsSpan = new LLMObservabilitySpan(spanKind)
158
+
151
159
  if (spanKind === 'llm' && mlObsTags[INPUT_MESSAGES]) {
152
160
  llmObsSpan.input = mlObsTags[INPUT_MESSAGES]
153
161
  inputType = 'messages'
154
162
  } else if (spanKind === 'embedding' && mlObsTags[INPUT_DOCUMENTS]) {
155
- input.documents = mlObsTags[INPUT_DOCUMENTS]
163
+ llmObsSpan.input = mlObsTags[INPUT_DOCUMENTS].map(doc => ({ content: doc.text, role: '' }))
164
+ inputType = 'documents'
156
165
  } else if (mlObsTags[INPUT_VALUE]) {
157
166
  llmObsSpan.input = [{ role: '', content: mlObsTags[INPUT_VALUE] }]
158
167
  inputType = 'value'
@@ -162,7 +171,8 @@ class LLMObsSpanProcessor {
162
171
  llmObsSpan.output = mlObsTags[OUTPUT_MESSAGES]
163
172
  outputType = 'messages'
164
173
  } else if (spanKind === 'retrieval' && mlObsTags[OUTPUT_DOCUMENTS]) {
165
- output.documents = mlObsTags[OUTPUT_DOCUMENTS]
174
+ llmObsSpan.output = mlObsTags[OUTPUT_DOCUMENTS].map(doc => ({ content: doc.text, role: '' }))
175
+ outputType = 'documents'
166
176
  } else if (mlObsTags[OUTPUT_VALUE]) {
167
177
  llmObsSpan.output = [{ role: '', content: mlObsTags[OUTPUT_VALUE] }]
168
178
  outputType = 'value'
@@ -194,6 +204,11 @@ class LLMObsSpanProcessor {
194
204
  input.messages = processedSpan.input
195
205
  } else if (inputType === 'value') {
196
206
  input.value = processedSpan.input[0].content
207
+ } else if (inputType === 'documents') {
208
+ input.documents = processedSpan.input.map((processedDocument, processedDocumentIdx) => ({
209
+ ...mlObsTags[INPUT_DOCUMENTS][processedDocumentIdx],
210
+ text: processedDocument.content,
211
+ }))
197
212
  }
198
213
  }
199
214
 
@@ -202,6 +217,11 @@ class LLMObsSpanProcessor {
202
217
  output.messages = processedSpan.output
203
218
  } else if (outputType === 'value') {
204
219
  output.value = processedSpan.output[0].content
220
+ } else if (outputType === 'documents') {
221
+ output.documents = processedSpan.output.map((processedDocument, processedDocumentIdx) => ({
222
+ ...mlObsTags[OUTPUT_DOCUMENTS][processedDocumentIdx],
223
+ text: processedDocument.content,
224
+ }))
205
225
  }
206
226
  }
207
227
 
@@ -12,6 +12,7 @@ function encodeUnicode (str = '') {
12
12
  for (let index = 0; index < str.length; index++) {
13
13
  if (str.charCodeAt(index) > 127) {
14
14
  let result = str.slice(0, index)
15
+ // eslint-disable-next-line sonarjs/updated-loop-counter -- inner loop continues from outer position
15
16
  for (; index < str.length; index++) {
16
17
  const code = str.charCodeAt(index)
17
18
  result += code > 127 ? String.raw`\u${code.toString(16).padStart(4, '0')}` : str[index]
@@ -8,11 +8,13 @@ const DEFAULT_MIN_SIZE = 2 * 1024 * 1024 // 2MB
8
8
  * either.
9
9
  */
10
10
  class MsgpackChunk {
11
+ #minSize
12
+
11
13
  constructor (minSize = DEFAULT_MIN_SIZE) {
12
14
  this.buffer = Buffer.allocUnsafe(minSize)
13
15
  this.view = new DataView(this.buffer.buffer)
14
16
  this.length = 0
15
- this._minSize = minSize
17
+ this.#minSize = minSize
16
18
  }
17
19
 
18
20
  write (value) {
@@ -50,13 +52,14 @@ class MsgpackChunk {
50
52
 
51
53
  reserve (size) {
52
54
  if (this.length + size > this.buffer.length) {
53
- this._resize(this._minSize * Math.ceil((this.length + size) / this._minSize))
55
+ const minSize = this.#minSize
56
+ this.#resize(minSize * Math.ceil((this.length + size) / minSize))
54
57
  }
55
58
 
56
59
  this.length += size
57
60
  }
58
61
 
59
- _resize (size) {
62
+ #resize (size) {
60
63
  const oldBuffer = this.buffer
61
64
 
62
65
  this.buffer = Buffer.allocUnsafe(size)
@@ -2,6 +2,18 @@
2
2
 
3
3
  const { NOOP_REASON } = require('./constants/constants')
4
4
 
5
+ /**
6
+ * @template T
7
+ * @param {T} defaultValue
8
+ * @returns {Promise<{value: T, reason: string}>}
9
+ */
10
+ function resolveDefault (defaultValue) {
11
+ return Promise.resolve({
12
+ value: defaultValue,
13
+ reason: NOOP_REASON,
14
+ })
15
+ }
16
+
5
17
  /**
6
18
  * No-op implementation of OpenFeature provider that always returns default values.
7
19
  * Used when the OpenFeature provider is not initialized or disabled.
@@ -20,59 +32,51 @@ class NoopFlaggingProvider {
20
32
  }
21
33
 
22
34
  /**
23
- * @param {string} flagKey - Flag key
24
- * @param {boolean} defaultValue - Default value to return
25
- * @param {object} context - Evaluation context
26
- * @param {object} logger - Logger instance
27
- * @returns {Promise<{value: boolean, reason: string}>} Resolution details
35
+ * @template T
36
+ * @param {string} flagKey
37
+ * @param {T} defaultValue
38
+ * @param {object} context
39
+ * @param {object} logger
40
+ * @returns {Promise<{value: T, reason: string}>}
28
41
  */
29
42
  resolveBooleanEvaluation (flagKey, defaultValue, context, logger) {
30
- return Promise.resolve({
31
- value: defaultValue,
32
- reason: NOOP_REASON,
33
- })
43
+ return resolveDefault(defaultValue)
34
44
  }
35
45
 
36
46
  /**
37
- * @param {string} flagKey - Flag key
38
- * @param {string} defaultValue - Default value to return
39
- * @param {object} context - Evaluation context
40
- * @param {object} logger - Logger instance
41
- * @returns {Promise<{value: string, reason: string}>} Resolution details
47
+ * @template T
48
+ * @param {string} flagKey
49
+ * @param {T} defaultValue
50
+ * @param {object} context
51
+ * @param {object} logger
52
+ * @returns {Promise<{value: T, reason: string}>}
42
53
  */
43
54
  resolveStringEvaluation (flagKey, defaultValue, context, logger) {
44
- return Promise.resolve({
45
- value: defaultValue,
46
- reason: NOOP_REASON,
47
- })
55
+ return resolveDefault(defaultValue)
48
56
  }
49
57
 
50
58
  /**
51
- * @param {string} flagKey - Flag key
52
- * @param {number} defaultValue - Default value to return
53
- * @param {object} context - Evaluation context
54
- * @param {object} logger - Logger instance
55
- * @returns {Promise<{value: number, reason: string}>} Resolution details
59
+ * @template T
60
+ * @param {string} flagKey
61
+ * @param {T} defaultValue
62
+ * @param {object} context
63
+ * @param {object} logger
64
+ * @returns {Promise<{value: T, reason: string}>}
56
65
  */
57
66
  resolveNumberEvaluation (flagKey, defaultValue, context, logger) {
58
- return Promise.resolve({
59
- value: defaultValue,
60
- reason: NOOP_REASON,
61
- })
67
+ return resolveDefault(defaultValue)
62
68
  }
63
69
 
64
70
  /**
65
- * @param {string} flagKey - Flag key
66
- * @param {object} defaultValue - Default value to return
67
- * @param {object} context - Evaluation context
68
- * @param {object} logger - Logger instance
69
- * @returns {Promise<{value: object, reason: string}>} Resolution details
71
+ * @template T
72
+ * @param {string} flagKey
73
+ * @param {T} defaultValue
74
+ * @param {object} context
75
+ * @param {object} logger
76
+ * @returns {Promise<{value: T, reason: string}>}
70
77
  */
71
78
  resolveObjectEvaluation (flagKey, defaultValue, context, logger) {
72
- return Promise.resolve({
73
- value: defaultValue,
74
- reason: NOOP_REASON,
75
- })
79
+ return resolveDefault(defaultValue)
76
80
  }
77
81
 
78
82
  /**
@@ -43,7 +43,7 @@ const BaseFFEWriter = require('./base')
43
43
  */
44
44
  class ExposuresWriter extends BaseFFEWriter {
45
45
  /**
46
- * @param {import('../../config')} config - Tracer configuration object
46
+ * @param {import('../../config/config-base')} config - Tracer configuration object
47
47
  */
48
48
  constructor (config) {
49
49
  // Build full EVP endpoint path
@@ -62,7 +62,19 @@ class ExposuresWriter extends BaseFFEWriter {
62
62
  })
63
63
  this._enabled = false // Start disabled until agent strategy is set
64
64
  this._pendingEvents = [] // Buffer events until enabled
65
- this._context = this._buildContext()
65
+
66
+ const context = {
67
+ service: config.service,
68
+ }
69
+ // Only include version and env if they are defined
70
+ if (config.version !== undefined) {
71
+ context.version = config.version
72
+ }
73
+ if (config.env !== undefined) {
74
+ context.env = config.env
75
+ }
76
+
77
+ this._context = context
66
78
  }
67
79
 
68
80
  /**
@@ -112,62 +124,31 @@ class ExposuresWriter extends BaseFFEWriter {
112
124
  * @returns {ExposureEventPayload} Formatted payload with service context
113
125
  */
114
126
  makePayload (events) {
115
- const formattedEvents = events.map(event => this._formatExposureEvent(event))
127
+ const formattedEvents = events.map(event => {
128
+ return {
129
+ timestamp: event.timestamp || Date.now(),
130
+ allocation: {
131
+ key: event.allocation?.key || event['allocation.key'],
132
+ },
133
+ flag: {
134
+ key: event.flag?.key || event['flag.key'],
135
+ },
136
+ variant: {
137
+ key: event.variant?.key || event['variant.key'],
138
+ },
139
+ subject: {
140
+ id: event.subject?.id || event['subject.id'],
141
+ type: event.subject?.type,
142
+ attributes: event.subject?.attributes,
143
+ },
144
+ }
145
+ })
116
146
 
117
147
  return {
118
148
  context: this._context,
119
149
  exposures: formattedEvents,
120
150
  }
121
151
  }
122
-
123
- /**
124
- * Builds service context metadata
125
- * @private
126
- * @returns {ExposureContext} Service context
127
- */
128
- _buildContext () {
129
- const context = {
130
- service: this._config.service || 'unknown',
131
- }
132
-
133
- // Only include version and env if they are defined
134
- if (this._config.version !== undefined) {
135
- context.version = this._config.version
136
- }
137
-
138
- if (this._config.env !== undefined) {
139
- context.env = this._config.env
140
- }
141
-
142
- return context
143
- }
144
-
145
- /**
146
- * @private
147
- * @param {ExposureEvent} event - Raw exposure event
148
- * @returns {ExposureEvent} Formatted exposure event
149
- */
150
- _formatExposureEvent (event) {
151
- // Ensure the event matches the expected schema
152
- const formattedEvent = {
153
- timestamp: event.timestamp || Date.now(),
154
- allocation: {
155
- key: event.allocation?.key || event['allocation.key'],
156
- },
157
- flag: {
158
- key: event.flag?.key || event['flag.key'],
159
- },
160
- variant: {
161
- key: event.variant?.key || event['variant.key'],
162
- },
163
- subject: {
164
- id: event.subject?.id || event['subject.id'],
165
- type: event.subject?.type,
166
- attributes: event.subject?.attributes,
167
- },
168
- }
169
- return formattedEvent
170
- }
171
152
  }
172
153
 
173
154
  module.exports = ExposuresWriter
@@ -141,8 +141,7 @@ class OtlpTransformerBase {
141
141
  */
142
142
  serializeToProtobuf (protoType, data) {
143
143
  const message = protoType.create(data)
144
- const buffer = protoType.encode(message).finish()
145
- return buffer
144
+ return protoType.encode(message).finish()
146
145
  }
147
146
 
148
147
  /**
@@ -130,28 +130,6 @@ class Tracer {
130
130
  }
131
131
  const attributes = sanitizeAttributes(options.attributes)
132
132
 
133
- // TODO: sampling API is not yet supported
134
- // // make sampling decision
135
- // const samplingResult = this._sampler.shouldSample(
136
- // context,
137
- // spanContext.traceId,
138
- // name,
139
- // spanKind,
140
- // attributes,
141
- // links
142
- // )
143
-
144
- // // Should use new span context
145
- // spanContext._ddContext._sampling.priority =
146
- // samplingResult.decision === api.SamplingDecision.RECORD_AND_SAMPLED
147
- // ? AUTO_KEEP
148
- // : AUTO_REJECT
149
-
150
- // if (samplingResult.decision === api.SamplingDecision.NOT_RECORD) {
151
- // api.diag.debug('Recording is off, propagating context in a non-recording span')
152
- // return api.trace.wrapSpanContext(spanContext)
153
- // }
154
-
155
133
  return new Span(
156
134
  this,
157
135
  context,
@@ -16,7 +16,7 @@ class DSMTextMapPropagator {
16
16
  inject (ctx, carrier) {
17
17
  if (!this.config.dsmEnabled) return
18
18
 
19
- this._injectDatadogDSMContext(ctx, carrier)
19
+ DsmPathwayCodec.encode(ctx, carrier)
20
20
 
21
21
  // eslint-disable-next-line eslint-rules/eslint-log-printf-style
22
22
  log.debug(() => `Inject into carrier (DSM): ${JSON.stringify(pick(carrier, logKeys))}.`)
@@ -25,7 +25,7 @@ class DSMTextMapPropagator {
25
25
  extract (carrier) {
26
26
  if (!this.config.dsmEnabled) return
27
27
 
28
- const dsmContext = this._extractDatadogDSMContext(carrier)
28
+ const dsmContext = DsmPathwayCodec.decode(carrier)
29
29
 
30
30
  if (!dsmContext) return dsmContext
31
31
 
@@ -33,15 +33,6 @@ class DSMTextMapPropagator {
33
33
  log.debug(() => `Extract from carrier (DSM): ${JSON.stringify(pick(carrier, logKeys))}.`)
34
34
  return dsmContext
35
35
  }
36
-
37
- _injectDatadogDSMContext (ctx, carrier) {
38
- DsmPathwayCodec.encode(ctx, carrier)
39
- }
40
-
41
- _extractDatadogDSMContext (carrier) {
42
- const ctx = DsmPathwayCodec.decode(carrier)
43
- return ctx
44
- }
45
36
  }
46
37
 
47
38
  module.exports = DSMTextMapPropagator
@@ -650,7 +650,7 @@ module.exports = {
650
650
  [GIT_TAG]: BITBUCKET_TAG,
651
651
  [GIT_REPOSITORY_URL]: BITBUCKET_GIT_SSH_ORIGIN || BITBUCKET_GIT_HTTP_ORIGIN,
652
652
  [CI_WORKSPACE_PATH]: BITBUCKET_CLONE_DIR,
653
- [CI_PIPELINE_ID]: BITBUCKET_PIPELINE_UUID && BITBUCKET_PIPELINE_UUID.replaceAll(/{|}/gm, ''),
653
+ [CI_PIPELINE_ID]: BITBUCKET_PIPELINE_UUID && BITBUCKET_PIPELINE_UUID.replaceAll(/[{}]/gm, ''),
654
654
  [GIT_PULL_REQUEST_BASE_BRANCH]: BITBUCKET_PR_DESTINATION_BRANCH,
655
655
  [PR_NUMBER]: BITBUCKET_PR_ID,
656
656
  }
@@ -53,14 +53,12 @@ function getCache (cacheKey) {
53
53
  try {
54
54
  const cacheFilePath = getCacheFilePath(cacheKey)
55
55
  if (!fs.existsSync(cacheFilePath)) {
56
- return null
56
+ return
57
57
  }
58
58
 
59
- const content = fs.readFileSync(cacheFilePath, 'utf8')
60
- return content
59
+ return fs.readFileSync(cacheFilePath, 'utf8')
61
60
  } catch (err) {
62
61
  log.error('Failed to read git cache', err)
63
- return null
64
62
  }
65
63
  }
66
64
 
@@ -87,7 +85,7 @@ function cachedExec (cmd, flags, options) {
87
85
  }
88
86
  const cacheKey = getCacheKey(cmd, flags)
89
87
  const cachedResult = getCache(cacheKey)
90
- if (cachedResult !== null) {
88
+ if (cachedResult !== undefined) {
91
89
  if (cachedResult.startsWith('__GIT_COMMAND_FAILED__')) {
92
90
  let error
93
91
  try {