dd-trace 5.95.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 (124) hide show
  1. package/index.d.ts +43 -0
  2. package/package.json +10 -8
  3. package/packages/datadog-esbuild/index.js +20 -9
  4. package/packages/datadog-instrumentations/src/ai.js +112 -0
  5. package/packages/datadog-instrumentations/src/child_process.js +7 -17
  6. package/packages/datadog-instrumentations/src/crypto.js +1 -2
  7. package/packages/datadog-instrumentations/src/cucumber.js +4 -1
  8. package/packages/datadog-instrumentations/src/cypress-config.js +324 -0
  9. package/packages/datadog-instrumentations/src/cypress.js +86 -4
  10. package/packages/datadog-instrumentations/src/dns.js +1 -2
  11. package/packages/datadog-instrumentations/src/express.js +4 -4
  12. package/packages/datadog-instrumentations/src/fs.js +27 -29
  13. package/packages/datadog-instrumentations/src/graphql.js +1 -1
  14. package/packages/datadog-instrumentations/src/helpers/ai-messages.js +182 -0
  15. package/packages/datadog-instrumentations/src/helpers/bundler-register.js +41 -13
  16. package/packages/datadog-instrumentations/src/helpers/hook.js +31 -6
  17. package/packages/datadog-instrumentations/src/helpers/hooks.js +12 -19
  18. package/packages/datadog-instrumentations/src/helpers/instrument.js +27 -13
  19. package/packages/datadog-instrumentations/src/helpers/register.js +103 -142
  20. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/ai.js +25 -0
  21. package/packages/datadog-instrumentations/src/http/client.js +2 -3
  22. package/packages/datadog-instrumentations/src/http/server.js +2 -5
  23. package/packages/datadog-instrumentations/src/http2/client.js +1 -3
  24. package/packages/datadog-instrumentations/src/http2/server.js +1 -3
  25. package/packages/datadog-instrumentations/src/jest.js +13 -4
  26. package/packages/datadog-instrumentations/src/limitd-client.js +1 -1
  27. package/packages/datadog-instrumentations/src/mocha/utils.js +14 -1
  28. package/packages/datadog-instrumentations/src/net.js +2 -8
  29. package/packages/datadog-instrumentations/src/pino.js +1 -1
  30. package/packages/datadog-instrumentations/src/playwright.js +4 -1
  31. package/packages/datadog-instrumentations/src/prisma.js +1 -2
  32. package/packages/datadog-instrumentations/src/selenium.js +4 -1
  33. package/packages/datadog-instrumentations/src/sequelize.js +1 -1
  34. package/packages/datadog-instrumentations/src/url.js +1 -3
  35. package/packages/datadog-instrumentations/src/vitest.js +5 -1
  36. package/packages/datadog-instrumentations/src/vm.js +1 -3
  37. package/packages/datadog-plugin-aws-sdk/src/base.js +4 -3
  38. package/packages/datadog-plugin-cucumber/src/index.js +7 -3
  39. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +57 -5
  40. package/packages/datadog-plugin-graphql/src/resolve.js +1 -1
  41. package/packages/datadog-plugin-jest/src/index.js +4 -2
  42. package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +31 -4
  43. package/packages/datadog-plugin-mocha/src/index.js +5 -2
  44. package/packages/datadog-plugin-next/src/index.js +2 -14
  45. package/packages/datadog-plugin-openai/src/services.js +1 -0
  46. package/packages/datadog-webpack/index.js +3 -3
  47. package/packages/dd-trace/index.js +12 -10
  48. package/packages/dd-trace/src/agent/url.js +2 -2
  49. package/packages/dd-trace/src/aiguard/index.js +64 -0
  50. package/packages/dd-trace/src/aiguard/sdk.js +4 -0
  51. package/packages/dd-trace/src/appsec/blocking.js +3 -0
  52. package/packages/dd-trace/src/appsec/iast/iast-plugin.js +1 -1
  53. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +1 -1
  54. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +1 -1
  55. package/packages/dd-trace/src/appsec/remote_config.js +1 -0
  56. package/packages/dd-trace/src/appsec/sdk/index.js +4 -0
  57. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +6 -1
  58. package/packages/dd-trace/src/ci-visibility/lage.js +39 -0
  59. package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +4 -0
  60. package/packages/dd-trace/src/config/defaults.js +316 -146
  61. package/packages/dd-trace/src/config/generated-config-types.d.ts +4 -1
  62. package/packages/dd-trace/src/config/helper.js +59 -10
  63. package/packages/dd-trace/src/config/index.js +570 -1503
  64. package/packages/dd-trace/src/config/parsers.js +256 -0
  65. package/packages/dd-trace/src/config/remote_config.js +59 -2
  66. package/packages/dd-trace/src/config/supported-configurations.json +367 -433
  67. package/packages/dd-trace/src/constants.js +1 -0
  68. package/packages/dd-trace/src/crashtracking/crashtracker.js +7 -1
  69. package/packages/dd-trace/src/crashtracking/index.js +1 -7
  70. package/packages/dd-trace/src/debugger/index.js +1 -1
  71. package/packages/dd-trace/src/dogstatsd.js +12 -9
  72. package/packages/dd-trace/src/encode/0.4.js +1 -1
  73. package/packages/dd-trace/src/exporter.js +5 -2
  74. package/packages/dd-trace/src/exporters/agent/writer.js +7 -1
  75. package/packages/dd-trace/src/exporters/common/request.js +9 -0
  76. package/packages/dd-trace/src/exporters/common/writer.js +12 -2
  77. package/packages/dd-trace/src/heap_snapshots.js +3 -0
  78. package/packages/dd-trace/src/index.js +5 -2
  79. package/packages/dd-trace/src/lambda/runtime/ritm.js +6 -6
  80. package/packages/dd-trace/src/llmobs/constants/text.js +3 -0
  81. package/packages/dd-trace/src/llmobs/index.js +13 -5
  82. package/packages/dd-trace/src/llmobs/plugins/ai/index.js +5 -1
  83. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +60 -12
  84. package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +4 -2
  85. package/packages/dd-trace/src/llmobs/sdk.js +12 -8
  86. package/packages/dd-trace/src/llmobs/span_processor.js +1 -1
  87. package/packages/dd-trace/src/llmobs/tagger.js +9 -6
  88. package/packages/dd-trace/src/llmobs/writers/base.js +2 -0
  89. package/packages/dd-trace/src/llmobs/writers/util.js +3 -0
  90. package/packages/dd-trace/src/log/index.js +26 -55
  91. package/packages/dd-trace/src/log/writer.js +7 -19
  92. package/packages/dd-trace/src/noop/proxy.js +8 -0
  93. package/packages/dd-trace/src/opentelemetry/logs/index.js +1 -1
  94. package/packages/dd-trace/src/opentelemetry/metrics/index.js +1 -1
  95. package/packages/dd-trace/src/opentracing/propagation/text_map.js +9 -4
  96. package/packages/dd-trace/src/payload-tagging/config/index.js +6 -5
  97. package/packages/dd-trace/src/plugin_manager.js +8 -6
  98. package/packages/dd-trace/src/plugins/ci_plugin.js +4 -0
  99. package/packages/dd-trace/src/plugins/plugin.js +7 -4
  100. package/packages/dd-trace/src/plugins/util/test.js +5 -0
  101. package/packages/dd-trace/src/process-tags/index.js +3 -0
  102. package/packages/dd-trace/src/profiler.js +27 -2
  103. package/packages/dd-trace/src/profiling/config.js +73 -241
  104. package/packages/dd-trace/src/profiling/exporter_cli.js +1 -4
  105. package/packages/dd-trace/src/profiling/exporters/event_serializer.js +6 -2
  106. package/packages/dd-trace/src/profiling/profiler.js +56 -44
  107. package/packages/dd-trace/src/profiling/profilers/events.js +2 -3
  108. package/packages/dd-trace/src/profiling/profilers/wall.js +89 -6
  109. package/packages/dd-trace/src/profiling/ssi-heuristics.js +4 -1
  110. package/packages/dd-trace/src/propagation-hash/index.js +2 -1
  111. package/packages/dd-trace/src/proxy.js +36 -3
  112. package/packages/dd-trace/src/remote_config/index.js +3 -0
  113. package/packages/dd-trace/src/require-package-json.js +8 -4
  114. package/packages/dd-trace/src/ritm.js +58 -26
  115. package/packages/dd-trace/src/runtime_metrics/index.js +3 -0
  116. package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +3 -0
  117. package/packages/dd-trace/src/sampler.js +1 -1
  118. package/packages/dd-trace/src/standalone/index.js +3 -0
  119. package/packages/dd-trace/src/startup-log.js +9 -0
  120. package/packages/dd-trace/src/telemetry/index.js +2 -3
  121. package/packages/dd-trace/src/telemetry/send-data.js +5 -19
  122. package/packages/dd-trace/src/telemetry/session-propagation.js +19 -44
  123. package/packages/dd-trace/src/telemetry/telemetry.js +28 -171
  124. package/packages/dd-trace/src/util.js +0 -9
