dd-trace 5.101.0 → 5.102.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/package.json +9 -7
  2. package/packages/datadog-instrumentations/src/aerospike.js +2 -2
  3. package/packages/datadog-instrumentations/src/ai.js +8 -8
  4. package/packages/datadog-instrumentations/src/amqplib.js +6 -7
  5. package/packages/datadog-instrumentations/src/anthropic.js +10 -10
  6. package/packages/datadog-instrumentations/src/apollo-server-core.js +3 -3
  7. package/packages/datadog-instrumentations/src/apollo-server.js +5 -5
  8. package/packages/datadog-instrumentations/src/avsc.js +6 -6
  9. package/packages/datadog-instrumentations/src/aws-sdk.js +151 -67
  10. package/packages/datadog-instrumentations/src/azure-durable-functions.js +8 -8
  11. package/packages/datadog-instrumentations/src/bluebird.js +2 -2
  12. package/packages/datadog-instrumentations/src/body-parser.js +2 -2
  13. package/packages/datadog-instrumentations/src/cassandra-driver.js +7 -7
  14. package/packages/datadog-instrumentations/src/child_process.js +12 -12
  15. package/packages/datadog-instrumentations/src/confluentinc-kafka-javascript.js +9 -9
  16. package/packages/datadog-instrumentations/src/connect.js +7 -7
  17. package/packages/datadog-instrumentations/src/cookie-parser.js +4 -4
  18. package/packages/datadog-instrumentations/src/cookie.js +2 -2
  19. package/packages/datadog-instrumentations/src/couchbase.js +16 -30
  20. package/packages/datadog-instrumentations/src/crypto.js +4 -4
  21. package/packages/datadog-instrumentations/src/cucumber.js +77 -16
  22. package/packages/datadog-instrumentations/src/dns.js +0 -3
  23. package/packages/datadog-instrumentations/src/elasticsearch.js +8 -11
  24. package/packages/datadog-instrumentations/src/express-mongo-sanitize.js +6 -6
  25. package/packages/datadog-instrumentations/src/express-session.js +4 -4
  26. package/packages/datadog-instrumentations/src/express.js +10 -11
  27. package/packages/datadog-instrumentations/src/fastify.js +2 -2
  28. package/packages/datadog-instrumentations/src/fs.js +14 -14
  29. package/packages/datadog-instrumentations/src/google-cloud-pubsub.js +5 -7
  30. package/packages/datadog-instrumentations/src/google-genai.js +4 -4
  31. package/packages/datadog-instrumentations/src/grpc/server.js +2 -2
  32. package/packages/datadog-instrumentations/src/hapi.js +2 -2
  33. package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +8 -8
  34. package/packages/datadog-instrumentations/src/helpers/promise.js +2 -2
  35. package/packages/datadog-instrumentations/src/hono.js +2 -2
  36. package/packages/datadog-instrumentations/src/http/client.js +6 -6
  37. package/packages/datadog-instrumentations/src/http/server.js +9 -9
  38. package/packages/datadog-instrumentations/src/jest.js +31 -31
  39. package/packages/datadog-instrumentations/src/kafkajs.js +9 -9
  40. package/packages/datadog-instrumentations/src/knex.js +17 -17
  41. package/packages/datadog-instrumentations/src/koa.js +12 -12
  42. package/packages/datadog-instrumentations/src/ldapjs.js +5 -5
  43. package/packages/datadog-instrumentations/src/light-my-request.js +2 -2
  44. package/packages/datadog-instrumentations/src/limitd-client.js +4 -4
  45. package/packages/datadog-instrumentations/src/lodash.js +4 -4
  46. package/packages/datadog-instrumentations/src/mariadb.js +13 -13
  47. package/packages/datadog-instrumentations/src/memcached.js +2 -2
  48. package/packages/datadog-instrumentations/src/microgateway-core.js +2 -2
  49. package/packages/datadog-instrumentations/src/mocha/common.js +3 -3
  50. package/packages/datadog-instrumentations/src/mocha/main.js +12 -10
  51. package/packages/datadog-instrumentations/src/mocha/utils.js +133 -16
  52. package/packages/datadog-instrumentations/src/mocha/worker.js +7 -5
  53. package/packages/datadog-instrumentations/src/mongodb-core.js +9 -22
  54. package/packages/datadog-instrumentations/src/mongodb.js +5 -5
  55. package/packages/datadog-instrumentations/src/mongoose.js +21 -21
  56. package/packages/datadog-instrumentations/src/mquery.js +5 -5
  57. package/packages/datadog-instrumentations/src/multer.js +4 -4
  58. package/packages/datadog-instrumentations/src/mysql.js +16 -16
  59. package/packages/datadog-instrumentations/src/mysql2.js +4 -4
  60. package/packages/datadog-instrumentations/src/net.js +14 -8
  61. package/packages/datadog-instrumentations/src/nyc.js +5 -5
  62. package/packages/datadog-instrumentations/src/openai.js +19 -19
  63. package/packages/datadog-instrumentations/src/oracledb.js +6 -6
  64. package/packages/datadog-instrumentations/src/passport-utils.js +5 -5
  65. package/packages/datadog-instrumentations/src/pg.js +15 -15
  66. package/packages/datadog-instrumentations/src/pino.js +6 -10
  67. package/packages/datadog-instrumentations/src/playwright.js +20 -15
  68. package/packages/datadog-instrumentations/src/protobufjs.js +16 -16
  69. package/packages/datadog-instrumentations/src/redis.js +1 -2
  70. package/packages/datadog-instrumentations/src/restify.js +2 -2
  71. package/packages/datadog-instrumentations/src/router.js +12 -12
  72. package/packages/datadog-instrumentations/src/stripe.js +12 -12
  73. package/packages/datadog-instrumentations/src/vitest.js +107 -26
  74. package/packages/datadog-instrumentations/src/winston.js +4 -4
  75. package/packages/datadog-instrumentations/src/ws.js +7 -7
  76. package/packages/datadog-plugin-aws-sdk/src/base.js +52 -4
  77. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +19 -12
  78. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +45 -35
  79. package/packages/datadog-plugin-aws-sdk/src/services/lambda.js +33 -22
  80. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +12 -13
  81. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +73 -54
  82. package/packages/datadog-plugin-aws-sdk/src/services/stepfunctions.js +19 -17
  83. package/packages/datadog-plugin-aws-sdk/src/util.js +22 -0
  84. package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +6 -6
  85. package/packages/datadog-plugin-cucumber/src/index.js +4 -0
  86. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +1 -4
  87. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +1 -5
  88. package/packages/datadog-plugin-google-cloud-pubsub/src/pubsub-push-subscription.js +3 -1
  89. package/packages/datadog-plugin-http/src/client.js +1 -5
  90. package/packages/datadog-plugin-jest/src/util.js +1 -2
  91. package/packages/datadog-plugin-mocha/src/index.js +4 -0
  92. package/packages/datadog-plugin-mongodb-core/src/index.js +2 -1
  93. package/packages/datadog-plugin-openai/src/tracing.js +12 -23
  94. package/packages/datadog-plugin-playwright/src/index.js +1 -1
  95. package/packages/datadog-plugin-vitest/src/index.js +8 -1
  96. package/packages/datadog-shimmer/src/shimmer.js +7 -1
  97. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-password-rules.js +1 -1
  98. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secret-rules.js +81 -81
  99. package/packages/dd-trace/src/appsec/iast/security-controls/index.js +2 -2
  100. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugins/kafka.js +2 -2
  101. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +2 -2
  102. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +2 -2
  103. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +2 -0
  104. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/index.js +1 -3
  105. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +83 -48
  106. package/packages/dd-trace/src/appsec/index.js +21 -24
  107. package/packages/dd-trace/src/appsec/reporter.js +3 -1
  108. package/packages/dd-trace/src/appsec/rule_manager.js +4 -2
  109. package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +31 -16
  110. package/packages/dd-trace/src/config/git_properties.js +2 -2
  111. package/packages/dd-trace/src/datastreams/index.js +2 -1
  112. package/packages/dd-trace/src/datastreams/processor.js +1 -2
  113. package/packages/dd-trace/src/debugger/devtools_client/snapshot-pruner.js +1 -0
  114. package/packages/dd-trace/src/encode/0.4.js +757 -232
  115. package/packages/dd-trace/src/encode/0.5.js +13 -7
  116. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +1 -2
  117. package/packages/dd-trace/src/llmobs/plugins/genai/util.js +6 -3
  118. package/packages/dd-trace/src/llmobs/sdk.js +24 -26
  119. package/packages/dd-trace/src/llmobs/span_processor.js +25 -5
  120. package/packages/dd-trace/src/llmobs/util.js +1 -0
  121. package/packages/dd-trace/src/msgpack/chunk.js +6 -3
  122. package/packages/dd-trace/src/openfeature/noop.js +40 -36
  123. package/packages/dd-trace/src/openfeature/writers/exposures.js +33 -52
  124. package/packages/dd-trace/src/opentelemetry/otlp/otlp_transformer_base.js +1 -2
  125. package/packages/dd-trace/src/opentelemetry/tracer.js +0 -22
  126. package/packages/dd-trace/src/opentracing/propagation/text_map_dsm.js +2 -11
  127. package/packages/dd-trace/src/plugins/util/ci.js +1 -1
  128. package/packages/dd-trace/src/plugins/util/git-cache.js +3 -5
  129. package/packages/dd-trace/src/plugins/util/test.js +19 -7
  130. package/packages/dd-trace/src/plugins/util/url.js +1 -3
  131. package/packages/dd-trace/src/plugins/util/user-provided-git.js +1 -1
  132. package/packages/dd-trace/src/plugins/util/web.js +5 -7
  133. package/packages/dd-trace/src/profiling/profilers/events.js +3 -23
  134. package/packages/dd-trace/src/profiling/profilers/wall.js +4 -5
  135. package/packages/dd-trace/src/runtime_metrics/index.js +2 -2
  136. package/packages/dd-trace/src/scope.js +3 -10
  137. package/packages/dd-trace/src/serverless.js +1 -4
  138. package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +7 -1
  139. package/packages/dd-trace/src/service-naming/schemas/v1/messaging.js +4 -0
  140. package/packages/dd-trace/src/tracer.js +7 -7
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dd-trace",
3
- "version": "5.101.0",
3
+ "version": "5.102.0",
4
4
  "description": "Datadog APM tracing client for JavaScript",
