dd-trace 3.12.1 → 3.15.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 (101) hide show
  1. package/LICENSE-3rdparty.csv +1 -0
  2. package/README.md +5 -5
  3. package/ci/init.js +3 -1
  4. package/index.d.ts +100 -1
  5. package/package.json +5 -4
  6. package/packages/datadog-instrumentations/src/aws-sdk.js +86 -0
  7. package/packages/datadog-instrumentations/src/cucumber.js +74 -15
  8. package/packages/datadog-instrumentations/src/cypress.js +1 -1
  9. package/packages/datadog-instrumentations/src/fs.js +358 -0
  10. package/packages/datadog-instrumentations/src/helpers/hooks.js +4 -0
  11. package/packages/datadog-instrumentations/src/helpers/register.js +1 -1
  12. package/packages/datadog-instrumentations/src/jest.js +24 -23
  13. package/packages/datadog-instrumentations/src/ldapjs.js +12 -2
  14. package/packages/datadog-instrumentations/src/mocha.js +10 -7
  15. package/packages/datadog-instrumentations/src/mongoose.js +1 -1
  16. package/packages/datadog-instrumentations/src/mysql.js +7 -1
  17. package/packages/datadog-instrumentations/src/mysql2.js +7 -1
  18. package/packages/datadog-instrumentations/src/next.js +2 -1
  19. package/packages/datadog-instrumentations/src/playwright.js +263 -0
  20. package/packages/datadog-plugin-aws-sdk/src/base.js +12 -5
  21. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +2 -2
  22. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +29 -24
  23. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +31 -16
  24. package/packages/datadog-plugin-cucumber/src/index.js +42 -11
  25. package/packages/datadog-plugin-cypress/src/plugin.js +129 -4
  26. package/packages/datadog-plugin-cypress/src/support.js +5 -0
  27. package/packages/datadog-plugin-fs/src/index.js +45 -0
  28. package/packages/datadog-plugin-hapi/src/index.js +5 -1
  29. package/packages/datadog-plugin-http/src/server.js +1 -1
  30. package/packages/datadog-plugin-http2/src/server.js +1 -1
  31. package/packages/datadog-plugin-jest/src/index.js +40 -70
  32. package/packages/datadog-plugin-mocha/src/index.js +44 -64
  33. package/packages/datadog-plugin-mysql/src/index.js +8 -7
  34. package/packages/datadog-plugin-playwright/src/index.js +112 -0
  35. package/packages/datadog-shimmer/src/shimmer.js +28 -11
  36. package/packages/dd-trace/src/appsec/addresses.js +3 -1
  37. package/packages/dd-trace/src/appsec/blocking.js +35 -9
  38. package/packages/dd-trace/src/appsec/callbacks/ddwaf.js +1 -1
  39. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
  40. package/packages/dd-trace/src/appsec/iast/analyzers/path-traversal-analyzer.js +60 -0
  41. package/packages/dd-trace/src/appsec/iast/iast-context.js +6 -2
  42. package/packages/dd-trace/src/appsec/iast/index.js +3 -2
  43. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +5 -2
  44. package/packages/dd-trace/src/appsec/index.js +5 -5
  45. package/packages/dd-trace/src/appsec/recommended.json +320 -184
  46. package/packages/dd-trace/src/appsec/remote_config/capabilities.js +2 -1
  47. package/packages/dd-trace/src/appsec/remote_config/index.js +3 -0
  48. package/packages/dd-trace/src/appsec/reporter.js +14 -14
  49. package/packages/dd-trace/src/appsec/sdk/index.js +41 -0
  50. package/packages/dd-trace/src/appsec/sdk/noop.js +17 -0
  51. package/packages/dd-trace/src/appsec/sdk/set_user.js +30 -0
  52. package/packages/dd-trace/src/appsec/sdk/track_event.js +74 -0
  53. package/packages/dd-trace/src/appsec/sdk/user_blocking.js +73 -0
  54. package/packages/dd-trace/src/appsec/sdk/utils.js +10 -0
  55. package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +1 -5
  56. package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +1 -5
  57. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +48 -11
  58. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +7 -1
  59. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-itr-configuration.js +4 -2
  60. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +5 -3
  61. package/packages/dd-trace/src/config.js +63 -7
  62. package/packages/dd-trace/src/encode/0.4.js +1 -1
  63. package/packages/dd-trace/src/encode/0.5.js +1 -1
  64. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +44 -4
  65. package/packages/dd-trace/src/encode/coverage-ci-visibility.js +52 -37
  66. package/packages/dd-trace/src/encode/tags-processors.js +3 -2
  67. package/packages/dd-trace/src/exporters/common/request.js +10 -3
  68. package/packages/dd-trace/src/lambda/handler.js +5 -6
  69. package/packages/dd-trace/src/log/channels.js +47 -0
  70. package/packages/dd-trace/src/log/index.js +79 -0
  71. package/packages/dd-trace/src/log/writer.js +124 -0
  72. package/packages/dd-trace/src/metrics.js +18 -0
  73. package/packages/dd-trace/src/noop/proxy.js +5 -2
  74. package/packages/dd-trace/src/opentracing/propagation/text_map.js +188 -36
  75. package/packages/dd-trace/src/opentracing/propagation/tracestate.js +99 -0
  76. package/packages/dd-trace/src/opentracing/span.js +2 -1
  77. package/packages/dd-trace/src/opentracing/span_context.js +6 -3
  78. package/packages/dd-trace/src/plugins/ci_plugin.js +72 -12
  79. package/packages/dd-trace/src/plugins/index.js +2 -0
  80. package/packages/dd-trace/src/plugins/util/ci.js +13 -21
  81. package/packages/dd-trace/src/plugins/util/exec.js +2 -2
  82. package/packages/dd-trace/src/plugins/util/git.js +16 -1
  83. package/packages/dd-trace/src/{appsec → plugins/util}/ip_extractor.js +1 -1
  84. package/packages/dd-trace/src/plugins/util/test.js +53 -10
  85. package/packages/dd-trace/src/plugins/util/user-provided-git.js +2 -7
  86. package/packages/dd-trace/src/plugins/util/web.js +11 -0
  87. package/packages/dd-trace/src/profiler.js +3 -0
  88. package/packages/dd-trace/src/profiling/config.js +8 -3
  89. package/packages/dd-trace/src/profiling/exporters/file.js +13 -2
  90. package/packages/dd-trace/src/profiling/profiler.js +23 -6
  91. package/packages/dd-trace/src/profiling/profilers/wall.js +1 -0
  92. package/packages/dd-trace/src/proxy.js +2 -0
  93. package/packages/dd-trace/src/span_processor.js +1 -1
  94. package/packages/dd-trace/src/span_sampler.js +68 -52
  95. package/packages/dd-trace/src/startup-log.js +3 -6
  96. package/packages/dd-trace/src/telemetry/index.js +23 -2
  97. package/packages/dd-trace/src/telemetry/send-data.js +4 -1
  98. package/packages/dd-trace/src/tracer.js +0 -16
  99. package/scripts/check-proposal-labels.js +71 -0
  100. package/packages/dd-trace/src/log.js +0 -143
  101. /package/packages/dd-trace/src/{appsec → plugins/util}/ip_blocklist.js +0 -0
