dd-trace 3.12.0 → 3.13.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 (46) hide show
  1. package/ci/init.js +1 -0
  2. package/index.d.ts +50 -0
  3. package/package.json +1 -1
  4. package/packages/datadog-instrumentations/src/fs.js +357 -0
  5. package/packages/datadog-instrumentations/src/helpers/hooks.js +3 -0
  6. package/packages/datadog-instrumentations/src/helpers/register.js +0 -2
  7. package/packages/datadog-instrumentations/src/jest.js +11 -1
  8. package/packages/datadog-instrumentations/src/mocha.js +3 -2
  9. package/packages/datadog-instrumentations/src/mysql.js +7 -1
  10. package/packages/datadog-instrumentations/src/mysql2.js +7 -1
  11. package/packages/datadog-instrumentations/src/playwright.js +236 -0
  12. package/packages/datadog-plugin-fs/src/index.js +45 -0
  13. package/packages/datadog-plugin-jest/src/index.js +45 -23
  14. package/packages/datadog-plugin-mocha/src/index.js +34 -6
  15. package/packages/datadog-plugin-mysql/src/index.js +8 -7
  16. package/packages/datadog-plugin-playwright/src/index.js +171 -0
  17. package/packages/dd-trace/src/appsec/callbacks/ddwaf.js +1 -1
  18. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
  19. package/packages/dd-trace/src/appsec/iast/analyzers/path-traversal-analyzer.js +60 -0
  20. package/packages/dd-trace/src/appsec/index.js +1 -1
  21. package/packages/dd-trace/src/appsec/recommended.json +247 -112
  22. package/packages/dd-trace/src/appsec/sdk/index.js +23 -0
  23. package/packages/dd-trace/src/appsec/sdk/noop.js +11 -0
  24. package/packages/dd-trace/src/appsec/sdk/track_event.js +74 -0
  25. package/packages/dd-trace/src/appsec/sdk/utils.js +10 -0
  26. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +1 -1
  27. package/packages/dd-trace/src/config.js +7 -0
  28. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +44 -4
  29. package/packages/dd-trace/src/encode/coverage-ci-visibility.js +52 -37
  30. package/packages/dd-trace/src/lambda/runtime/patch.js +1 -1
  31. package/packages/dd-trace/src/lambda/runtime/ritm.js +6 -11
  32. package/packages/dd-trace/src/log/channels.js +47 -0
  33. package/packages/dd-trace/src/log/index.js +79 -0
  34. package/packages/dd-trace/src/log/writer.js +108 -0
  35. package/packages/dd-trace/src/noop/proxy.js +3 -0
  36. package/packages/dd-trace/src/plugins/index.js +1 -0
  37. package/packages/dd-trace/src/plugins/util/ci.js +13 -21
  38. package/packages/dd-trace/src/{appsec → plugins/util}/ip_blocklist.js +0 -0
  39. package/packages/dd-trace/src/{appsec → plugins/util}/ip_extractor.js +1 -1
  40. package/packages/dd-trace/src/plugins/util/test.js +27 -10
  41. package/packages/dd-trace/src/plugins/util/user-provided-git.js +2 -7
  42. package/packages/dd-trace/src/plugins/util/web.js +11 -0
  43. package/packages/dd-trace/src/proxy.js +2 -0
  44. package/packages/dd-trace/src/startup-log.js +1 -1
  45. package/scripts/check-proposal-labels.js +71 -0
  46. package/packages/dd-trace/src/log.js +0 -143
