dd-trace 5.96.0 → 5.97.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 (114) hide show
  1. package/index.d.ts +34 -0
  2. package/package.json +9 -7
  3. package/packages/datadog-esbuild/index.js +20 -9
  4. package/packages/datadog-instrumentations/src/child_process.js +7 -17
  5. package/packages/datadog-instrumentations/src/crypto.js +1 -2
  6. package/packages/datadog-instrumentations/src/cucumber.js +4 -1
  7. package/packages/datadog-instrumentations/src/cypress-config.js +324 -0
  8. package/packages/datadog-instrumentations/src/cypress.js +86 -4
  9. package/packages/datadog-instrumentations/src/dns.js +1 -2
  10. package/packages/datadog-instrumentations/src/express.js +4 -4
  11. package/packages/datadog-instrumentations/src/fs.js +27 -29
  12. package/packages/datadog-instrumentations/src/graphql.js +1 -1
  13. package/packages/datadog-instrumentations/src/helpers/bundler-register.js +41 -13
  14. package/packages/datadog-instrumentations/src/helpers/hook.js +31 -6
  15. package/packages/datadog-instrumentations/src/helpers/hooks.js +12 -19
  16. package/packages/datadog-instrumentations/src/helpers/instrument.js +27 -13
  17. package/packages/datadog-instrumentations/src/helpers/register.js +103 -142
  18. package/packages/datadog-instrumentations/src/http/client.js +2 -3
  19. package/packages/datadog-instrumentations/src/http/server.js +2 -5
  20. package/packages/datadog-instrumentations/src/http2/client.js +1 -3
  21. package/packages/datadog-instrumentations/src/http2/server.js +1 -3
  22. package/packages/datadog-instrumentations/src/jest.js +13 -4
  23. package/packages/datadog-instrumentations/src/limitd-client.js +1 -1
  24. package/packages/datadog-instrumentations/src/mocha/utils.js +4 -1
  25. package/packages/datadog-instrumentations/src/net.js +2 -8
  26. package/packages/datadog-instrumentations/src/pino.js +1 -1
  27. package/packages/datadog-instrumentations/src/playwright.js +4 -1
  28. package/packages/datadog-instrumentations/src/prisma.js +1 -2
  29. package/packages/datadog-instrumentations/src/selenium.js +4 -1
  30. package/packages/datadog-instrumentations/src/sequelize.js +1 -1
  31. package/packages/datadog-instrumentations/src/url.js +1 -3
  32. package/packages/datadog-instrumentations/src/vitest.js +5 -1
  33. package/packages/datadog-instrumentations/src/vm.js +1 -3
  34. package/packages/datadog-plugin-aws-sdk/src/base.js +4 -3
  35. package/packages/datadog-plugin-cucumber/src/index.js +7 -3
  36. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +57 -5
  37. package/packages/datadog-plugin-graphql/src/resolve.js +1 -1
  38. package/packages/datadog-plugin-jest/src/index.js +4 -2
  39. package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +31 -4
  40. package/packages/datadog-plugin-mocha/src/index.js +5 -2
  41. package/packages/datadog-plugin-next/src/index.js +2 -14
  42. package/packages/datadog-plugin-openai/src/services.js +1 -0
  43. package/packages/datadog-webpack/index.js +3 -3
  44. package/packages/dd-trace/index.js +12 -10
  45. package/packages/dd-trace/src/agent/url.js +2 -2
  46. package/packages/dd-trace/src/aiguard/sdk.js +4 -0
  47. package/packages/dd-trace/src/appsec/blocking.js +3 -0
  48. package/packages/dd-trace/src/appsec/iast/iast-plugin.js +1 -1
  49. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +1 -1
  50. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +1 -1
  51. package/packages/dd-trace/src/appsec/remote_config.js +1 -0
  52. package/packages/dd-trace/src/appsec/sdk/index.js +4 -0
  53. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +6 -1
  54. package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +4 -0
  55. package/packages/dd-trace/src/config/defaults.js +316 -146
  56. package/packages/dd-trace/src/config/generated-config-types.d.ts +4 -1
  57. package/packages/dd-trace/src/config/helper.js +59 -10
  58. package/packages/dd-trace/src/config/index.js +569 -1505
  59. package/packages/dd-trace/src/config/parsers.js +256 -0
  60. package/packages/dd-trace/src/config/remote_config.js +59 -2
  61. package/packages/dd-trace/src/config/supported-configurations.json +350 -433
  62. package/packages/dd-trace/src/crashtracking/crashtracker.js +7 -1
  63. package/packages/dd-trace/src/crashtracking/index.js +1 -7
  64. package/packages/dd-trace/src/debugger/index.js +1 -1
  65. package/packages/dd-trace/src/dogstatsd.js +12 -9
  66. package/packages/dd-trace/src/encode/0.4.js +1 -1
  67. package/packages/dd-trace/src/exporters/agent/writer.js +7 -1
  68. package/packages/dd-trace/src/exporters/common/request.js +9 -0
  69. package/packages/dd-trace/src/exporters/common/writer.js +12 -2
  70. package/packages/dd-trace/src/heap_snapshots.js +3 -0
  71. package/packages/dd-trace/src/index.js +5 -2
  72. package/packages/dd-trace/src/lambda/runtime/ritm.js +6 -6
  73. package/packages/dd-trace/src/llmobs/index.js +4 -1
  74. package/packages/dd-trace/src/llmobs/plugins/ai/index.js +5 -1
  75. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +60 -12
  76. package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +4 -2
  77. package/packages/dd-trace/src/llmobs/sdk.js +12 -8
  78. package/packages/dd-trace/src/llmobs/span_processor.js +1 -1
  79. package/packages/dd-trace/src/llmobs/tagger.js +9 -6
  80. package/packages/dd-trace/src/llmobs/writers/base.js +2 -0
  81. package/packages/dd-trace/src/llmobs/writers/util.js +3 -0
  82. package/packages/dd-trace/src/log/index.js +26 -55
  83. package/packages/dd-trace/src/log/writer.js +7 -19
  84. package/packages/dd-trace/src/noop/proxy.js +8 -0
  85. package/packages/dd-trace/src/opentelemetry/logs/index.js +1 -1
  86. package/packages/dd-trace/src/opentelemetry/metrics/index.js +1 -1
  87. package/packages/dd-trace/src/opentracing/propagation/text_map.js +9 -4
  88. package/packages/dd-trace/src/payload-tagging/config/index.js +6 -5
  89. package/packages/dd-trace/src/plugin_manager.js +8 -6
  90. package/packages/dd-trace/src/plugins/ci_plugin.js +4 -0
  91. package/packages/dd-trace/src/plugins/plugin.js +7 -4
  92. package/packages/dd-trace/src/process-tags/index.js +3 -0
  93. package/packages/dd-trace/src/profiler.js +27 -2
  94. package/packages/dd-trace/src/profiling/config.js +73 -241
  95. package/packages/dd-trace/src/profiling/exporter_cli.js +1 -4
  96. package/packages/dd-trace/src/profiling/exporters/event_serializer.js +6 -2
  97. package/packages/dd-trace/src/profiling/profiler.js +56 -44
  98. package/packages/dd-trace/src/profiling/profilers/events.js +2 -3
  99. package/packages/dd-trace/src/profiling/profilers/wall.js +89 -6
  100. package/packages/dd-trace/src/profiling/ssi-heuristics.js +4 -1
  101. package/packages/dd-trace/src/propagation-hash/index.js +2 -1
  102. package/packages/dd-trace/src/proxy.js +32 -3
  103. package/packages/dd-trace/src/remote_config/index.js +3 -0
  104. package/packages/dd-trace/src/require-package-json.js +8 -4
  105. package/packages/dd-trace/src/ritm.js +58 -26
  106. package/packages/dd-trace/src/runtime_metrics/index.js +3 -0
  107. package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +3 -0
  108. package/packages/dd-trace/src/sampler.js +1 -1
  109. package/packages/dd-trace/src/standalone/index.js +3 -0
  110. package/packages/dd-trace/src/telemetry/index.js +2 -3
  111. package/packages/dd-trace/src/telemetry/send-data.js +5 -19
  112. package/packages/dd-trace/src/telemetry/session-propagation.js +19 -44
  113. package/packages/dd-trace/src/telemetry/telemetry.js +28 -171
  114. package/packages/dd-trace/src/util.js +0 -9
