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
@@ -4,48 +4,146 @@ const shimmer = require('../../datadog-shimmer')
4
4
  const { channel, addHook } = require('./helpers/instrument')
5
5
 
6
6
  const patchedClientConfigProtocols = new WeakSet()
7
+ const patchedCommandPrototypes = new WeakSet()
8
+
9
+ // Resource identifiers that already match the channel-suffix slug. Anything
10
+ // else falls back to `'default'`. Hoisted out of the per-call hot path so we
11
+ // don't allocate a fresh Array literal + run `.includes` on every AWS send.
12
+ const KNOWN_CHANNEL_SUFFIXES = new Set([
13
+ 'cloudwatchlogs',
14
+ 'dynamodb',
15
+ 'eventbridge',
16
+ 'kinesis',
17
+ 'lambda',
18
+ 'redshift',
19
+ 's3',
20
+ 'sfn',
21
+ 'sns',
22
+ 'sqs',
23
+ 'states',
24
+ 'stepfunctions',
25
+ 'bedrockruntime',
26
+ ])
27
+
28
+ /**
29
+ * @typedef {object} ChannelBag
30
+ * @property {ReturnType<typeof channel>} start
31
+ * @property {ReturnType<typeof channel>} complete
32
+ * @property {ReturnType<typeof channel>} region
33
+ * @property {ReturnType<typeof channel>} responseStart
34
+ * @property {ReturnType<typeof channel>} responseFinish
35
+ * @property {ReturnType<typeof channel>} deserialize
36
+ * @property {ReturnType<typeof channel>} streamedChunk
37
+ */
38
+
39
+ /** @type {Map<string, ChannelBag>} */
40
+ const channelBags = new Map()
41
+
42
+ /**
43
+ * Returns the cached set of diagnostic-channel handles for a given AWS
44
+ * service slug. Each `channel(...)` call hashes the channel name into a
45
+ * shared registry and allocates a per-call template-literal string; doing
46
+ * that ~8 times per AWS send was a measurable per-request cost.
47
+ *
48
+ * @param {string} suffix
49
+ * @returns {ChannelBag}
50
+ */
51
+ function getChannelBag (suffix) {
52
+ let bag = channelBags.get(suffix)
53
+ if (bag === undefined) {
54
+ bag = {
55
+ start: channel(`apm:aws:request:start:${suffix}`),
56
+ complete: channel(`apm:aws:request:complete:${suffix}`),
57
+ region: channel(`apm:aws:request:region:${suffix}`),
58
+ responseStart: channel(`apm:aws:response:start:${suffix}`),
59
+ responseFinish: channel(`apm:aws:response:finish:${suffix}`),
60
+ deserialize: channel(`apm:aws:response:deserialize:${suffix}`),
61
+ streamedChunk: channel(`apm:aws:response:streamed-chunk:${suffix}`),
62
+ }
63
+ channelBags.set(suffix, bag)
64
+ }
65
+ return bag
66
+ }
67
+
68
+ /** @type {WeakMap<Function, string>} */
69
+ const clientNameCache = new WeakMap()
70
+
71
+ /**
72
+ * @param {Function} clientCtor
73
+ * @returns {string}
74
+ */
75
+ function getClientName (clientCtor) {
76
+ let name = clientNameCache.get(clientCtor)
77
+ if (name === undefined) {
78
+ name = clientCtor.name.replace(/Client$/, '')
79
+ clientNameCache.set(clientCtor, name)
80
+ }
81
+ return name
82
+ }
83
+
84
+ /** @type {WeakMap<Function, string>} */
85
+ const operationCache = new WeakMap()
86
+
87
+ /**
88
+ * @param {Function} commandCtor
89
+ * @returns {string}
90
+ */
91
+ function getOperationName (commandCtor) {
92
+ let operation = operationCache.get(commandCtor)
93
+ if (operation === undefined) {
94
+ const commandName = commandCtor.name
95
+ operation = `${commandName[0].toLowerCase()}${commandName.slice(1).replace(/Command$/, '')}`
96
+ operationCache.set(commandCtor, operation)
97
+ }
98
+ return operation
99
+ }
7
100
 