@@ -0,0 +1,358 @@
1
+
2
+ 'use strict'
3
+
4
+ const {
5
+ channel,
6
+ addHook,
7
+ AsyncResource
8
+ } = require('./helpers/instrument')
9
+ const shimmer = require('../../datadog-shimmer')
10
+
11
+ const startChannel = channel('apm:fs:operation:start')
12
+ const finishChannel = channel('apm:fs:operation:finish')
13
+ const errorChannel = channel('apm:fs:operation:error')
14
+ const ddFhSym = Symbol('ddFileHandle')
15
+ let kHandle, kDirReadPromisified, kDirClosePromisified
16
+
17
+ const paramsByMethod = {
18
+ access: ['path', 'mode'],
19
+ appendFile: ['path', 'data', 'options'],
20
+ chmod: ['path', 'mode'],
21
+ chown: ['path', 'uid', 'gid'],
22
+ close: ['fd'],
23
+ copyFile: ['src', 'dest', 'mode'],
24
+ cp: ['src', 'dest', 'options'],
25
+ exists: ['path'],
26
+ fchmod: ['fd', 'mode'],
27
+ fchown: ['fd', 'uid', 'gid'],
28
+ fdatasync: ['fd'],
29
+ fstat: ['fd', 'options'],
30
+ fsync: ['fd'],
31
+ ftruncate: ['fd', 'len'],
32
+ futimes: ['fd', 'atime', 'mtime'],
33
+ lchmod: ['path', 'mode'],
34
+ lchown: ['path', 'uid', 'gid'],
35
+ link: ['existingPath', 'newPath'],
36
+ lstat: ['path', 'options'],
37
+ lutimes: ['path', 'atime', 'mtime'],
38
+ mkdir: ['path', 'options'],
39
+ mkdtemp: ['prefix', 'options'],
40
+ open: ['path', 'flag', 'mode'],
41
+ opendir: ['path', 'options'],
42
+ read: ['fd'],
43
+ readdir: ['path', 'options'],
44
+ readFile: ['path', 'options'],
45
+ readlink: ['path', 'options'],
46
+ readv: ['fd'],
47
+ realpath: ['path', 'options'],
48
+ rename: ['oldPath', 'newPath'],
49
+ rmdir: ['path', 'options'],
50
+ rm: ['path', 'options'],
51
+ stat: ['path', 'options'],
52
+ symlink: ['target', 'path', 'type'],
53
+ truncate: ['path', 'len'],
54
+ unlink: ['path'],
55
+ utimes: ['path', 'atime', 'mtime'],
56
+ write: ['fd'],
57
+ writeFile: ['file', 'data', 'options'],
58
+ writev: ['fd']
59
+ }
60
+
61
+ const watchMethods = {
62
+ unwatchFile: ['path', 'listener'],
63
+ watch: ['path', 'options', 'listener'],
64
+ watchFile: ['path', 'options', 'listener']
65
+ }
66
+
67
+ const paramsByFileHandleMethods = {
68
+ appendFile: ['data', 'options'],
69
+ chmod: ['mode'],
70
+ chown: ['uid', 'gid'],
71
+ close: [],
72
+ createReadStream: ['options'],
73
+ createWriteStream: ['options'],
74
+ datasync: [],
75
+ read: ['buffer', 'offset', 'length', 'position'],
76
+ readableWebStream: [],
77
+ readFile: ['options'],
78
+ readLines: ['options'],
79
+ readv: ['buffers', 'position'],
80
+ stat: ['options'],
81
+ sync: [],
82
+ truncate: ['len'],
83
+ utimes: ['atime', 'mtime'],
84
+ write: ['buffer', 'offset', 'length', 'position'],
85
+ writeFile: ['data', 'options'],
86
+ writev: ['buffers', 'position']
87
+ }
88
+ const names = ['fs', 'node:fs']
89
+ names.forEach(name => {
90
+ addHook({ name }, fs => {
91
+ const asyncMethods = Object.keys(paramsByMethod)
92
+ const syncMethods = asyncMethods.map(name => `${name}Sync`)
93
+
94
+ massWrap(fs, asyncMethods, createWrapFunction())
95
+ massWrap(fs, syncMethods, createWrapFunction())
96
+ massWrap(fs.promises, asyncMethods, createWrapFunction('promises.'))
97
+
98
+ wrap(fs.realpath, 'native', createWrapFunction('', 'realpath.native'))
99
+ wrap(fs.realpathSync, 'native', createWrapFunction('', 'realpath.native'))
100
+ wrap(fs.promises.realpath, 'native', createWrapFunction('', 'realpath.native'))
101
+
102
+ wrap(fs, 'createReadStream', wrapCreateStream)
103
+ wrap(fs, 'createWriteStream', wrapCreateStream)
104
+ if (fs.Dir) {
105
+ wrap(fs.Dir.prototype, 'close', createWrapFunction('dir.'))
106
+ wrap(fs.Dir.prototype, 'closeSync', createWrapFunction('dir.'))
107
+ wrap(fs.Dir.prototype, 'read', createWrapFunction('dir.'))
108
+ wrap(fs.Dir.prototype, 'readSync', createWrapFunction('dir.'))
109
+ wrap(fs.Dir.prototype, Symbol.asyncIterator, createWrapDirAsyncIterator())
110
+ }
111
+
112
+ wrap(fs, 'unwatchFile', createWatchWrapFunction())
113
+ wrap(fs, 'watch', createWatchWrapFunction())
114
+ wrap(fs, 'watchFile', createWatchWrapFunction())
115
+
116
+ return fs
117
+ })
118
+ })
119
+ function isFirstMethodReturningFileHandle (original) {
120
+ return !kHandle && original.name === 'open'
121
+ }
122
+ function wrapFileHandle (fh) {
123
+ const fileHandlePrototype = getFileHandlePrototype(fh)
124
+ const desc = Reflect.getOwnPropertyDescriptor(fileHandlePrototype, kHandle)
125
+ if (!desc || !desc.get) {
126
+ Reflect.defineProperty(fileHandlePrototype, kHandle, {
127
+ get () {
128
+ return this[ddFhSym]
129
+ },
130
+ set (h) {
131
+ this[ddFhSym] = h
132
+ wrap(this, 'close', createWrapFunction('filehandle.'))
133
+ },
134
+ configurable: true
135
+ })
136
+ }
137
+ for (const name of Reflect.ownKeys(fileHandlePrototype)) {
138
+ if (typeof name !== 'string' || name === 'constructor' || name === 'fd' || name === 'getAsyncId') {
139
+ continue
140
+ }
141
+ wrap(fileHandlePrototype, name, createWrapFunction('filehandle.'))
142
+ }
143
+ }
144
+
145
+ function getFileHandlePrototype (fh) {
146
+ if (!kHandle) {
147
+ kHandle = Reflect.ownKeys(fh).find(key => typeof key === 'symbol' && key.toString().includes('kHandle'))
148
+ }
149
+ return Object.getPrototypeOf(fh)
150
+ }
151
+
152
+ function getSymbolName (sym) {
153
+ return sym.description || sym.toString()
154
+ }
155
+ function initDirAsyncIteratorProperties (iterator) {
156
+ const keys = Reflect.ownKeys(iterator)
157
+ for (const key of keys) {
158
+ if (kDirReadPromisified && kDirClosePromisified) break
159
+ if (typeof key !== 'symbol') continue
160
+ if (!kDirReadPromisified && getSymbolName(key).includes('kDirReadPromisified')) {
161
+ kDirReadPromisified = key
162
+ }
163
+ if (!kDirClosePromisified && getSymbolName(key).includes('kDirClosePromisified')) {
164
+ kDirClosePromisified = key
165
+ }
166
+ }
167
+ }
168
+
169
+ function createWrapDirAsyncIterator () {
170
+ return function wrapDirAsyncIterator (asyncIterator) {
171
+ return function wrappedAsyncIterator () {
172
+ if (!kDirReadPromisified || !kDirClosePromisified) {
173
+ initDirAsyncIteratorProperties(this)
174
+ }
175
+ wrap(this, kDirReadPromisified, createWrapFunction('dir.', 'read'))
176
+ wrap(this, kDirClosePromisified, createWrapFunction('dir.', 'close'))
177
+ return asyncIterator.apply(this, arguments)
178
+ }
179
+ }
180
+ }
181
+
182
+ function wrapCreateStream (original) {
183
+ const classes = {
184
+ createReadStream: 'ReadStream',
185
+ createWriteStream: 'WriteStream'
186
+ }
187
+ const name = classes[original.name]
188
+
189
+ return function (path, options) {
190
+ if (!startChannel.hasSubscribers) return original.apply(this, arguments)
191
+
192
+ const innerResource = new AsyncResource('bound-anonymous-fn')
193
+ const message = getMessage(name, ['path', 'options'], arguments)
194
+
195
+ return innerResource.runInAsyncScope(() => {
196
+ startChannel.publish(message)
197
+
198
+ try {
199
+ const stream = original.apply(this, arguments)
200
+ const onError = innerResource.bind(error => {
201
+ errorChannel.publish(error)
202
+ onFinish()
203
+ })
204
+ const onFinish = innerResource.bind(() => {
205
+ finishChannel.publish()
206
+ stream.off('close', onFinish)
207
+ stream.off('end', onFinish)
208
+ stream.off('finish', onFinish)
209
+ stream.off('error', onError)
210
+ })
211
+
212
+ stream.once('close', onFinish)
213
+ stream.once('end', onFinish)
214
+ stream.once('finish', onFinish)
215
+ stream.once('error', onError)
216
+
217
+ return stream
218
+ } catch (error) {
219
+ errorChannel.publish(error)
220
+ finishChannel.publish()
221
+ }
222
+ })
223
+ }
224
+ }
225
+
226
+ function getMethodParamsRelationByPrefix (prefix) {
227
+ if (prefix === 'filehandle.') {
228
+ return paramsByFileHandleMethods
229
+ }
230
+ return paramsByMethod
231
+ }
232
+
233
+ function createWatchWrapFunction (override = '') {
234
+ return function wrapFunction (original) {
235
+ const name = override || original.name
236
+ const method = name
237
+ const operation = name
238
+ return function () {
239
+ if (!startChannel.hasSubscribers) return original.apply(this, arguments)
240
+ const message = getMessage(method, watchMethods[operation], arguments, this)
241
+ const innerResource = new AsyncResource('bound-anonymous-fn')
242
+ return innerResource.runInAsyncScope(() => {
243
+ startChannel.publish(message)
244
+ try {
245
+ const result = original.apply(this, arguments)
246
+ finishChannel.publish()
247
+ return result
248
+ } catch (error) {
249
+ errorChannel.publish(error)
250
+ finishChannel.publish()
251
+ throw error
252
+ }
253
+ })
254
+ }
255
+ }
256
+ }
257
+
258
+ function createWrapFunction (prefix = '', override = '') {
259
+ return function wrapFunction (original) {
260
+ const name = override || original.name
261
+ const method = `${prefix}${name}`
262
+ const operation = name.match(/^(.+?)(Sync)?(\.native)?$/)[1]
263
+
264
+ return function () {
265
+ if (!startChannel.hasSubscribers) return original.apply(this, arguments)
266
+
267
+ const lastIndex = arguments.length - 1
268
+ const cb = typeof arguments[lastIndex] === 'function' && arguments[lastIndex]
269
+ const innerResource = new AsyncResource('bound-anonymous-fn')
270
+ const message = getMessage(method, getMethodParamsRelationByPrefix(prefix)[operation], arguments, this)
271
+
272
+ if (cb) {
273
+ const outerResource = new AsyncResource('bound-anonymous-fn')
274
+
275
+ arguments[lastIndex] = innerResource.bind(function (e) {
276
+ if (typeof e === 'object') { // fs.exists receives a boolean
277
+ errorChannel.publish(e)
278
+ }
279
+
280
+ finishChannel.publish()
281
+
282
+ return outerResource.runInAsyncScope(() => cb.apply(this, arguments))
283
+ })
284
+ }
285
+
286
+ return innerResource.runInAsyncScope(() => {
287
+ startChannel.publish(message)
288
+ try {
289
+ const result = original.apply(this, arguments)
290
+ if (cb) return result
291
+ if (result && typeof result.then === 'function') {
292
+ // TODO method open returning promise and filehandle prototype not initialized, initialize it
293
+
294
+ return result.then(
295
+ value => {
296
+ if (isFirstMethodReturningFileHandle(original)) {
297
+ wrapFileHandle(value)
298
+ }
299
+ finishChannel.publish()
300
+ return value
301
+ },
302
+ error => {
303
+ errorChannel.publish(error)
304
+ finishChannel.publish()
305
+ throw error
306
+ }
307
+ )
308
+ }
309
+
310
+ finishChannel.publish()
311
+
312
+ return result
313
+ } catch (error) {
314
+ errorChannel.publish(error)
315
+ finishChannel.publish()
316
+ throw error
317
+ }
318
+ })
319
+ }
320
+ }
321
+ }
322
+
323
+ function getMessage (operation, params, args, self) {
324
+ const metadata = {}
325
+ if (params) {
326
+ for (let i = 0; i < params.length; i++) {
327
+ if (!params[i] || typeof args[i] === 'function') continue
328
+ metadata[params[i]] = args[i]
329
+ }
330
+ }
331
+
332
+ if (self) {
333
+ // For `Dir` the path is available on `this.path`
334
+ if (self.path) {
335
+ metadata.path = self.path
336
+ }
337
+ // For FileHandle fs is available on `this.fd`
338
+ if (self.fd) {
339
+ metadata.fd = self.fd
340
+ }
341
+ }
342
+
343
+ return { operation, ...metadata }
344
+ }
345
+
346
+ function massWrap (target, methods, wrapper) {
347
+ for (const method of methods) {
348
+ wrap(target, method, wrapper)
349
+ }
350
+ }
351
+
352
+ function wrap (target, method, wrapper) {
353
+ try {
354
+ shimmer.wrap(target, method, wrapper)
355
+ } catch (e) {
356
+ // skip unavailable method
357
+ }
358
+ }
@@ -1,7 +1,9 @@
1
1
  'use strict'