5
5
  "main": "index.js",
6
6
  "typings": "index.d.ts",
@@ -8,6 +8,7 @@
8
8
  "env": "bash ./plugin-env",
9
9
  "prepare": "cd vendor && npm ci --include=dev",
10
10
  "preinstall": "node scripts/preinstall.js",
11
+ "prepack": "node scripts/release/swap-v5-types.js",
11
12
  "bench": "node benchmark/index.js",
12
13
  "bench:e2e:test-optimization": "node benchmark/e2e-test-optimization/benchmark-run.js",
13
14
  "dependencies:dedupe": "yarn-deduplicate yarn.lock",
@@ -18,8 +19,8 @@
18
19
  "type:check": "tsc --noEmit -p tsconfig.dev.json",
19
20
  "type:doc:build": "cd docs && yarn && yarn build",
20
21
  "type:doc:test": "cd docs && yarn && yarn test",
21
- "lint": "node scripts/check_licenses.js && node scripts/check-no-coverage-artifacts.js && node scripts/check-no-mcr-images.js && eslint . --concurrency=auto --max-warnings 0",
22
- "lint:fix": "node scripts/check_licenses.js && node scripts/check-no-coverage-artifacts.js && node scripts/check-no-mcr-images.js && eslint . --concurrency=auto --max-warnings 0 --fix",
22
+ "lint": "node scripts/check_licenses.js && node scripts/check-no-coverage-artifacts.js && node scripts/check-no-mcr-images.js && node scripts/check-docker-image-shas.js && eslint . --concurrency=auto --max-warnings 0",
23
+ "lint:fix": "node scripts/check_licenses.js && node scripts/check-no-coverage-artifacts.js && node scripts/check-no-mcr-images.js && node scripts/check-docker-image-shas.js && eslint . --concurrency=auto --max-warnings 0 --fix",
23
24
  "lint:inspect": "npx @eslint/config-inspector@latest",
