dd-trace 5.102.0 → 5.104.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 (201) hide show
  1. package/ext/exporters.js +1 -0
  2. package/index.d.ts +25 -3
  3. package/package.json +15 -13
  4. package/packages/datadog-esbuild/src/utils.js +2 -2
  5. package/packages/datadog-instrumentations/src/ai.js +1 -1
  6. package/packages/datadog-instrumentations/src/aws-sdk.js +2 -2
  7. package/packages/datadog-instrumentations/src/cassandra-driver.js +5 -2
  8. package/packages/datadog-instrumentations/src/confluentinc-kafka-javascript.js +32 -15
  9. package/packages/datadog-instrumentations/src/couchbase.js +69 -220
  10. package/packages/datadog-instrumentations/src/cucumber.js +104 -31
  11. package/packages/datadog-instrumentations/src/elasticsearch.js +4 -4
  12. package/packages/datadog-instrumentations/src/electron/preload.js +42 -0
  13. package/packages/datadog-instrumentations/src/electron.js +240 -0
  14. package/packages/datadog-instrumentations/src/fetch.js +5 -5
  15. package/packages/datadog-instrumentations/src/graphql.js +13 -17
  16. package/packages/datadog-instrumentations/src/grpc/client.js +48 -32
  17. package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +2 -2
  18. package/packages/datadog-instrumentations/src/helpers/hook.js +4 -1
  19. package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
  20. package/packages/datadog-instrumentations/src/helpers/instrument.js +2 -2
  21. package/packages/datadog-instrumentations/src/helpers/kafka.js +58 -0
  22. package/packages/datadog-instrumentations/src/helpers/rewriter/compiler.js +3 -2
  23. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +19 -5
  24. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +14 -13
  25. package/packages/datadog-instrumentations/src/http/client.js +2 -2
  26. package/packages/datadog-instrumentations/src/ioredis.js +18 -14
  27. package/packages/datadog-instrumentations/src/jest.js +382 -84
  28. package/packages/datadog-instrumentations/src/kafkajs.js +184 -174
  29. package/packages/datadog-instrumentations/src/mariadb.js +1 -1
  30. package/packages/datadog-instrumentations/src/memcached.js +2 -1
  31. package/packages/datadog-instrumentations/src/mocha/main.js +309 -56
  32. package/packages/datadog-instrumentations/src/mocha/utils.js +48 -8
  33. package/packages/datadog-instrumentations/src/mongodb-core.js +34 -9
  34. package/packages/datadog-instrumentations/src/mongoose.js +10 -12
  35. package/packages/datadog-instrumentations/src/mysql.js +2 -2
  36. package/packages/datadog-instrumentations/src/mysql2.js +1 -1
  37. package/packages/datadog-instrumentations/src/pg.js +25 -11
  38. package/packages/datadog-instrumentations/src/playwright.js +449 -60
  39. package/packages/datadog-instrumentations/src/redis.js +19 -10
  40. package/packages/datadog-instrumentations/src/router.js +4 -2
  41. package/packages/datadog-instrumentations/src/vitest.js +246 -149
  42. package/packages/datadog-plugin-apollo/src/gateway/request.js +1 -21
  43. package/packages/datadog-plugin-aws-sdk/src/base.js +18 -24
  44. package/packages/datadog-plugin-aws-sdk/src/services/cloudwatchlogs.js +1 -1
  45. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +1 -1
  46. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +1 -1
  47. package/packages/datadog-plugin-aws-sdk/src/services/lambda.js +1 -1
  48. package/packages/datadog-plugin-aws-sdk/src/services/redshift.js +1 -1
  49. package/packages/datadog-plugin-aws-sdk/src/services/s3.js +1 -1
  50. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +2 -2
  51. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +1 -1
  52. package/packages/datadog-plugin-aws-sdk/src/services/stepfunctions.js +1 -1
  53. package/packages/datadog-plugin-couchbase/src/index.js +58 -52
  54. package/packages/datadog-plugin-cucumber/src/index.js +1 -0
  55. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +239 -40
  56. package/packages/datadog-plugin-cypress/src/support.js +13 -1
  57. package/packages/datadog-plugin-elasticsearch/src/index.js +28 -8
  58. package/packages/datadog-plugin-electron/src/index.js +17 -0
  59. package/packages/datadog-plugin-electron/src/ipc.js +143 -0
  60. package/packages/datadog-plugin-electron/src/net.js +82 -0
  61. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +27 -18
  62. package/packages/datadog-plugin-graphql/src/execute.js +6 -28
  63. package/packages/datadog-plugin-graphql/src/resolve.js +30 -35
  64. package/packages/datadog-plugin-graphql/src/tools/signature.js +32 -7
  65. package/packages/datadog-plugin-graphql/src/tools/transforms.js +118 -100
  66. package/packages/datadog-plugin-graphql/src/utils.js +33 -1
  67. package/packages/datadog-plugin-grpc/src/client.js +6 -7
  68. package/packages/datadog-plugin-grpc/src/util.js +57 -22
  69. package/packages/datadog-plugin-http/src/client.js +2 -2
  70. package/packages/datadog-plugin-jest/src/index.js +92 -50
  71. package/packages/datadog-plugin-kafkajs/src/producer.js +32 -0
  72. package/packages/datadog-plugin-mocha/src/index.js +1 -0
  73. package/packages/datadog-plugin-mongodb-core/src/index.js +70 -69
  74. package/packages/datadog-plugin-mysql/src/index.js +1 -1
  75. package/packages/datadog-plugin-openai/src/services.js +2 -1
  76. package/packages/datadog-plugin-pg/src/index.js +3 -3
  77. package/packages/datadog-plugin-playwright/src/index.js +4 -0
  78. package/packages/datadog-plugin-redis/src/index.js +54 -24
  79. package/packages/datadog-plugin-undici/src/index.js +19 -0
  80. package/packages/datadog-plugin-vitest/src/index.js +19 -7
  81. package/packages/datadog-shimmer/src/shimmer.js +35 -0
  82. package/packages/dd-trace/src/aiguard/index.js +3 -1
  83. package/packages/dd-trace/src/aiguard/sdk.js +36 -30
  84. package/packages/dd-trace/src/aiguard/tags.js +20 -11
  85. package/packages/dd-trace/src/appsec/blocking.js +2 -2
  86. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +2 -2
  87. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +1 -1
  88. package/packages/dd-trace/src/appsec/index.js +10 -3
  89. package/packages/dd-trace/src/appsec/reporter.js +19 -5
  90. package/packages/dd-trace/src/azure_metadata.js +17 -6
  91. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +4 -4
  92. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +4 -2
  93. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +6 -4
  94. package/packages/dd-trace/src/ci-visibility/requests/fs-cache.js +1 -1
  95. package/packages/dd-trace/src/ci-visibility/requests/request.js +3 -1
  96. package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +5 -3
  97. package/packages/dd-trace/src/config/defaults.js +3 -14
  98. package/packages/dd-trace/src/config/generated-config-types.d.ts +4 -1
  99. package/packages/dd-trace/src/config/helper.js +4 -0
  100. package/packages/dd-trace/src/config/index.js +2 -2
  101. package/packages/dd-trace/src/config/major-overrides.js +98 -0
  102. package/packages/dd-trace/src/config/parsers.js +7 -1
  103. package/packages/dd-trace/src/config/supported-configurations.json +60 -38
  104. package/packages/dd-trace/src/crashtracking/crashtracker.js +15 -3
  105. package/packages/dd-trace/src/datastreams/checkpointer.js +2 -2
  106. package/packages/dd-trace/src/datastreams/context.js +4 -2
  107. package/packages/dd-trace/src/datastreams/manager.js +1 -1
  108. package/packages/dd-trace/src/datastreams/processor.js +2 -2
  109. package/packages/dd-trace/src/debugger/devtools_client/snapshot/collector.js +2 -2
  110. package/packages/dd-trace/src/debugger/devtools_client/source-maps.js +1 -1
  111. package/packages/dd-trace/src/debugger/devtools_client/state.js +2 -1
  112. package/packages/dd-trace/src/debugger/index.js +7 -7
  113. package/packages/dd-trace/src/dogstatsd.js +2 -2
  114. package/packages/dd-trace/src/encode/0.4.js +45 -54
  115. package/packages/dd-trace/src/encode/0.5.js +34 -3
  116. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +26 -19
  117. package/packages/dd-trace/src/encode/agentless-json.js +1 -1
  118. package/packages/dd-trace/src/exporter.js +2 -0
  119. package/packages/dd-trace/src/exporters/agent/index.js +2 -1
  120. package/packages/dd-trace/src/exporters/agentless/index.js +3 -2
  121. package/packages/dd-trace/src/exporters/agentless/writer.js +2 -2
  122. package/packages/dd-trace/src/exporters/common/agents.js +3 -1
  123. package/packages/dd-trace/src/exporters/common/buffering-exporter.js +2 -1
  124. package/packages/dd-trace/src/exporters/common/request.js +4 -2
  125. package/packages/dd-trace/src/exporters/electron/index.js +49 -0
  126. package/packages/dd-trace/src/external-logger/src/index.js +2 -1
  127. package/packages/dd-trace/src/git_metadata.js +10 -8
  128. package/packages/dd-trace/src/id.js +17 -4
  129. package/packages/dd-trace/src/lambda/handler-paths.js +52 -0
  130. package/packages/dd-trace/src/lambda/handler.js +2 -4
  131. package/packages/dd-trace/src/lambda/index.js +62 -14
  132. package/packages/dd-trace/src/lambda/runtime/patch.js +21 -46
  133. package/packages/dd-trace/src/llmobs/index.js +13 -2
  134. package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +45 -15
  135. package/packages/dd-trace/src/llmobs/sdk.js +10 -0
  136. package/packages/dd-trace/src/llmobs/writers/base.js +2 -1
  137. package/packages/dd-trace/src/log/writer.js +3 -1
  138. package/packages/dd-trace/src/noop/span.js +3 -1
  139. package/packages/dd-trace/src/openfeature/writers/base.js +2 -1
  140. package/packages/dd-trace/src/openfeature/writers/exposures.js +51 -20
  141. package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +3 -2
  142. package/packages/dd-trace/src/opentracing/propagation/text_map.js +20 -9
  143. package/packages/dd-trace/src/payload-tagging/config/index.js +2 -2
  144. package/packages/dd-trace/src/plugins/apollo.js +3 -1
  145. package/packages/dd-trace/src/plugins/ci_plugin.js +52 -17
  146. package/packages/dd-trace/src/plugins/database.js +54 -12
  147. package/packages/dd-trace/src/plugins/index.js +1 -0
  148. package/packages/dd-trace/src/plugins/log_plugin.js +3 -1
  149. package/packages/dd-trace/src/plugins/plugin.js +2 -4
  150. package/packages/dd-trace/src/plugins/tracing.js +5 -3
  151. package/packages/dd-trace/src/plugins/util/ci.js +8 -8
  152. package/packages/dd-trace/src/plugins/util/git-cache.js +20 -18
  153. package/packages/dd-trace/src/plugins/util/git.js +3 -1
  154. package/packages/dd-trace/src/plugins/util/stacktrace.js +2 -2
  155. package/packages/dd-trace/src/plugins/util/test.js +119 -5
  156. package/packages/dd-trace/src/plugins/util/user-provided-git.js +17 -15
  157. package/packages/dd-trace/src/plugins/util/web.js +11 -0
  158. package/packages/dd-trace/src/priority_sampler.js +1 -1
  159. package/packages/dd-trace/src/profiling/profiler.js +1 -1
  160. package/packages/dd-trace/src/profiling/profilers/wall.js +1 -1
  161. package/packages/dd-trace/src/profiling/ssi-heuristics.js +1 -1
  162. package/packages/dd-trace/src/rate_limiter.js +1 -1
  163. package/packages/dd-trace/src/remote_config/scheduler.js +1 -1
  164. package/packages/dd-trace/src/ritm.js +2 -1
  165. package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +5 -8
  166. package/packages/dd-trace/src/scope.js +7 -5
  167. package/packages/dd-trace/src/serverless.js +5 -2
  168. package/packages/dd-trace/src/service-naming/extra-services.js +14 -0
  169. package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +20 -0
  170. package/packages/dd-trace/src/service-naming/schemas/v0/web.js +4 -0
  171. package/packages/dd-trace/src/service-naming/schemas/v1/messaging.js +20 -0
  172. package/packages/dd-trace/src/service-naming/schemas/v1/web.js +4 -0
  173. package/packages/dd-trace/src/span_stats.js +1 -1
  174. package/packages/dd-trace/src/telemetry/dependencies.js +1 -1
  175. package/packages/dd-trace/src/telemetry/endpoints.js +1 -1
  176. package/packages/dd-trace/src/telemetry/telemetry.js +2 -2
  177. package/packages/dd-trace/src/lambda/runtime/ritm.js +0 -133
  178. package/vendor/dist/opentracing/LICENSE +0 -201
  179. package/vendor/dist/opentracing/binary_carrier.d.ts +0 -11
  180. package/vendor/dist/opentracing/constants.d.ts +0 -61
  181. package/vendor/dist/opentracing/examples/demo/demo.d.ts +0 -2
  182. package/vendor/dist/opentracing/ext/tags.d.ts +0 -90
  183. package/vendor/dist/opentracing/functions.d.ts +0 -20
  184. package/vendor/dist/opentracing/global_tracer.d.ts +0 -14
  185. package/vendor/dist/opentracing/index.d.ts +0 -12
  186. package/vendor/dist/opentracing/index.js +0 -1
  187. package/vendor/dist/opentracing/mock_tracer/index.d.ts +0 -5
  188. package/vendor/dist/opentracing/mock_tracer/mock_context.d.ts +0 -13
  189. package/vendor/dist/opentracing/mock_tracer/mock_report.d.ts +0 -16
  190. package/vendor/dist/opentracing/mock_tracer/mock_span.d.ts +0 -50
  191. package/vendor/dist/opentracing/mock_tracer/mock_tracer.d.ts +0 -26
  192. package/vendor/dist/opentracing/noop.d.ts +0 -8
  193. package/vendor/dist/opentracing/reference.d.ts +0 -33
  194. package/vendor/dist/opentracing/span.d.ts +0 -147
  195. package/vendor/dist/opentracing/span_context.d.ts +0 -26
  196. package/vendor/dist/opentracing/test/api_compatibility.d.ts +0 -16
  197. package/vendor/dist/opentracing/test/mocktracer_implemenation.d.ts +0 -3
  198. package/vendor/dist/opentracing/test/noop_implementation.d.ts +0 -4
  199. package/vendor/dist/opentracing/test/opentracing_api.d.ts +0 -3
  200. package/vendor/dist/opentracing/test/unittest.d.ts +0 -2
  201. package/vendor/dist/opentracing/tracer.d.ts +0 -127