package/index.d.ts CHANGED
@@ -130,6 +130,11 @@ interface Tracer extends opentracing.Tracer {
130
130
 
131
131
  appsec: tracer.Appsec;
132
132
 
133
+ /**
134
+ * Profiling API for attaching custom labels to profiler samples.
135
+ */
136
+ profiling: tracer.Profiling;
137
+
133
138
  TracerProvider: tracer.opentelemetry.TracerProvider;
134
139
 
135
140
  dogstatsd: tracer.DogStatsD;
@@ -786,6 +791,15 @@ declare namespace tracer {
786
791
  * Programmatic configuration takes precedence over the environment variables listed above.
787
792
  */
788
793
  enabled?: boolean,
794
+ /**
795
+ * Whether to request blocking mode when evaluating prompts via auto-instrumentation.
796
+ * When `true`, AI Guard will block requests that violate security policies.
797
+ * When `false`, AI Guard evaluates but never blocks (monitor-only mode).
798
+ * @default false
799
+ * @env DD_AI_GUARD_BLOCK
800
+ * Programmatic configuration takes precedence over the environment variables listed above.
801
+ */
802
+ block?: boolean,
789
803
  /**
790
804
  * URL of the AI Guard REST API.
791
805
  * @env DD_AI_GUARD_ENDPOINT
@@ -1561,6 +1575,35 @@ declare namespace tracer {
1561
1575
  trackUserLoginFailure(login: string, metadata?: any): void;
1562
1576
  }
1563
1577
 
1578
+ export interface Profiling {
1579
+ /**
1580
+ * Declares the set of custom label keys that will be used with
1581
+ * {@link runWithLabels}. This is used for profile upload metadata
1582
+ * (so the Datadog UI knows which keys to index for filtering) and
1583
+ * for pprof serialization optimization.
1584
+ *
1585
+ * @param keys Custom label key names.
1586
+ */
1587
+ setCustomLabelKeys(keys: Iterable<string>): void;
1588
+
1589
+ /**
1590
+ * Runs a function with custom profiling labels attached to all wall profiler
1591
+ * samples taken during its execution. Labels are key-value pairs that appear
1592
+ * in the pprof output and can be used to filter flame graphs in the Datadog UI.
1593
+ *
1594
+ * Requires AsyncContextFrame (ACF) to be enabled. Supports nesting: inner
1595
+ * calls merge labels with outer calls, with inner values taking precedence.
1596
+ *
1597
+ * When profiling is not enabled or ACF is not active, the function is still
1598
+ * called but labels are silently dropped.
1599
+ *
1600
+ * @param labels Custom labels to attach to profiler samples.
1601
+ * @param fn Function to execute with the labels.
1602
+ * @returns The return value of fn.
1603
+ */
1604
+ runWithLabels<T>(labels: Record<string, string | number>, fn: () => T): T;
1605
+ }
1606
+
1564
1607
  export interface Appsec {
1565
1608
  /**
1566
1609
  * Links a successful login event to the current trace. Will link the passed user to the current trace with Appsec.setUser() internally.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dd-trace",
3
- "version": "5.95.0",
3
+ "version": "5.97.0",
4
4
  "description": "Datadog APM tracing client for JavaScript",
5
5
  "main": "index.js",
6
6
  "typings": "index.d.ts",
@@ -11,6 +11,8 @@
11
11
  "bench": "node benchmark/index.js",
12
12
  "bench:e2e:test-optimization": "node benchmark/e2e-test-optimization/benchmark-run.js",
13
13
  "dependencies:dedupe": "yarn-deduplicate yarn.lock",
14
+ "generate:config:types": "node scripts/generate-config-types.js",
15
+ "verify:config:types": "node scripts/generate-config-types.js --check",
14
16
  "type:check": "tsc --noEmit -p tsconfig.dev.json",
15
17
  "type:doc:build": "cd docs && yarn && yarn build",
16
18
  "type:doc:test": "cd docs && yarn && yarn test",
@@ -139,10 +141,10 @@
139
141
  ],
140
142
  "dependencies": {
141
143
  "dc-polyfill": "^0.1.10",
142
- "import-in-the-middle": "^3.0.0"
144
+ "import-in-the-middle": "^3.0.1"
143
145
  },
144
146
  "optionalDependencies": {
145
- "@datadog/libdatadog": "0.9.2",
147
+ "@datadog/libdatadog": "0.9.3",
146
148
  "@datadog/native-appsec": "11.0.1",
147
149
  "@datadog/native-iast-taint-tracking": "4.1.0",
148
150
  "@datadog/native-metrics": "3.1.1",
@@ -166,19 +168,19 @@
166
168
  "@types/mocha": "^10.0.10",
167
169
  "@types/node": "^18.19.106",
168
170
  "@types/sinon": "^21.0.0",
169
- "axios": "^1.13.4",
171
+ "axios": "^1.15.0",
170
172
  "benchmark": "^2.1.4",
171
173
  "body-parser": "^2.2.2",
172
174
  "bun": "1.3.11",
173
175
  "codeowners-audit": "^2.9.0",
174
176
  "eslint": "^9.39.2",
175
- "eslint-plugin-cypress": "^6.2.1",
177
+ "eslint-plugin-cypress": "^6.2.2",
176
178
  "eslint-plugin-import": "^2.32.0",
177
- "eslint-plugin-jsdoc": "^62.8.1",
179
+ "eslint-plugin-jsdoc": "^62.9.0",
178
180
  "eslint-plugin-mocha": "^11.2.0",
179
181
  "eslint-plugin-n": "^17.23.2",
180
182
  "eslint-plugin-promise": "^7.2.1",
181
- "eslint-plugin-unicorn": "^63.0.0",
183
+ "eslint-plugin-unicorn": "^64.0.0",
182
184
  "express": "^5.1.0",
183
185
  "glob": "^10.4.5",
184
186
  "globals": "^17.2.0",
@@ -200,7 +202,7 @@
200
202
  "semver": "^7.7.2",
201
203
  "sinon": "^21.0.3",
202
204
  "tiktoken": "^1.0.21",
203
- "typescript": "^5.9.2",
205
+ "typescript": "^6.0.2",
204
206
  "workerpool": "^10.0.0",
205
207
  "yaml": "^2.8.3",
206
208
  "yarn-deduplicate": "^6.0.2"
@@ -2,7 +2,6 @@
2
2
 
3
3
  const { execSync } = require('node:child_process')
4
4
  const fs = require('node:fs')
5
- const RAW_BUILTINS = require('node:module').builtinModules
6
5
  const path = require('node:path')
7
6
  const { pathToFileURL, fileURLToPath } = require('node:url')
8
7
 
@@ -25,15 +24,27 @@ for (const hook of Object.values(hooks)) {
25
24
  }
26
25
  }
27
26
 
27
+ function moduleOfInterestKey (name, file) {
28
+ return file ? `${name}/${file}` : name
29
+ }
30
+
31
+ const builtinModules = new Set(require('module').builtinModules)
32
+
33
+ function addModuleOfInterest (name, file) {
34
+ if (!name) return
35
+
36
+ modulesOfInterest.add(moduleOfInterestKey(name, file))
37
+
38
+ if (builtinModules.has(name)) {
39
+ modulesOfInterest.add(moduleOfInterestKey(`node:${name}`, file))
40
+ }
41
+ }
42
+
28
43
  const modulesOfInterest = new Set()
29
44
 
30
- for (const instrumentation of Object.values(instrumentations)) {
45
+ for (const [name, instrumentation] of Object.entries(instrumentations)) {
31
46
  for (const entry of instrumentation) {
32
- if (entry.file) {
33
- modulesOfInterest.add(`${entry.name}/${entry.file}`) // e.g. "redis/my/file.js"
34
- } else {
35
- modulesOfInterest.add(entry.name) // e.g. "redis"
36
- }
47
+ addModuleOfInterest(name, entry.file)
37
48
  }
38
49
  }
39
50
 
@@ -41,7 +52,7 @@ const CHANNEL = 'dd-trace:bundler:load'
41
52
 
42
53
  const builtins = new Set()
43
54
 
44
- for (const builtin of RAW_BUILTINS) {
55
+ for (const builtin of builtinModules) {
45
56
  builtins.add(builtin)
46
57
  builtins.add(`node:${builtin}`)
47
58
  }
@@ -247,7 +258,7 @@ ${build.initialOptions.banner.js}`
247
258
  }
248
259
 
249
260
  try {
250
- const packageJson = JSON.parse(fs.readFileSync(/** @type {string} */ (pathToPackageJson)).toString())
261
+ const packageJson = JSON.parse(fs.readFileSync(/** @type {string} */(pathToPackageJson)).toString())
251
262
 