24
25
  "lint:codeowners": "codeowners-audit",
25
26
  "lint:codeowners:ci": "codeowners-audit --glob='**/*.spec.js' --glob='benchmark/sirun/**'",
@@ -83,16 +84,16 @@
83
84
  "test:integration:webpack": "mocha --timeout 60000 \"integration-tests/webpack/*.spec.js\"",
84
85
  "test:integration:openfeature": "mocha --timeout 60000 \"integration-tests/openfeature/*.spec.js\"",
85
86
  "test:integration:openfeature:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/openfeature/*.spec.js\"",
86
- "test:integration:jest": "mocha --timeout 60000 \"integration-tests/jest/*.spec.js\"",
87
- "test:integration:jest:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/jest/*.spec.js\"",
87
+ "test:integration:jest": "mocha --timeout 60000 \"integration-tests/jest/${SPEC:-jest*}.spec.js\"",
88
+ "test:integration:jest:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/jest/${SPEC:-jest*}.spec.js\"",
88
89
  "test:integration:mocha": "mocha --timeout 60000 \"integration-tests/mocha/*.spec.js\"",
89
90
  "test:integration:mocha:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/mocha/*.spec.js\"",
90
91
  "test:integration:playwright": "mocha --timeout 60000 \"integration-tests/playwright/${SPEC:-playwright-*}.spec.js\"",