2
2
 
3
3
  module.exports = {
4
+ '@aws-sdk/smithy-client': () => require('../aws-sdk'),
4
5
  '@cucumber/cucumber': () => require('../cucumber'),
6
+ '@playwright/test': () => require('../playwright'),
5
7
  '@elastic/elasticsearch': () => require('../elasticsearch'),
6
8
  '@elastic/transport': () => require('../elasticsearch'),
7
9
  '@google-cloud/pubsub': () => require('../google-cloud-pubsub'),
@@ -31,6 +33,8 @@ module.exports = {
31
33
  'express': () => require('../express'),
32
34
  'fastify': () => require('../fastify'),
33
35
  'find-my-way': () => require('../find-my-way'),
36
+ 'fs': () => require('../fs'),
37
+ 'node:fs': () => require('../fs'),
34
38
  'graphql': () => require('../graphql'),
35
39
  'grpc': () => require('../grpc'),
36
40
  'hapi': () => require('../hapi'),
@@ -32,7 +32,7 @@ for (const packageName of names) {
32
32
  try {
33
33
  loadChannel.publish({ name, version, file })
34
34
 
35
- moduleExports = hook(moduleExports)
35
+ moduleExports = hook(moduleExports, version)
36
36
  } catch (e) {
37
37
  log.error(e)
38
38
  }
@@ -72,7 +72,7 @@ function getTestEnvironmentOptions (config) {
72
72
  return {}
73
73
  }
74
74
 
75
- function getWrappedEnvironment (BaseEnvironment) {
75
+ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
76
76
  return class DatadogEnvironment extends BaseEnvironment {
77
77
  constructor (config, context) {
78
78
  super(config, context)
@@ -116,7 +116,8 @@ function getWrappedEnvironment (BaseEnvironment) {
116
116
  name: getJestTestName(event.test),
117
117
  suite: this.testSuite,
118
118
  runner: 'jest-circus',
119
- testParameters
119
+ testParameters,
120
+ frameworkVersion: jestVersion
120
121
  })
121
122
  originalTestFns.set(event.test, event.test.fn)
122
123
  event.test.fn = asyncResource.bind(event.test.fn)
@@ -142,7 +143,8 @@ function getWrappedEnvironment (BaseEnvironment) {
142
143
  testSkippedCh.publish({
143
144
  name: getJestTestName(event.test),
144
145
  suite: this.testSuite,
145
- runner: 'jest-circus'
146
+ runner: 'jest-circus',
147
+ frameworkVersion: jestVersion
146
148
  })
147
149
  })
148
150
  }
@@ -150,14 +152,14 @@ function getWrappedEnvironment (BaseEnvironment) {
150
152
  }
151
153
  }
152
154
 
153
- function getTestEnvironment (pkg) {
155
+ function getTestEnvironment (pkg, jestVersion) {
154
156
  if (pkg.default) {
155
- const wrappedTestEnvironment = getWrappedEnvironment(pkg.default)
157
+ const wrappedTestEnvironment = getWrappedEnvironment(pkg.default, jestVersion)
156
158
  pkg.default = wrappedTestEnvironment
157
159
  pkg.TestEnvironment = wrappedTestEnvironment
158
160
  return pkg
159
161
  }
160
- return getWrappedEnvironment(pkg)
162
+ return getWrappedEnvironment(pkg, jestVersion)
161
163
  }
162
164
 
163
165
  addHook({
@@ -170,7 +172,7 @@ addHook({
170
172
  versions: ['>=24.8.0']
171
173
  }, getTestEnvironment)
172
174
 
173
- function cliWrapper (cli) {
175
+ function cliWrapper (cli, jestVersion) {
174
176
  const wrapped = shimmer.wrap(cli, 'runCLI', runCLI => async function () {
175
177
  let onDone
176
178
  const configurationPromise = new Promise((resolve) => {
@@ -186,13 +188,12 @@ function cliWrapper (cli) {
186
188
 
187
189
  try {
188
190
  const { err, itrConfig } = await configurationPromise
189
- if (err) {
190
- log.error(err)
191
+ if (!err) {
192
+ isCodeCoverageEnabled = itrConfig.isCodeCoverageEnabled
193
+ isSuitesSkippingEnabled = itrConfig.isSuitesSkippingEnabled
191
194
  }
192
- isCodeCoverageEnabled = itrConfig.isCodeCoverageEnabled
193
- isSuitesSkippingEnabled = itrConfig.isSuitesSkippingEnabled
194
- } catch (e) {
195
- log.error(e)
195
+ } catch (err) {
196
+ log.error(err)
196
197
  }
197
198
 
198
199
  if (isSuitesSkippingEnabled) {
@@ -206,13 +207,11 @@ function cliWrapper (cli) {
206
207
 
207
208
  try {
208
209
  const { err, skippableSuites: receivedSkippableSuites } = await skippableSuitesPromise
209
- if (err) {
210
- log.error(err)
211
- } else {
210
+ if (!err) {
212
211
  skippableSuites = receivedSkippableSuites
213
212
  }
214
- } catch (e) {
215
- log.error(e)
213
+ } catch (err) {
214
+ log.error(err)
216
215
  }
217
216
  }
218
217
 
@@ -220,7 +219,7 @@ function cliWrapper (cli) {
220
219
 
221
220
  const processArgv = process.argv.slice(2).join(' ')
222
221
  sessionAsyncResource.runInAsyncScope(() => {
223
- testSessionStartCh.publish(`jest ${processArgv}`)
222
+ testSessionStartCh.publish({ command: `jest ${processArgv}`, frameworkVersion: jestVersion })
224
223
  })
225
224
 
226
225
  const result = await runCLI.apply(this, arguments)
@@ -288,7 +287,7 @@ addHook({
288
287
  versions: ['>=24.8.0']
289
288
  }, cliWrapper)
290
289
 
291
- function jestAdapterWrapper (jestAdapter) {
290
+ function jestAdapterWrapper (jestAdapter, jestVersion) {
292
291
  const adapter = jestAdapter.default ? jestAdapter.default : jestAdapter
293
292
  const newAdapter = shimmer.wrap(adapter, function () {
294
293
  const environment = arguments[2]
@@ -299,7 +298,8 @@ function jestAdapterWrapper (jestAdapter) {
299
298
  return asyncResource.runInAsyncScope(() => {
300
299
  testSuiteStartCh.publish({
301
300
  testSuite: environment.testSuite,
302
- testEnvironmentOptions: environment.testEnvironmentOptions
301
+ testEnvironmentOptions: environment.testEnvironmentOptions,
302
+ frameworkVersion: jestVersion
303
303
  })
304
304
  return adapter.apply(this, arguments).then(suiteResults => {
305
305
  const { numFailingTests, skipped, failureMessage: errorMessage } = suiteResults
@@ -440,7 +440,7 @@ addHook({
440
440
  versions: ['24.8.0 - 24.9.0']
441
441
  }, jestConfigSyncWrapper)
442
442
 
443
- function jasmineAsyncInstallWraper (jasmineAsyncInstallExport) {
443
+ function jasmineAsyncInstallWraper (jasmineAsyncInstallExport, jestVersion) {
444
444
  return function (globalConfig, globalInput) {
445
445
  globalInput._ddtrace = global._ddtrace
446
446
  shimmer.wrap(globalInput.jasmine.Spec.prototype, 'execute', execute => function (onComplete) {
@@ -450,7 +450,8 @@ function jasmineAsyncInstallWraper (jasmineAsyncInstallExport) {
450
450
  testStartCh.publish({
451
451
  name: this.getFullName(),
452
452
  suite: testSuite,
453
- runner: 'jest-jasmine2'
453
+ runner: 'jest-jasmine2',
454
+ frameworkVersion: jestVersion
454
455
  })
455
456
  const spec = this
456
457
  const callback = asyncResource.bind(function () {
@@ -35,7 +35,7 @@ function wrapEmitter (corkedEmitter) {
35
35
  }
36
36
  arguments[1] = bindedFn
37
37
  }
38
- on.apply(this, arguments)
38
+ return on.apply(this, arguments)
39
39
  }
40
40
  shimmer.wrap(corkedEmitter, 'on', addListener)
41
41
  shimmer.wrap(corkedEmitter, 'addListener', addListener)
@@ -47,7 +47,7 @@ function wrapEmitter (corkedEmitter) {
47
47
  arguments[1] = emitterOn
48
48
  }
49
49
  }
50
- off.apply(this, arguments)
50
+ return off.apply(this, arguments)
51
51
  }
52
52
  shimmer.wrap(corkedEmitter, 'off', removeListener)
53
53
  shimmer.wrap(corkedEmitter, 'removeListener', removeListener)
@@ -87,5 +87,15 @@ addHook({ name: 'ldapjs', versions: ['>=2'] }, ldapjs => {
87
87
  return _send.apply(this, arguments)
88
88
  })
89
89
 
90
+ shimmer.wrap(ldapjs.Client.prototype, 'bind', bind => function (dn, password, controls, callback) {
91
+ if (typeof controls === 'function') {
92
+ arguments[2] = AsyncResource.bind(controls)
93
+ } else if (typeof callback === 'function') {
94
+ arguments[3] = AsyncResource.bind(callback)
95
+ }
96
+
97
+ return bind.apply(this, arguments)
98
+ })
99
+
90
100
  return ldapjs
91
101
  })
@@ -2,7 +2,6 @@ const { createCoverageMap } = require('istanbul-lib-coverage')
2
2
 
3
3
  const { addHook, channel, AsyncResource } = require('./helpers/instrument')
4
4
  const shimmer = require('../../datadog-shimmer')
5
- const log = require('../../dd-trace/src/log')
6
5
  const {
7
6
  getCoveredFilenamesFromCoverage,
8
7
  resetCoverage,
@@ -39,6 +38,7 @@ const testFileToSuiteAr = new Map()
39
38
  const originalCoverageMap = createCoverageMap()
40
39
 
41
40
  let suitesToSkip = []
41
+ let frameworkVersion
42
42
 
43
43
  function getSuitesByTestFile (root) {
44
44
  const suitesByTestFile = {}
@@ -128,7 +128,7 @@ function mochaHook (Runner) {
128
128
  this.once('start', testRunAsyncResource.bind(function () {
129
129
  const processArgv = process.argv.slice(2).join(' ')
130
130
  const command = `mocha ${processArgv}`
131
- testSessionStartCh.publish(command)
131
+ testSessionStartCh.publish({ command, frameworkVersion })
132
132
  }))
133
133
 
134
134
  this.on('suite', function (suite) {
@@ -313,9 +313,9 @@ addHook({
313
313
  name: 'mocha',
314
314
  versions: ['>=5.2.0'],
315
315
  file: 'lib/mocha.js'
316
- }, (Mocha) => {
316
+ }, (Mocha, mochaVersion) => {
317
+ frameworkVersion = mochaVersion
317
318
  const mochaRunAsyncResource = new AsyncResource('bound-anonymous-fn')
318
-
319
319
  /**
320
320
  * Get ITR configuration and skippable suites
321
321
  * If ITR is disabled, `onDone` is called immediately on the subscriber
@@ -330,7 +330,6 @@ addHook({
330
330
 
331
331
  const onReceivedSkippableSuites = ({ err, skippableSuites }) => {
332
332
  if (err) {
333
- log.error(err)
334
333
  suitesToSkip = []
335
334
  } else {
336
335
  suitesToSkip = skippableSuites
@@ -342,7 +341,6 @@ addHook({
342
341
 
343
342
  const onReceivedConfiguration = ({ err }) => {
344
343
  if (err) {
345
- log.error(err)
346
344
  return global.run()
347
345
  }
348
346
  if (!skippableSuitesCh.hasSubscribers) {
@@ -417,8 +415,13 @@ addHook({
417
415
 
418
416
  // we store the original function, not to lose it
419
417
  originalFns.set(newFn, this.fn)
420
-
421
418
  this.fn = newFn
419
+
420
+ // Temporarily keep functionality when .asyncResource is removed from node
421
+ // in https://github.com/nodejs/node/pull/46432
422
+ if (!this.fn.asyncResource) {
423
+ this.fn.asyncResource = asyncResource
424
+ }
422
425
  }
423
426
  }
424
427
 
@@ -19,7 +19,7 @@ function wrapAddQueue (addQueue) {
19
19
 
20
20
  addHook({
21
21
  name: 'mongoose',
22
- versions: ['>=4.6.4']
22
+ versions: ['>=4.6.4 <7'] // TODO: Mongoose v7 compat
23
23
  }, mongoose => {
24
24
  if (mongoose.Promise !== global.Promise) {
25
25
  shimmer.wrap(mongoose.Promise.prototype, 'then', wrapThen)
@@ -19,13 +19,19 @@ addHook({ name: 'mysql', file: 'lib/Connection.js', versions: ['>=2'] }, Connect
19
19
 
20
20
  const sql = arguments[0].sql ? arguments[0].sql : arguments[0]
21
21
  const conf = this.config
22
+ const payload = { sql, conf }
22
23
 
23
24
  const callbackResource = new AsyncResource('bound-anonymous-fn')
24
25
  const asyncResource = new AsyncResource('bound-anonymous-fn')
25
26
 
26
27
  return asyncResource.runInAsyncScope(() => {
27
- startCh.publish({ sql, conf })
28
+ startCh.publish(payload)
28
29
 
30
+ if (arguments[0].sql) {
31
+ arguments[0].sql = payload.sql
32
+ } else {
33
+ arguments[0] = payload.sql
34
+ }
29
35
  try {
30
36
  const res = query.apply(this, arguments)
31
37
 
@@ -45,8 +45,14 @@ addHook({ name: 'mysql2', file: 'lib/connection.js', versions: ['>=1'] }, Connec
45
45
 
46
46
  return asyncResource.bind(function executeWithTrace (packet, connection) {
47
47
  const sql = cmd.statement ? cmd.statement.query : cmd.sql
48
+ const payload = { sql, conf: config }
49
+ startCh.publish(payload)
48
50
 
49
- startCh.publish({ sql, conf: config })
51
+ if (cmd.statement) {
52
+ cmd.statement.query = payload.sql
53
+ } else {
54
+ cmd.sql = payload.sql
55
+ }
50
56
 
51
57
  if (this.onResult) {
52
58
  const onResult = callbackResource.bind(this.onResult)
@@ -127,7 +127,8 @@ function finish (req, res, result, err) {
127
127
  return result
128
128
  }
129
129
 
130
- addHook({ name: 'next', versions: ['>=11.1'], file: 'dist/server/next-server.js' }, nextServer => {
130
+ // TODO: 13.2 support
131
+ addHook({ name: 'next', versions: ['>=11.1 <13.2'], file: 'dist/server/next-server.js' }, nextServer => {
131
132
  const Server = nextServer.default
132
133
 
133
134
  shimmer.wrap(Server.prototype, 'handleRequest', wrapHandleRequest)