252
263
  const isESM = isESMFile(fullPathToModule, pathToPackageJson, packageJson)
253
264
  if (isESM && !interceptedESMModules.has(fullPathToModule)) {
@@ -3,11 +3,113 @@
3
3
  const { channel, tracingChannel } = require('dc-polyfill')
4
4
  const shimmer = require('../../datadog-shimmer')
5
5
  const { addHook, getHooks } = require('./helpers/instrument')
6
+ const { convertVercelPromptToMessages, buildOutputMessages } = require('./helpers/ai-messages')
6
7
 
7
8
  const vercelAiTracingChannel = tracingChannel('dd-trace:vercel-ai')
8
9
  const vercelAiSpanSetAttributesChannel = channel('dd-trace:vercel-ai:span:setAttributes')
10
+ const aiguardChannel = channel('dd-trace:ai:aiguard')
9
11
 
10
12
  const tracers = new WeakSet()
13
+ const wrappedModels = new WeakSet()
14
+
15
+ /**
16
+ * Publishes already-converted AI guard style messages to the AIGuard channel.
17
+ *
18
+ * @param {Array<object>} messages - AI guard style messages to evaluate
19
+ * @returns {Promise<void>}
20
+ */
21
+ function publishToAIGuard (messages) {
22
+ return new Promise((resolve, reject) => {
23
+ aiguardChannel.publish({ messages, resolve, reject })
24
+ })
25
+ }
26
+
27
+ /**
28
+ * Wraps a Vercel AI language model's doGenerate and doStream methods to evaluate
29
+ * messages with AIGuard.
30
+ *
31
+ * @param {object} model - A Vercel AI language model instance
32
+ */
33
+ function wrapModelWithAIGuard (model) {
34
+ if (!model || wrappedModels.has(model)) return
35
+ wrappedModels.add(model)
36
+
37
+ if (typeof model.doGenerate === 'function') {
38
+ shimmer.wrap(model, 'doGenerate', function (original) {
39
+ return function (options) {
40
+ const originalResult = original.call(this, options)
41
+
42
+ if (!aiguardChannel.hasSubscribers) return originalResult
43
+ if (!options.prompt?.length) return originalResult
44
+
45
+ const inputMessages = convertVercelPromptToMessages(options.prompt)
46
+ if (!inputMessages.length) return originalResult
47
+
48
+ // Run AI Guard input evaluation and LLM call in parallel.
49
+ // The LLM has no side effects so it is safe to discard its result if AI Guard blocks.
50
+ return Promise.all([publishToAIGuard(inputMessages), originalResult])
51
+ .then(([, result]) => {
52
+ if (!result.content?.length) return result
53
+ return publishToAIGuard(buildOutputMessages(inputMessages, result.content))
54
+ .then(() => result)
55
+ })
56
+ }
57
+ })
58
+ }
59
+
60
+ if (typeof model.doStream === 'function') {
61
+ shimmer.wrap(model, 'doStream', function (original) {
62
+ return function (options) {
63
+ const originalResult = original.call(this, options)
64
+
65
+ if (!aiguardChannel.hasSubscribers) return originalResult
66
+ if (!options.prompt?.length) return originalResult
67
+
68
+ const inputMessages = convertVercelPromptToMessages(options.prompt)
69
+ if (!inputMessages.length) return originalResult
70
+
71
+ // Run AI Guard input evaluation and LLM call in parallel.
72
+ // The LLM has no side effects so it is safe to discard its result if AI Guard blocks.
73
+ return Promise.all([publishToAIGuard(inputMessages), originalResult])
74
+ .then(([, result]) => {
75
+ const chunks = []
76
+ const reader = result.stream.getReader()
77
+
78
+ function readAll () {
79
+ return reader.read().then(({ done, value }) => {
80
+ if (done) return
81
+ chunks.push(value)
82
+ return readAll()
83
+ })
84
+ }
85
+
86
+ return readAll().then(() => {
87
+ const toolCalls = chunks.filter(c => c?.type === 'tool-call')
88
+ const text = chunks.filter(c => c?.type === 'text-delta').map(c => c.textDelta).join('')
89
+ const content = toolCalls.length ? toolCalls : text ? [{ type: 'text', text }] : []
90
+
91
+ const evaluate = content.length
92
+ ? publishToAIGuard(buildOutputMessages(inputMessages, content))
93
+ : Promise.resolve()
94
+
95
+ return evaluate.then(() => {
96
+ // eslint-disable-next-line n/no-unsupported-features/node-builtins
97
+ const stream = new ReadableStream({
98
+ start (controller) {
99
+ for (const chunk of chunks) {
100
+ controller.enqueue(chunk)
101
+ }
102
+ controller.close()
103
+ },
104
+ })
105
+ return { ...result, stream }
106
+ })
107
+ })
108
+ })
109
+ }
110
+ })
111
+ }
112
+ }
11
113
 
12
114
  function wrapTracer (tracer) {
13
115
  if (tracers.has(tracer)) {
@@ -114,6 +216,16 @@ for (const hook of getHooks('ai')) {
114
216
  },
115
217
  })
116
218
 
219
+ // resolveLanguageModel is called by all LLM entry points (generateText, streamText,
220
+ // generateObject, streamObject)
221
+ tracingChannel('orchestrion:ai:resolveLanguageModel').subscribe({
222
+ end (ctx) {
223
+ wrapModelWithAIGuard(ctx.result)
224
+ },
225
+ })
226
+
117
227
  return exports
118
228
  })