91
92
  "test:integration:playwright:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/playwright/${SPEC:-playwright-*}.spec.js\"",
92
93
  "test:integration:selenium": "mocha --timeout 60000 \"integration-tests/selenium/*.spec.js\"",
93
94
  "test:integration:selenium:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/selenium/*.spec.js\"",
94
- "test:integration:vitest": "mocha --timeout 60000 \"integration-tests/vitest/*.spec.js\"",
95
- "test:integration:vitest:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/vitest/*.spec.js\"",
95
+ "test:integration:vitest": "mocha --timeout 60000 \"integration-tests/vitest/${SPEC:-vitest*}.spec.js\"",
96
+ "test:integration:vitest:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 60000 \"integration-tests/vitest/${SPEC:-vitest*}.spec.js\"",
96
97
  "test:integration:testopt": "mocha --timeout 120000 \"integration-tests/ci-visibility/*.spec.js\"",
97
98
  "test:integration:testopt:coverage": "node ./integration-tests/coverage/run-suite.js --timeout 120000 \"integration-tests/ci-visibility/*.spec.js\"",
98
99
  "test:integration:profiler": "mocha --timeout 180000 \"integration-tests/profiler/*.spec.js\"",
@@ -198,6 +199,7 @@
198
199
  "eslint-plugin-mocha": "^11.2.0",
199
200
  "eslint-plugin-n": "^17.23.2",
200
201
  "eslint-plugin-promise": "^7.3.0",
202
+ "eslint-plugin-sonarjs": "^4.0.3",
201
203
  "eslint-plugin-unicorn": "^64.0.0",
202
204
  "express": "^5.1.0",
203
205
  "glob": "^10.4.5",