package/ci/init.js CHANGED
@@ -34,6 +34,7 @@ so dd-trace will not be initialized.`)
34
34
 
35
35
  if (shouldInit) {
36
36
  tracer.init(options)
37
+ tracer.use('fs', false)
37
38
  }
38
39
 
39
40
  module.exports = tracer
package/index.d.ts CHANGED
@@ -115,6 +115,8 @@ export declare interface Tracer extends opentracing.Tracer {
115
115
  * @returns {Tracer} The Tracer instance for chaining.
116
116
  */
117
117
  setUser (user: User): Tracer;
118
+
119
+ appsec: Appsec;
118
120
  }
119
121
 
120
122
  export declare interface TraceOptions extends Analyzable {
@@ -537,6 +539,17 @@ export declare interface TracerOptions {
537
539
  */
538
540
  pollInterval?: number,
539
541
  }
542
+
543
+ /**
544
+ * Whether to enable client IP collection from relevant IP headers
545
+ * @default false
546
+ */
547
+ clientIpEnabled?: boolean
548
+
549
+ /**
550
+ * Custom header name to source the http.client_ip tag from.
551
+ */
552
+ clientIpHeader?: string,
540
553
  }
541
554
 
542
555
  /**
@@ -582,6 +595,36 @@ export declare interface User {
582
595
  [key: string]: string | undefined
583
596
  }
584
597
 
598
+ export declare interface Appsec {
599
+ /**
600
+ * Links a successful login event to the current trace. Will link the passed user to the current trace with Appsec.setUser() internally.
601
+ * @param {User} user Properties of the authenticated user. Accepts custom fields.
602
+ * @param {[key: string]: string} metadata Custom fields to link to the login success event.
603
+ *
604
+ * @beta This method is in beta and could change in future versions.
605
+ */
606
+ trackUserLoginSuccessEvent(user: User, metadata?: { [key: string]: string }): void
607
+
608
+ /**
609
+ * Links a failed login event to the current trace.
610
+ * @param {string} userId The user id of the attemped login.
611
+ * @param {boolean} exists If the user id exists.
612
+ * @param {[key: string]: string} metadata Custom fields to link to the login failure event.
613
+ *
614
+ * @beta This method is in beta and could change in future versions.
615
+ */
616
+ trackUserLoginFailureEvent(userId: string, exists: boolean, metadata?: { [key: string]: string }): void
617
+
618
+ /**
619
+ * Links a custom event to the current trace.
620
+ * @param {string} eventName The name of the event.
621
+ * @param {[key: string]: string} metadata Custom fields to link to the event.
622
+ *
623
+ * @beta This method is in beta and could change in future versions.
624
+ */
625
+ trackCustomEvent(eventName: string, metadata?: { [key: string]: string }): void
626
+ }
627
+
585
628
  /** @hidden */
586
629
  declare type anyObject = {
587
630
  [key: string]: any;
@@ -669,6 +712,7 @@ interface Plugins {
669
712
  "opensearch": plugins.opensearch;
670
713
  "oracledb": plugins.oracledb;
671
714
  "paperplane": plugins.paperplane;
715
+ "playwright": plugins.playwright;
672
716
  "pg": plugins.pg;
673
717
  "pino": plugins.pino;
674
718
  "redis": plugins.redis;
@@ -1358,6 +1402,12 @@ declare namespace plugins {
1358
1402
  */
1359
1403
  interface paperplane extends HttpServer {}
1360
1404
 
1405
+ /**
1406
+ * This plugin automatically instruments the
1407
+ * [playwright](https://github.com/microsoft/playwright) module.
1408
+ */
1409
+ interface playwright extends Integration {}
1410
+
1361
1411
  /**
1362
1412
  * This plugin automatically instruments the
1363
1413
  * [pg](https://node-postgres.com/) module.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dd-trace",
3
- "version": "3.12.0",
3
+ "version": "3.13.0",
4
4
  "description": "Datadog APM tracing client for JavaScript",
5
5
  "main": "index.js",
6
6
  "typings": "index.d.ts",
@@ -0,0 +1,357 @@
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
+
89
+ addHook({ name: 'fs' }, fs => {
90
+ const asyncMethods = Object.keys(paramsByMethod)
91
+ const syncMethods = asyncMethods.map(name => `${name}Sync`)
92
+
93
+ massWrap(fs, asyncMethods, createWrapFunction())
94
+ massWrap(fs, syncMethods, createWrapFunction())
95
+ massWrap(fs.promises, asyncMethods, createWrapFunction('promises.'))
96
+
97
+ wrap(fs.realpath, 'native', createWrapFunction('', 'realpath.native'))
98
+ wrap(fs.realpathSync, 'native', createWrapFunction('', 'realpath.native'))
99
+ wrap(fs.promises.realpath, 'native', createWrapFunction('', 'realpath.native'))
100
+
101
+ wrap(fs, 'createReadStream', wrapCreateStream)
102
+ wrap(fs, 'createWriteStream', wrapCreateStream)
103
+ if (fs.Dir) {
104
+ wrap(fs.Dir.prototype, 'close', createWrapFunction('dir.'))
105
+ wrap(fs.Dir.prototype, 'closeSync', createWrapFunction('dir.'))
106
+ wrap(fs.Dir.prototype, 'read', createWrapFunction('dir.'))
107
+ wrap(fs.Dir.prototype, 'readSync', createWrapFunction('dir.'))
108
+ wrap(fs.Dir.prototype, Symbol.asyncIterator, createWrapDirAsyncIterator())
109
+ }
110
+
111
+ wrap(fs, 'unwatchFile', createWatchWrapFunction())
112
+ wrap(fs, 'watch', createWatchWrapFunction())
113
+ wrap(fs, 'watchFile', createWatchWrapFunction())
114
+
115
+ return fs
116
+ })
117
+
118
+ function isFirstMethodReturningFileHandle (original) {
119
+ return !kHandle && original.name === 'open'
120
+ }
121
+ function wrapFileHandle (fh) {
122
+ const fileHandlePrototype = getFileHandlePrototype(fh)
123
+ const desc = Reflect.getOwnPropertyDescriptor(fileHandlePrototype, kHandle)
124
+ if (!desc || !desc.get) {
125
+ Reflect.defineProperty(fileHandlePrototype, kHandle, {
126
+ get () {
127
+ return this[ddFhSym]
128
+ },
129
+ set (h) {
130
+ this[ddFhSym] = h
131
+ wrap(this, 'close', createWrapFunction('filehandle.'))
132
+ },
133
+ configurable: true
134
+ })
135
+ }
136
+ for (const name of Reflect.ownKeys(fileHandlePrototype)) {
137
+ if (typeof name !== 'string' || name === 'constructor' || name === 'fd' || name === 'getAsyncId') {
138
+ continue
139
+ }
140
+ wrap(fileHandlePrototype, name, createWrapFunction('filehandle.'))
141
+ }
142
+ }
143
+
144
+ function getFileHandlePrototype (fh) {
145
+ if (!kHandle) {
146
+ kHandle = Reflect.ownKeys(fh).find(key => typeof key === 'symbol' && key.toString().includes('kHandle'))
147
+ }
148
+ return Object.getPrototypeOf(fh)
149
+ }
150
+
151
+ function getSymbolName (sym) {
152
+ return sym.description || sym.toString()
153
+ }
154
+ function initDirAsyncIteratorProperties (iterator) {
155
+ const keys = Reflect.ownKeys(iterator)
156
+ for (const key of keys) {
157
+ if (kDirReadPromisified && kDirClosePromisified) break
158
+ if (typeof key !== 'symbol') continue
159
+ if (!kDirReadPromisified && getSymbolName(key).includes('kDirReadPromisified')) {
160
+ kDirReadPromisified = key
161
+ }
162
+ if (!kDirClosePromisified && getSymbolName(key).includes('kDirClosePromisified')) {
163
+ kDirClosePromisified = key
164
+ }
165
+ }
166
+ }
167
+
168
+ function createWrapDirAsyncIterator () {
169
+ return function wrapDirAsyncIterator (asyncIterator) {
170
+ return function wrappedAsyncIterator () {
171
+ if (!kDirReadPromisified || !kDirClosePromisified) {
172
+ initDirAsyncIteratorProperties(this)
173
+ }
174
+ wrap(this, kDirReadPromisified, createWrapFunction('dir.', 'read'))
175
+ wrap(this, kDirClosePromisified, createWrapFunction('dir.', 'close'))
176
+ return asyncIterator.apply(this, arguments)
177
+ }
178
+ }
179
+ }
180
+
181
+ function wrapCreateStream (original) {
182
+ const classes = {
183
+ createReadStream: 'ReadStream',
184
+ createWriteStream: 'WriteStream'
185
+ }
186
+ const name = classes[original.name]
187
+
188
+ return function (path, options) {
189
+ if (!startChannel.hasSubscribers) return original.apply(this, arguments)
190
+
191
+ const innerResource = new AsyncResource('bound-anonymous-fn')
192
+ const message = getMessage(name, ['path', 'options'], arguments)
193
+
194
+ return innerResource.runInAsyncScope(() => {
195
+ startChannel.publish(message)
196
+
197
+ try {
198
+ const stream = original.apply(this, arguments)
199
+ const onError = innerResource.bind(error => {
200
+ errorChannel.publish(error)
201
+ onFinish()
202
+ })
203
+ const onFinish = innerResource.bind(() => {
204
+ finishChannel.publish()
205
+ stream.off('close', onFinish)
206
+ stream.off('end', onFinish)
207
+ stream.off('finish', onFinish)
208
+ stream.off('error', onError)
209
+ })
210
+
211
+ stream.once('close', onFinish)
212
+ stream.once('end', onFinish)
213
+ stream.once('finish', onFinish)
214
+ stream.once('error', onError)
215
+
216
+ return stream
217
+ } catch (error) {
218
+ errorChannel.publish(error)
219
+ finishChannel.publish()
220
+ }
221
+ })
222
+ }
223
+ }
224
+
225
+ function getMethodParamsRelationByPrefix (prefix) {
226
+ if (prefix === 'filehandle.') {
227
+ return paramsByFileHandleMethods
228
+ }
229
+ return paramsByMethod
230
+ }
231
+
232
+ function createWatchWrapFunction (override = '') {
233
+ return function wrapFunction (original) {
234
+ const name = override || original.name
235
+ const method = name
236
+ const operation = name
237
+ return function () {
238
+ if (!startChannel.hasSubscribers) return original.apply(this, arguments)
239
+ const message = getMessage(method, watchMethods[operation], arguments, this)
240
+ const innerResource = new AsyncResource('bound-anonymous-fn')
241
+ return innerResource.runInAsyncScope(() => {
242
+ startChannel.publish(message)
243
+ try {
244
+ const result = original.apply(this, arguments)
245
+ finishChannel.publish()
246
+ return result
247
+ } catch (error) {
248
+ errorChannel.publish(error)
249
+ finishChannel.publish()
250
+ throw error
251
+ }
252
+ })
253
+ }
254
+ }
255
+ }
256
+
257
+ function createWrapFunction (prefix = '', override = '') {
258
+ return function wrapFunction (original) {
259
+ const name = override || original.name
260
+ const method = `${prefix}${name}`
261
+ const operation = name.match(/^(.+?)(Sync)?(\.native)?$/)[1]
262
+
263
+ return function () {
264
+ if (!startChannel.hasSubscribers) return original.apply(this, arguments)
265
+
266
+ const lastIndex = arguments.length - 1
267
+ const cb = typeof arguments[lastIndex] === 'function' && arguments[lastIndex]
268
+ const innerResource = new AsyncResource('bound-anonymous-fn')
269
+ const message = getMessage(method, getMethodParamsRelationByPrefix(prefix)[operation], arguments, this)
270
+
271
+ if (cb) {
272
+ const outerResource = new AsyncResource('bound-anonymous-fn')
273
+
274
+ arguments[lastIndex] = innerResource.bind(function (e) {
275
+ if (typeof e === 'object') { // fs.exists receives a boolean
276
+ errorChannel.publish(e)
277
+ }
278
+
279
+ finishChannel.publish()
280
+
281
+ return outerResource.runInAsyncScope(() => cb.apply(this, arguments))
282
+ })
283
+ }
284
+
285
+ return innerResource.runInAsyncScope(() => {
286
+ startChannel.publish(message)
287
+ try {
288
+ const result = original.apply(this, arguments)
289
+ if (cb) return result
290
+ if (result && typeof result.then === 'function') {
291
+ // TODO method open returning promise and filehandle prototype not initialized, initialize it
292
+
293
+ return result.then(
294
+ value => {
295
+ if (isFirstMethodReturningFileHandle(original)) {
296
+ wrapFileHandle(value)
297
+ }
298
+ finishChannel.publish()
299
+ return value
300
+ },
301
+ error => {
302
+ errorChannel.publish(error)
303
+ finishChannel.publish()
304
+ throw error
305
+ }
306
+ )
307
+ }
308
+
309
+ finishChannel.publish()
310
+
311
+ return result
312
+ } catch (error) {
313
+ errorChannel.publish(error)
314
+ finishChannel.publish()
315
+ throw error
316
+ }
317
+ })
318
+ }
319
+ }
320
+ }
321
+
322
+ function getMessage (operation, params, args, self) {
323
+ const metadata = {}
324
+ if (params) {
325
+ for (let i = 0; i < params.length; i++) {
326
+ if (!params[i] || typeof args[i] === 'function') continue
327
+ metadata[params[i]] = args[i]
328
+ }
329
+ }
330
+
331
+ if (self) {
332
+ // For `Dir` the path is available on `this.path`
333
+ if (self.path) {
334
+ metadata.path = self.path
335
+ }
336
+ // For FileHandle fs is available on `this.fd`
337
+ if (self.fd) {
338
+ metadata.fd = self.fd
339
+ }
340
+ }
341
+
342
+ return { operation, ...metadata }
343
+ }
344
+
345
+ function massWrap (target, methods, wrapper) {
346
+ for (const method of methods) {
347
+ wrap(target, method, wrapper)
348
+ }
349
+ }
350
+
351
+ function wrap (target, method, wrapper) {
352
+ try {
353
+ shimmer.wrap(target, method, wrapper)
354
+ } catch (e) {
355
+ // skip unavailable method
356
+ }
357
+ }
@@ -2,6 +2,7 @@
2
2
 
3
3
  module.exports = {
4
4
  '@cucumber/cucumber': () => require('../cucumber'),
5
+ '@playwright/test': () => require('../playwright'),
5
6
  '@elastic/elasticsearch': () => require('../elasticsearch'),
6
7
  '@elastic/transport': () => require('../elasticsearch'),
7
8
  '@google-cloud/pubsub': () => require('../google-cloud-pubsub'),
@@ -31,6 +32,8 @@ module.exports = {
31
32
  'express': () => require('../express'),
32
33
  'fastify': () => require('../fastify'),
33
34
  'find-my-way': () => require('../find-my-way'),
35
+ 'fs': () => require('../fs'),
36
+ 'node:fs': () => require('../fs'),
34
37
  'graphql': () => require('../graphql'),
35
38
  'grpc': () => require('../grpc'),
36
39
  'hapi': () => require('../hapi'),
@@ -60,7 +60,5 @@ function filename (name, file) {
60
60
 
61
61
  module.exports = {
62
62
  filename,
63
- getVersion,
64
- matchVersion,
65
63
  pathSepExpr
66
64
  }
@@ -218,9 +218,19 @@ function cliWrapper (cli) {
218
218
 
219
219
  const isSuitesSkipped = !!skippableSuites.length
220
220
 
221
+ let testFrameworkVersion
222
+ try {
223
+ testFrameworkVersion = this.getVersion()
224
+ } catch (e) {
225
+ try {
226
+ testFrameworkVersion = this.default.getVersion()
227
+ } catch (e) {
228
+ // ignore errors
229
+ }
230
+ }
221
231
  const processArgv = process.argv.slice(2).join(' ')
222
232
  sessionAsyncResource.runInAsyncScope(() => {
223
- testSessionStartCh.publish(`jest ${processArgv}`)
233
+ testSessionStartCh.publish({ command: `jest ${processArgv}`, testFrameworkVersion })
224
234
  })
225
235
 
226
236
  const result = await runCLI.apply(this, arguments)
@@ -39,6 +39,7 @@ const testFileToSuiteAr = new Map()
39
39
  const originalCoverageMap = createCoverageMap()
40
40
 
41
41
  let suitesToSkip = []
42
+ let mochaVersion
42
43
 
43
44
  function getSuitesByTestFile (root) {
44
45
  const suitesByTestFile = {}
@@ -128,7 +129,7 @@ function mochaHook (Runner) {
128
129
  this.once('start', testRunAsyncResource.bind(function () {
129
130
  const processArgv = process.argv.slice(2).join(' ')
130
131
  const command = `mocha ${processArgv}`
131
- testSessionStartCh.publish(command)
132
+ testSessionStartCh.publish({ command, frameworkVersion: mochaVersion })
132
133
  }))
133
134
 
134
135
  this.on('suite', function (suite) {
@@ -315,12 +316,12 @@ addHook({
315
316
  file: 'lib/mocha.js'
316
317
  }, (Mocha) => {
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
322
322
  */
323
323
  shimmer.wrap(Mocha.prototype, 'run', run => function () {
324
+ mochaVersion = this.version
324
325
  if (!itrConfigurationCh.hasSubscribers) {
325
326
  return run.apply(this, arguments)
326
327
  }
@@ -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)