119
229
  }
230
+
231
+ module.exports = { wrapModelWithAIGuard }
@@ -14,11 +14,6 @@ const childProcessChannel = dc.tracingChannel('datadog:child_process:execution')
14
14
  // ignored exec method because it calls to execFile directly
15
15
  const execAsyncMethods = ['execFile', 'spawn', 'fork']
16
16
 
17
- const names = ['child_process', 'node:child_process']
18
-
19
- // child_process and node:child_process returns the same object instance, we only want to add hooks once
20
- let patched = false
21
-
22
17
  function throwSyncError (error) {
23
18
  throw error
24
19
  }
@@ -37,19 +32,14 @@ function returnSpawnSyncError (error, context) {
37
32
  return context.result
38
33
  }
39
34
 
40
- for (const name of names) {
41
- addHook({ name }, childProcess => {
42
- if (!patched) {
43
- patched = true
44
- shimmer.massWrap(childProcess, execAsyncMethods, wrapChildProcessAsyncMethod(childProcess.ChildProcess))
45
- shimmer.wrap(childProcess, 'execSync', wrapChildProcessSyncMethod(throwSyncError, true))
46
- shimmer.wrap(childProcess, 'execFileSync', wrapChildProcessSyncMethod(throwSyncError))
47
- shimmer.wrap(childProcess, 'spawnSync', wrapChildProcessSyncMethod(returnSpawnSyncError))
48
- }
35
+ addHook({ name: 'child_process' }, childProcess => {
36
+ shimmer.massWrap(childProcess, execAsyncMethods, wrapChildProcessAsyncMethod(childProcess.ChildProcess))
37
+ shimmer.wrap(childProcess, 'execSync', wrapChildProcessSyncMethod(throwSyncError, true))
38
+ shimmer.wrap(childProcess, 'execFileSync', wrapChildProcessSyncMethod(throwSyncError))
39
+ shimmer.wrap(childProcess, 'spawnSync', wrapChildProcessSyncMethod(returnSpawnSyncError))
49
40
 
50
- return childProcess
51
- })
52
- }
41
+ return childProcess
42
+ })
53
43
 
