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
@@ -2,8 +2,7 @@
2
2
 
3
3
  const { storage } = require('../../../datadog-core')
4
4
  const ApolloBasePlugin = require('../../../dd-trace/src/plugins/apollo')
5
-
6
- let tools
5
+ const { getSignature } = require('../../../datadog-plugin-graphql/src/utils')
7
6
 
8
7
  const OPERATION_DEFINITION = 'OperationDefinition'
9
8
  const FRAGMENT_DEFINITION = 'FragmentDefinition'
@@ -100,23 +99,4 @@ function buildOperationContext (schema, operationDocument, operationName) {
100
99
  }
101
100
  }
102
101
 
103
- function getSignature (document, operationName, operationType, calculate) {
104
- if (calculate !== false && tools !== false) {
105
- try {
106
- try {
107
- tools = tools || require('../../../datadog-plugin-graphql/src/tools')
108
- } catch (e) {
109
- tools = false
110
- throw e
111
- }
112
-
113
- return tools.defaultEngineReportingSignature(document, operationName)
114
- } catch {
115
- // safety net
116
- }
117
- }
118
-
119
- return [operationType, operationName].filter(Boolean).join(' ')
120
- }
121
-
122
102
  module.exports = ApolloGatewayRequestPlugin
@@ -3,15 +3,55 @@
3
3
  const analyticsSampler = require('../../dd-trace/src/analytics_sampler')
4
4
  const ClientPlugin = require('../../dd-trace/src/plugins/client')
5
5
  const { storage } = require('../../datadog-core')
6
- const { isTrue } = require('../../dd-trace/src/util')
7
6
  const { tagsFromRequest, tagsFromResponse } = require('../../dd-trace/src/payload-tagging')
8
- const { getValueFromEnvSources } = require('../../dd-trace/src/config/helper')
7
+ const getConfig = require('../../dd-trace/src/config')
9
8
  const { IS_SERVERLESS } = require('../../dd-trace/src/serverless')
10
9
 
