dd-trace 5.56.0 → 5.57.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 (134) hide show
  1. package/index.d.ts +44 -2
  2. package/init.js +4 -1
  3. package/package.json +21 -21
  4. package/packages/datadog-esbuild/index.js +22 -0
  5. package/packages/datadog-instrumentations/src/cassandra-driver.js +43 -60
  6. package/packages/datadog-instrumentations/src/confluentinc-kafka-javascript.js +12 -12
  7. package/packages/datadog-instrumentations/src/cucumber.js +4 -6
  8. package/packages/datadog-instrumentations/src/elasticsearch.js +16 -19
  9. package/packages/datadog-instrumentations/src/fastify.js +91 -9
  10. package/packages/datadog-instrumentations/src/helpers/bundler-register.js +20 -5
  11. package/packages/datadog-instrumentations/src/helpers/check-require-cache.js +2 -2
  12. package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
  13. package/packages/datadog-instrumentations/src/helpers/register.js +17 -5
  14. package/packages/datadog-instrumentations/src/ioredis.js +8 -13
  15. package/packages/datadog-instrumentations/src/iovalkey.js +10 -14
  16. package/packages/datadog-instrumentations/src/jest.js +28 -6
  17. package/packages/datadog-instrumentations/src/memcached.js +17 -24
  18. package/packages/datadog-instrumentations/src/mocha/main.js +7 -6
  19. package/packages/datadog-instrumentations/src/moleculer/client.js +9 -10
  20. package/packages/datadog-instrumentations/src/moleculer/server.js +12 -13
  21. package/packages/datadog-instrumentations/src/openai.js +30 -2
  22. package/packages/datadog-instrumentations/src/playwright.js +4 -1
  23. package/packages/datadog-instrumentations/src/prisma.js +116 -0
  24. package/packages/datadog-instrumentations/src/redis.js +32 -43
  25. package/packages/datadog-instrumentations/src/router.js +1 -1
  26. package/packages/datadog-instrumentations/src/sharedb.js +10 -16
  27. package/packages/datadog-instrumentations/src/vitest.js +4 -4
  28. package/packages/datadog-plugin-aws-sdk/src/base.js +6 -1
  29. package/packages/datadog-plugin-aws-sdk/src/services/dynamodb.js +9 -4
  30. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +3 -2
  31. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +2 -1
  32. package/packages/datadog-plugin-aws-sdk/src/util.js +2 -2
  33. package/packages/datadog-plugin-bunyan/src/index.js +2 -2
  34. package/packages/datadog-plugin-cassandra-driver/src/index.js +6 -2
  35. package/packages/datadog-plugin-confluentinc-kafka-javascript/src/batch-consumer.js +1 -1
  36. package/packages/datadog-plugin-confluentinc-kafka-javascript/src/consumer.js +1 -1
  37. package/packages/datadog-plugin-confluentinc-kafka-javascript/src/index.js +1 -1
  38. package/packages/datadog-plugin-confluentinc-kafka-javascript/src/producer.js +1 -1
  39. package/packages/datadog-plugin-cucumber/src/index.js +4 -2
  40. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +9 -5
  41. package/packages/datadog-plugin-elasticsearch/src/index.js +12 -4
  42. package/packages/datadog-plugin-http/src/client.js +1 -0
  43. package/packages/datadog-plugin-http/src/server.js +2 -1
  44. package/packages/datadog-plugin-http2/src/client.js +1 -0
  45. package/packages/datadog-plugin-http2/src/server.js +1 -0
  46. package/packages/datadog-plugin-jest/src/index.js +4 -3
  47. package/packages/datadog-plugin-memcached/src/index.js +6 -2
  48. package/packages/datadog-plugin-mocha/src/index.js +3 -2
  49. package/packages/datadog-plugin-moleculer/src/client.js +15 -9
  50. package/packages/datadog-plugin-moleculer/src/server.js +9 -5
  51. package/packages/datadog-plugin-next/src/index.js +2 -1
  52. package/packages/datadog-plugin-openai/src/tracing.js +127 -80
  53. package/packages/datadog-plugin-pino/src/index.js +2 -2
  54. package/packages/datadog-plugin-prisma/src/client.js +62 -0
  55. package/packages/datadog-plugin-prisma/src/engine.js +81 -0
  56. package/packages/datadog-plugin-prisma/src/index.js +22 -0
  57. package/packages/datadog-plugin-protobufjs/src/schema_iterator.js +1 -1
  58. package/packages/datadog-plugin-redis/src/index.js +9 -3
  59. package/packages/datadog-plugin-router/src/index.js +1 -0
  60. package/packages/datadog-plugin-sharedb/src/index.js +13 -5
  61. package/packages/datadog-plugin-winston/src/index.js +2 -2
  62. package/packages/dd-trace/src/appsec/channels.js +26 -21
  63. package/packages/dd-trace/src/appsec/iast/analyzers/unvalidated-redirect-analyzer.js +13 -20
  64. package/packages/dd-trace/src/appsec/iast/taint-tracking/source-types.js +0 -1
  65. package/packages/dd-trace/src/appsec/index.js +16 -1
  66. package/packages/dd-trace/src/appsec/rasp/utils.js +0 -5
  67. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +3 -3
  68. package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +1 -1
  69. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +1 -1
  70. package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +1 -1
  71. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +2 -2
  72. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +6 -6
  73. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +2 -3
  74. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +3 -3
  75. package/packages/dd-trace/src/config.js +286 -270
  76. package/packages/dd-trace/src/constants.js +2 -1
  77. package/packages/dd-trace/src/crashtracking/crashtracker.js +12 -14
  78. package/packages/dd-trace/src/datastreams/context.js +1 -1
  79. package/packages/dd-trace/src/datastreams/processor.js +1 -1
  80. package/packages/dd-trace/src/datastreams/writer.js +3 -3
  81. package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +6 -3
  82. package/packages/dd-trace/src/debugger/devtools_client/condition.js +1 -1
  83. package/packages/dd-trace/src/debugger/devtools_client/index.js +2 -3
  84. package/packages/dd-trace/src/debugger/devtools_client/state.js +7 -4
  85. package/packages/dd-trace/src/dogstatsd.js +3 -3
  86. package/packages/dd-trace/src/exporters/agent/index.js +10 -5
  87. package/packages/dd-trace/src/exporters/agent/writer.js +1 -1
  88. package/packages/dd-trace/src/exporters/common/agent-info-exporter.js +2 -2
  89. package/packages/dd-trace/src/exporters/log/index.js +1 -1
  90. package/packages/dd-trace/src/exporters/span-stats/writer.js +2 -2
  91. package/packages/dd-trace/src/guardrails/index.js +3 -1
  92. package/packages/dd-trace/src/guardrails/telemetry.js +1 -1
  93. package/packages/dd-trace/src/llmobs/index.js +11 -5
  94. package/packages/dd-trace/src/llmobs/plugins/base.js +2 -2
  95. package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +1 -1
  96. package/packages/dd-trace/src/llmobs/tagger.js +13 -13
  97. package/packages/dd-trace/src/llmobs/writers/base.js +2 -2
  98. package/packages/dd-trace/src/llmobs/writers/spans.js +2 -2
  99. package/packages/dd-trace/src/opentelemetry/tracer.js +1 -1
  100. package/packages/dd-trace/src/opentracing/propagation/text_map.js +4 -4
  101. package/packages/dd-trace/src/opentracing/span.js +1 -0
  102. package/packages/dd-trace/src/plugin_manager.js +3 -3
  103. package/packages/dd-trace/src/plugins/cache.js +2 -2
  104. package/packages/dd-trace/src/plugins/ci_plugin.js +11 -7
  105. package/packages/dd-trace/src/plugins/database.js +3 -1
  106. package/packages/dd-trace/src/plugins/index.js +1 -0
  107. package/packages/dd-trace/src/plugins/log_plugin.js +5 -1
  108. package/packages/dd-trace/src/plugins/outbound.js +8 -6
  109. package/packages/dd-trace/src/plugins/structured_log_plugin.js +9 -0
  110. package/packages/dd-trace/src/plugins/tracing.js +1 -1
  111. package/packages/dd-trace/src/plugins/util/ci.js +83 -30
  112. package/packages/dd-trace/src/plugins/util/git.js +1 -0
  113. package/packages/dd-trace/src/plugins/util/inferred_proxy.js +3 -2
  114. package/packages/dd-trace/src/plugins/util/ip_extractor.js +1 -0
  115. package/packages/dd-trace/src/plugins/util/tags.js +4 -1
  116. package/packages/dd-trace/src/plugins/util/test.js +80 -10
  117. package/packages/dd-trace/src/plugins/util/web.js +1 -0
  118. package/packages/dd-trace/src/profiler.js +0 -2
  119. package/packages/dd-trace/src/profiling/exporter_cli.js +1 -3
  120. package/packages/dd-trace/src/profiling/ssi-heuristics.js +18 -126
  121. package/packages/dd-trace/src/proxy.js +12 -27
  122. package/packages/dd-trace/src/runtime_metrics/index.js +1 -1
  123. package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +14 -45
  124. package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +2 -2
  125. package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +4 -0
  126. package/packages/dd-trace/src/service-naming/schemas/v1/messaging.js +2 -2
  127. package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +4 -0
  128. package/packages/dd-trace/src/supported-configurations.json +12 -3
  129. package/packages/dd-trace/src/telemetry/telemetry.js +5 -1
  130. package/packages/dd-trace/src/tracer.js +11 -0
  131. package/packages/dd-trace/src/tracer_metadata.js +25 -0
  132. package/packages/dd-trace/src/util.js +11 -4
  133. package/version.js +3 -1
  134. package/packages/dd-trace/src/profiling/ssi-telemetry-mock-profiler.js +0 -30