@@ -14,11 +14,14 @@ const finishChannel = channel('apm:grpc:client:request:finish')
14
14
  const emitChannel = channel('apm:grpc:client:request:emit')
15
15
 
16
16
  function createWrapMakeRequest (type, hasPeer = false) {
17
+ const metadataIndex = type === types.client_stream || type === types.bidi ? 3 : 4
18
+
17
19
  return function wrapMakeRequest (makeRequest) {
18
20
  return function (path) {
19
- const args = ensureMetadata(this, arguments, 4)
21
+ if (!startChannel.hasSubscribers) return makeRequest.apply(this, arguments)
20
22
 
21
- return callMethod(this, makeRequest, args, path, args[4], type, hasPeer)
23
+ const { metadata, args } = resolveMetadata(this, arguments, metadataIndex)
24
+ return callMethod(this, makeRequest, args, path, metadata, type, hasPeer)
22
25
  }
23
26
  }
24
27
  }
@@ -82,9 +85,13 @@ function wrapMethod (method, path, type, hasPeer) {
82
85
  return method
83
86
  }
84
87
 
88
+ const metadataIndex = type === types.client_stream || type === types.bidi ? 0 : 1
89
+
85
90
  const wrapped = shimmer.wrapFunction(method, method => function () {
86
- const args = ensureMetadata(this, arguments, 1)
87
- return callMethod(this, method, args, path, args[1], type, hasPeer)
91
+ if (!startChannel.hasSubscribers) return method.apply(this, arguments)
92
+
93
+ const { metadata, args } = resolveMetadata(this, arguments, metadataIndex)
94
+ return callMethod(this, method, args, path, metadata, type, hasPeer)
88
95
  })
