dd-trace 5.101.0 → 5.103.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 (235) hide show
  1. package/ext/exporters.js +1 -0
  2. package/package.json +20 -17
  3. package/packages/datadog-esbuild/src/utils.js +2 -2
  4. package/packages/datadog-instrumentations/src/aerospike.js +2 -2
  5. package/packages/datadog-instrumentations/src/ai.js +9 -9
  6. package/packages/datadog-instrumentations/src/amqplib.js +6 -7
  7. package/packages/datadog-instrumentations/src/anthropic.js +10 -10
  8. package/packages/datadog-instrumentations/src/apollo-server-core.js +3 -3
  9. package/packages/datadog-instrumentations/src/apollo-server.js +5 -5
  10. package/packages/datadog-instrumentations/src/avsc.js +6 -6
  11. package/packages/datadog-instrumentations/src/aws-sdk.js +151 -67
  12. package/packages/datadog-instrumentations/src/azure-durable-functions.js +8 -8
  13. package/packages/datadog-instrumentations/src/bluebird.js +2 -2
  14. package/packages/datadog-instrumentations/src/body-parser.js +2 -2
  15. package/packages/datadog-instrumentations/src/cassandra-driver.js +7 -7
  16. package/packages/datadog-instrumentations/src/child_process.js +12 -12
  17. package/packages/datadog-instrumentations/src/confluentinc-kafka-javascript.js +41 -24
  18. package/packages/datadog-instrumentations/src/connect.js +7 -7
  19. package/packages/datadog-instrumentations/src/cookie-parser.js +4 -4
  20. package/packages/datadog-instrumentations/src/cookie.js +2 -2
  21. package/packages/datadog-instrumentations/src/couchbase.js +73 -238
  22. package/packages/datadog-instrumentations/src/crypto.js +4 -4
  23. package/packages/datadog-instrumentations/src/cucumber.js +78 -17
  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/electron/preload.js +42 -0
  27. package/packages/datadog-instrumentations/src/electron.js +240 -0
  28. package/packages/datadog-instrumentations/src/express-mongo-sanitize.js +6 -6
  29. package/packages/datadog-instrumentations/src/express-session.js +4 -4
  30. package/packages/datadog-instrumentations/src/express.js +10 -11
  31. package/packages/datadog-instrumentations/src/fastify.js +2 -2
  32. package/packages/datadog-instrumentations/src/fetch.js +5 -5
  33. package/packages/datadog-instrumentations/src/fs.js +14 -14
  34. package/packages/datadog-instrumentations/src/google-cloud-pubsub.js +5 -7
  35. package/packages/datadog-instrumentations/src/google-genai.js +4 -4
  36. package/packages/datadog-instrumentations/src/graphql.js +13 -12
  37. package/packages/datadog-instrumentations/src/grpc/server.js +2 -2
  38. package/packages/datadog-instrumentations/src/hapi.js +2 -2
  39. package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +9 -9
  40. package/packages/datadog-instrumentations/src/helpers/hook.js +4 -1
  41. package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
  42. package/packages/datadog-instrumentations/src/helpers/instrument.js +2 -2
  43. package/packages/datadog-instrumentations/src/helpers/kafka.js +41 -0
  44. package/packages/datadog-instrumentations/src/helpers/promise.js +2 -2
  45. package/packages/datadog-instrumentations/src/hono.js +2 -2
  46. package/packages/datadog-instrumentations/src/http/client.js +6 -6
  47. package/packages/datadog-instrumentations/src/http/server.js +9 -9
  48. package/packages/datadog-instrumentations/src/ioredis.js +16 -12
  49. package/packages/datadog-instrumentations/src/jest.js +382 -81
  50. package/packages/datadog-instrumentations/src/kafkajs.js +165 -174
  51. package/packages/datadog-instrumentations/src/knex.js +17 -17
  52. package/packages/datadog-instrumentations/src/koa.js +12 -12
  53. package/packages/datadog-instrumentations/src/ldapjs.js +5 -5
  54. package/packages/datadog-instrumentations/src/light-my-request.js +2 -2
  55. package/packages/datadog-instrumentations/src/limitd-client.js +4 -4
  56. package/packages/datadog-instrumentations/src/lodash.js +4 -4
  57. package/packages/datadog-instrumentations/src/mariadb.js +13 -13
  58. package/packages/datadog-instrumentations/src/memcached.js +2 -2
  59. package/packages/datadog-instrumentations/src/microgateway-core.js +2 -2
  60. package/packages/datadog-instrumentations/src/mocha/common.js +3 -3
  61. package/packages/datadog-instrumentations/src/mocha/main.js +85 -11
  62. package/packages/datadog-instrumentations/src/mocha/utils.js +133 -16
  63. package/packages/datadog-instrumentations/src/mocha/worker.js +7 -5
  64. package/packages/datadog-instrumentations/src/mongodb-core.js +42 -30
  65. package/packages/datadog-instrumentations/src/mongodb.js +5 -5
  66. package/packages/datadog-instrumentations/src/mongoose.js +21 -21
  67. package/packages/datadog-instrumentations/src/mquery.js +5 -5
  68. package/packages/datadog-instrumentations/src/multer.js +4 -4
  69. package/packages/datadog-instrumentations/src/mysql.js +16 -16
  70. package/packages/datadog-instrumentations/src/mysql2.js +4 -4
  71. package/packages/datadog-instrumentations/src/net.js +14 -8
  72. package/packages/datadog-instrumentations/src/nyc.js +5 -5
  73. package/packages/datadog-instrumentations/src/openai.js +19 -19
  74. package/packages/datadog-instrumentations/src/oracledb.js +6 -6
  75. package/packages/datadog-instrumentations/src/passport-utils.js +5 -5
  76. package/packages/datadog-instrumentations/src/pg.js +39 -25
  77. package/packages/datadog-instrumentations/src/pino.js +6 -10
  78. package/packages/datadog-instrumentations/src/playwright.js +445 -68
  79. package/packages/datadog-instrumentations/src/protobufjs.js +16 -16
  80. package/packages/datadog-instrumentations/src/redis.js +20 -12
  81. package/packages/datadog-instrumentations/src/restify.js +2 -2
  82. package/packages/datadog-instrumentations/src/router.js +12 -12
  83. package/packages/datadog-instrumentations/src/stripe.js +12 -12
  84. package/packages/datadog-instrumentations/src/vitest.js +107 -26
  85. package/packages/datadog-instrumentations/src/winston.js +4 -4
  86. package/packages/datadog-instrumentations/src/ws.js +7 -7
  87. package/packages/datadog-plugin-apollo/src/gateway/request.js +1 -21
  88. package/packages/datadog-plugin-aws-sdk/src/base.js +70 -28
  89. package/packages/datadog-plugin-aws-sdk/src/services/cloudwatchlogs.js +1 -1
  90. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +20 -13
  91. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +46 -36
  92. package/packages/datadog-plugin-aws-sdk/src/services/lambda.js +34 -23
  93. package/packages/datadog-plugin-aws-sdk/src/services/redshift.js +1 -1
  94. package/packages/datadog-plugin-aws-sdk/src/services/s3.js +1 -1
  95. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +14 -15
  96. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +74 -55
  97. package/packages/datadog-plugin-aws-sdk/src/services/stepfunctions.js +20 -18
  98. package/packages/datadog-plugin-aws-sdk/src/util.js +22 -0
  99. package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +6 -6
  100. package/packages/datadog-plugin-couchbase/src/index.js +58 -52
  101. package/packages/datadog-plugin-cucumber/src/index.js +5 -0
  102. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +215 -26
  103. package/packages/datadog-plugin-cypress/src/support.js +13 -1
  104. package/packages/datadog-plugin-electron/src/index.js +17 -0
  105. package/packages/datadog-plugin-electron/src/ipc.js +143 -0
  106. package/packages/datadog-plugin-electron/src/net.js +82 -0
  107. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +1 -5
  108. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +27 -18
  109. package/packages/datadog-plugin-google-cloud-pubsub/src/pubsub-push-subscription.js +3 -1
  110. package/packages/datadog-plugin-graphql/src/execute.js +6 -28
  111. package/packages/datadog-plugin-graphql/src/resolve.js +30 -35
  112. package/packages/datadog-plugin-graphql/src/tools/signature.js +32 -7
  113. package/packages/datadog-plugin-graphql/src/tools/transforms.js +118 -100
  114. package/packages/datadog-plugin-graphql/src/utils.js +29 -0
  115. package/packages/datadog-plugin-grpc/src/client.js +6 -7
  116. package/packages/datadog-plugin-grpc/src/util.js +57 -22
  117. package/packages/datadog-plugin-http/src/client.js +3 -7
  118. package/packages/datadog-plugin-jest/src/index.js +92 -50
  119. package/packages/datadog-plugin-jest/src/util.js +1 -2
  120. package/packages/datadog-plugin-mocha/src/index.js +5 -0
  121. package/packages/datadog-plugin-mongodb-core/src/index.js +36 -69
  122. package/packages/datadog-plugin-mysql/src/index.js +1 -1
  123. package/packages/datadog-plugin-openai/src/services.js +2 -1
  124. package/packages/datadog-plugin-openai/src/tracing.js +12 -23
  125. package/packages/datadog-plugin-pg/src/index.js +3 -3
  126. package/packages/datadog-plugin-playwright/src/index.js +5 -1
  127. package/packages/datadog-plugin-redis/src/index.js +18 -23
  128. package/packages/datadog-plugin-vitest/src/index.js +8 -1
  129. package/packages/datadog-shimmer/src/shimmer.js +7 -1
  130. package/packages/dd-trace/src/aiguard/index.js +3 -1
  131. package/packages/dd-trace/src/aiguard/sdk.js +36 -30
  132. package/packages/dd-trace/src/aiguard/tags.js +20 -11
  133. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-password-rules.js +1 -1
  134. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secret-rules.js +81 -81
  135. package/packages/dd-trace/src/appsec/iast/security-controls/index.js +2 -2
  136. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugins/kafka.js +2 -2
  137. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +4 -4
  138. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +2 -2
  139. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +2 -0
  140. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/index.js +1 -3
  141. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +83 -48
  142. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +1 -1
  143. package/packages/dd-trace/src/appsec/index.js +21 -24
  144. package/packages/dd-trace/src/appsec/reporter.js +3 -1
  145. package/packages/dd-trace/src/appsec/rule_manager.js +4 -2
  146. package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +31 -16
  147. package/packages/dd-trace/src/azure_metadata.js +17 -6
  148. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +4 -4
  149. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +4 -2
  150. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +6 -4
  151. package/packages/dd-trace/src/ci-visibility/requests/fs-cache.js +1 -1
  152. package/packages/dd-trace/src/config/defaults.js +3 -14
  153. package/packages/dd-trace/src/config/generated-config-types.d.ts +3 -1
  154. package/packages/dd-trace/src/config/git_properties.js +2 -2
  155. package/packages/dd-trace/src/config/helper.js +4 -0
  156. package/packages/dd-trace/src/config/index.js +2 -2
  157. package/packages/dd-trace/src/config/major-overrides.js +98 -0
  158. package/packages/dd-trace/src/config/parsers.js +7 -1
  159. package/packages/dd-trace/src/config/supported-configurations.json +51 -38
  160. package/packages/dd-trace/src/datastreams/checkpointer.js +2 -2
  161. package/packages/dd-trace/src/datastreams/index.js +2 -1
  162. package/packages/dd-trace/src/datastreams/manager.js +1 -1
  163. package/packages/dd-trace/src/datastreams/processor.js +3 -4
  164. package/packages/dd-trace/src/debugger/devtools_client/snapshot/collector.js +2 -2
  165. package/packages/dd-trace/src/debugger/devtools_client/snapshot-pruner.js +1 -0
  166. package/packages/dd-trace/src/debugger/devtools_client/source-maps.js +1 -1
  167. package/packages/dd-trace/src/debugger/devtools_client/state.js +2 -1
  168. package/packages/dd-trace/src/debugger/index.js +7 -7
  169. package/packages/dd-trace/src/dogstatsd.js +2 -2
  170. package/packages/dd-trace/src/encode/0.4.js +748 -232
  171. package/packages/dd-trace/src/encode/0.5.js +47 -10
  172. package/packages/dd-trace/src/encode/agentless-json.js +1 -1
  173. package/packages/dd-trace/src/exporter.js +2 -0
  174. package/packages/dd-trace/src/exporters/agent/index.js +2 -1
  175. package/packages/dd-trace/src/exporters/agentless/index.js +3 -2
  176. package/packages/dd-trace/src/exporters/agentless/writer.js +2 -2
  177. package/packages/dd-trace/src/exporters/common/buffering-exporter.js +2 -1
  178. package/packages/dd-trace/src/exporters/common/request.js +1 -1
  179. package/packages/dd-trace/src/exporters/electron/index.js +49 -0
  180. package/packages/dd-trace/src/external-logger/src/index.js +2 -1
  181. package/packages/dd-trace/src/git_metadata.js +10 -8
  182. package/packages/dd-trace/src/lambda/handler-paths.js +52 -0
  183. package/packages/dd-trace/src/lambda/index.js +62 -14
  184. package/packages/dd-trace/src/lambda/runtime/patch.js +21 -46
  185. package/packages/dd-trace/src/llmobs/index.js +13 -2
  186. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +1 -2
  187. package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +45 -15
  188. package/packages/dd-trace/src/llmobs/plugins/genai/util.js +6 -3
  189. package/packages/dd-trace/src/llmobs/sdk.js +24 -26
  190. package/packages/dd-trace/src/llmobs/span_processor.js +25 -5
  191. package/packages/dd-trace/src/llmobs/util.js +1 -0
  192. package/packages/dd-trace/src/llmobs/writers/base.js +2 -1
  193. package/packages/dd-trace/src/msgpack/chunk.js +6 -3
  194. package/packages/dd-trace/src/openfeature/noop.js +40 -36
  195. package/packages/dd-trace/src/openfeature/writers/base.js +2 -1
  196. package/packages/dd-trace/src/openfeature/writers/exposures.js +33 -52
  197. package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +2 -1
  198. package/packages/dd-trace/src/opentelemetry/otlp/otlp_transformer_base.js +1 -2
  199. package/packages/dd-trace/src/opentelemetry/tracer.js +0 -22
  200. package/packages/dd-trace/src/opentracing/propagation/text_map.js +20 -9
  201. package/packages/dd-trace/src/opentracing/propagation/text_map_dsm.js +2 -11
  202. package/packages/dd-trace/src/payload-tagging/config/index.js +2 -2
  203. package/packages/dd-trace/src/plugins/ci_plugin.js +49 -4
  204. package/packages/dd-trace/src/plugins/database.js +54 -12
  205. package/packages/dd-trace/src/plugins/index.js +1 -0
  206. package/packages/dd-trace/src/plugins/plugin.js +2 -4
  207. package/packages/dd-trace/src/plugins/util/ci.js +9 -9
  208. package/packages/dd-trace/src/plugins/util/git-cache.js +23 -23
  209. package/packages/dd-trace/src/plugins/util/stacktrace.js +2 -2
  210. package/packages/dd-trace/src/plugins/util/test.js +56 -12
  211. package/packages/dd-trace/src/plugins/util/url.js +1 -3
  212. package/packages/dd-trace/src/plugins/util/user-provided-git.js +18 -16
  213. package/packages/dd-trace/src/plugins/util/web.js +5 -7
  214. package/packages/dd-trace/src/priority_sampler.js +1 -1
  215. package/packages/dd-trace/src/profiling/profiler.js +1 -1
  216. package/packages/dd-trace/src/profiling/profilers/events.js +3 -23
  217. package/packages/dd-trace/src/profiling/profilers/wall.js +5 -6
  218. package/packages/dd-trace/src/profiling/ssi-heuristics.js +1 -1
  219. package/packages/dd-trace/src/rate_limiter.js +1 -1
  220. package/packages/dd-trace/src/remote_config/scheduler.js +1 -1
  221. package/packages/dd-trace/src/ritm.js +2 -1
  222. package/packages/dd-trace/src/runtime_metrics/index.js +2 -2
  223. package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +5 -8
  224. package/packages/dd-trace/src/scope.js +3 -10
  225. package/packages/dd-trace/src/serverless.js +6 -6
  226. package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +27 -1
  227. package/packages/dd-trace/src/service-naming/schemas/v0/web.js +4 -0
  228. package/packages/dd-trace/src/service-naming/schemas/v1/messaging.js +24 -0
  229. package/packages/dd-trace/src/service-naming/schemas/v1/web.js +4 -0
  230. package/packages/dd-trace/src/span_stats.js +1 -1
  231. package/packages/dd-trace/src/telemetry/dependencies.js +1 -1
  232. package/packages/dd-trace/src/telemetry/endpoints.js +1 -1
  233. package/packages/dd-trace/src/telemetry/telemetry.js +2 -2
  234. package/packages/dd-trace/src/tracer.js +7 -7
  235. package/packages/dd-trace/src/lambda/runtime/ritm.js +0 -133