54
44
  function normalizeArgs (args, shell) {
55
45
  const childProcessInfo = {
@@ -11,9 +11,8 @@ const cryptoCipherCh = channel('datadog:crypto:cipher:start')
11
11
 
12
12
  const hashMethods = ['createHash', 'createHmac', 'createSign', 'createVerify', 'sign', 'verify']
13
13
  const cipherMethods = ['createCipheriv', 'createDecipheriv']
14
- const names = ['crypto', 'node:crypto']
15
14
 
16
- addHook({ name: names }, crypto => {
15
+ addHook({ name: 'crypto' }, crypto => {
17
16
  shimmer.massWrap(crypto, hashMethods, wrapCryptoMethod(cryptoHashCh))
18
17
  shimmer.massWrap(crypto, cipherMethods, wrapCryptoMethod(cryptoCipherCh))
19
18
  return crypto
@@ -61,6 +61,8 @@ const numRetriesByPickleId = new Map()
61
61
  const numAttemptToCtx = new Map()
62
62
  const newTestsByTestFullname = new Map()
63
63
  const modifiedTestsByPickleId = new Map()
64
+ // Pickle IDs for tests that are genuinely new (not in known tests list).
65
+ const newTestPickleIds = new Set()
64
66
 
65
67
  let eventDataCollector = null
66
68
  let pickleByFile = {}
@@ -359,7 +361,7 @@ function wrapRun (pl, isLatestVersion, version) {
359
361
  }
360
362
 
361
363
  if (isKnownTestsEnabled && status !== 'skip') {
362
- isNew = numRetries !== undefined
364
+ isNew = newTestPickleIds.has(this.pickle.id)
363
365
  }
364
366
 
365
367
  if (isNew || isModified) {
@@ -714,6 +716,7 @@ function getWrappedRunTestCase (runTestCaseFunction, isNewerCucumberVersion = fa
714
716
  if (isKnownTestsEnabled && !isAttemptToFix) {
715
717
  isNew = isNewTest(testSuitePath, pickle.name)
716
718
  if (isNew) {
719
+ newTestPickleIds.add(pickle.id)
717
720
  numRetriesByPickleId.set(pickle.id, 0)
718
721
  }
719
722
  }