10
+ const RESPONSE_SKIP_KEYS = new Set(['request', 'requestId', 'error', '$metadata'])
11
+
11
12
  class BaseAwsSdkPlugin extends ClientPlugin {
12
13
  static id = 'aws'
13
14
  static isPayloadReporter = false
14
15
 
16
+ /**
17
+ * Append `"<key>": <JSON.stringify(value)>` to a JSON-encoded object
18
+ * payload without re-parsing when possible.
19
+ *
20
+ * Fast path: `payload` is `{}` (returns `{"<key>":<json>}`) or ends with
21
+ * `}` preceded by a non-whitespace, non-`{` byte and does not contain
22
+ * `"<key>"` anywhere. The new field is spliced in before the trailing
23
+ * brace.
24
+ *
25
+ * Slow path falls back to `JSON.parse` + assign + `JSON.stringify` so the
26
+ * result still matches the previous round-trip when the payload has
27
+ * whitespace before the trailing `}`, is not a JSON object, or already
28
+ * contains `key`. The slow path replaces an existing `key` rather than
29
+ * merging — callers that need to preserve nested fields under `key` must
30
+ * read and merge before calling.
31
+ *
32
+ * @param {string} payload
33
+ * @param {string} key Top-level key to insert. Must be a simple
34
+ * identifier that does not need JSON escaping.
35
+ * @param {object} value Value to inject; will be `JSON.stringify`'d.
36
+ * @returns {string}
37
+ */
38
+ static injectFieldIntoJsonObject (payload, key, value) {
39
+ const last = payload.length - 1
40
+ if (last >= 1 && payload[last] === '}') {
41
+ if (last === 1) {
42
+ return `{"${key}":${JSON.stringify(value)}}`
43
+ }
44
+ const before = payload.charCodeAt(last - 1)
45
+ const isWhitespace = before === 0x20 || before === 0x09 || before === 0x0A || before === 0x0D
46
+ if (!isWhitespace && before !== 0x7B && !payload.includes(`"${key}"`)) {
47
+ return `${payload.slice(0, last)},"${key}":${JSON.stringify(value)}}`
48
+ }
49
+ }
50
+ const obj = JSON.parse(payload)
51
+ obj[key] = value
52
+ return JSON.stringify(obj)
53
+ }
54
+
15
55
  get serviceIdentifier () {
16
56
  const id = this.constructor.id.toLowerCase()
17
57
  Object.defineProperty(this, 'serviceIdentifier', {
@@ -204,16 +244,15 @@ class BaseAwsSdkPlugin extends ClientPlugin {
204
244
  if (!span || !response.request) return
205
245
  const params = response.request.params
206
246
  const operation = response.request.operation
207
- const extraTags = this.generateTags(params, operation, response) || {}
208
247
 
209
- const tags = {
210
- 'aws.response.request_id': response.requestId,
211
- 'resource.name': operation,
212
- 'span.kind': 'client',
213
- ...extraTags,
214
- }
248
+ // `'span.kind': 'client'` is already set by the start-meta; SQS overrides via `generateTags`.
249
+ span.setTag('aws.response.request_id', response.requestId)
250
+ span.setTag('resource.name', operation)
215
251
 
216
- span.addTags(tags)
252
+ const extraTags = this.generateTags(params, operation, response)
253
+ if (extraTags) {
254
+ span.addTags(extraTags)
255
+ }
217
256
 
218
257
  if (this.constructor.isPayloadReporter && this.cloudTaggingConfig.response) {
219
258
  const maxDepth = this.cloudTaggingConfig.maxDepth
@@ -224,12 +263,19 @@ class BaseAwsSdkPlugin extends ClientPlugin {
224
263
  }
225
264
 
226
265
  extractResponseBody (response) {
227
- if (response.hasOwnProperty('data')) {
266
+ if (Object.hasOwn(response, 'data')) {
228
267
  return response.data
229
268
  }
230
- return Object.fromEntries(
231
- Object.entries(response).filter(([key]) => !['request', 'requestId', 'error', '$metadata'].includes(key))
232
- )
269
+ // `{ ...response }` followed by `delete body.X` allocates a copy and then
270
+ // pushes the copy into V8 dictionary mode for every SDK response. Filter
271
+ // on build instead -- ~2.3x faster on the typical 4-of-8-keys shape.
272
+ const body = {}
273
+ for (const key of Object.keys(response)) {
274
+ if (!RESPONSE_SKIP_KEYS.has(key)) {
275
+ body[key] = response[key]
276
+ }
277
+ }
278
+ return body
233
279
  }
234
280
 
235
281
  generateTags () {
@@ -266,29 +312,25 @@ function normalizeConfig (config, serviceIdentifier) {
266
312
  const hooks = getHooks(config)
267
313
 
268
314
  let specificConfig = config[serviceIdentifier]
269
- switch (typeof specificConfig) {
270
- case 'undefined':
271
- specificConfig = {}
272
- break
273
- case 'boolean':
274
- specificConfig = { enabled: specificConfig }
275
- break
315
+ if (typeof specificConfig === 'boolean') {
316
+ specificConfig = { enabled: specificConfig }
276
317
  }
277
318
 
278
- // check if AWS batch propagation or AWS_[SERVICE] batch propagation is enabled via env variable
319
+ // Check if AWS batch propagation or AWS_[SERVICE] batch propagation is enabled via env variable
320
+ const tracerConfig = getConfig()
279
321
  const serviceId = serviceIdentifier.toUpperCase()
280
- const batchPropagationEnabled = isTrue(
281
- specificConfig.batchPropagationEnabled ??
282
- getValueFromEnvSources(`DD_TRACE_AWS_SDK_${serviceId}_BATCH_PROPAGATION_ENABLED`) ??
283
- config.batchPropagationEnabled ??
284
- getValueFromEnvSources('DD_TRACE_AWS_SDK_BATCH_PROPAGATION_ENABLED')
322
+ const serviceBatchKey = /** @type {import('../../dd-trace/src/config/config-types').ConfigPath} */(
323
+ `DD_TRACE_AWS_SDK_${serviceId}_BATCH_PROPAGATION_ENABLED`
285
324
  )
325
+ const batchPropagationEnabled = tracerConfig.getOrigin(serviceBatchKey) === 'default'
326
+ ? tracerConfig.DD_TRACE_AWS_SDK_BATCH_PROPAGATION_ENABLED
327
+ : tracerConfig[serviceBatchKey]
286
328
 
287
329
  // Merge the specific config back into the main config
288
330
  return {
331
+ batchPropagationEnabled,
289
332
  ...config,
290
333
  ...specificConfig,
291
- batchPropagationEnabled,
292
334
  hooks,
293
335
  }
294
336
  }
@@ -6,7 +6,7 @@ class CloudwatchLogs extends BaseAwsSdkPlugin {
6
6
  static id = 'cloudwatchlogs'
7
7
 
8
8
  generateTags (params, operation) {
9
- if (!params?.logGroupName) return {}
9
+ if (!params?.logGroupName) return
10
10
 
11
11
  return {
12
12
  'resource.name': `${operation} ${params.logGroupName}`,
@@ -7,7 +7,7 @@ class EventBridge extends BaseAwsSdkPlugin {
7
7
  static isPayloadReporter = true
8
8
 
9
9
  generateTags (params, operation, response) {
10
- if (!params?.source) return {}
10
+ if (!params?.source) return
11
11
  const rulename = params.Name ?? ''
12
12
  return {
13
13
  'resource.name': operation ? `${operation} ${params.source}` : params.source,
@@ -34,20 +34,27 @@ class EventBridge extends BaseAwsSdkPlugin {
34
34
  request.params.Entries &&
35
35
  request.params.Entries.length > 0 &&
36
36
  request.params.Entries[0].Detail) {
37
+ const injected = {}
38
+ this.tracer.inject(span, 'text_map', injected)
39
+
40
+ // Only `injectFieldIntoJsonObject` can throw (the slow path
41
+ // `JSON.parse` for non-`{...}` payloads). Tighten the catch around
42
+ // it so the rest of the body stays in V8's optimisable surface.
43
+ let finalData
37
44
  try {
38
- const details = JSON.parse(request.params.Entries[0].Detail)
39
- details._datadog = {}
40
- this.tracer.inject(span, 'text_map', details._datadog)
41
- const finalData = JSON.stringify(details)
42
- const byteSize = Buffer.byteLength(finalData)
43
- if (byteSize >= (1024 * 256)) {
44
- log.info('Payload size too large to pass context')
45
- return
46
- }
47
- request.params.Entries[0].Detail = finalData
48
- } catch (e) {
49
- log.error('EventBridge error injecting request', e)
45
+ finalData = BaseAwsSdkPlugin.injectFieldIntoJsonObject(
46
+ request.params.Entries[0].Detail, '_datadog', injected
47
+ )
48
+ } catch (error) {
49
+ log.error('EventBridge error injecting request', error)
50
+ return
51
+ }
52
+
53
+ if (Buffer.byteLength(finalData) >= 1024 * 256) {
54
+ log.info('Payload size too large to pass context')
55
+ return
50
56
  }
57
+ request.params.Entries[0].Detail = finalData
51
58
  }
52
59
  }
53
60
  }
@@ -2,6 +2,11 @@
2
2
  const { DsmPathwayCodec, getSizeOrZero } = require('../../../dd-trace/src/datastreams')
3
3
  const log = require('../../../dd-trace/src/log')
4
4
  const BaseAwsSdkPlugin = require('../base')
5
+ const { isEmpty } = require('../util')
6
+
7
+ function recordDataAsString (data) {
8
+ return Buffer.isBuffer(data) ? data.toString('utf8') : Buffer.from(data).toString('utf8')
9
+ }
5
10
 
6
11
  class Kinesis extends BaseAwsSdkPlugin {
7
12
  static id = 'kinesis'
@@ -63,7 +68,7 @@ class Kinesis extends BaseAwsSdkPlugin {
63
68
  }
64
69
 
65
70
  generateTags (params, operation, response) {
66
- if (!params || !params.StreamName) return {}
71
+ if (!params || !params.StreamName) return
67
72
 
68
73
  return {
69
74
  'resource.name': `${operation} ${params.StreamName}`,
@@ -90,14 +95,14 @@ class Kinesis extends BaseAwsSdkPlugin {
90
95
  const record = response.Records[0]
91
96
 
92
97
  try {
93
- const decodedData = JSON.parse(Buffer.from(record.Data).toString())
98
+ const decodedData = JSON.parse(recordDataAsString(record.Data))
94
99
 
95
100
  return {
96
101
  maybeChildOf: this.tracer.extract('text_map', decodedData._datadog),
97
102
  parsedAttributes: decodedData._datadog,
98
103
  }
99
- } catch (e) {
100
- log.error('Kinesis error extracting response', e)
104
+ } catch (error) {
105
+ log.error('Kinesis error extracting response', error)
101
106
  }
102
107
  }
103
108
 
@@ -107,27 +112,32 @@ class Kinesis extends BaseAwsSdkPlugin {
107
112
  if (operation !== 'getRecords') return
108
113
  if (!response || !response.Records || !response.Records[0]) return
109
114
 
110
- // we only want to set the payloadSize on the span if we have one message, not repeatedly
115
+ // Only attribute payloadSize to the span when there is a single record.
111
116
  span = response.Records.length > 1 ? null : span
112
117
 
118
+ const tags = streamName
119
+ ? ['direction:in', `topic:${streamName}`, 'type:kinesis']
120
+ : ['direction:in', 'type:kinesis']
121
+
113
122
  for (const record of response.Records) {
114
- const parsedAttributes = JSON.parse(Buffer.from(record.Data).toString())
123
+ let parsedAttributes
124
+ try {
125
+ parsedAttributes = JSON.parse(recordDataAsString(record.Data))
126
+ } catch {
127
+ // Non-JSON record. Skip DSM context for this entry; the
128
+ // checkpoint payload size below is still reported.
129
+ }
115
130
 
116
131
  const payloadSize = getSizeOrZero(record.Data)
117
132
  if (parsedAttributes?._datadog) {
118
133
  this.tracer.decodeDataStreamsContext(parsedAttributes._datadog)
119
134
  }
120
- const tags = streamName
121
- ? ['direction:in', `topic:${streamName}`, 'type:kinesis']
122
- : ['direction:in', 'type:kinesis']
123
- this.tracer
124
- .setCheckpoint(tags, span, payloadSize)
135
+ this.tracer.setCheckpoint(tags, span, payloadSize)
125
136
  }
126
137
  }
127
138
 
128
- // AWS-SDK will b64 kinesis payloads
129
- // or will accept an already b64 encoded payload
130
- // This method handles both
139
+ // AWS-SDK base64-encodes kinesis payloads but also accepts an already
140
+ // base64-encoded payload; both shapes land here.
131
141
  _tryParse (body) {
132
142
  try {
133
143
  return JSON.parse(body)
@@ -135,7 +145,7 @@ class Kinesis extends BaseAwsSdkPlugin {
135
145
  log.info('Not JSON string. Trying Base64 encoded JSON string')
136
146
  }
137
147
  try {
138
- return JSON.parse(Buffer.from(body, 'base64').toString('ascii'), true)
148
+ return JSON.parse(Buffer.from(body, 'base64').toString('ascii'))
139
149
  } catch {
140
150
  return null
141
151
  }
@@ -179,36 +189,36 @@ class Kinesis extends BaseAwsSdkPlugin {
179
189
  }
180
190
 
181
191
  const ddInfo = {}
182
- // for now, we only want to inject to the first message, this may change for batches in the future
183
- if (injectTraceContext) { this.tracer.inject(span, 'text_map', ddInfo) }
192
+ // For now we only inject to the first message; batches may change later.
193
+ if (injectTraceContext) {
194
+ this.tracer.inject(span, 'text_map', ddInfo)
195
+ }
184
196
 
185
- // set DSM hash if enabled
186
197
  if (this.config.dsmEnabled) {
187
198
  parsedData._datadog = ddInfo
188
- const dataStreamsContext = this.setDSMCheckpoint(span, parsedData, stream)
189
- DsmPathwayCodec.encode(dataStreamsContext, ddInfo)
199
+ const dataStreamsContext = this.setDSMCheckpoint(span, params, stream)
200
+ if (dataStreamsContext) {
201
+ DsmPathwayCodec.encode(dataStreamsContext, ddInfo)
202
+ }
190
203
  }
191
204
 
192
- if (Object.keys(ddInfo).length !== 0) {
193
- parsedData._datadog = ddInfo
194
- const finalData = Buffer.from(JSON.stringify(parsedData))
195
- const byteSize = finalData.length
196
- // Kinesis max payload size is 1MB
197
- // So we must ensure adding DD context won't go over that (512b is an estimate)
198
- if (byteSize >= 1_048_576) {
199
- log.info('Payload size too large to pass context')
200
- return
201
- }
202
- params.Data = finalData
205
+ if (isEmpty(ddInfo)) return
206
+
207
+ parsedData._datadog = ddInfo
208
+ const serialized = JSON.stringify(parsedData)
209
+ const byteSize = Buffer.byteLength(serialized, 'utf8')
210
+ // Kinesis max payload size is 1 MiB; bail if our context push tipped us over.
211
+ if (byteSize >= 1_048_576) {
212
+ log.info('Payload size too large to pass context')
213
+ return
203
214
  }
215
+ params.Data = Buffer.from(serialized, 'utf8')
204
216
  }
205
217
 
206
- setDSMCheckpoint (span, parsedData, stream) {
207
- // get payload size of request data
208
- const payloadSize = Buffer.byteLength(JSON.stringify(parsedData))
209
- const dataStreamsContext = this.tracer
218
+ setDSMCheckpoint (span, params, stream) {
219
+ const payloadSize = getSizeOrZero(params.Data)
220
+ return this.tracer
210
221
  .setCheckpoint(['direction:out', `topic:${stream}`, 'type:kinesis'], span, payloadSize)
211
- return dataStreamsContext
212
222
  }
213
223
  }
214
224
 
@@ -7,7 +7,7 @@ class Lambda extends BaseAwsSdkPlugin {
7
7
  static id = 'lambda'
8
8
 
9
9
  generateTags (params, operation, response) {
10
- if (!params?.FunctionName) return {}
10
+ if (!params?.FunctionName) return
11
11
 
12
12
  return {
13
13
  'resource.name': `${operation} ${params.FunctionName}`,
@@ -18,33 +18,44 @@ class Lambda extends BaseAwsSdkPlugin {
18
18
 
19
19
  requestInject (span, request) {
20
20
  const operation = request.operation
21
- if (operation === 'invoke') {
22
- if (!request.params) {
23
- request.params = {}
24
- }
21
+ if (operation !== 'invoke') return
22
+
23
+ if (!request.params) {
24
+ request.params = {}
25
+ }
26
+
27
+ const isSyncInvocation = !request.params.InvocationType ||
28
+ request.params.InvocationType === 'RequestResponse'
29
+ if (!isSyncInvocation) return
30
+
31
+ const injected = {}
32
+ this.tracer.inject(span, 'text_map', injected)
25
33
 
26
- const isSyncInvocation = !request.params.InvocationType ||
27
- request.params.InvocationType === 'RequestResponse'
34
+ let newContextJson
35
+ if (request.params.ClientContext) {
36
+ const clientContextJson = Buffer.from(request.params.ClientContext, 'base64').toString('utf8')
28
37
 
29
- if (isSyncInvocation) {
30
- try {
31
- // Check to see if there's already a config on the request
32
- let clientContext = {}
33
- if (request.params.ClientContext) {
34
- const clientContextJson = Buffer.from(request.params.ClientContext, 'base64').toString('utf8')
35
- clientContext = JSON.parse(clientContextJson)
36
- }
37
- if (!clientContext.custom) {
38
- clientContext.custom = {}
39
- }
40
- this.tracer.inject(span, 'text_map', clientContext.custom)
41
- const newContextBase64 = Buffer.from(JSON.stringify(clientContext)).toString('base64')
42
- request.params.ClientContext = newContextBase64
43
- } catch (err) {
44
- log.error('Lambda error injecting request', err)
38
+ // The two throwing surfaces here are the inline `JSON.parse` and the
39
+ // slow path inside `injectFieldIntoJsonObject`. Tighten the catch
40
+ // around the JSON ops so the rest of the inject stays optimisable.
41
+ try {
42
+ if (clientContextJson.includes('"custom"')) {
43
+ // Existing customer keys under `custom` survive the round-trip.
44
+ const clientContext = JSON.parse(clientContextJson)
45
+ if (!clientContext.custom) clientContext.custom = {}
46
+ Object.assign(clientContext.custom, injected)
47
+ newContextJson = JSON.stringify(clientContext)
48
+ } else {
49
+ newContextJson = BaseAwsSdkPlugin.injectFieldIntoJsonObject(clientContextJson, 'custom', injected)
45
50
  }
51
+ } catch (error) {
52
+ log.error('Lambda error injecting request', error)
53
+ return
46
54
  }
55
+ } else {
56
+ newContextJson = `{"custom":${JSON.stringify(injected)}}`
47
57
  }
58
+ request.params.ClientContext = Buffer.from(newContextJson).toString('base64')
48
59
  }
49
60
 
50
61
  operationFromRequest (request) {
@@ -6,7 +6,7 @@ class Redshift extends BaseAwsSdkPlugin {
6
6
  static id = 'redshift'
7
7
 
8
8
  generateTags (params, operation, response) {
9
- if (!params?.ClusterIdentifier) return {}
9
+ if (!params?.ClusterIdentifier) return
10
10
 
11
11
  return {
12
12
  'resource.name': `${operation} ${params.ClusterIdentifier}`,
@@ -11,7 +11,7 @@ class S3 extends BaseAwsSdkPlugin {
11
11
  static isPayloadReporter = true
12
12
 
13
13
  generateTags (params, operation, response) {
14
- if (!params?.Bucket) return {}
14
+ if (!params?.Bucket) return
15
15
 
16
16
  return {
17
17
  'resource.name': `${operation} ${params.Bucket}`,
@@ -2,6 +2,7 @@
2
2
  const { DsmPathwayCodec, getHeadersSize } = require('../../../dd-trace/src/datastreams')
3
3
  const log = require('../../../dd-trace/src/log')
4
4
  const BaseAwsSdkPlugin = require('../base')
5
+ const { isEmpty } = require('../util')
5
6
 
6
7
  class Sns extends BaseAwsSdkPlugin {
7
8
  static id = 'sns'
@@ -9,17 +10,15 @@ class Sns extends BaseAwsSdkPlugin {
9
10
  static isPayloadReporter = true
10
11
 
11
12
  generateTags (params, operation, response) {
12
- if (!params) return {}
13
+ if (!params) return
13
14
 
14
- if (!params.TopicArn && !(response.data && response.data.TopicArn)) return {}
15
+ if (!params.TopicArn && !(response.data && response.data.TopicArn)) return
15
16
  const TopicArn = params.TopicArn || response.data.TopicArn
16
17
 
17
- // Split the ARN into its parts
18
- // ex.'arn:aws:sns:us-east-1:123456789012:my-topic'
19
- const arnParts = TopicArn.split(':')
20
-
21
- // Get the topic name from the last part of the ARN
22
- const topicName = arnParts.at(-1)
18
+ // Get the topic name from the last `:`-delimited segment of the ARN
19
+ // (e.g. 'my-topic' in 'arn:aws:sns:us-east-1:123456789012:my-topic')
20
+ // without allocating an intermediate parts array.
21
+ const topicName = TopicArn.slice(TopicArn.lastIndexOf(':') + 1)
23
22
 
24
23
  return {
25
24
  'resource.name': `${operation} ${params.TopicArn || response.data.TopicArn}`,
@@ -103,12 +102,14 @@ class Sns extends BaseAwsSdkPlugin {
103
102
  DsmPathwayCodec.encode(dataStreamsContext, ddInfo)
104
103
  }
105
104
 
106
- if (Object.keys(ddInfo).length !== 0) {
105
+ if (isEmpty(ddInfo)) {
106
+ if (params.MessageAttributes._datadog) {
107
+ // let's avoid adding any additional information to payload if we failed to inject
108
+ delete params.MessageAttributes._datadog
109
+ }
110
+ } else {
107
111
  // BINARY types are automatically base64 encoded
108
112
  params.MessageAttributes._datadog.BinaryValue = Buffer.from(JSON.stringify(ddInfo))
109
- } else if (params.MessageAttributes._datadog) {
110
- // let's avoid adding any additional information to payload if we failed to inject
111
- delete params.MessageAttributes._datadog
112
113
  }
113
114
  }
114
115
 
@@ -116,9 +117,7 @@ class Sns extends BaseAwsSdkPlugin {
116
117
  // only set a checkpoint if publishing to a topic
117
118
  if (topicArn) {
118
119
  const payloadSize = getHeadersSize(params)
119
- const dataStreamsContext = this.tracer
120
- .setCheckpoint(['direction:out', `topic:${topicArn}`, 'type:sns'], span, payloadSize)
121
- return dataStreamsContext
120
+ return this.tracer.setCheckpoint(['direction:out', `topic:${topicArn}`, 'type:sns'], span, payloadSize)
122
121
  }
123
122
  }
124
123
  }