8
101
  function wrapRequest (send) {
102
+ // V8 deopts both this function and `send.apply(this, arguments)` once
103
+ // `arguments[0] = wrapCb(...)` materialises the arguments object on the
104
+ // hot path. Pass the (at most one-arg) call site through explicitly --
105
+ // `Request.send` only accepts an optional callback in both v2 and v3 SDKs.
9
106
  return function wrappedRequest (cb) {
10
107
  if (!this.service) return send.apply(this, arguments)
11
108
 
12
109
  const serviceIdentifier = this.service.serviceIdentifier
13
110
  const channelSuffix = getChannelSuffix(serviceIdentifier)
14
- const startCh = channel(`apm:aws:request:start:${channelSuffix}`)
15
- if (!startCh.hasSubscribers) return send.apply(this, arguments)
111
+ const channels = getChannelBag(channelSuffix)
112
+ if (!channels.start.hasSubscribers) return send.apply(this, arguments)
16
113
 
114
+ const cbExists = typeof cb === 'function'
17
115
  const ctx = {
18
116
  serviceIdentifier,
19
117
  operation: this.operation,
20
118
  awsRegion: this.service.config && this.service.config.region,
21
119
  awsService: this.service.api && this.service.api.className,
22
120
  request: this,
23
- cbExists: typeof cb === 'function',
121
+ cbExists,
24
122
  }
25
123
 
124
+ // AWS SDK v2 mixes in its own `SequentialExecutor` (no `once`), so stick
125
+ // to `on('complete')`. The event fires exactly once per Request — even
126
+ // across retries — so we don't get duplicate publishes.
26
127
  this.on('complete', response => {
27
128
  ctx.response = response
28
- channel(`apm:aws:request:complete:${channelSuffix}`).publish(ctx)
129
+ channels.complete.publish(ctx)
29
130
  })
30
131
 
31
- if (ctx.cbExists) {
32
- arguments[0] = wrapCb(cb, channelSuffix, ctx)
132
+ if (cbExists) {
133
+ return channels.start.runStores(ctx, send, this, wrapCb(cb, channels, ctx))
33
134
  }
34
-
35
- return startCh.runStores(ctx, send, this, ...arguments)
135
+ return channels.start.runStores(ctx, send, this)
36
136
  }
37
137
  }
38
138
 
39
- function wrapDeserialize (deserialize, channelSuffix, responseIndex = 0) {
40
- const headersCh = channel(`apm:aws:response:deserialize:${channelSuffix}`)
41
-
42
- return function () {
43
- const response = arguments[responseIndex]
139
+ function wrapDeserialize (deserialize, headersCh, responseIndex = 0) {
140
+ return function (...args) {
141
+ const response = args[responseIndex]
44
142
  if (headersCh.hasSubscribers) {
45
143
  headersCh.publish({ headers: response.headers })
46
144
  }
47
145
 
48
- return deserialize.apply(this, arguments)
146
+ return deserialize.apply(this, args)
49
147
  }
50
148
  }
51
149
 
@@ -54,26 +152,32 @@ function wrapSmithySend (send) {
54
152
  const cb = args.at(-1)
55
153
  const serviceIdentifier = this.config.serviceId.toLowerCase()
56
154
  const channelSuffix = getChannelSuffix(serviceIdentifier)
57
- const commandName = command.constructor.name
58
- const clientName = this.constructor.name.replace(/Client$/, '')
59
- const operation = `${commandName[0].toLowerCase()}${commandName.slice(1).replace(/Command$/, '')}`
155
+ const channels = getChannelBag(channelSuffix)
156
+ const clientName = getClientName(this.constructor)
157
+ const operation = getOperationName(command.constructor)
60
158
  const request = {
61
159
  operation,
62
160
  params: command.input,
63
161
  }
64
162
 
65
- const startCh = channel(`apm:aws:request:start:${channelSuffix}`)
66
- const regionCh = channel(`apm:aws:request:region:${channelSuffix}`)
67
- const responseStartChannel = channel(`apm:aws:response:start:${channelSuffix}`)
68
- const responseFinishChannel = channel(`apm:aws:response:finish:${channelSuffix}`)
69
-
70
163
  if (typeof command.deserialize === 'function') {
71
- shimmer.wrap(command, 'deserialize', deserialize => wrapDeserialize(deserialize, channelSuffix))
164
+ const proto = Object.getPrototypeOf(command)
165
+ // Wrap once per Command class via the prototype when `deserialize` is
166
+ // inherited; fall back to per-instance wrap when a command shadows it
167
+ // as an own property (rare in @aws-sdk v3).
168
+ if (proto && proto.deserialize === command.deserialize) {
169
+ if (!patchedCommandPrototypes.has(proto)) {
170
+ shimmer.wrap(proto, 'deserialize', deserialize => wrapDeserialize(deserialize, channels.deserialize))
171
+ patchedCommandPrototypes.add(proto)
172
+ }
173
+ } else {
174
+ shimmer.wrap(command, 'deserialize', deserialize => wrapDeserialize(deserialize, channels.deserialize))
175
+ }
72
176
  } else if (this.config?.protocol?.deserializeResponse && !patchedClientConfigProtocols.has(this.config.protocol)) {
73
177
  shimmer.wrap(
74
178
  this.config.protocol,
75
179
  'deserializeResponse',
76
- deserializeResponse => wrapDeserialize(deserializeResponse, channelSuffix, 2)
180
+ deserializeResponse => wrapDeserialize(deserializeResponse, channels.deserialize, 2)
77
181
  )
78
182
 
79
183
  patchedClientConfigProtocols.add(this.config.protocol)
@@ -86,25 +190,25 @@ function wrapSmithySend (send) {
86
190
  request,
87
191
  }
88
192
 
89
- return startCh.runStores(ctx, () => {
193
+ return channels.start.runStores(ctx, () => {
90
194
  // When the region is not set this never resolves so we can't await.
91
195
  this.config.region().then(region => {
92
196
  ctx.region = region
93
- regionCh.publish(ctx)
197
+ channels.region.publish(ctx)
94
198
  })
95
199
 
96
200
  if (typeof cb === 'function') {
97
201
  args[args.length - 1] = shimmer.wrapFunction(cb, cb => function (err, result) {
98
202
  addResponse(ctx, err, result)
99
203
 
100
- handleCompletion(result, ctx, channelSuffix)
204
+ handleCompletion(result, ctx, channels)
101
205
 
102
206
  const responseCtx = { request, response: ctx.response }
103
207
 
104
- responseStartChannel.runStores(responseCtx, () => {
208
+ channels.responseStart.runStores(responseCtx, () => {
105
209
  cb.apply(this, arguments)
106
210
 
107
- responseFinishChannel.publish(responseCtx)
211
+ channels.responseFinish.publish(responseCtx)
108
212
  })
109
213
  })
110
214
  } else { // always a promise
@@ -112,12 +216,12 @@ function wrapSmithySend (send) {
112
216
  .then(
113
217
  result => {
114
218
  addResponse(ctx, null, result)
115
- handleCompletion(result, ctx, channelSuffix)
219
+ handleCompletion(result, ctx, channels)
116
220
  return result
117
221
  },
118
222
  error => {
119
223
  addResponse(ctx, error)
120
- handleCompletion(null, ctx, channelSuffix)
224
+ handleCompletion(null, ctx, channels)
121
225
  throw error
122
226
  }
123
227
  )
@@ -128,35 +232,32 @@ function wrapSmithySend (send) {
128
232
  }
129
233
  }
130
234
 
131
- function handleCompletion (result, ctx, channelSuffix) {
132
- const completeChannel = channel(`apm:aws:request:complete:${channelSuffix}`)
133
- const streamedChunkChannel = channel(`apm:aws:response:streamed-chunk:${channelSuffix}`)
134
-
235
+ function handleCompletion (result, ctx, channels) {
135
236
  const iterator = result?.body?.[Symbol.asyncIterator]
136
237
  if (!iterator) {
137
- completeChannel.publish(ctx)
238
+ channels.complete.publish(ctx)
138
239
  return
139
240
  }
140
241
 
141
242
  shimmer.wrap(result.body, Symbol.asyncIterator, function (asyncIterator) {
142
- return function () {
143
- const iterator = asyncIterator.apply(this, arguments)
243
+ return function (...args) {
244
+ const iterator = asyncIterator.apply(this, args)
144
245
  shimmer.wrap(iterator, 'next', function (next) {
145
- return function () {
146
- return next.apply(this, arguments)
246
+ return function (...args) {
247
+ return next.apply(this, args)
147
248
  .then(result => {
148
249
  const { done, value: chunk } = result
149
- streamedChunkChannel.publish({ ctx, chunk, done })
250
+ channels.streamedChunk.publish({ ctx, chunk, done })
150
251
 
151
252
  if (done) {
152
- completeChannel.publish(ctx)
253
+ channels.complete.publish(ctx)
153
254
  }
154
255
 
155
256
  return result
156
257
  })
157
258
  .catch(err => {
158
259
  addResponse(ctx, err)
159
- completeChannel.publish(ctx)
260
+ channels.complete.publish(ctx)
160
261
  throw err
161
262
  })
162
263
  }
@@ -167,30 +268,29 @@ function handleCompletion (result, ctx, channelSuffix) {
167
268
  })
168
269
  }
169
270
 
170
- function wrapCb (cb, serviceName, ctx) {
271
+ function wrapCb (cb, channels, ctx) {
171
272
  // eslint-disable-next-line n/handle-callback-err
172
273
  return shimmer.wrapFunction(cb, cb => function wrappedCb (err, response) {
173
274
  ctx = { request: ctx.request, response }
174
- return channel(`apm:aws:response:start:${serviceName}`).runStores(ctx, () => {
175
- const finishChannel = channel(`apm:aws:response:finish:${serviceName}`)
275
+ return channels.responseStart.runStores(ctx, () => {
176
276
  try {
177
277
  let result = cb.apply(this, arguments)
178
278
  if (result && result.then) {
179
279
  result = result.then(x => {
180
- finishChannel.publish(ctx)
280
+ channels.responseFinish.publish(ctx)
181
281
  return x
182
282
  }, e => {
183
283
  ctx.error = e
184
- finishChannel.publish(ctx)
284
+ channels.responseFinish.publish(ctx)
185
285
  throw e
186
286
  })
187
287
  } else {
188
- finishChannel.publish(ctx)
288
+ channels.responseFinish.publish(ctx)
189
289
  }
190
290
  return result
191
291
  } catch (e) {
192
292
  ctx.error = e
193
- finishChannel.publish(ctx)
293
+ channels.responseFinish.publish(ctx)
194
294
  throw e
195
295
  }
196
296
  })
@@ -211,23 +311,7 @@ function addResponse (ctx, error, result) {
211
311
  function getChannelSuffix (name) {
212
312
  // some resource identifiers have spaces between ex: bedrock runtime
213
313
  name = String(name).replaceAll(' ', '')
214
- return [
215
- 'cloudwatchlogs',
216
- 'dynamodb',
217
- 'eventbridge',
218
- 'kinesis',
219
- 'lambda',
220
- 'redshift',
221
- 's3',
222
- 'sfn',
223
- 'sns',
224
- 'sqs',
225
- 'states',
226
- 'stepfunctions',
227
- 'bedrockruntime',
228
- ].includes(name)
229
- ? name
230
- : 'default'
314
+ return KNOWN_CHANNEL_SUFFIXES.has(name) ? name : 'default'
231
315
  }
232
316
 
233
317
  addHook({ name: '@smithy/smithy-client', versions: ['>=1.0.3'] }, smithy => {
@@ -38,14 +38,14 @@ function entityWrapper (method) {
38
38
  }
39
39
 
40
40
  function entityHandler (handler, entityName) {
41
- return function () {
42
- if (!azureDurableFunctionsChannel.hasSubscribers) return handler.apply(this, arguments)
41
+ return function (...args) {
42
+ if (!azureDurableFunctionsChannel.hasSubscribers) return handler.apply(this, args)
43
43
 
44
- const entityContext = arguments[0]
44
+ const entityContext = args[0]
45
45
  return azureDurableFunctionsChannel.traceSync(
46
46
  handler,
47
47
  { trigger: 'Entity', functionName: entityName, operationName: entityContext?.df?.operationName },
48
- this, ...arguments)
48
+ this, ...args)
49
49
  }
50
50
  }
51
51
 
@@ -55,19 +55,19 @@ function activityHandler (method) {
55
55
  const isAsync =
56
56
  handler && handler.constructor && handler.constructor.name === 'AsyncFunction'
57
57
 
58
- return function () {
59
- if (!azureDurableFunctionsChannel.hasSubscribers) return handler.apply(this, arguments)
58
+ return function (...args) {
59
+ if (!azureDurableFunctionsChannel.hasSubscribers) return handler.apply(this, args)
60
60
 
61
61
  // use tracePromise if this is an async handler. otherwise, use traceSync
62
62
  return isAsync
63
63
  ? azureDurableFunctionsChannel.tracePromise(
64
64
  handler,
65
65
  { trigger: 'Activity', functionName: activityName },
66
- this, ...arguments)
66
+ this, ...args)
67
67
  : azureDurableFunctionsChannel.traceSync(
68
68
  handler,
69
69
  { trigger: 'Activity', functionName: activityName },
70
- this, ...arguments)
70
+ this, ...args)
71
71
  }
72
72
  })
73
73
  return method.apply(this, arguments)
@@ -6,8 +6,8 @@ const { wrapThen } = require('./helpers/promise')
6
6
 
7
7
  function createGetNewLibraryCopyWrap (originalLib) {
8
8
  return function wrapGetNewLibraryCopy (getNewLibraryCopy) {
9
- return function getNewLibraryCopyWithTrace () {
10
- const libraryCopy = getNewLibraryCopy.apply(this, arguments)
9
+ return function getNewLibraryCopyWithTrace (...args) {
10
+ const libraryCopy = getNewLibraryCopy.apply(this, args)
11
11
  shimmer.wrap(libraryCopy.prototype, '_then', wrapThen)
12
12
  shimmer.wrap(libraryCopy, 'getNewLibraryCopy', createGetNewLibraryCopyWrap(originalLib))
13
13
  return libraryCopy
@@ -6,7 +6,7 @@ const { channel, addHook, AsyncResource } = require('./helpers/instrument')
6
6
  const bodyParserReadCh = channel('datadog:body-parser:read:finish')
7
7
 
8
8
  function publishRequestBodyAndNext (req, res, next) {
9
- return shimmer.wrapFunction(next, next => function () {
9
+ return shimmer.wrapFunction(next, next => function (...args) {
10
10
  if (bodyParserReadCh.hasSubscribers && req) {
11
11
  const abortController = new AbortController()
12
12
  const body = req.body
@@ -16,7 +16,7 @@ function publishRequestBodyAndNext (req, res, next) {
16
16
  if (abortController.signal.aborted) return
17
17
  }
18
18
 
19
- return next.apply(this, arguments)
19
+ return next.apply(this, args)
20
20
  })
21
21
  }
22
22
 
@@ -100,13 +100,13 @@ addHook({ name: 'cassandra-driver', versions: ['3 - 4.3'], patchDefault: false }
100
100
  })
101
101
 
102
102
  addHook({ name: 'cassandra-driver', versions: ['>=3.3'], file: 'lib/request-execution.js' }, RequestExecution => {
103
- shimmer.wrap(RequestExecution.prototype, '_sendOnConnection', _sendOnConnection => function () {
103
+ shimmer.wrap(RequestExecution.prototype, '_sendOnConnection', _sendOnConnection => function (...args) {
104
104
  if (!startCh.hasSubscribers) {
105
- return _sendOnConnection.apply(this, arguments)
105
+ return _sendOnConnection.apply(this, args)
106
106
  }
107
107
  startCtx = { hostname: this._connection.address, port: this._connection.port, ...startCtx }
108
108
  connectCh.publish(startCtx)
109
- return _sendOnConnection.apply(this, arguments)
109
+ return _sendOnConnection.apply(this, args)
110
110
  })
111
111
  return RequestExecution
112
112
  })
@@ -122,9 +122,9 @@ addHook({ name: 'cassandra-driver', versions: ['3.3 - 4.3'], file: 'lib/request-
122
122
  return start.apply(this, arguments)
123
123
  }
124
124
 
125
- arguments[0] = function () {
125
+ arguments[0] = function (...args) {
126
126
  startCtx = { hostname: execution._connection.address, port: execution._connection.port, ...startCtx }
127
- return connectCh.runStores(startCtx, getHostCallback, this, ...arguments)
127
+ return connectCh.runStores(startCtx, getHostCallback, this, ...args)
128
128
  }
129
129
 
130
130
  return start.apply(this, arguments)
@@ -143,9 +143,9 @@ addHook({ name: 'cassandra-driver', versions: ['3 - 3.2'], file: 'lib/request-ha
143
143
  return send.apply(this, arguments)
144
144
  }
145
145
 
146
- arguments[2] = function () {
146
+ arguments[2] = function (...args) {
147
147
  startCtx = { hostname: handler.connection.address, port: handler.connection.port, ...startCtx }
148
- return connectCh.runStores(startCtx, callback, this, ...arguments)
148
+ return connectCh.runStores(startCtx, callback, this, ...args)
149
149
  }
150
150
 
151
151
  return send.apply(this, arguments)
@@ -82,12 +82,12 @@ function createContextFromChildProcessInfo (childProcessInfo) {
82
82
 
83
83
  function wrapChildProcessSyncMethod (returnError, shell = false) {
84
84
  return function wrapMethod (childProcessMethod) {
85
- return function () {
86
- if (!childProcessChannel.start.hasSubscribers || arguments.length === 0) {
87
- return childProcessMethod.apply(this, arguments)
85
+ return function (...args) {
86
+ if (!childProcessChannel.start.hasSubscribers || args.length === 0) {
87
+ return childProcessMethod.apply(this, args)
88
88
  }
89
89
 
90
- const callArgs = [...arguments]
90
+ const callArgs = [...args]
91
91
  const childProcessInfo = normalizeArgs(callArgs, shell)
92
92
  const context = createContextFromChildProcessInfo(childProcessInfo)
93
93
  context.callArgs = callArgs
@@ -118,12 +118,12 @@ function wrapChildProcessSyncMethod (returnError, shell = false) {
118
118
  }
119
119
 
120
120
  function wrapChildProcessCustomPromisifyMethod (customPromisifyMethod, shell) {
121
- return function () {
122
- if (!childProcessChannel.start.hasSubscribers || arguments.length === 0) {
123
- return customPromisifyMethod.apply(this, arguments)
121
+ return function (...args) {
122
+ if (!childProcessChannel.start.hasSubscribers || args.length === 0) {
123
+ return customPromisifyMethod.apply(this, args)
124
124
  }
125
125
 
126
- const callArgs = [...arguments]
126
+ const callArgs = [...args]
127
127
  const childProcessInfo = normalizeArgs(callArgs, shell)
128
128
 
129
129
  const context = createContextFromChildProcessInfo(childProcessInfo)
@@ -170,12 +170,12 @@ function wrapChildProcessCustomPromisifyMethod (customPromisifyMethod, shell) {
170
170
 
171
171
  function wrapChildProcessAsyncMethod (ChildProcess, shell = false) {
172
172
  return function wrapMethod (childProcessMethod) {
173
- function wrappedChildProcessMethod () {
174
- if (!childProcessChannel.start.hasSubscribers || arguments.length === 0) {
175
- return childProcessMethod.apply(this, arguments)
173
+ function wrappedChildProcessMethod (...args) {
174
+ if (!childProcessChannel.start.hasSubscribers || args.length === 0) {
175
+ return childProcessMethod.apply(this, args)
176
176
  }
177
177
 
178
- const callArgs = [...arguments]
178
+ const callArgs = [...args]
179
179
  const childProcessInfo = normalizeArgs(callArgs, shell)
180
180
 
181
181
  const context = createContextFromChildProcessInfo(childProcessInfo)
@@ -7,6 +7,7 @@ const {
7
7
  addHook,
8
8
  channel,
9
9
  } = require('./helpers/instrument')
10
+ const { cloneMessages } = require('./helpers/kafka')
10
11
 
11
12
  // Create channels for Confluent Kafka JavaScript
12
13
  const channels = {
@@ -47,8 +48,8 @@ function instrumentBaseModule (module) {
47
48
  // Helper function to wrap producer classes
48
49
  function wrapProducerClass (ProducerClass, className) {
49
50
  return shimmer.wrap(module, className, function wrapProducer (Original) {
50
- return function wrappedProducer () {
51
- const producer = new Original(...arguments)
51
+ return function wrappedProducer (...args) {
52
+ const producer = new Original(...args)
52
53
 
53
54
  // Hook the produce method
54
55
  if (typeof producer?.produce === 'function') {
@@ -94,9 +95,9 @@ function instrumentBaseModule (module) {
94
95
  // Helper function to wrap consumer classes
95
96
  function wrapConsumerClass (ConsumerClass, className) {
96
97
  return shimmer.wrap(module, className, function wrapConsumer (Original) {
97
- return function wrappedConsumer () {
98
- const consumer = new Original(...arguments)
99
- const groupId = this.groupId || (arguments[0]?.['group.id'])
98
+ return function wrappedConsumer (...args) {
99
+ const consumer = new Original(...args)
100
+ const groupId = this.groupId || (args[0]?.['group.id'])
100
101
 
101
102
  // Wrap the consume method
102
103
  if (typeof consumer?.consume === 'function') {
@@ -196,11 +197,11 @@ function instrumentKafkaJS (kafkaJS) {
196
197
  // Wrap the producer method if it exists
197
198
  if (typeof kafka?.producer === 'function') {
198
199
  shimmer.wrap(kafka, 'producer', function wrapProducerMethod (producerMethod) {
199
- return function wrappedProducerMethod () {
200
- const producer = producerMethod.apply(this, arguments)
200
+ return function wrappedProducerMethod (...args) {
201
+ const producer = producerMethod.apply(this, args)
201
202
 
202
- if (!brokers && arguments?.[0]?.['bootstrap.servers']) {
203
- kafka._ddBrokers = arguments[0]['bootstrap.servers']
203
+ if (!brokers && args?.[0]?.['bootstrap.servers']) {
204
+ kafka._ddBrokers = args[0]['bootstrap.servers']
204
205
  }
205
206
 
206
207
  // Wrap the send method of the producer
@@ -211,46 +212,62 @@ function instrumentKafkaJS (kafkaJS) {
211
212
  return send.apply(this, arguments)
212
213
  }
213
214
 
215
+ const disableHeaderInjection = disabledHeaderWeakSet.has(producer)
216
+
217
+ // Hand the underlying client a shallow clone so neither
218
+ // injection nor the client's auto-fields (it sets
219
+ // `headers: null` on messages without headers) ever
220
+ // touch caller-owned objects. With injection disabled the
221
+ // clone must not seed `headers: {}` either: brokers that
222
+ // reject any header field cannot recover otherwise.
223
+ let outgoingPayload = payload
224
+ if (payload && Array.isArray(payload.messages)) {
225
+ outgoingPayload = {
226
+ ...payload,
227
+ messages: cloneMessages(payload.messages, !disableHeaderInjection),
228
+ }
229
+ }
230
+
214
231
  const ctx = {
215
- topic: payload?.topic,
216
- messages: payload?.messages || [],
232
+ topic: outgoingPayload?.topic,
233
+ messages: outgoingPayload?.messages || [],
217
234
  bootstrapServers: kafka._ddBrokers,
218
- disableHeaderInjection: disabledHeaderWeakSet.has(producer),
235
+ disableHeaderInjection,
219
236
  }
220
237
 
221
238
  return channels.producerStart.runStores(ctx, () => {
222
239
  try {
223
- const result = send.apply(this, arguments)
240
+ const result = send.call(this, outgoingPayload)
224
241
 
225
242
  result.then((res) => {
226
243
  ctx.result = res
227
244
  channels.producerCommit.publish(ctx)
228
245
  channels.producerFinish.publish(ctx)
229
- }, (err) => {
230
- if (err) {
231
- // Fixes bug where we would inject message headers for kafka brokers
232
- // that don't support headers (version <0.11). On the error, we disable
233
- // header injection. Tnfortunately the error name / type is not more specific.
234
- // This approach is implemented by other tracers as well.
235
- if (err.name === 'KafkaJSError' && err.type === 'ERR_UNKNOWN') {
246
+ }, (error) => {
247
+ if (error) {
248
+ // KafkaJS-compat reports `ERR_UNKNOWN` for brokers
249
+ // <0.11 that cannot parse headers. Stop injecting
250
+ // for this producer; subsequent sends to the same
251
+ // broker succeed.
252
+ if (error.name === 'KafkaJSError' && error.type === 'ERR_UNKNOWN') {
236
253
  disabledHeaderWeakSet.add(producer)
237
254
  log.error(
238
255
  // eslint-disable-next-line @stylistic/max-len
239
256
  'Kafka Broker responded with UNKNOWN_SERVER_ERROR (-1). Please look at broker logs for more information. Tracer message header injection for Kafka is disabled.'
240
257
  )
241
258
  }
242
- ctx.error = err
259
+ ctx.error = error
243
260
  channels.producerError.publish(ctx)
244
261
  }
245
262
  channels.producerFinish.publish(ctx)
246
263
  })
247
264
 
248
265
  return result
249
- } catch (e) {
250
- ctx.error = e
266
+ } catch (error) {
267
+ ctx.error = error
251
268
  channels.producerError.publish(ctx)
252
269
  channels.producerFinish.publish(ctx)
253
- throw e
270
+ throw error
254
271
  }
255
272
  })
256
273
  }