@@ -1,9 +1,9 @@
1
1
  'use strict'
2
2
 
3
+ const { builtinModules } = require('module')
3
4
  const path = require('path')
4
5
  const { channel } = require('dc-polyfill')
5
6
  const satisfies = require('../../../../vendor/dist/semifies')
6
- const requirePackageJson = require('../../../dd-trace/src/require-package-json')
7
7
  const log = require('../../../dd-trace/src/log')
8
8
  const telemetry = require('../../../dd-trace/src/guardrails/telemetry')
9
9
  const { IS_SERVERLESS } = require('../../../dd-trace/src/serverless')
@@ -36,27 +36,47 @@ if (!disabledInstrumentations.has('process')) {
36
36
  require('../process')
37
37
  }
38
38
 
39
- const HOOK_SYMBOL = Symbol('hookExportsSet')
40
-
41
39
  if (DD_TRACE_DEBUG && DD_TRACE_DEBUG.toLowerCase() !== 'false') {
42
40
  checkRequireCache.checkForRequiredModules()
43
41
  setImmediate(checkRequireCache.checkForPotentialConflicts)
44
42
  }
45
43
 
46
- const seenCombo = new Set()
47
- const allInstrumentations = {}
48
-
49
44
  for (const inst of disabledInstrumentations) {
50
45
  rewriter.disable(inst)
51
46
  }
52
47
 