@@ -12,8 +12,8 @@ const ch = tracingChannel('apm:aerospike:command')
12
12
  function wrapCreateCommand (createCommand) {
13
13
  if (typeof createCommand !== 'function') return createCommand
14
14
 
15
- return function commandWithTrace () {
16
- const CommandClass = createCommand.apply(this, arguments)
15
+ return function commandWithTrace (...args) {
16
+ const CommandClass = createCommand.apply(this, args)
17
17
 
18
18
  if (!CommandClass) return CommandClass
19
19
 
@@ -119,17 +119,17 @@ function wrapTracer (tracer) {
119
119
  tracers.add(tracer)
120
120
 
121
121
  shimmer.wrap(tracer, 'startActiveSpan', function (startActiveSpan) {
122
- return function () {
123
- const name = arguments[0]
124
- const options = arguments.length > 2 ? (arguments[1] ?? {}) : {} // startActiveSpan(name, fn)
125
- const cb = arguments[arguments.length - 1]
122
+ return function (...args) {
123
+ const name = args[0]
124
+ const options = args.length > 2 ? (args[1] ?? {}) : {} // startActiveSpan(name, fn)
125
+ const cb = args[args.length - 1]
126
126
 
127
127
  const ctx = {
128
128
  name,
129
129
  attributes: options.attributes ?? {},
130
130
  }
131
131
 
132
- arguments[arguments.length - 1] = shimmer.wrapFunction(cb, function (originalCb) {
132
+ args[args.length - 1] = shimmer.wrapFunction(cb, function (originalCb) {
133
133
  return function (span) {
134
134
  // the below is necessary in the case that the span is vercel ai's noopSpan.
135
135
  // while we don't want to patch the noopSpan more than once, we do want to treat each as a
@@ -138,9 +138,9 @@ function wrapTracer (tracer) {
138
138
  const freshSpan = Object.create(span) // TODO: does this cause memory leaks?
139
139
 
140
140
  shimmer.wrap(freshSpan, 'end', function (spanEnd) {
141
- return function () {
141
+ return function (...args) {
142
142
  vercelAiTracingChannel.asyncEnd.publish(ctx)
143
- return spanEnd.apply(this, arguments)
143
+ return spanEnd.apply(this, args)
144
144
  }
145
145
  })
146
146
 
@@ -164,7 +164,7 @@ function wrapTracer (tracer) {
164
164
  })
165
165
 
166
166
  return vercelAiTracingChannel.start.runStores(ctx, () => {
167
- const result = startActiveSpan.apply(this, arguments)
167
+ const result = startActiveSpan.apply(this, args)
168
168
  vercelAiTracingChannel.end.publish(ctx)
169
169
  return result
170
170
  })
@@ -35,14 +35,13 @@ addHook({ name: 'amqplib', file: 'lib/defs.js', versions: [MIN_VERSION] }, defs
35
35
  addHook({ name: 'amqplib', file: 'lib/channel_model.js', versions: [MIN_VERSION] }, x => {
36
36
  shimmer.wrap(x.Channel.prototype, 'get', getMessage => function (queue, options) {
37
37
  return getMessage.apply(this, arguments).then(message => {
38
- if (message === null) {
39
- return message
38
+ if (message !== null) {
39
+ const ctx = { method: 'basic.get', message, fields: message.fields, queue }
40
+ consumeStartCh.runStores(ctx, () => {
41
+ // finish right away
42
+ consumeFinishCh.publish(ctx)
43
+ })
40
44
  }
41
- const ctx = { method: 'basic.get', message, fields: message.fields, queue }
42
- consumeStartCh.runStores(ctx, () => {
43
- // finish right away
44
- consumeFinishCh.publish(ctx)
45
- })
46
45
  return message
47
46
  })
48
47
  })
@@ -8,10 +8,10 @@ const anthropicTracingChannel = tracingChannel('apm:anthropic:request')
8
8
  const onStreamedChunkCh = channel('apm:anthropic:request:chunk')
9
9
 
10
10
  function wrapStreamIterator (iterator, ctx) {
11
- return function () {
12
- const itr = iterator.apply(this, arguments)
13
- shimmer.wrap(itr, 'next', next => function () {
14
- return next.apply(this, arguments)
11
+ return function (...args) {
12
+ const itr = iterator.apply(this, args)
13
+ shimmer.wrap(itr, 'next', next => function (...args) {
14
+ return next.apply(this, args)
15
15
  .then(res => {
16
16
  const { done, value: chunk } = res
17
17
  onStreamedChunkCh.publish({ ctx, chunk, done })
@@ -33,12 +33,12 @@ function wrapStreamIterator (iterator, ctx) {
33
33
  }
34
34
 
35
35
  function wrapCreate (create) {
36
- return function () {
36
+ return function (...args) {
37
37
  if (!anthropicTracingChannel.start.hasSubscribers) {
38
- return create.apply(this, arguments)
38
+ return create.apply(this, args)
39
39
  }
40
40
 
41
- const options = arguments[0]
41
+ const options = args[0]
42
42
  const stream = options.stream
43
43
 
44
44
  const ctx = { options, resource: 'create', baseUrl: this._client?.baseURL }
@@ -46,14 +46,14 @@ function wrapCreate (create) {
46
46
  return anthropicTracingChannel.start.runStores(ctx, () => {
47
47
  let apiPromise
48
48
  try {
49
- apiPromise = create.apply(this, arguments)
49
+ apiPromise = create.apply(this, args)
50
50
  } catch (error) {
51
51
  finish(ctx, null, error)
52
52
  throw error
53
53
  }
54
54
 
55
- shimmer.wrap(apiPromise, 'parse', parse => function () {
56
- return parse.apply(this, arguments)
55
+ shimmer.wrap(apiPromise, 'parse', parse => function (...args) {
56
+ return parse.apply(this, args)
57
57
  .then(response => {
58
58
  if (stream) {
59
59
  shimmer.wrap(response, Symbol.asyncIterator, iterator => wrapStreamIterator(iterator, ctx))
@@ -10,9 +10,9 @@ addHook({ name: 'apollo-server-core', file: 'dist/runHttpQuery.js', versions: ['
10
10
  const HttpQueryError = runHttpQueryModule.HttpQueryError
11
11
 
12
12
  shimmer.wrap(runHttpQueryModule, 'runHttpQuery', function wrapRunHttpQuery (originalRunHttpQuery) {
13
- return function runHttpQuery () {
13
+ return function runHttpQuery (...args) {
14
14
  if (!requestChannel.start.hasSubscribers) {
15
- return originalRunHttpQuery.apply(this, arguments)
15
+ return originalRunHttpQuery.apply(this, args)
16
16
  }
17
17
 
18
18
  const abortController = new AbortController()
@@ -22,7 +22,7 @@ addHook({ name: 'apollo-server-core', file: 'dist/runHttpQuery.js', versions: ['
22
22
  originalRunHttpQuery,
23
23
  { abortController, abortData },
24
24
  this,
25
- ...arguments)
25
+ ...args)
26
26
 
27
27
  const abortPromise = new Promise((resolve, reject) => {
28
28
  abortController.signal.addEventListener('abort', (event) => {
@@ -13,9 +13,9 @@ const requestChannel = dc.tracingChannel('datadog:apollo:request')
13
13
  let HeaderMap
14
14
 
15
15
  function wrapExecuteHTTPGraphQLRequest (originalExecuteHTTPGraphQLRequest) {
16
- return function executeHTTPGraphQLRequest () {
16
+ return function executeHTTPGraphQLRequest (...args) {
17
17
  if (!HeaderMap || !requestChannel.start.hasSubscribers) {
18
- return originalExecuteHTTPGraphQLRequest.apply(this, arguments)
18
+ return originalExecuteHTTPGraphQLRequest.apply(this, args)
19
19
  }
20
20
 
21
21
  const abortController = new AbortController()
@@ -25,7 +25,7 @@ function wrapExecuteHTTPGraphQLRequest (originalExecuteHTTPGraphQLRequest) {
25
25
  originalExecuteHTTPGraphQLRequest,
26
26
  { abortController, abortData },
27
27
  this,
28
- ...arguments)
28
+ ...args)
29
29
 
30
30
  const abortPromise = new Promise((resolve, reject) => {
31
31
  abortController.signal.addEventListener('abort', (event) => {
@@ -89,10 +89,10 @@ function wrapEmit (emit) {
89
89
  }
90
90
 
91
91
  function wrapListen (originalListen) {
92
- return function wrappedListen () {
92
+ return function wrappedListen (...args) {
93
93
  shimmer.wrap(this, 'emit', wrapEmit)
94
94
 
95
- return originalListen.apply(this, arguments)
95
+ return originalListen.apply(this, args)
96
96
  }
97
97
  }
98
98
 
@@ -8,21 +8,21 @@ const serializeChannel = dc.channel('apm:avsc:serialize-start')
8
8
  const deserializeChannel = dc.channel('apm:avsc:deserialize-end')
9
9
 
10
10
  function wrapSerialization (Type) {
11
- shimmer.wrap(Type.prototype, 'toBuffer', original => function () {
11
+ shimmer.wrap(Type.prototype, 'toBuffer', original => function (...args) {
12
12
  if (!serializeChannel.hasSubscribers) {
13
- return original.apply(this, arguments)
13
+ return original.apply(this, args)
14
14
  }
15
15
  serializeChannel.publish({ messageClass: this })
16
- return original.apply(this, arguments)
16
+ return original.apply(this, args)
17
17
  })
18
18
  }
19
19
 
20
20
  function wrapDeserialization (Type) {
21
- shimmer.wrap(Type.prototype, 'fromBuffer', original => function () {
21
+ shimmer.wrap(Type.prototype, 'fromBuffer', original => function (...args) {
22
22
  if (!deserializeChannel.hasSubscribers) {
23
- return original.apply(this, arguments)
23
+ return original.apply(this, args)
24
24
  }
25
- const result = original.apply(this, arguments)
25
+ const result = original.apply(this, args)
26
26
  deserializeChannel.publish({ messageClass: result })
27
27
  return result
28
28
  })
@@ -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)