@@ -6,8 +6,14 @@ const { addHook, channel, AsyncResource } = require('./helpers/instrument')
6
6
  const errorChannel = channel('apm:fastify:middleware:error')
7
7
  const handleChannel = channel('apm:fastify:request:handle')
8
8
  const routeAddedChannel = channel('apm:fastify:route:added')
9
+ const bodyParserReadCh = channel('datadog:fastify:body-parser:finish')
10
+ const queryParamsReadCh = channel('datadog:fastify:query-params:finish')
11
+ const cookieParserReadCh = channel('datadog:fastify-cookie:read:finish')
12
+ const responsePayloadReadCh = channel('datadog:fastify:response:finish')
13
+ const pathParamsReadCh = channel('datadog:fastify:path-params:finish')
9
14
 
10
15
  const parsingResources = new WeakMap()
16
+ const cookiesPublished = new WeakSet()
11
17
 
12
18
  function wrapFastify (fastify, hasParsingEvents) {
13
19
  if (typeof fastify !== 'function') return fastify
@@ -45,26 +51,46 @@ function wrapAddHook (addHook) {
45
51
  const req = getReq(request)
46
52
 
47
53
  try {
48
- if (typeof done === 'function') {
49
- done = arguments[arguments.length - 1]
54
+ // done callback is always the last argument
55
+ const doneCallback = arguments[arguments.length - 1]
50
56
 
57
+ if (typeof doneCallback === 'function') {
51
58
  arguments[arguments.length - 1] = function (err) {
52
59
  publishError(err, req)
53
60
 
61
+ const hasCookies = request.cookies && Object.keys(request.cookies).length > 0
62
+
63
+ if (cookieParserReadCh.hasSubscribers && hasCookies && !cookiesPublished.has(req)) {
64
+ const res = getRes(reply)
65
+ const abortController = new AbortController()
66
+
67
+ cookieParserReadCh.publish({
68
+ req,
69
+ res,
70
+ abortController,
71
+ cookies: request.cookies
72
+ })
73
+
74
+ cookiesPublished.add(req)
75
+
76
+ if (abortController.signal.aborted) return
77
+ }
78
+
54
79
  if (name === 'onRequest' || name === 'preParsing') {
55
80
  const parsingResource = new AsyncResource('bound-anonymous-fn')
56
81
 
57
82
  parsingResources.set(req, parsingResource)
58
83
 
59
84
  return parsingResource.runInAsyncScope(() => {
60
- return done.apply(this, arguments)
85
+ return doneCallback.apply(this, arguments)
61
86
  })
62
87
  }
63
- return done.apply(this, arguments)
88
+ return doneCallback.apply(this, arguments)
64
89
  }
65
90
 
66
91
  return fn.apply(this, arguments)
67
92
  }
93
+
68
94
  const promise = fn.apply(this, arguments)
69
95
 
70
96
  if (promise && typeof promise.catch === 'function') {
@@ -106,11 +132,52 @@ function preHandler (request, reply, done) {
106
132
 
107
133
  function preValidation (request, reply, done) {
108
134
  const req = getReq(request)
135
+ const res = getRes(reply)
109
136
  const parsingResource = parsingResources.get(req)
110
137
 
111
- if (!parsingResource) return done()
138
+ const processInContext = () => {
139
+ let abortController
112
140
 
113
- parsingResource.runInAsyncScope(() => done())
141
+ if (queryParamsReadCh.hasSubscribers && request.query) {
142
+ abortController ??= new AbortController()
143
+
144
+ queryParamsReadCh.publish({
145
+ req,
146
+ res,
147
+ abortController,
148
+ query: request.query
149
+ })
150
+
151
+ if (abortController.signal.aborted) return
152
+ }
153
+
154
+ if (bodyParserReadCh.hasSubscribers && request.body) {
155
+ abortController ??= new AbortController()
156
+
157
+ bodyParserReadCh.publish({ req, res, body: request.body, abortController })
158
+
159
+ if (abortController.signal.aborted) return
160
+ }
161
+
162
+ if (pathParamsReadCh.hasSubscribers && request.params) {
163
+ abortController ??= new AbortController()
164
+
165
+ pathParamsReadCh.publish({
166
+ req,
167
+ res,
168
+ abortController,
169
+ params: request.params
170
+ })
171
+
172
+ if (abortController.signal.aborted) return
173
+ }
174
+
175
+ done()
176
+ }
177
+
178
+ if (!parsingResource) return processInContext()
179
+
180
+ parsingResource.runInAsyncScope(processInContext)
114
181
  }
115
182
 
116
183
  function preParsing (request, reply, payload, done) {
@@ -126,9 +193,12 @@ function preParsing (request, reply, payload, done) {
126
193
  }
127
194
 
128
195
  function wrapSend (send, req) {
129
- return function sendWithTrace (error) {
130
- if (error instanceof Error) {
131
- errorChannel.publish({ req, error })
196
+ return function sendWithTrace (payload) {
197
+ if (payload instanceof Error) {
198
+ errorChannel.publish({ req, error: payload })
199
+ } else if (canPublishResponsePayload(payload)) {
200
+ const res = getRes(this)
201
+ responsePayloadReadCh.publish({ req, res, body: payload })
132
202
  }
133
203
 
134
204
  return send.apply(this, arguments)
@@ -159,6 +229,18 @@ function onRoute (routeOptions) {
159
229
  routeAddedChannel.publish({ routeOptions, onRoute })
160
230
  }
161
231
 
232
+ // send() payload types: https://fastify.dev/docs/latest/Reference/Reply/#senddata
233
+ function canPublishResponsePayload (payload) {
234
+ return responsePayloadReadCh.hasSubscribers &&
235
+ payload &&
236
+ typeof payload === 'object' &&
237
+ typeof payload.pipe !== 'function' && // Node streams
238
+ typeof payload.body?.pipe !== 'function' && // Response with body stream
239
+ !Buffer.isBuffer(payload) && // Buffer
240
+ !(payload instanceof ArrayBuffer) && // ArrayBuffer
241
+ !ArrayBuffer.isView(payload) // TypedArray
242
+ }
243
+
162
244
  addHook({ name: 'fastify', versions: ['>=3'] }, fastify => {
163
245
  const wrapped = shimmer.wrapFunction(fastify, fastify => wrapFastify(fastify, true))
164
246
 
@@ -26,14 +26,29 @@ if (!dc.unsubscribe) {
26
26
  }
27
27
  }
28
28
 
29
- dc.subscribe(CHANNEL, (payload) => {
30
- try {
31
- hooks[payload.package]()
32
- } catch (err) {
29
+ function doHook (payload) {
30
+ const hook = hooks[payload.package]
31
+ if (!hook) {
33
32
  log.error('esbuild-wrapped %s missing in list of hooks', payload.package)
34
- throw err
33
+ return
34
+ }
35
+
36
+ const hookFn = hook.fn ?? hook
37
+ if (typeof hookFn !== 'function') {
38
+ log.error('esbuild-wrapped hook %s is not a function', payload.package)
39
+ return
35
40
  }
36
41
 
42
+ try {
43
+ hookFn()
44
+ } catch {
45
+ log.error('esbuild-wrapped %s hook failed', payload.package)
46
+ }
47
+ }
48
+
49
+ dc.subscribe(CHANNEL, (payload) => {
50
+ doHook(payload)
51
+
37
52
  if (!instrumentations[payload.package]) {
38
53
  log.error('esbuild-wrapped %s missing in list of instrumentations', payload.package)
39
54
  return
@@ -55,7 +55,7 @@ module.exports.checkForRequiredModules = function () {
55
55
  if (naughties.has(pkg)) continue
56
56
  if (!(pkg in packages)) continue
57
57
 
58
- warnings.push(`Warning: Package '${pkg}' was loaded before dd-trace! This may break instrumentation.`)
58
+ warnings.push(() => `Warning: Package '${pkg}' was loaded before dd-trace! This may break instrumentation.`)
59
59
 
60
60
  naughties.add(pkg)
61
61
  didWarn = true
@@ -87,7 +87,7 @@ module.exports.checkForPotentialConflicts = function () {
87
87
  if (naughties.has(pkg)) continue
88
88
  if (!potentialConflicts.has(pkg)) continue
89
89
 
90
- warnings.push(`Warning: Package '${pkg}' may cause conflicts with dd-trace.`)
90
+ warnings.push(() => `Warning: Package '${pkg}' may cause conflicts with dd-trace.`)
91
91
 
92
92
  naughties.add(pkg)
93
93
  didWarn = true
@@ -24,6 +24,7 @@ module.exports = {
24
24
  '@node-redis/client': () => require('../redis'),
25
25
  '@opensearch-project/opensearch': () => require('../opensearch'),
26
26
  '@opentelemetry/sdk-trace-node': () => require('../otel-sdk-trace'),
27
+ '@prisma/client': () => require('../prisma'),
27
28
  '@redis/client': () => require('../redis'),
28
29
  '@smithy/smithy-client': () => require('../aws-sdk'),
29
30
  '@vitest/runner': { esmFirst: true, fn: () => require('../vitest') },
@@ -9,6 +9,7 @@ const log = require('../../../dd-trace/src/log')
9
9
  const checkRequireCache = require('./check-require-cache')
10
10
  const telemetry = require('../../../dd-trace/src/guardrails/telemetry')
11
11
  const { isInServerlessEnvironment } = require('../../../dd-trace/src/serverless')
12
+ const { isFalse, isTrue, normalizePluginEnvName } = require('../../../dd-trace/src/util')
12
13
  const { getEnvironmentVariables } = require('../../../dd-trace/src/config-helper')
13
14
 
14
15
  const envs = getEnvironmentVariables()
@@ -22,16 +23,22 @@ const hooks = require('./hooks')
22
23
  const instrumentations = require('./instrumentations')
23
24
  const names = Object.keys(hooks)
24
25
  const pathSepExpr = new RegExp(`\\${path.sep}`, 'g')
26
+
25
27
  const disabledInstrumentations = new Set(
26
- DD_TRACE_DISABLED_INSTRUMENTATIONS ? DD_TRACE_DISABLED_INSTRUMENTATIONS.split(',') : []
28
+ DD_TRACE_DISABLED_INSTRUMENTATIONS?.split(',').map(name => normalizePluginEnvName(name, true)) ?? []
27
29
  )
30
+ const reenabledInstrumentations = new Set()
28
31
 
29
32
  // Check for DD_TRACE_<INTEGRATION>_ENABLED environment variables
30
33
  for (const [key, value] of Object.entries(envs)) {
31
34
  const match = key.match(/^DD_TRACE_(.+)_ENABLED$/)
32
- if (match && (value?.toLowerCase() === 'false' || value === '0')) {
33
- const integration = match[1].toLowerCase()
34
- disabledInstrumentations.add(integration)
35
+ if (match && value) {
36
+ const integration = normalizePluginEnvName(match[1], true)
37
+ if (isFalse(value)) {
38
+ disabledInstrumentations.add(integration)
39
+ } else if (isTrue(value)) {
40
+ reenabledInstrumentations.add(integration)
41
+ }
35
42
  }
36
43
  }
37
44
 
@@ -58,7 +65,8 @@ const allInstrumentations = {}
58
65
 
59
66
  // TODO: make this more efficient
60
67
  for (const packageName of names) {
61
- if (disabledInstrumentations.has(packageName)) continue
68
+ const normalizedPackageName = normalizePluginEnvName(packageName, true)
69
+ if (disabledInstrumentations.has(normalizedPackageName)) continue
62
70
 
63
71
  const hookOptions = {}
64
72
 
@@ -67,6 +75,10 @@ for (const packageName of names) {
67
75
  if (typeof hook === 'object') {
68
76
  if (hook.serverless === false && isInServerlessEnvironment()) continue
69
77
 
78
+ // some integrations are disabled by default, but can be enabled by setting
79
+ // the DD_TRACE_<INTEGRATION>_ENABLED environment variable to true
80
+ if (hook.disabled && !reenabledInstrumentations.has(normalizedPackageName)) continue
81
+
70
82
  hookOptions.internals = hook.esmFirst
71
83
  hook = hook.fn
72
84
  }
@@ -2,8 +2,7 @@
2
2
 
3
3
  const {
4
4
  channel,
5
- addHook,
6
- AsyncResource
5
+ addHook
7
6
  } = require('./helpers/instrument')
8
7
  const shimmer = require('../../datadog-shimmer')
9
8
 
@@ -22,14 +21,9 @@ addHook({ name: 'ioredis', versions: ['>=2'] }, Redis => {
22
21
  const db = options.db
23
22
  const connectionOptions = { host: options.host, port: options.port }
24
23
 
25
- const asyncResource = new AsyncResource('bound-anonymous-fn')
26
- return asyncResource.runInAsyncScope(() => {
27
- startCh.publish({ db, command: command.name, args: command.args, connectionOptions, connectionName })
28
-
29
- const onResolve = asyncResource.bind(() => finish(finishCh, errorCh))
30
- const onReject = asyncResource.bind(err => finish(finishCh, errorCh, err))
31
-
32
- command.promise.then(onResolve, onReject)
24
+ const ctx = { db, command: command.name, args: command.args, connectionOptions, connectionName }
25
+ return startCh.runStores(ctx, () => {
26
+ command.promise.then(() => finish(finishCh, errorCh, ctx), err => finish(finishCh, errorCh, ctx, err))
33
27
 
34
28
  try {
35
29
  return sendCommand.apply(this, arguments)
@@ -43,9 +37,10 @@ addHook({ name: 'ioredis', versions: ['>=2'] }, Redis => {
43
37
  return Redis
44
38
  })
45
39
 
46
- function finish (finishCh, errorCh, error) {
40
+ function finish (finishCh, errorCh, ctx, error) {
47
41
  if (error) {
48
- errorCh.publish(error)
42
+ ctx.error = error
43
+ errorCh.publish(ctx)
49
44
  }
50
- finishCh.publish()
45
+ finishCh.publish(ctx)
51
46
  }
@@ -2,8 +2,7 @@
2
2
 
3
3
  const {
4
4
  channel,
5
- addHook,
6
- AsyncResource
5
+ addHook
7
6
  } = require('./helpers/instrument')
8
7
  const shimmer = require('../../datadog-shimmer')
9
8
 
@@ -22,19 +21,15 @@ addHook({ name: 'iovalkey', versions: ['>=0.0.1'] }, Valkey => {
22
21
  const db = options.db
23
22
  const connectionOptions = { host: options.host, port: options.port }
24
23
 
25
- const asyncResource = new AsyncResource('bound-anonymous-fn')
26
- return asyncResource.runInAsyncScope(() => {
27
- startCh.publish({ db, command: command.name, args: command.args, connectionOptions, connectionName })
28
-
29
- const onResolve = asyncResource.bind(() => finishCh.publish())
30
- const onReject = asyncResource.bind(err => finish(finishCh, errorCh, err))
31
-
32
- command.promise.then(onResolve, onReject)
24
+ const ctx = { db, command: command.name, args: command.args, connectionOptions, connectionName }
25
+ return startCh.runStores(ctx, () => {
26
+ command.promise.then(() => finish(finishCh, errorCh, ctx), err => finish(finishCh, errorCh, ctx, err))
33
27
 
34
28
  try {
35
29
  return sendCommand.apply(this, arguments)
36
30
  } catch (err) {
37
- errorCh.publish(err)
31
+ ctx.error = err
32
+ errorCh.publish(ctx)
38
33
 
39
34
  throw err
40
35
  }
@@ -43,9 +38,10 @@ addHook({ name: 'iovalkey', versions: ['>=0.0.1'] }, Valkey => {
43
38
  return Valkey
44
39
  })
45
40
 
46
- function finish (finishCh, errorCh, error) {
41
+ function finish (finishCh, errorCh, ctx, error) {
47
42
  if (error) {
48
- errorCh.publish(error)
43
+ ctx.error = error
44
+ errorCh.publish(ctx)
49
45
  }
50
- finishCh.publish()
46
+ finishCh.publish(ctx)
51
47
  }
@@ -3,6 +3,7 @@
3
3
  const { addHook, channel } = require('./helpers/instrument')
4
4
  const shimmer = require('../../datadog-shimmer')
5
5
  const log = require('../../dd-trace/src/log')
6
+ const path = require('path')
6
7
  const {
7
8
  getCoveredFilenamesFromCoverage,
8
9
  JEST_WORKER_TRACE_PAYLOAD_CODE,
@@ -90,6 +91,7 @@ const retriedTestsToNumAttempts = new Map()
90
91
  const newTestsTestStatuses = new Map()
91
92
  const attemptToFixRetriedTestsStatuses = new Map()
92
93
  const wrappedWorkers = new WeakSet()
94
+ const testSuiteMockedFiles = new Map()
93
95
 
94
96
  const BREAKPOINT_HIT_GRACE_PERIOD_MS = 200
95
97
 
@@ -137,6 +139,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
137
139
  this.nameToParams = {}
138
140
  this.global._ddtrace = global._ddtrace
139
141
  this.hasSnapshotTests = undefined
142
+ this.testSuiteAbsolutePath = context.testPath
140
143
 
141
144
  this.displayName = config.projectConfig?.displayName?.name
142
145
  this.testEnvironmentOptions = getTestEnvironmentOptions(config)
@@ -291,7 +294,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
291
294
  // We'll still detect new tests, but we won't retry them.
292
295
  // TODO: do not bail out of retrying tests for the whole test suite
293
296
  if (this.getHasSnapshotTests()) {
294
- log.warn(`${retryType} is disabled for suites with snapshots`)
297
+ log.warn('%s is disabled for suites with snapshots', retryType)
295
298
  return
296
299
  }
297
300
 
@@ -299,7 +302,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
299
302
  if (this.global.test) {
300
303
  this.global.test(addRetryStringToTestName(testName, retryIndex), event.fn, event.timeout)
301
304
  } else {
302
- log.error(`${retryType} could not retry test because global.test is undefined`)
305
+ log.error('%s could not retry test because global.test is undefined', retryType)
303
306
  }
304
307
  }
305
308
  }
@@ -726,7 +729,7 @@ function getCliWrapper (isNewJestVersion) {
726
729
  return runCLI.apply(this, arguments)
727
730
  }
728
731
 
729
- libraryConfigurationCh.publish({ onDone })
732
+ libraryConfigurationCh.publish({ onDone, frameworkVersion: jestVersion })
730
733
 
731
734
  try {
732
735
  const { err, libraryConfig } = await configurationPromise
@@ -1095,10 +1098,12 @@ function jestAdapterWrapper (jestAdapter, jestVersion) {
1095
1098
  if (environment.testEnvironmentOptions?._ddTestCodeCoverageEnabled) {
1096
1099
  const root = environment.repositoryRoot || environment.rootDir
1097
1100
 
1098
- const coverageFiles = getCoveredFilenamesFromCoverage(environment.global.__coverage__)
1099
- .map(filename => getTestSuitePath(filename, root))
1101
+ const getFilesWithPath = (files) => files.map(file => getTestSuitePath(file, root))
1100
1102
 
1101
- testSuiteCodeCoverageCh.publish({ coverageFiles, testSuite: environment.testSourceFile })
1103
+ const coverageFiles = getFilesWithPath(getCoveredFilenamesFromCoverage(environment.global.__coverage__))
1104
+ const mockedFiles = getFilesWithPath(testSuiteMockedFiles.get(environment.testSuiteAbsolutePath) || [])
1105
+
1106
+ testSuiteCodeCoverageCh.publish({ coverageFiles, testSuite: environment.testSourceFile, mockedFiles })
1102
1107
  }
1103
1108
  testSuiteFinishCh.publish({ status, errorMessage })
1104
1109
  return suiteResults
@@ -1267,6 +1272,23 @@ addHook({
1267
1272
  }, (runtimePackage) => {
1268
1273
  const Runtime = runtimePackage.default ?? runtimePackage
1269
1274
 
1275
+ shimmer.wrap(Runtime.prototype, '_createJestObjectFor', _createJestObjectFor => function (from) {
1276
+ const result = _createJestObjectFor.apply(this, arguments)
1277
+ const suiteFilePath = this._testPath
1278
+
1279
+ shimmer.wrap(result, 'mock', mock => function (moduleName) {
1280
+ if (suiteFilePath) {
1281
+ const existingMockedFiles = testSuiteMockedFiles.get(suiteFilePath) || []
1282
+ const suiteDir = path.dirname(suiteFilePath)
1283
+ const mockPath = path.resolve(suiteDir, moduleName)
1284
+ existingMockedFiles.push(mockPath)
1285
+ testSuiteMockedFiles.set(suiteFilePath, existingMockedFiles)
1286
+ }
1287
+ return mock.apply(this, arguments)
1288
+ })
1289
+ return result
1290
+ })
1291
+
1270
1292
  shimmer.wrap(Runtime.prototype, 'requireModuleOrMock', requireModuleOrMock => function (from, moduleName) {
1271
1293
  // TODO: do this for every library that we instrument
1272
1294
  if (shouldBypassJestRequireEngine(moduleName)) {
@@ -2,8 +2,7 @@
2
2
 
3
3
  const {
4
4
  channel,
5
- addHook,
6
- AsyncResource
5
+ addHook
7
6
  } = require('./helpers/instrument')
8
7
  const shimmer = require('../../datadog-shimmer')
9
8
 
@@ -17,35 +16,29 @@ addHook({ name: 'memcached', versions: ['>=2.2'] }, Memcached => {
17
16
  return command.apply(this, arguments)
18
17
  }
19
18
 
20
- const callbackResource = new AsyncResource('bound-anonymous-fn')
21
- const asyncResource = new AsyncResource('bound-anonymous-fn')
22
-
23
19
  const client = this
24
20
 
25
- const wrappedQueryCompiler = asyncResource.bind(function () {
21
+ const wrappedQueryCompiler = function () {
26
22
  const query = queryCompiler.apply(this, arguments)
27
- const callback = callbackResource.bind(query.callback)
28
-
29
- query.callback = shimmer.wrapFunction(callback, callback => asyncResource.bind(function (err) {
30
- if (err) {
31
- errorCh.publish(err)
32
- }
33
- finishCh.publish()
34
-
35
- return callback.apply(this, arguments)
36
- }))
37
- startCh.publish({ client, server, query })
38
23
 
24
+ const ctx = { client, server, query }
25
+ startCh.runStores(ctx, () => {
26
+ query.callback = shimmer.wrapFunction(query.callback, callback => function (err) {
27
+ if (err) {
28
+ ctx.error = err
29
+ errorCh.publish(ctx)
30
+ }
31
+ finishCh.publish(ctx)
32
+
33
+ return finishCh.runStores(ctx, callback, this, ...arguments)
34
+ })
35
+ })
39
36
  return query
40
- })
41
-
42
- return asyncResource.runInAsyncScope(() => {
43
- arguments[0] = wrappedQueryCompiler
37
+ }
44
38
 
45
- const result = command.apply(this, arguments)
39
+ arguments[0] = wrappedQueryCompiler
46
40
 
47
- return result
48
- })
41
+ return command.apply(this, arguments)
49
42
  })
50
43
 
51
44
  return Memcached
@@ -201,9 +201,10 @@ function getOnEndHandler (isParallel) {
201
201
  }
202
202
  }
203
203
 
204
- function getExecutionConfiguration (runner, isParallel, onFinishRequest) {
204
+ function getExecutionConfiguration (runner, isParallel, frameworkVersion, onFinishRequest) {
205
205
  const ctx = {
206
- isParallel
206
+ isParallel,
207
+ frameworkVersion
207
208
  }
208
209
 
209
210
  const onReceivedSkippableSuites = ({ err, skippableSuites, itrCorrelationId: responseItrCorrelationId }) => {
@@ -343,7 +344,7 @@ addHook({
343
344
  name: 'mocha',
344
345
  versions: ['>=5.2.0'],
345
346
  file: 'lib/mocha.js'
346
- }, (Mocha) => {
347
+ }, (Mocha, frameworkVersion) => {
347
348
  shimmer.wrap(Mocha.prototype, 'run', run => function () {
348
349
  // Workers do not need to request any data, just run the tests
349
350
  if (!testFinishCh.hasSubscribers || getEnvironmentVariable('MOCHA_WORKER_ID') || this.options.parallel) {
@@ -363,7 +364,7 @@ addHook({
363
364
  }
364
365
  })
365
366
 
366
- getExecutionConfiguration(runner, false, () => {
367
+ getExecutionConfiguration(runner, false, frameworkVersion, () => {
367
368
  if (config.isKnownTestsEnabled) {
368
369
  const testSuites = this.files.map(file => getTestSuitePath(file, process.cwd()))
369
370
  const isFaulty = getIsFaultyEarlyFlakeDetection(
@@ -521,7 +522,7 @@ addHook({
521
522
  if (ctx) {
522
523
  testSuiteFinishCh.publish({ status, ...ctx.currentStore }, () => {})
523
524
  } else {
524
- log.warn(() => `No ctx found for suite ${suite.file}`)
525
+ log.warn('No ctx found for suite', suite.file)
525
526
  }
526
527
  })
527
528
 
@@ -616,7 +617,7 @@ addHook({
616
617
  this.once('start', getOnStartHandler(true, frameworkVersion))
617
618
  this.once('end', getOnEndHandler(true))
618
619
 
619
- getExecutionConfiguration(this, true, () => {
620
+ getExecutionConfiguration(this, true, frameworkVersion, () => {
620
621
  if (config.isKnownTestsEnabled) {
621
622
  const testSuites = files.map(file => getTestSuitePath(file, process.cwd()))
622
623
  const isFaulty = getIsFaultyEarlyFlakeDetection(
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const { channel, addHook, AsyncResource } = require('../helpers/instrument')
3
+ const { channel, addHook } = require('../helpers/instrument')
4
4
  const shimmer = require('../../../datadog-shimmer')
5
5
 
6
6
  const startChannel = channel('apm:moleculer:call:start')
@@ -9,29 +9,28 @@ const errorChannel = channel('apm:moleculer:call:error')
9
9
 
10
10
  function wrapCall (call) {
11
11
  return function (actionName, params, opts) {
12
- const callResource = new AsyncResource('bound-anonymous-fn')
13
-
14
12
  opts = arguments[2] = opts || {}
15
13
  opts.meta = opts.meta || {}
16
14
 
17
15
  arguments.length = Math.max(3, arguments.length)
18
16
 
19
- return callResource.runInAsyncScope(() => {
20
- startChannel.publish({ actionName, params, opts })
21
-
17
+ const ctx = { actionName, params, opts }
18
+ return startChannel.runStores(ctx, () => {
22
19
  const promise = call.apply(this, arguments)
23
20
  const broker = this
24
- const ctx = promise.ctx
21
+ ctx.promiseCtx = promise.ctx
22
+ ctx.broker = broker
25
23
 
26
24
  return promise
27
25
  .then(
28
26
  result => {
29
- finishChannel.publish({ broker, ctx })
27
+ finishChannel.publish(ctx)
30
28
  return result
31
29
  },
32
30
  error => {
33
- errorChannel.publish(error)
34
- finishChannel.publish({ broker, ctx })
31
+ ctx.error = error
32
+ errorChannel.publish(ctx)
33
+ finishChannel.publish(ctx)
35
34
  throw error
36
35
  }
37
36
  )
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const { channel, addHook, AsyncResource } = require('../helpers/instrument')
3
+ const { channel, addHook } = require('../helpers/instrument')
4
4
  const shimmer = require('../../../datadog-shimmer')
5
5
 
6
6
  const startChannel = channel('apm:moleculer:action:start')
@@ -24,27 +24,26 @@ function createMiddleware () {
24
24
  localAction (next, action) {
25
25
  const broker = this
26
26
 
27
- return shimmer.wrapFunction(next, next => function datadogMiddleware (ctx) {
28
- const actionResource = new AsyncResource('bound-anonymous-fn')
29
-
30
- return actionResource.runInAsyncScope(() => {
31
- startChannel.publish({ action, ctx, broker })
32
-
27
+ return shimmer.wrapFunction(next, next => function datadogMiddleware (middlewareCtx) {
28
+ const ctx = { action, middlewareCtx, broker }
29
+ return startChannel.runStores(ctx, () => {
33
30
  try {
34
- return next(ctx).then(
31
+ return next(middlewareCtx).then(
35
32
  result => {
36
- finishChannel.publish()
33
+ finishChannel.publish(ctx)
37
34
  return result
38
35
  },
39
36
  error => {
40
- errorChannel.publish(error)
41
- finishChannel.publish()
37
+ ctx.error = error
38
+ errorChannel.publish(ctx)
39
+ finishChannel.publish(ctx)
42
40
  throw error
43
41
  }
44
42
  )
45
43
  } catch (e) {
46
- errorChannel.publish(e)
47
- finishChannel.publish()
44
+ ctx.error = e
45
+ errorChannel.publish(ctx)
46
+ finishChannel.publish(ctx)
48
47
  }
49
48
  })
50
49
  })