89
96
 
90
97
  patched.add(wrapped)
@@ -140,24 +147,25 @@ function createWrapEmit (ctx, hasPeer = false) {
140
147
  }
141
148
 
142
149
  function callMethod (client, method, args, path, metadata, type, hasPeer = false) {
143
- if (!startChannel.hasSubscribers) return method.apply(client, args)
144
-
145
- const length = args.length
146
- const callback = args[length - 1]
147
-
148
150
  const ctx = { metadata, path, type }
149
151
 
150
152
  return startChannel.runStores(ctx, () => {
151
153
  try {
154
+ let callArgs = args
155
+
152
156
  if (type === types.unary || type === types.client_stream) {
157
+ if (!Array.isArray(callArgs)) callArgs = [...callArgs]
158
+
159
+ const length = callArgs.length
160
+ const callback = callArgs[length - 1]
153
161
  if (typeof callback === 'function') {
154
- args[length - 1] = wrapCallback(ctx, callback)
162
+ callArgs[length - 1] = wrapCallback(ctx, callback)
155
163
  } else {
156
- args[length] = wrapCallback(ctx)
164
+ callArgs[length] = wrapCallback(ctx)
157
165
  }
158
166
  }
159
167
 
160
- const call = method.apply(client, args)
168
+ const call = method.apply(client, callArgs)
161
169
 
162
170
  if (call && typeof call.emit === 'function') {
163
171
  shimmer.wrap(call, 'emit', createWrapEmit(ctx, hasPeer))
@@ -167,36 +175,44 @@ function callMethod (client, method, args, path, metadata, type, hasPeer = false
167
175
  } catch (e) {
168
176
  ctx.error = e
169
177
  errorChannel.publish(ctx)
178
+ throw e
170
179
  }
171
180
  // No end channel needed
172
181
  })
173
182
  }
174
183
 
175
- function ensureMetadata (client, args, index) {
176
- const grpc = getGrpc(client)
177
-
178
- if (!client || !grpc) return args
179
-
180
- const meta = args[index]
181
- const normalized = []
182
-
183
- for (let i = 0; i < index; i++) {
184
- normalized.push(args[i])
184
+ /**
185
+ * Returns the `Metadata` for a gRPC client invocation, splicing or replacing
186
+ * one at `index` when the user did not pass their own.
187
+ *
188
+ * @param {object} client
189
+ * @param {ArrayLike<unknown>} args
190
+ * @param {number} index
191
+ * @returns {{ metadata: object | undefined, args: ArrayLike<unknown> }}
192
+ */
193
+ function resolveMetadata (client, args, index) {
194
+ const grpc = client && getGrpc(client)
195
+ if (!grpc) return { metadata: undefined, args }
196
+
197
+ const slot = args[index]
198
+
199
+ if (slot instanceof grpc.Metadata || slot?.constructor?.name === 'Metadata') {
200
+ return { metadata: slot, args }
185
201
  }
186
202
 
187
- if (!meta || !meta.constructor || meta.constructor.name !== 'Metadata') {
188
- normalized.push(new grpc.Metadata())
189
- }
190
-
191
- if (meta) {
192
- normalized.push(meta)
193
- }
203
+ const metadata = new grpc.Metadata()
194
204
 
195
- for (let i = index + 1; i < args.length; i++) {
196
- normalized.push(args[i])
205
+ if (slot == null) {
206
+ const out = [...args]
207
+ out[index] = metadata
208
+ return { metadata, args: out }
197
209
  }
198
210
 
199
- return normalized
211
+ const out = new Array(args.length + 1)
212
+ for (let i = 0; i < index; i++) out[i] = args[i]
213
+ out[index] = metadata
214
+ for (let i = index; i < args.length; i++) out[i + 1] = args[i]
215
+ return { metadata, args: out }
200
216
  }
201
217
 
202
218
  function getType (definition) {
@@ -19,7 +19,7 @@ const { channel } = require('./instrument')
19
19
  *
20
20
  * @param {string} prefix
21
21
  * @param {object} [options]
22
- * @param {boolean} [options.captureResult=false] set `ctx.result` to the callback's first
22
+ * @param {boolean} [options.captureResult] set `ctx.result` to the callback's first
23
23
  * non-error argument before publishing `:finish`. Plugins that tag spans from the call's
24
24
  * return value (e.g. the DNS lookup plugin) rely on this.
25
25
  * @returns {(buildContext: (thisArg: unknown, args: IArguments) => object | undefined) =>
@@ -45,7 +45,7 @@ function createCallbackInstrumentor (prefix, { captureResult = false } = {}) {
45
45
  }
46
46
 
47
47
  return startCh.runStores(ctx, () => {
48
- args[lastIndex] = shimmer.wrapFunction(cb, cb => function (error, ...rest) {
48
+ args[lastIndex] = shimmer.wrapCallback(cb, cb => function (error, ...rest) {
49
49
  if (error) {
50
50
  ctx.error = error
51
51
  errorCh.publish(ctx)
@@ -16,7 +16,10 @@ function getVersion (moduleBaseDir) {
16
16
  return requirePackageJson(moduleBaseDir, /** @type {import('module').Module} */ (module)).version
17
17
  }
18
18
 
19
- return process.version
19
+ // In a packaged Electron binary, built-in modules (like 'electron', 'electron/main') have no
20
+ // moduleBaseDir. Use the Electron version for version checks when available, otherwise fall back
21
+ // to the Node.js version.
22
+ return process.versions?.electron ?? process.version
20
23
  }
21
24
 
22
25
  /**
@@ -68,6 +68,7 @@ module.exports = {
68
68
  cypress: () => require('../cypress'),
69
69
  'dd-trace-api': () => require('../dd-trace-api'),
70
70
  elasticsearch: () => require('../elasticsearch'),
71
+ electron: () => require('../electron'),
71
72
  express: () => require('../express'),
72
73
  'express-mongo-sanitize': () => require('../express-mongo-sanitize'),
73
74
  'express-session': () => require('../express-session'),
@@ -55,9 +55,9 @@ exports.getHooks = function getHooks (names) {
55
55
  * @param {object} args
56
56
  * @param {string} args.name module name
57
57
  * @param {string[]} [args.versions] array of semver range strings
58
- * @param {string} [args.file='index.js'] path to file within package to instrument
58
+ * @param {string} [args.file] path to file within package to instrument. Defaults to 'index.js'.
59
59
  * @param {string} [args.filePattern] pattern to match files within package to instrument
60
- * @param {boolean} [args.patchDefault=true] whether to patch the default export
60
+ * @param {boolean} [args.patchDefault] whether to patch the default export. Defaults to true.
61
61
  * @param {(moduleExports: unknown, version: string, isIitm?: boolean) => unknown} [hook] Patches module exports
62
62
  */
63
63
  exports.addHook = function addHook ({ name, versions, file, filePattern, patchDefault }, hook) {
@@ -0,0 +1,58 @@
1
+ 'use strict'
2
+
3
+ // Produce API key 0; v0–v2 use the legacy MessageSet format with no header
4
+ // field, so trace headers can only be carried on v3+ (Kafka >=0.11).
5
+ const PRODUCE_API_KEY = 0
6
+ const PRODUCE_VERSION_WITH_HEADERS = 3
7
+
8
+ // Side-table mapping a kafkajs producer/consumer to the cluster captured at
9
+ // creation time. The boundary uses it to read `cluster.brokerPool` lazily on
10
+ // first send/consume instead of opening a parallel admin connection. A
11
+ // WeakMap keeps the kafkajs object itself untouched: no Symbol-keyed
12
+ // property to leak through `Reflect.ownKeys`, no string-keyed underscore for
13
+ // user serializers to pick up, and the entry drops as soon as the producer
14
+ // is GC'd.
15
+ const clientToCluster = new WeakMap()
16
+
17
+ /**
18
+ * Shallow-clone each message and its headers so the boundary, kafkajs, and
19
+ * the user never share the same nested objects. With `ensureHeaders` true
20
+ * (header injection enabled) messages without `headers` get an empty object
21
+ * the producer plugin can inject into; with it false (broker rejected
22
+ * headers) the absence of `headers` is preserved so brokers that fail on any
23
+ * header field can recover.
24
+ *
25
+ * @param {Array<unknown>} messages
26
+ * @param {boolean} ensureHeaders
27
+ */
28
+ function cloneMessages (messages, ensureHeaders) {
29
+ const result = new Array(messages.length)
30
+ for (let i = 0; i < messages.length; i++) {
31
+ const message = messages[i]
32
+ if (message === null || typeof message !== 'object') {
33
+ result[i] = message
34
+ } else if (message.headers) {
35
+ result[i] = { ...message, headers: { ...message.headers } }
36
+ } else {
37
+ result[i] = ensureHeaders ? { ...message, headers: {} } : { ...message }
38
+ }
39
+ }
40
+ return result
41
+ }
42
+
43
+ /**
44
+ * @param {{ versions?: Record<number, { minVersion: number, maxVersion: number }> } | undefined} brokerPool
45
+ * kafkajs's `cluster.brokerPool`. `versions` is populated once the seed
46
+ * broker handshakes; before that, the answer is unknown and we return
47
+ * `true` so the caller defaults to injection.
48
+ */
49
+ function brokerSupportsMessageHeaders (brokerPool) {
50
+ const produce = brokerPool?.versions?.[PRODUCE_API_KEY]
51
+ return !produce || produce.maxVersion >= PRODUCE_VERSION_WITH_HEADERS
52
+ }
53
+
54
+ module.exports = {
55
+ brokerSupportsMessageHeaders,
56
+ clientToCluster,
57
+ cloneMessages,
58
+ }
@@ -19,9 +19,10 @@ const compiler = {
19
19
  // TODO: Figure out ESBuild `createRequire` issue and remove this hack.
20
20
  const oxc = runtimeRequire(['oxc', 'parser'].join('-'))
21
21
 
22
- compiler.parse = (sourceText, options) => {
22
+ compiler.parse = (sourceText, { range, isModule } = {}) => {
23
23
  const { program, errors } = oxc.parseSync('index.js', sourceText, {
24
- ...options,
24
+ range,
25
+ sourceType: isModule ? 'module' : 'script',
25
26
  preserveParens: false,
26
27
  })
27
28
 
@@ -2,15 +2,25 @@
2
2
 
3
3
  const { readFileSync } = require('fs')
4
4
  const { join } = require('path')
5
+ const { pathToFileURL } = require('url')
5
6
  const log = require('../../../../dd-trace/src/log')
6
7
  const { create } = require('../../../../../vendor/dist/@apm-js-collab/code-transformer')
7
8
  const { traceAsyncIterator, traceIterator } = require('./transforms')
8
9
  const instrumentations = require('./instrumentations')
9
10
 
10
- let dcPolyfill
11
+ // `dc-polyfill` is referenced from injected `require()` (CJS) and `import`
12
+ // (ESM) statements that the transformer splices into the rewritten module.
13
+ // `require()` accepts an absolute filesystem path; the ESM resolver rejects it
14
+ // with `ERR_INVALID_MODULE_SPECIFIER` and needs a `file://` URL instead. We
15
+ // pre-compute both forms here so each matcher hands the transformer a
16
+ // specifier that is valid for the module type it is rewriting.
17
+ let dcPolyfillCjs
18
+ let dcPolyfillEsm
11
19
 
12
20
  try {
13
- dcPolyfill = require.resolve('dc-polyfill').replaceAll('\\', '/')
21
+ const resolved = require.resolve('dc-polyfill')
22
+ dcPolyfillCjs = resolved.replaceAll('\\', '/')
23
+ dcPolyfillEsm = pathToFileURL(resolved).href
14
24
  } catch {
15
25
  // The `dc-polyfill` module is unavailable for some reason (like bundling).
16
26
  // Let's just keep the default of using `diagnostics-channel` as a fallback
@@ -20,10 +30,13 @@ try {
20
30
  /** @type {Record<string, string>} map of module base name to version */
21
31
  const moduleVersions = {}
22
32
  const disabled = new Set()
23
- const matcher = create(instrumentations, dcPolyfill)
33
+ const matcherCjs = create(instrumentations, dcPolyfillCjs)
34
+ const matcherEsm = create(instrumentations, dcPolyfillEsm)
24
35
 
25
- matcher.addTransform('traceIterator', traceIterator)
26
- matcher.addTransform('traceAsyncIterator', traceAsyncIterator)
36
+ for (const matcher of [matcherCjs, matcherEsm]) {
37
+ matcher.addTransform('traceIterator', traceIterator)
38
+ matcher.addTransform('traceAsyncIterator', traceAsyncIterator)
39
+ }
27
40
 
28
41
  function rewrite (content, filename, format) {
29
42
  if (!content) return content
@@ -41,6 +54,7 @@ function rewrite (content, filename, format) {
41
54
 
42
55
  if (disabled.has(moduleName)) return content
43
56
 
57
+ const matcher = moduleType === 'esm' ? matcherEsm : matcherCjs
44
58
  const transformer = matcher.getTransformer(moduleName, version, filePath)
45
59
 
46
60
  if (!transformer) return content
@@ -10,17 +10,25 @@ const tracingChannelPredicate = (node) => (
10
10
  )
11
11
 
12
12
  const transforms = module.exports = {
13
- tracingChannelImport ({ dcModule, sourceType }, node) {
13
+ /**
14
+ * @param {{ dcModule: string, moduleType: 'esm' | 'cjs' }} state
15
+ * @param {import('estree').Program} node
16
+ */
17
+ tracingChannelImport ({ dcModule, moduleType }, node) {
14
18
  if (node.body.some(tracingChannelPredicate)) return
15
19
 
20
+ // The vendored matcher state exposes `moduleType` (`esm` / `cjs`), so we
21
+ // read that field directly. Naming it `sourceType` here used to silently
22
+ // pick the CJS branch for every ESM file, leaving `require()` baked into
23
+ // pure ESM modules like `@langchain/langgraph/dist/pregel/index.js`.
24
+ const isModule = moduleType === 'esm'
25
+
16
26
  const index = node.body.findIndex(child => child.directive === 'use strict')
17
- const code = isModuleSourceType(sourceType)
18
- ? `import { tracingChannel as tr_ch_apm_tracingChannel } from "${dcModule}"`
27
+ const code = isModule
28
+ ? `import tr_ch_apm_dc from "${dcModule}"; const {tracingChannel: tr_ch_apm_tracingChannel} = tr_ch_apm_dc`
19
29
  : `const {tracingChannel: tr_ch_apm_tracingChannel} = require("${dcModule}")`
20
30
 
21
- node.body.splice(index + 1, 0, parse(code, {
22
- isModule: isModuleSourceType(sourceType),
23
- }).body[0])
31
+ node.body.splice(index + 1, 0, ...parse(code, { isModule }).body)
24
32
  },
25
33
 
26
34
  tracingChannelDeclaration (state, node) {
@@ -53,13 +61,6 @@ function traceAny (state, node, _parent, ancestry) {
53
61
  }
54
62
  }
55
63
 
56
- /**
57
- * @param {string} sourceType
58
- */
59
- function isModuleSourceType (sourceType) {
60
- return sourceType === 'module' || sourceType === 'esm'
61
- }
62
-
63
64
  function traceFunction (state, node, program) {
64
65
  transforms.tracingChannelDeclaration(state, program)
65
66
 
@@ -188,8 +188,8 @@ function patch (http, methodName) {
188
188
  let finished = false
189
189
  let callback = args.callback
190
190
 
191
- if (callback) {
192
- callback = shimmer.wrapFunction(args.callback, cb => function (...args) {
191
+ if (typeof callback === 'function') {
192
+ callback = shimmer.wrapCallback(args.callback, cb => function (...args) {
193
193
  return asyncStartChannel.runStores(ctx, () => {
194
194
  return cb.apply(this, args)
195
195
  })
@@ -10,28 +10,32 @@ const startCh = channel('apm:ioredis:command:start')
10
10
  const finishCh = channel('apm:ioredis:command:finish')
11
11
  const errorCh = channel('apm:ioredis:command:error')
12
12
 
13
+ const connectionOptionsCache = new WeakMap()
14
+
13
15
  function wrapRedis (Redis) {
14
16
  shimmer.wrap(Redis.prototype, 'sendCommand', sendCommand => function (command, stream) {
15
- if (!startCh.hasSubscribers) return sendCommand.apply(this, arguments)
17
+ if (!startCh.hasSubscribers) return sendCommand.call(this, command, stream)
16
18
 
17
- if (!command || !command.promise) return sendCommand.apply(this, arguments)
19
+ if (!command?.promise) return sendCommand.call(this, command, stream)
18
20
 
19
21
  const options = this.options || {}
20
- const connectionName = options.connectionName
21
- const db = options.db
22
- const connectionOptions = { host: options.host, port: options.port }
23
-
24
- const ctx = { db, command: command.name, args: command.args, connectionOptions, connectionName }
22
+ let connectionOptions = connectionOptionsCache.get(this)
23
+ if (connectionOptions === undefined) {
24
+ connectionOptions = { host: options.host, port: options.port }
25
+ connectionOptionsCache.set(this, connectionOptions)
26
+ }
27
+
28
+ const ctx = {
29
+ db: options.db,
30
+ command: command.name,
31
+ args: command.args,
32
+ connectionOptions,
33
+ connectionName: options.connectionName,
34
+ }
25
35
  return startCh.runStores(ctx, () => {
26
36
  command.promise.then(() => finish(finishCh, errorCh, ctx), err => finish(finishCh, errorCh, ctx, err))
27
37
 
28
- try {
29
- return sendCommand.apply(this, arguments)
30
- } catch (err) {
31
- errorCh.publish(err)
32
-
33
- throw err
34
- }
38
+ return sendCommand.call(this, command, stream)
35
39
  })
36
40
  })
37
41
  return Redis