53
- // TODO: make this more efficient
54
- for (const packageName of names) {
55
- if (disabledInstrumentations.has(packageName)) continue
48
+ /** @type {Map<string, object>} */
49
+ const instrumentedNodeModules = new Map()
50
+ /** @type {Map<string, boolean>} */
51
+ const instrumentedIntegrationsSuccess = new Map()
52
+ /** @type {Set<string>} */
53
+ const alreadyLoggedIncompatibleIntegrations = new Set()
54
+
55
+ // Always disable prefixed and unprefixed node modules if one is disabled.
56
+ if (disabledInstrumentations.size) {
57
+ const builtinsSet = new Set(builtinModules)
58
+ for (const name of disabledInstrumentations) {
59
+ const hasPrefix = name.startsWith('node:')
60
+ if (hasPrefix || builtinsSet.has(name)) {
61
+ if (hasPrefix) {
62
+ const unprefixedName = name.slice(5)
63
+ if (!disabledInstrumentations.has(unprefixedName)) {
64
+ disabledInstrumentations.add(unprefixedName)
65
+ }
66
+ } else if (!disabledInstrumentations.has(`node:${name}`)) {
67
+ disabledInstrumentations.add(`node:${name}`)
68
+ }
69
+ }
70
+ }
71
+ builtinsSet.clear()
72
+ }
73
+
74
+ for (const name of names) {
75
+ if (disabledInstrumentations.has(name)) continue
56
76
 
57
77
  const hookOptions = {}
58
78
 
59
- let hook = hooks[packageName]
79
+ let hook = hooks[name]
60
80
 
61
81
  if (hook !== null && typeof hook === 'object') {
62
82
  if (hook.serverless === false && IS_SERVERLESS) continue
@@ -65,173 +85,114 @@ for (const packageName of names) {
65
85
  hook = hook.fn
66
86
  }
67
87
 
68
- // get the instrumentation file name to save all hooked versions
69
- const instrumentationFileName = parseHookInstrumentationFileName(packageName)
70
-
71
- Hook([packageName], hookOptions, (moduleExports, moduleName, moduleBaseDir, moduleVersion, isIitm) => {
72
- moduleName = moduleName.replace(pathSepExpr, '/')
88
+ Hook([name], hookOptions, (moduleExports, moduleName, moduleBaseDir, moduleVersion, isIitm) => {
89
+ // All loaded versions are first expected to fail instrumentation.
90
+ if (!instrumentedIntegrationsSuccess.has(`${name}@${moduleVersion}`)) {
91
+ instrumentedIntegrationsSuccess.set(`${name}@${moduleVersion}`, false)
92
+ }
73
93
 
74
94
  // This executes the integration file thus adding its entries to `instrumentations`
75
95
  hook()
76
96
 
77
- if (!instrumentations[packageName]) {
97
+ if (!instrumentations[name] || moduleExports === instrumentedNodeModules.get(name)) {
78
98
  return moduleExports
79
99
  }
80
100
 
81
- const namesAndSuccesses = {}
82
- for (const { name, file, versions, hook, filePattern, patchDefault } of instrumentations[packageName]) {
83
- if (patchDefault === false && !moduleExports.default && isIitm) {
84
- return moduleExports
85
- } else if (patchDefault === true && moduleExports.default && isIitm) {
86
- moduleExports = moduleExports.default
101
+ // Used for node: prefixed modules to prevent double instrumentation.
102
+ if (moduleBaseDir) {
103
+ moduleName = moduleName.replace(pathSepExpr, '/')
104
+ } else {
105
+ instrumentedNodeModules.set(name, moduleExports)
106
+ }
107
+
108
+ for (const { file, versions, hook, filePattern, patchDefault } of instrumentations[name]) {
109
+ if (isIitm && patchDefault === !!moduleExports.default) {
110
+ if (patchDefault) {
111
+ moduleExports = moduleExports.default
112
+ } else {
113
+ return moduleExports
114
+ }
87
115
  }
88
116
 
89
- let fullFilePattern = filePattern
90
117
  const fullFilename = filename(name, file)
91
- if (fullFilePattern) {
92
- fullFilePattern = filename(name, fullFilePattern)
93
- }
94
118
 
95
- // Create a WeakSet associated with the hook function so that patches on the same moduleExport only happens once
96
- // for example by instrumenting both dns and node:dns double the spans would be created
97
- // since they both patch the same moduleExport, this WeakSet is used to mitigate that
98
- // TODO(BridgeAR): Instead of using a WeakSet here, why not just use aliases for the hook in register?
99
- // That way it would also not be duplicated. The actual name being used has to be identified else wise.
100
- // Maybe it is also not important to know what name was actually used?
101
- hook[HOOK_SYMBOL] ??= new WeakSet()
102
119
  let matchesFile = moduleName === fullFilename
103
120
 
104
121
  if (!matchesFile && isRelativeRequire(name)) matchesFile = true
105
122
 
123
+ const fullFilePattern = filePattern && filename(name, filePattern)
106
124
  if (fullFilePattern) {
107
125
  // Some libraries include a hash in their filenames when installed,
108
126
  // so our instrumentation has to include a '.*' to match them for more than a single version.
109
- matchesFile = matchesFile || new RegExp(fullFilePattern).test(moduleName)
127
+ matchesFile ||= new RegExp(fullFilePattern).test(moduleName)
110
128
  }
111
129
 
112
- if (matchesFile) {
113
- let version = moduleVersion
130
+ if (matchesFile && matchVersion(moduleVersion, versions)) {
131
+ // Do not log in case of an error to prevent duplicate telemetry for the same integration version.
132
+ instrumentedIntegrationsSuccess.set(`${name}@${moduleVersion}`, true)
114
133
  try {
115
- version = version || getVersion(moduleBaseDir)
116
- allInstrumentations[instrumentationFileName] = allInstrumentations[instrumentationFileName] || false
117
- } catch (e) {
118
- log.error('Error getting version for "%s": %s', name, e.message, e)
119
- continue
120
- }
121
- if (namesAndSuccesses[`${name}@${version}`] === undefined && !file) {
122
- // TODO If `file` is present, we might elsewhere instrument the result of the module
123
- // for a version range that actually matches, so we can't assume that we're _not_
124
- // going to instrument that. However, the way the data model around instrumentation
125
- // works, we can't know either way just yet, so to avoid false positives, we'll just
126
- // ignore this if there is a `file` in the hook. The thing to do here is rework
127
- // everything so that we can be sure that there are _no_ instrumentations that it
128
- // could match.
129
- namesAndSuccesses[`${name}@${version}`] = false
130
- }
131
-
132
- if (matchVersion(version, versions)) {
133
- allInstrumentations[instrumentationFileName] = true
134
-
135
- // Check if the hook already has a set moduleExport
136
- if (hook[HOOK_SYMBOL].has(moduleExports)) {
137
- namesAndSuccesses[`${name}@${version}`] = true
138
- return moduleExports
139
- }
140
-
141
- try {
142
- loadChannel.publish({ name, version, file })
143
- // Send the name and version of the module back to the callback because now addHook
144
- // takes in an array of names so by passing the name the callback will know which module name is being used
145
- // TODO(BridgeAR): This is only true in case the name is identical
146
- // in all loads. If they deviate, the deviating name would not be
147
- // picked up due to the unification. Check what modules actually use the name.
148
- // TODO(BridgeAR): Only replace moduleExports if the hook returns a new value.
149
- // This allows to reduce the instrumentation code (no return needed).
150
-
151
- moduleExports = hook(moduleExports, version, name, isIitm) ?? moduleExports
152
- // Set the moduleExports in the hooks WeakSet
153
- hook[HOOK_SYMBOL].add(moduleExports)
154
- } catch (e) {
155
- log.info('Error during ddtrace instrumentation of application, aborting.', e)
156
- telemetry('error', [
157
- `error_type:${e.constructor.name}`,
158
- `integration:${name}`,
159
- `integration_version:${version}`,
160
- ], {
161
- result: 'error',
162
- result_class: 'internal_error',
163
- result_reason: `Error during instrumentation of ${name}@${version}: ${e.message}`,
164
- })
165
- }
166
- namesAndSuccesses[`${name}@${version}`] = true
134
+ loadChannel.publish({ name })
135
+
136
+ moduleExports = hook(moduleExports, moduleVersion, isIitm) ?? moduleExports
137
+ } catch (error) {
138
+ log.info('Error during ddtrace instrumentation of application, aborting.', error)
139
+ telemetry('error', [
140
+ `error_type:${error.constructor.name}`,
141
+ `integration:${name}`,
142
+ `integration_version:${moduleVersion}`,
143
+ ], {
144
+ result: 'error',
145
+ result_class: 'internal_error',
146
+ result_reason: `Error during instrumentation of ${name}@${moduleVersion}: ${error.message}`,
147
+ })
167
148
  }
168
149
  }
169
150
  }
170
- for (const nameVersion of Object.keys(namesAndSuccesses)) {
171
- const [name, version] = nameVersion.split('@')
172
- const success = namesAndSuccesses[nameVersion]
173
- // we check allVersions to see if any version of the integration was successfully instrumented
174
- if (!success && !seenCombo.has(nameVersion) && !allInstrumentations[instrumentationFileName]) {
175
- telemetry('abort.integration', [
176
- `integration:${name}`,
177
- `integration_version:${version}`,
178
- ], {
179
- result: 'abort',
180
- result_class: 'incompatible_library',
181
- result_reason: `Incompatible integration version: ${name}@${version}`,
182
- })
183
- log.info('Found incompatible integration version: %s', nameVersion)
184
- seenCombo.add(nameVersion)
185
- }
186
- }
187
151
 
188
152
  return moduleExports
189
153
  })
190
154
  }
191
155
 
192
- function matchVersion (version, ranges) {
193
- return !version || !ranges || ranges.some(range => satisfies(version, range))
194
- }
156
+ globalThis[Symbol.for('dd-trace')]?.beforeExitHandlers.add(logAbortedIntegrations)
157
+ // TODO: check if we want to stop using channels for single subscriber tasks
158
+ channel('dd-trace:exporter:first-flush').subscribe(logAbortedIntegrations)
195
159
 
196
- function getVersion (moduleBaseDir) {
197
- if (moduleBaseDir) {
198
- return requirePackageJson(moduleBaseDir, module).version
160
+ function logAbortedIntegrations () {
161
+ for (const [nameVersion, success] of instrumentedIntegrationsSuccess) {
162
+ // Only ever log a single version of an integration, even if it is loaded later.
163
+ if (!success && !alreadyLoggedIncompatibleIntegrations.has(nameVersion)) {
164
+ const [name, version] = nameVersion.split('@')
165
+ telemetry('abort.integration', [
166
+ `integration:${name}`,
167
+ `integration_version:${version}`,
168
+ ], {
169
+ result: 'abort',
170
+ result_class: 'incompatible_library',
171
+ result_reason: `Incompatible integration version: ${name}@${version}`,
172
+ })
173
+ log.info('Found incompatible integration version: %s', nameVersion)
174
+ alreadyLoggedIncompatibleIntegrations.add(nameVersion)
175
+ }
199
176
  }
177
+ // Clear the map to avoid reporting the same integration version again.
178
+ instrumentedIntegrationsSuccess.clear()
200
179
  }
201
180
 
202
- function filename (name, file) {
203
- return [name, file].filter(Boolean).join('/')
181
+ /**
182
+ * @param {string|undefined} version
183
+ * @param {string[]|undefined} ranges
184
+ */
185
+ function matchVersion (version, ranges) {
186
+ return !version || !ranges || ranges.some(range => satisfies(version, range))
204
187
  }
205
188
 
206
- // This function captures the instrumentation file name for a given package by parsing the hook require
207
- // function given the module name. It is used to ensure that instrumentations such as redis
208
- // that have several different modules being hooked, ie: 'redis' main package, and @redis/client submodule
209
- // return a consistent instrumentation name. This is used later to ensure that at least some portion of
210
- // the integration was successfully instrumented. Prevents incorrect `Found incompatible integration version: ` messages
211
- // Example:
212
- // redis -> "() => require('../redis')" -> redis
213
- // @redis/client -> "() => require('../redis')" -> redis
214
- //
215
- function parseHookInstrumentationFileName (packageName) {
216
- let hook = hooks[packageName]
217
- if (hook.fn) {
218
- hook = hook.fn
219
- }
220
- const hookString = hook.toString()
221
- const regex = /require\('([^']*)'\)/
222
- const match = hookString.match(regex)
223
-
224
- // try to capture the hook require file location.
225
- if (match && match[1]) {
226
- let moduleName = match[1]
227
- // Remove leading '../' if present
228
- if (moduleName.startsWith('../')) {
229
- moduleName = moduleName.slice(3)
230
- }
231
- return moduleName
232
- }
233
-
234
- return null
189
+ /**
190
+ * @param {string} name
191
+ * @param {string} [file]
192
+ * @returns {string}
193
+ */
194
+ function filename (name, file) {
195
+ return file ? `${name}/${file}` : name
235
196
  }
236
197
 
237
198
  module.exports = {
@@ -16,9 +16,8 @@ const asyncStartChannel = channel('apm:http:client:request:asyncStart')
16
16
  const errorChannel = channel('apm:http:client:request:error')
17
17
  const responseFinishChannel = channel('apm:http:client:response:finish')
18
18
 
19
- const names = ['http', 'https', 'node:http', 'node:https']
20
-
21
- addHook({ name: names }, hookFn)
19
+ addHook({ name: 'http' }, hookFn)
20
+ addHook({ name: 'https' }, hookFn)
22
21
 
23
22
  function hookFn (http) {
24
23
  patch(http, 'request')
@@ -16,10 +16,7 @@ const startSetHeaderCh = channel('datadog:http:server:response:set-header:start'
16
16
 
17
17
  const requestFinishedSet = new WeakSet()
18
18
 
19
- const httpNames = ['http', 'node:http']
20
- const httpsNames = ['https', 'node:https']
21
-
22
- addHook({ name: httpNames }, http => {
19
+ addHook({ name: 'http' }, http => {
23
20
  shimmer.wrap(http.ServerResponse.prototype, 'emit', wrapResponseEmit)
24
21
  shimmer.wrap(http.Server.prototype, 'emit', wrapEmit)
25
22
  shimmer.wrap(http.ServerResponse.prototype, 'writeHead', wrapWriteHead)
@@ -34,7 +31,7 @@ addHook({ name: httpNames }, http => {
34
31
  return http
35
32
  })
36
33
 
37
- addHook({ name: httpsNames }, http => {
34
+ addHook({ name: 'https' }, http => {
38
35
  // http.ServerResponse not present on https
39
36
  shimmer.wrap(http.Server.prototype, 'emit', wrapEmit)
40
37
  return http
@@ -10,8 +10,6 @@ const asyncStartChannel = channel('apm:http2:client:request:asyncStart')
10
10
  const asyncEndChannel = channel('apm:http2:client:request:asyncEnd')
11
11
  const errorChannel = channel('apm:http2:client:request:error')
12
12
 
13
- const names = ['http2', 'node:http2']
14
-
15
13
  function createWrapEmit (ctx) {
16
14
  return function wrapEmit (emit) {
17
15
  return function (event, arg1) {
@@ -68,7 +66,7 @@ function wrapConnect (connect) {
68
66
  }
69
67
  }
70
68
 
71
- addHook({ name: names }, http2 => {
69
+ addHook({ name: 'http2' }, http2 => {
72
70
  shimmer.wrap(http2, 'connect', wrapConnect)
73
71
  if (http2.default) http2.default.connect = http2.connect
74
72
 
@@ -13,9 +13,7 @@ const startServerCh = channel('apm:http2:server:request:start')
13
13
  const errorServerCh = channel('apm:http2:server:request:error')
14
14
  const emitCh = channel('apm:http2:server:response:emit')
15
15
 
16
- const names = ['http2', 'node:http2']
17
-
18
- addHook({ name: names }, http2 => {
16
+ addHook({ name: 'http2' }, http2 => {
19
17
  shimmer.wrap(http2, 'createSecureServer', wrapCreateServer)
20
18
  shimmer.wrap(http2, 'createServer', wrapCreateServer)
21
19
  })
@@ -1,5 +1,8 @@
1
1
  'use strict'
2
2
 
3
+ // Capture real timers at module load time, before any test can install fake timers.
4
+ const realSetTimeout = setTimeout
5
+
3
6
  const path = require('path')
4
7
  const shimmer = require('../../datadog-shimmer')
5
8
  const log = require('../../dd-trace/src/log')
@@ -111,6 +114,8 @@ const efdDeterminedRetries = new Map()
111
114
  const efdSlowAbortedTests = new Set()
112
115
  // Tests added as EFD new-test candidates (not ATF, not impacted).
113
116
  const efdNewTestCandidates = new Set()
117
+ // Tests that are genuinely new (not in known tests list).
118
+ const newTests = new Set()
114
119
  const testSuiteAbsolutePathsWithFastCheck = new Set()
115
120
  const testSuiteJestObjects = new Map()
116
121
 
@@ -485,7 +490,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
485
490
  }
486
491
 
487
492
  if (this.isKnownTestsEnabled) {
488
- isNewTest = retriedTestsToNumAttempts.has(testName)
493
+ isNewTest = newTests.has(testName)
489
494
  }
490
495
 
491
496
  const willRunEfd = this.isEarlyFlakeDetectionEnabled && (isNewTest || isModified)
@@ -605,6 +610,9 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
605
610
  }
606
611
  if (!isAttemptToFix && this.isKnownTestsEnabled) {
607
612
  const isNew = !this.knownTestsForThisSuite.includes(testFullName)
613
+ if (isNew && !isSkipped) {
614
+ newTests.add(testFullName)
615
+ }
608
616
  if (isNew && !isSkipped && !retriedTestsToNumAttempts.has(testFullName)) {
609
617
  if (DYNAMIC_NAME_RE.test(testFullName)) {
610
618
  // Populated directly for runInBand; for parallel workers the main process
@@ -715,7 +723,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
715
723
  let isEfdRetry = false
716
724
  // We'll store the test statuses of the retries
717
725
  if (this.isKnownTestsEnabled) {
718
- const isNewTest = retriedTestsToNumAttempts.has(testName)
726
+ const isNewTest = newTests.has(testName)
719
727
  if (isNewTest) {
720
728
  if (newTestsTestStatuses.has(testName)) {
721
729
  newTestsTestStatuses.get(testName).push(status)
@@ -776,7 +784,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
776
784
  // This means that tests retried with DI are BREAKPOINT_HIT_GRACE_PERIOD_MS slower at least.
777
785
  if (status === 'fail' && mightHitBreakpoint) {
778
786
  await new Promise(resolve => {
779
- setTimeout(() => {
787
+ realSetTimeout(() => {
780
788
  resolve()
781
789
  }, BREAKPOINT_HIT_GRACE_PERIOD_MS)
782
790
  })
@@ -811,6 +819,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
811
819
  efdDeterminedRetries.clear()
812
820
  efdSlowAbortedTests.clear()
813
821
  efdNewTestCandidates.clear()
822
+ newTests.clear()
814
823
  retriedTestsToNumAttempts.clear()
815
824
  attemptToFixRetriedTestsStatuses.clear()
816
825
  testsToBeRetried.clear()
@@ -1345,7 +1354,7 @@ function getCliWrapper (isNewJestVersion) {
1345
1354
  })
1346
1355
 
1347
1356
  const timeoutPromise = new Promise((resolve) => {
1348
- timeoutId = setTimeout(() => {
1357
+ timeoutId = realSetTimeout(() => {
1349
1358
  resolve('timeout')
1350
1359
  }, FLUSH_TIMEOUT).unref()
1351
1360
  })
@@ -14,7 +14,7 @@ function wrapRequest (original) {
14
14
  addHook({
15
15
  name: 'limitd-client',
16
16
  versions: ['>=2.8'],
17
- file: ['client.js'],
17
+ file: 'client.js',
18
18
  }, LimitdClient => {
19
19
  shimmer.wrap(LimitdClient.prototype, '_directRequest', wrapRequest)
20
20
  shimmer.wrap(LimitdClient.prototype, '_retriedRequest', wrapRequest)
@@ -1,5 +1,8 @@
1
1
  'use strict'
2
2
 
3
+ // Capture real timers at module load time, before any test can install fake timers.
4
+ const realSetTimeout = setTimeout
5
+
3
6
  const { getTestSuitePath, DYNAMIC_NAME_RE } = require('../../../dd-trace/src/plugins/util/test')
4
7
  const { channel } = require('../helpers/instrument')
5
8
  const shimmer = require('../../../datadog-shimmer')
@@ -293,7 +296,7 @@ function getOnTestEndHandler (config) {
293
296
  // This means that tests retried with DI are BREAKPOINT_HIT_GRACE_PERIOD_MS slower at least.
294
297
  if (test._ddShouldWaitForHitProbe || test._retriedTest?._ddShouldWaitForHitProbe) {
295
298
  await new Promise((resolve) => {
296
- setTimeout(() => {
299
+ realSetTimeout(() => {
297
300
  resolve()
298
301
  }, BREAKPOINT_HIT_GRACE_PERIOD_MS)
299
302
  })
@@ -16,16 +16,10 @@ const errorTCPCh = channel('apm:net:tcp:error')
16
16
  const readyCh = channel('apm:net:tcp:ready')
17
17
  const connectionCh = channel('apm:net:tcp:connection')
18
18
 
19
- const names = ['net', 'node:net']
20
-
21
- addHook({ name: names }, (net, version, name) => {
19
+ addHook({ name: 'net' }, (net) => {
22
20
  // explicitly require dns so that net gets an instrumented instance
23
21
  // so that we don't miss the dns calls
24
- if (name === 'net') {
25
- require('dns')
26
- } else {
27
- require('node:dns')
28
- }
22
+ require('node:dns')
29
23
 
30
24
  shimmer.wrap(net.Socket.prototype, 'connect', connect => function () {
31
25
  if (!startICPCh.hasSubscribers || !startTCPCh.hasSubscribers) {
@@ -97,7 +97,7 @@ addHook({ name: 'pino', versions: ['>=5.14.0 <6.8.0'] }, (pino) => {
97
97
  return wrapped
98
98
  })
99
99
 
100
- addHook({ name: 'pino', versions: ['>=6.8.0'], patchDefault: false }, (pino, _1, _2, isIitm) => {
100
+ addHook({ name: 'pino', versions: ['>=6.8.0'], patchDefault: false }, (pino) => {
101
101
  const mixinSym = pino.symbols.mixinSym
102
102
 
103
103
  const wrapped = shimmer.wrapFunction(pino, pino => wrapPino(mixinSym, wrapMixin, pino))
@@ -1,5 +1,8 @@
1
1
  'use strict'
2
2
 
3
+ // Capture real timers at module load time, before any test can install fake timers.
4
+ const realSetTimeout = setTimeout
5
+
3
6
  const satisfies = require('../../../vendor/dist/semifies')
4
7
 
5
8
  const shimmer = require('../../datadog-shimmer')
@@ -1216,7 +1219,7 @@ addHook({
1216
1219
 
1217
1220
  if (isRumActive) {
1218
1221
  // Give some time RUM to flush data, similar to what we do in selenium
1219
- await new Promise(resolve => setTimeout(resolve, RUM_FLUSH_WAIT_TIME))
1222
+ await new Promise(resolve => realSetTimeout(resolve, RUM_FLUSH_WAIT_TIME))
1220
1223
  const url = page.url()
1221
1224
  if (url) {
1222
1225
  const domain = new URL(url).hostname
@@ -136,11 +136,10 @@ function resolveClientDbConfig (clientConfig, datasourceName, runtimeDbConfig) {
136
136
  /**
137
137
  * @param {unknown} runtime
138
138
  * @param {string} versions
139
- * @param {string} [name]
140
139
  * @param {boolean} [isIitm]
141
140
  * @returns {object}
142
141
  */
143
- const prismaHook = (runtime, versions, name, isIitm) => {
142
+ const prismaHook = (runtime, versions, isIitm) => {
144
143
  /**
145
144
  * @typedef {{ getPrismaClient?: (config: PrismaRuntimeConfig, ...args: unknown[]) => Function }} PrismaRuntime
146
145
  */
@@ -1,5 +1,8 @@
1
1
  'use strict'
2
2
 
3
+ // Capture real timers at module load time, before any test can install fake timers.
4
+ const realSetTimeout = setTimeout
5
+
3
6
  const shimmer = require('../../datadog-shimmer')
4
7
  const { getValueFromEnvSources } = require('../../dd-trace/src/config/helper')
5
8
  const { addHook, channel } = require('./helpers/instrument')
@@ -66,7 +69,7 @@ addHook({
66
69
  if (isRumActive) {
67
70
  // We'll have time for RUM to flush the events (there's no callback to know when it's done)
68
71
  await new Promise(resolve => {
69
- setTimeout(() => {
72
+ realSetTimeout(() => {
70
73
  resolve()
71
74
  }, DD_CIVISIBILITY_RUM_FLUSH_WAIT_MILLIS)
72
75
  })
@@ -6,7 +6,7 @@ const {
6
6
  addHook,
7
7
  } = require('./helpers/instrument')
8
8
 
9
- addHook({ name: 'sequelize', versions: ['>=4'], file: ['lib/sequelize.js'] }, Sequelize => {
9
+ addHook({ name: 'sequelize', versions: ['>=4'], file: 'lib/sequelize.js' }, Sequelize => {
10
10
  const startCh = channel('datadog:sequelize:query:start')
11
11
  const finishCh = channel('datadog:sequelize:query:finish')
12
12
 
@@ -2,13 +2,11 @@
2
2
 
3
3
  const shimmer = require('../../datadog-shimmer')
4
4
  const { addHook, channel } = require('./helpers/instrument')
5
- const names = ['url', 'node:url']
6
-
7
5
  const parseFinishedChannel = channel('datadog:url:parse:finish')
8
6
  const urlGetterChannel = channel('datadog:url:getter:finish')
9
7
  const instrumentedGetters = ['host', 'origin', 'hostname']
10
8
 
11
- addHook({ name: names }, function (url) {
9
+ addHook({ name: 'url' }, function (url) {
12
10
  shimmer.wrap(url, 'parse', (parse) => {
13
11
  return function wrappedParse (input) {
14
12
  const parsedValue = parse.apply(this, arguments)
@@ -1,4 +1,8 @@
1
1
  'use strict'
2
+
3
+ // Capture real timers at module load time, before any test can install fake timers.
4
+ const realSetTimeout = setTimeout
5
+
2
6
  const path = require('node:path')
3
7
 
4
8
  const shimmer = require('../../datadog-shimmer')
@@ -83,7 +87,7 @@ function getTestCommand () {
83
87
 
84
88
  function waitForHitProbe () {
85
89
  return new Promise(resolve => {
86
- setTimeout(() => {
90
+ realSetTimeout(() => {
87
91
  resolve()
88
92
  }, BREAKPOINT_HIT_GRACE_PERIOD_MS)
89
93
  })
@@ -2,12 +2,10 @@
2
2
 
3
3
  const shimmer = require('../../datadog-shimmer')
4
4
  const { channel, addHook } = require('./helpers/instrument')
5
- const names = ['vm', 'node:vm']
6
-
7
5
  const runScriptStartChannel = channel('datadog:vm:run-script:start')
8
6
  const sourceTextModuleStartChannel = channel('datadog:vm:source-text-module:start')
9
7
 
10
- addHook({ name: names }, function (vm) {
8
+ addHook({ name: 'vm' }, function (vm) {
11
9
  vm.Script = class extends vm.Script {
12
10
  constructor (code) {
13
11
  super(...arguments)
@@ -23,12 +23,13 @@ class BaseAwsSdkPlugin extends ClientPlugin {
23
23
  return id
24
24
  }
25
25
 
26
+ /** @type {import('../../dd-trace/src/config/config-types').ConfigProperties['cloudPayloadTagging']} */
26
27
  get cloudTaggingConfig () {
27
28
  return this._tracerConfig.cloudPayloadTagging
28
29
  }
29
30
 
30
31
  get payloadTaggingRules () {
31
- return this.cloudTaggingConfig.rules.aws?.[this.constructor.id]
32
+ return this.cloudTaggingConfig.rules?.aws?.[this.constructor.id]
32
33
  }
33
34
 
34
35
  constructor (...args) {
@@ -78,7 +79,7 @@ class BaseAwsSdkPlugin extends ClientPlugin {
78
79
  this.requestInject(span, request)
79
80
  })
80
81
 
81
- if (this.constructor.isPayloadReporter && this.cloudTaggingConfig.requestsEnabled) {
82
+ if (this.constructor.isPayloadReporter && this.cloudTaggingConfig.request) {
82
83
  const maxDepth = this.cloudTaggingConfig.maxDepth
83
84
  const requestTags = tagsFromRequest(this.payloadTaggingRules, request.params, { maxDepth })
84
85
  span.addTags(requestTags)
@@ -215,7 +216,7 @@ class BaseAwsSdkPlugin extends ClientPlugin {
215
216
 
216
217
  span.addTags(tags)
217
218
 
218
- if (this.constructor.isPayloadReporter && this.cloudTaggingConfig.responsesEnabled) {
219
+ if (this.constructor.isPayloadReporter && this.cloudTaggingConfig.response) {
219
220
  const maxDepth = this.cloudTaggingConfig.maxDepth
220
221
  const responseBody = this.extractResponseBody(response)
221
222
  const responseTags = tagsFromResponse(this.payloadTaggingRules, responseBody, { maxDepth })