@@ -3,7 +3,7 @@
3
3
  const log = require('../../../dd-trace/src/log')
4
4
  const BaseAwsSdkPlugin = require('../base')
5
5
  const { DsmPathwayCodec, getHeadersSize } = require('../../../dd-trace/src/datastreams')
6
- const { extractQueueMetadata } = require('../util')
6
+ const { extractQueueMetadata, isEmpty } = require('../util')
7
7
 
8
8
  class Sqs extends BaseAwsSdkPlugin {
9
9
  static id = 'sqs'
@@ -23,25 +23,32 @@ class Sqs extends BaseAwsSdkPlugin {
23
23
 
24
24
  let store = this._parentMap.get(request)
25
25
  let span
26
- let parsedMessageAttributes = null
27
- if (contextExtraction && contextExtraction.datadogContext) {
28
- ctx.needsFinish = true
29
- const options = {
30
- childOf: contextExtraction.datadogContext,
31
- meta: {
32
- ...this.requestTags.get(request),
33
- 'span.kind': 'server',
34
- },
35
- integrationName: 'aws-sdk',
26
+ let parsedMessageAttributes
27
+ let parsedFirstBody
28
+ let firstBodyChecked = false
29
+ if (contextExtraction !== undefined) {
30
+ parsedFirstBody = contextExtraction.parsedBody
31
+ firstBodyChecked = contextExtraction.bodyChecked === true
32
+ if (contextExtraction.datadogContext !== undefined) {
33
+ ctx.needsFinish = true
34
+ const options = {
35
+ childOf: contextExtraction.datadogContext,
36
+ meta: {
37
+ ...this.requestTags.get(request),
38
+ 'span.kind': 'server',
39
+ },
40
+ integrationName: 'aws-sdk',
41
+ }
42
+ parsedMessageAttributes = contextExtraction.parsedAttributes
43
+ span = this.startSpan('aws.response', options, ctx)
44
+ store = ctx.currentStore
36
45
  }
37
- parsedMessageAttributes = contextExtraction.parsedAttributes
38
- span = this.startSpan('aws.response', options, ctx)
39
- store = ctx.currentStore
40
46
  }
41
47
 
42
- // extract DSM context after as we might not have a parent-child but may have a DSM context
48
+ // Extract DSM context after, as we might not have a parent-child but may have a DSM context.
43
49
  this.responseExtractDSMContext(
44
- request.operation, request.params, response, span || null, { parsedAttributes: parsedMessageAttributes }
50
+ request.operation, request.params, response, span ?? null,
51
+ { parsedAttributes: parsedMessageAttributes, parsedFirstBody, firstBodyChecked }
45
52
  )
46
53
 
47
54
  return store
@@ -92,7 +99,7 @@ class Sqs extends BaseAwsSdkPlugin {
92
99
  }
93
100
 
94
101
  generateTags (params, operation, response) {
95
- if (!params || (!params.QueueName && !params.QueueUrl)) return {}
102
+ if (!params || (!params.QueueName && !params.QueueUrl)) return
96
103
 
97
104
  const queueMetadata = extractQueueMetadata(params.QueueUrl)
98
105
  const queueName = queueMetadata?.queueName || params.QueueName
@@ -128,21 +135,23 @@ class Sqs extends BaseAwsSdkPlugin {
128
135
  if (!response || !response.Messages || !response.Messages[0]) return
129
136
 
130
137
  let message = response.Messages[0]
138
+ let parsedBody
131
139
 
132
140
  if (message.Body) {
133
141
  try {
134
- const body = JSON.parse(message.Body)
135
-
136
- // SNS to SQS
137
- if (body.Type === 'Notification') {
138
- message = body
139
- }
142
+ parsedBody = JSON.parse(message.Body)
140
143
  } catch {
141
144
  // SQS to SQS
142
145
  }
146
+ // SNS to SQS
147
+ if (parsedBody?.Type === 'Notification') {
148
+ message = parsedBody
149
+ }
143
150
  }
144
151
 
145
- if (!message.MessageAttributes || !message.MessageAttributes._datadog) return
152
+ if (!message.MessageAttributes || !message.MessageAttributes._datadog) {
153
+ return { parsedBody, bodyChecked: true }
154
+ }
146
155
 
147
156
  const datadogAttribute = message.MessageAttributes._datadog
148
157
 
@@ -151,8 +160,12 @@ class Sqs extends BaseAwsSdkPlugin {
151
160
  return {
152
161
  datadogContext: this.tracer.extract('text_map', parsedAttributes),
153
162
  parsedAttributes,
163
+ parsedBody,
164
+ bodyChecked: true,
154
165
  }
155
166
  }
167
+
168
+ return { parsedBody, bodyChecked: true }
156
169
  }
157
170
 
158
171
  parseDatadogAttributes (attributes) {
@@ -164,36 +177,43 @@ class Sqs extends BaseAwsSdkPlugin {
164
177
  const buffer = Buffer.from(attributes.Value ?? attributes.BinaryValue, 'base64')
165
178
  return JSON.parse(buffer)
166
179
  }
167
- } catch (e) {
168
- log.error('Sqs error parsing DD attributes', e)
180
+ } catch (error) {
181
+ log.error('Sqs error parsing DD attributes', error)
169
182
  }
170
183
  }
171
184
 
172
185
  responseExtractDSMContext (operation, params, response, span, kwargs = {}) {
173
186
  let { parsedAttributes } = kwargs
187
+ const { parsedFirstBody, firstBodyChecked } = kwargs
174
188
  if (!this.config.dsmEnabled) return
175
189
  if (operation !== 'receiveMessage') return
176
190
  if (!response || !response.Messages || !response.Messages[0]) return
177
191
 
178
- // we only want to set the payloadSize on the span if we have one message
192
+ // Only attribute payloadSize to the span when there is a single message.
179
193
  span = response.Messages.length > 1 ? null : span
180
194
 
181
- for (let message of response.Messages) {
182
- // we may have already parsed the message attributes when extracting trace context
195
+ // QueueUrl is the same for the whole receive batch.
196
+ const queue = params.QueueUrl.slice(params.QueueUrl.lastIndexOf('/') + 1)
197
+
198
+ for (let i = 0; i < response.Messages.length; i++) {
199
+ let message = response.Messages[i]
183
200
  if (!parsedAttributes) {
184
- if (message.Body) {
201
+ let body
202
+ // responseExtract already parsed message[0]; reuse that result instead of re-parsing.
203
+ if (i === 0 && firstBodyChecked) {
204
+ body = parsedFirstBody
205
+ } else if (message.Body) {
185
206
  try {
186
- const body = JSON.parse(message.Body)
187
-
188
- // SNS to SQS
189
- if (body.Type === 'Notification') {
190
- message = body
191
- }
207
+ body = JSON.parse(message.Body)
192
208
  } catch {
193
209
  // SQS to SQS
194
210
  }
195
211
  }
196
- if (!parsedAttributes && message.MessageAttributes && message.MessageAttributes._datadog) {
212
+ // SNS to SQS
213
+ if (body?.Type === 'Notification') {
214
+ message = body
215
+ }
216
+ if (message.MessageAttributes && message.MessageAttributes._datadog) {
197
217
  parsedAttributes = this.parseDatadogAttributes(message.MessageAttributes._datadog)
198
218
  }
199
219
  }
@@ -201,7 +221,6 @@ class Sqs extends BaseAwsSdkPlugin {
201
221
  Body: message.Body,
202
222
  MessageAttributes: message.MessageAttributes,
203
223
  })
204
- const queue = params.QueueUrl.split('/').pop()
205
224
  if (parsedAttributes) {
206
225
  this.tracer.decodeDataStreamsContext(parsedAttributes)
207
226
  }
@@ -253,34 +272,35 @@ class Sqs extends BaseAwsSdkPlugin {
253
272
  // TODO: add test when the test suite is fixed
254
273
  return
255
274
  }
275
+
256
276
  const ddInfo = {}
257
- // for now, we only want to inject to the first message, this may change for batches in the future
277
+ // For now we only inject to the first message; batches may change later.
258
278
  if (injectTraceContext) {
259
279
  this.tracer.inject(span, 'text_map', ddInfo)
260
- params.MessageAttributes._datadog = {
261
- DataType: 'String',
262
- StringValue: JSON.stringify(ddInfo),
263
- }
264
280
  }
265
281
 
266
282
  if (this.config.dsmEnabled) {
267
- if (!params.MessageAttributes._datadog) {
268
- params.MessageAttributes._datadog = {
269
- DataType: 'String',
270
- StringValue: JSON.stringify(ddInfo),
271
- }
283
+ // Attach `_datadog` before measuring so the DSM payload size metric
284
+ // matches the on-wire payload, then update with the encoded context.
285
+ params.MessageAttributes._datadog = {
286
+ DataType: 'String',
287
+ StringValue: JSON.stringify(ddInfo),
272
288
  }
273
-
274
289
  const dataStreamsContext = this.setDSMCheckpoint(span, params, queueUrl)
275
290
  if (dataStreamsContext) {
276
291
  DsmPathwayCodec.encode(dataStreamsContext, ddInfo)
277
292
  params.MessageAttributes._datadog.StringValue = JSON.stringify(ddInfo)
293
+ } else if (isEmpty(ddInfo)) {
294
+ delete params.MessageAttributes._datadog
278
295
  }
296
+ return
279
297
  }
280
298
 
281
- if (params.MessageAttributes._datadog && Object.keys(ddInfo).length === 0) {
282
- // let's avoid adding any additional information to payload if we failed to inject
283
- delete params.MessageAttributes._datadog
299
+ if (isEmpty(ddInfo)) return
300
+
301
+ params.MessageAttributes._datadog = {
302
+ DataType: 'String',
303
+ StringValue: JSON.stringify(ddInfo),
284
304
  }
285
305
  }
286
306
 
@@ -289,10 +309,9 @@ class Sqs extends BaseAwsSdkPlugin {
289
309
  Body: params.MessageBody,
290
310
  MessageAttributes: params.MessageAttributes,
291
311
  })
292
- const queue = queueUrl.split('/').pop()
293
- const dataStreamsContext = this.tracer
312
+ const queue = queueUrl.slice(queueUrl.lastIndexOf('/') + 1)
313
+ return this.tracer
294
314
  .setCheckpoint(['direction:out', `topic:${queue}`, 'type:sqs'], span, payloadSize)
295
- return dataStreamsContext
296
315
  }
297
316
  }
298
317
 
@@ -28,7 +28,7 @@ class Stepfunctions extends BaseAwsSdkPlugin {
28
28
  // }
29
29
 
30
30
  generateTags (params, operation, response) {
31
- if (!params) return {}
31
+ if (!params) return
32
32
  const tags = { 'resource.name': params.name ? `${operation} ${params.name}` : `${operation}` }
33
33
  if (operation === 'startExecution' || operation === 'startSyncExecution') {
34
34
  tags.statemachinearn = `${params.stateMachineArn}`
@@ -38,25 +38,27 @@ class Stepfunctions extends BaseAwsSdkPlugin {
38
38
 
39
39
  requestInject (span, request) {
40
40
  const operation = request.operation
41
- if (operation === 'startExecution' || operation === 'startSyncExecution') {
42
- if (!request.params || !request.params.input) {
43
- return
44
- }
41
+ if ((operation !== 'startExecution' && operation !== 'startSyncExecution') || !request.params?.input) return
42
+
43
+ const input = request.params.input
44
+ if (typeof input !== 'string' || input.length < 2) return
45
+
46
+ // Skip non-object payloads up front to avoid a `JSON.parse` round-trip.
47
+ // `trimEnd` is the identity on payloads with no trailing whitespace;
48
+ // for the rare whitespace-suffixed object the slow path inside
49
+ // `injectFieldIntoJsonObject` handles the parse + restringify.
50
+ const trimmed = input.trimEnd()
51
+ if (trimmed.length < 2 || trimmed.charCodeAt(trimmed.length - 1) !== 0x7D) return
45
52
 
46
- const input = request.params.input
53
+ const injected = {}
54
+ this.tracer.inject(span, 'text_map', injected)
47
55
 
48
- try {
49
- const inputObj = JSON.parse(input)
50
- if (inputObj !== null && typeof inputObj === 'object') {
51
- // We've parsed the input JSON string
52
- inputObj._datadog = {}
53
- this.tracer.inject(span, 'text_map', inputObj._datadog)
54
- const newInput = JSON.stringify(inputObj)
55
- request.params.input = newInput
56
- }
57
- } catch {
58
- log.info('Unable to treat input as JSON')
59
- }
56
+ // `injectFieldIntoJsonObject` is the only throwing call path
57
+ // (`JSON.parse` slow path for non-trivial JSON shapes).
58
+ try {
59
+ request.params.input = BaseAwsSdkPlugin.injectFieldIntoJsonObject(input, '_datadog', injected)
60
+ } catch {
61
+ log.info('Unable to treat input as JSON')
60
62
  }
61
63
  }
62
64
  }
@@ -143,9 +143,31 @@ const extractQueueMetadata = queueURL => {
143
143
  return { queueName, arn }
144
144
  }
145
145
 
146
+ /**
147
+ * Returns true when `obj` has no own enumerable properties. The
148
+ * `for-in` loop with an early return is the only allocation-free shape
149
+ * for this check; benchmarks pin it as 1.3-1.4x faster than
150
+ * `Object.keys(obj).length === 0` across small / medium / large
151
+ * objects, and this is the hot path on every AWS messaging send.
152
+ *
153
+ * Callers in this package only pass plain objects they construct
154
+ * locally, so prototype-enumerable keys are not a concern here. Do not
155
+ * reuse this helper on caller-supplied objects without revisiting that
156
+ * assumption.
157
+ *
158
+ * @param {object} obj
159
+ * @returns {boolean}
160
+ */
161
+ const isEmpty = obj => {
162
+ // eslint-disable-next-line no-unreachable-loop
163
+ for (const _ in obj) return false
164
+ return true
165
+ }
166
+
146
167
  module.exports = {
147
168
  generatePointerHash,
148
169
  encodeValue,
149
170
  extractPrimaryKeys,
150
171
  extractQueueMetadata,
172
+ isEmpty,
151
173
  }
@@ -5,7 +5,7 @@ const shellParser = require('../../../vendor/dist/shell-quote').parse
5
5
  const ALLOWED_ENV_VARIABLES = new Set(['LD_PRELOAD', 'LD_LIBRARY_PATH', 'PATH'])
6
6
  const PROCESS_DENYLIST = new Set(['md5'])
7
7
 
8
- const VARNAMES_REGEX = /\$([\w\d_]*)(?:[^\w\d_]|$)/gmi
8
+ const VARNAMES_REGEX = /\$(\w*)(?:[^\w]|$)/gmi
9
9
  // eslint-disable-next-line @stylistic/max-len
10
10
  const PARAM_PATTERN = '^-{0,2}(?:p(?:ass(?:w(?:or)?d)?)?|address|api[-_]?key|e?mail|secret(?:[-_]?key)?|a(?:ccess|uth)[-_]?token|mysql_pwd|credentials|(?:stripe)?token)$'
11
11
  const regexParam = new RegExp(PARAM_PATTERN, 'i')
@@ -104,13 +104,13 @@ function scrubChildProcessCmd (expression) {
104
104
  result.push(token)
105
105
 
106
106
  if (PROCESS_DENYLIST.has(token)) {
107
- for (index++; index < expressionTokens.length; index++) {
108
- const token = expressionTokens[index]
107
+ for (let i = index + 1; i < expressionTokens.length; i++) {
108
+ const innerToken = expressionTokens[i]
109
109
 
110
- if (token.op) {
111
- result.push(token.op)
110
+ if (innerToken.op) {
111
+ result.push(innerToken.op)
112
112
  } else {
113
- expressionTokens[index] = REDACTED
113
+ expressionTokens[i] = REDACTED
114
114
  result.push(REDACTED)
115
115
  }
116
116
  }
@@ -1,18 +1,49 @@
1
1
  'use strict'
2
2
 
3
3
  const StoragePlugin = require('../../dd-trace/src/plugins/storage')
4
- const { storage } = require('../../datadog-core')
5
4
 
6
5
  class CouchBasePlugin extends StoragePlugin {
7
6
  static id = 'couchbase'
8
7
  static peerServicePrecursors = ['db.couchbase.seed.nodes']
9
8
 
10
- addBinds (func, start) {
11
- this.addBind(`apm:couchbase:${func}:start`, start)
12
- this.addSub(`apm:couchbase:${func}:error`, ({ error }) => this.addError(error))
13
- this.addSub(`apm:couchbase:${func}:finish`, ctx => this.finish(ctx))
14
- this.addBind(`apm:couchbase:${func}:callback:start`, callbackStart)
15
- this.addBind(`apm:couchbase:${func}:callback:finish`, callbackFinish)
9
+ constructor (...args) {
10
+ super(...args)
11
+
12
+ this.#addOpSubs('query', (ctx) => {
13
+ const { resource, bucket, seedNodes } = ctx
14
+ this.startSpan(
15
+ 'query',
16
+ {
17
+ 'span.type': 'sql',
18
+ 'resource.name': resource,
19
+ 'span.kind': this.constructor.kind,
20
+ },
21
+ { bucket, seedNodes },
22
+ ctx
23
+ )
24
+ return ctx.currentStore
25
+ })
26
+
27
+ for (const op of ['upsert', 'insert', 'replace']) {
28
+ this.#addOpSubs(op, (ctx) => {
29
+ const { bucket, collection, seedNodes } = ctx
30
+ this.startSpan(op, {}, { bucket, collection, seedNodes }, ctx)
31
+ return ctx.currentStore
32
+ })
33
+ }
34
+ }
35
+
36
+ /**
37
+ * @param {string} op Operation name (`query`, `upsert`, ...).
38
+ * @param {(ctx: object) => object} bindStart Operation-specific span starter.
39
+ */
40
+ #addOpSubs (op, bindStart) {
41
+ const prefix = `tracing:apm:couchbase:${op}`
42
+ this.addBind(`${prefix}:start`, bindStart)
43
+ this.addBind(`${prefix}:asyncStart`, bindAsyncStart)
44
+ this.addSub(`${prefix}:asyncEnd`, finishSpan)
45
+ this.addSub(`${prefix}:end`, finishSpanIfSync)
46
+ this.addSub(`${prefix}:error`, setSpanError)
16
47
  }
17
48
 
18
49
  startSpan (operation, customTags, { bucket, collection, seedNodes }, ctx) {
@@ -27,8 +58,8 @@ class CouchBasePlugin extends StoragePlugin {
27
58
  if (bucket) tags['couchbase.bucket.name'] = bucket.name
28
59
  if (collection) tags['couchbase.collection.name'] = collection.name
29
60
 
30
- for (const tag in customTags) {
31
- tags[tag] = customTags[tag]
61
+ for (const key of Object.keys(customTags)) {
62
+ tags[key] = customTags[key]
32
63
  }
33
64
 
34
65
  return super.startSpan(
@@ -40,55 +71,30 @@ class CouchBasePlugin extends StoragePlugin {
40
71
  ctx
41
72
  )
42
73
  }
74
+ }
43
75
 
44
- constructor (...args) {
45
- super(...args)
46
-
47
- this.addBinds('query', (ctx) => {
48
- const { resource, bucket, seedNodes } = ctx
49
-
50
- this.startSpan(
51
- 'query',
52
- {
53
- 'span.type': 'sql',
54
- 'resource.name': resource,
55
- 'span.kind': this.constructor.kind,
56
- },
57
- { bucket, seedNodes },
58
- ctx
59
- )
60
-
61
- return ctx.currentStore
62
- })
63
- this.addBind('apm:couchbase:bucket:maybeInvoke:callback:start', callbackStart)
64
- this.addBind('apm:couchbase:bucket:maybeInvoke:callback:finish', callbackFinish)
65
- this.addBind('apm:couchbase:cluster:maybeInvoke:callback:start', callbackStart)
66
- this.addBind('apm:couchbase:cluster:maybeInvoke:callback:finish', callbackFinish)
67
-
68
- this._addCommandSubs('upsert')
69
- this._addCommandSubs('insert')
70
- this._addCommandSubs('replace')
71
- this._addCommandSubs('append')
72
- this._addCommandSubs('prepend')
73
- }
74
-
75
- _addCommandSubs (name) {
76
- this.addBinds(name, (ctx) => {
77
- const { bucket, collection, seedNodes } = ctx
76
+ function bindAsyncStart (ctx) {
77
+ return ctx.parentStore
78
+ }
78
79
 
79
- this.startSpan(name, {}, { bucket, collection, seedNodes }, ctx)
80
- return ctx.currentStore
81
- })
82
- }
80
+ function finishSpan (ctx) {
81
+ ctx.currentStore?.span?.finish()
83
82
  }
84
83
 
85
- function callbackStart (ctx) {
86
- ctx.parentStore = storage('legacy').getStore()
87
- return ctx.parentStore
84
+ // `end` fires synchronously after the wrapped function returns. For async
85
+ // resolutions ctx.result and ctx.error are still unset at that point and the
86
+ // span is closed later via asyncEnd. For a sync throw or sync-resolved
87
+ // callback, this is the only finalization signal.
88
+ function finishSpanIfSync (ctx) {
89
+ if ((ctx.error !== undefined || ctx.result !== undefined) && ctx.currentStore?.span) {
90
+ ctx.currentStore.span.finish()
91
+ }
88
92
  }
89
93
 
90
- function callbackFinish (ctx) {
91
- return ctx.parentStore
94
+ function setSpanError (ctx) {
95
+ if (ctx.error && ctx.currentStore?.span) {
96
+ ctx.currentStore.span.setTag('error', ctx.error)
97
+ }
92
98
  }
93
99
 
94
100
  module.exports = CouchBasePlugin
@@ -141,6 +141,7 @@ class CucumberPlugin extends CiPlugin {
141
141
  'cucumber'
142
142
  ),
143
143
  ...this.getSessionRequestErrorTags(),
144
+ ...this.getSessionItrSkippingEnabledTags(),
144
145
  }
145
146
  if (isUnskippable) {
146
147
  this.telemetry.count(TELEMETRY_ITR_UNSKIPPABLE, { testLevel: 'suite' })
@@ -308,6 +309,7 @@ class CucumberPlugin extends CiPlugin {
308
309
  isDisabled,
309
310
  isQuarantined,
310
311
  isModified,
312
+ earlyFlakeAbortReason,
311
313
  finalStatus,
312
314
  }) => {
313
315
  const statusTag = isStep ? 'step.status' : TEST_STATUS
@@ -317,6 +319,9 @@ class CucumberPlugin extends CiPlugin {
317
319
  if (finalStatus) {
318
320
  span.setTag(TEST_FINAL_STATUS, finalStatus)
319
321
  }
322
+ if (earlyFlakeAbortReason) {
323
+ span.setTag(TEST_EARLY_FLAKE_ABORT_REASON, earlyFlakeAbortReason)
324
+ }
320
325
 
321
326
  if (isNew) {
322
327
  span.setTag(TEST_IS_NEW, 'true')