mssql 12.3.0 → 12.4.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.
@@ -3,11 +3,12 @@
3
3
  const debug = require('debug')('mssql:base')
4
4
  const { EventEmitter } = require('node:events')
5
5
  const { Readable } = require('node:stream')
6
- const { IDS, objectHasProperty } = require('../utils')
6
+ const { IDS, objectHasProperty, getPoolId } = require('../utils')
7
7
  const globalConnection = require('../global-connection')
8
8
  const { RequestError, ConnectionError } = require('../error')
9
9
  const { TYPES } = require('../datatypes')
10
10
  const shared = require('../shared')
11
+ const { CHANNELS, tracePromise, traceCallback, publish } = require('../diagnostics')
11
12
 
12
13
  /**
13
14
  * Class Request.
@@ -37,6 +38,7 @@ class Request extends EventEmitter {
37
38
 
38
39
  this.canceled = false
39
40
  this._paused = false
41
+ this._internal = false
40
42
  this.parent = parent || globalConnection.pool
41
43
  this.parameters = {}
42
44
  this.stream = null
@@ -218,6 +220,24 @@ class Request extends EventEmitter {
218
220
  return this.output(name, type, value)
219
221
  }
220
222
 
223
+ _getParameterNames () {
224
+ return Object.keys(this.parameters)
225
+ }
226
+
227
+ _tracedPromise (channel, contextFactory, fn) {
228
+ if (this._internal) {
229
+ return fn()
230
+ }
231
+ return tracePromise(channel, fn, contextFactory)
232
+ }
233
+
234
+ _tracedCallback (channel, contextFactory, fn, position, args) {
235
+ if (this._internal) {
236
+ return fn.apply(this, args)
237
+ }
238
+ return traceCallback(channel, fn, position, contextFactory, this, args)
239
+ }
240
+
221
241
  /**
222
242
  * Execute the SQL batch.
223
243
  *
@@ -232,7 +252,11 @@ class Request extends EventEmitter {
232
252
  this.rowsAffected = 0
233
253
 
234
254
  if (typeof callback === 'function') {
235
- this._batch(batch, (err, recordsets, output, rowsAffected) => {
255
+ this._tracedCallback(CHANNELS.TRACE_BATCH, () => ({
256
+ command: batch,
257
+ requestId: IDS.get(this),
258
+ poolId: getPoolId(this)
259
+ }), this._batch, 1, [batch, (err, recordsets, output, rowsAffected) => {
236
260
  if (this.stream) {
237
261
  if (err) this.emit('error', err)
238
262
  err = null
@@ -250,7 +274,7 @@ class Request extends EventEmitter {
250
274
  output,
251
275
  rowsAffected
252
276
  })
253
- })
277
+ }])
254
278
  return this
255
279
  }
256
280
 
@@ -261,24 +285,31 @@ class Request extends EventEmitter {
261
285
  batch = this._template(strings, values)
262
286
  }
263
287
 
264
- return new shared.Promise((resolve, reject) => {
265
- this._batch(batch, (err, recordsets, output, rowsAffected) => {
266
- if (this.stream) {
267
- if (err) this.emit('error', err)
268
- err = null
288
+ const batchCommand = batch
289
+ return this._tracedPromise(CHANNELS.TRACE_BATCH, () => ({
290
+ command: batchCommand,
291
+ requestId: IDS.get(this),
292
+ poolId: getPoolId(this)
293
+ }), () => {
294
+ return new shared.Promise((resolve, reject) => {
295
+ this._batch(batchCommand, (err, recordsets, output, rowsAffected) => {
296
+ if (this.stream) {
297
+ if (err) this.emit('error', err)
298
+ err = null
299
+
300
+ this.emit('done', {
301
+ output,
302
+ rowsAffected
303
+ })
304
+ }
269
305
 
270
- this.emit('done', {
306
+ if (err) return reject(err)
307
+ resolve({
308
+ recordsets,
309
+ recordset: recordsets && recordsets[0],
271
310
  output,
272
311
  rowsAffected
273
312
  })
274
- }
275
-
276
- if (err) return reject(err)
277
- resolve({
278
- recordsets,
279
- recordset: recordsets && recordsets[0],
280
- output,
281
- rowsAffected
282
313
  })
283
314
  })
284
315
  })
@@ -324,7 +355,12 @@ class Request extends EventEmitter {
324
355
  if (this.arrayRowMode === null && this.parent) this.arrayRowMode = this.parent.config.arrayRowMode
325
356
 
326
357
  if (this.stream || typeof callback === 'function') {
327
- this._bulk(table, options, (err, rowsAffected) => {
358
+ this._tracedCallback(CHANNELS.TRACE_BULK, () => ({
359
+ table: table.path || table.name,
360
+ rowCount: table.rows ? table.rows.length : 0,
361
+ requestId: IDS.get(this),
362
+ poolId: getPoolId(this)
363
+ }), this._bulk, 2, [table, options, (err, rowsAffected) => {
328
364
  if (this.stream) {
329
365
  if (err) this.emit('error', err)
330
366
  return this.emit('done', {
@@ -336,15 +372,22 @@ class Request extends EventEmitter {
336
372
  callback(null, {
337
373
  rowsAffected
338
374
  })
339
- })
375
+ }])
340
376
  return this
341
377
  }
342
378
 
343
- return new shared.Promise((resolve, reject) => {
344
- this._bulk(table, options, (err, rowsAffected) => {
345
- if (err) return reject(err)
346
- resolve({
347
- rowsAffected
379
+ return this._tracedPromise(CHANNELS.TRACE_BULK, () => ({
380
+ table: table.path || table.name,
381
+ rowCount: table.rows ? table.rows.length : 0,
382
+ requestId: IDS.get(this),
383
+ poolId: getPoolId(this)
384
+ }), () => {
385
+ return new shared.Promise((resolve, reject) => {
386
+ this._bulk(table, options, (err, rowsAffected) => {
387
+ if (err) return reject(err)
388
+ resolve({
389
+ rowsAffected
390
+ })
348
391
  })
349
392
  })
350
393
  })
@@ -429,7 +472,12 @@ class Request extends EventEmitter {
429
472
  this.rowsAffected = 0
430
473
 
431
474
  if (typeof callback === 'function') {
432
- this._query(command, (err, recordsets, output, rowsAffected, columns) => {
475
+ this._tracedCallback(CHANNELS.TRACE_QUERY, () => ({
476
+ command,
477
+ parameters: this._getParameterNames(),
478
+ requestId: IDS.get(this),
479
+ poolId: getPoolId(this)
480
+ }), this._query, 1, [command, (err, recordsets, output, rowsAffected, columns) => {
433
481
  if (this.stream) {
434
482
  if (err) this.emit('error', err)
435
483
  err = null
@@ -449,7 +497,7 @@ class Request extends EventEmitter {
449
497
  }
450
498
  if (this.arrayRowMode) result.columns = columns
451
499
  callback(null, result)
452
- })
500
+ }])
453
501
  return this
454
502
  }
455
503
 
@@ -460,27 +508,34 @@ class Request extends EventEmitter {
460
508
  command = this._template(strings, values)
461
509
  }
462
510
 
463
- return new shared.Promise((resolve, reject) => {
464
- this._query(command, (err, recordsets, output, rowsAffected, columns) => {
465
- if (this.stream) {
466
- if (err) this.emit('error', err)
467
- err = null
511
+ return this._tracedPromise(CHANNELS.TRACE_QUERY, () => ({
512
+ command,
513
+ parameters: this._getParameterNames(),
514
+ requestId: IDS.get(this),
515
+ poolId: getPoolId(this)
516
+ }), () => {
517
+ return new shared.Promise((resolve, reject) => {
518
+ this._query(command, (err, recordsets, output, rowsAffected, columns) => {
519
+ if (this.stream) {
520
+ if (err) this.emit('error', err)
521
+ err = null
522
+
523
+ this.emit('done', {
524
+ output,
525
+ rowsAffected
526
+ })
527
+ }
468
528
 
469
- this.emit('done', {
529
+ if (err) return reject(err)
530
+ const result = {
531
+ recordsets,
532
+ recordset: recordsets && recordsets[0],
470
533
  output,
471
534
  rowsAffected
472
- })
473
- }
474
-
475
- if (err) return reject(err)
476
- const result = {
477
- recordsets,
478
- recordset: recordsets && recordsets[0],
479
- output,
480
- rowsAffected
481
- }
482
- if (this.arrayRowMode) result.columns = columns
483
- resolve(result)
535
+ }
536
+ if (this.arrayRowMode) result.columns = columns
537
+ resolve(result)
538
+ })
484
539
  })
485
540
  })
486
541
  }
@@ -518,7 +573,12 @@ class Request extends EventEmitter {
518
573
  this.rowsAffected = 0
519
574
 
520
575
  if (typeof callback === 'function') {
521
- this._execute(command, (err, recordsets, output, returnValue, rowsAffected, columns) => {
576
+ this._tracedCallback(CHANNELS.TRACE_EXECUTE, () => ({
577
+ procedure: command,
578
+ parameters: this._getParameterNames(),
579
+ requestId: IDS.get(this),
580
+ poolId: getPoolId(this)
581
+ }), this._execute, 1, [command, (err, recordsets, output, returnValue, rowsAffected, columns) => {
522
582
  if (this.stream) {
523
583
  if (err) this.emit('error', err)
524
584
  err = null
@@ -540,33 +600,40 @@ class Request extends EventEmitter {
540
600
  }
541
601
  if (this.arrayRowMode) result.columns = columns
542
602
  callback(null, result)
543
- })
603
+ }])
544
604
  return this
545
605
  }
546
606
 
547
- return new shared.Promise((resolve, reject) => {
548
- this._execute(command, (err, recordsets, output, returnValue, rowsAffected, columns) => {
549
- if (this.stream) {
550
- if (err) this.emit('error', err)
551
- err = null
607
+ return this._tracedPromise(CHANNELS.TRACE_EXECUTE, () => ({
608
+ procedure: command,
609
+ parameters: this._getParameterNames(),
610
+ requestId: IDS.get(this),
611
+ poolId: getPoolId(this)
612
+ }), () => {
613
+ return new shared.Promise((resolve, reject) => {
614
+ this._execute(command, (err, recordsets, output, returnValue, rowsAffected, columns) => {
615
+ if (this.stream) {
616
+ if (err) this.emit('error', err)
617
+ err = null
618
+
619
+ this.emit('done', {
620
+ output,
621
+ rowsAffected,
622
+ returnValue
623
+ })
624
+ }
552
625
 
553
- this.emit('done', {
626
+ if (err) return reject(err)
627
+ const result = {
628
+ recordsets,
629
+ recordset: recordsets && recordsets[0],
554
630
  output,
555
631
  rowsAffected,
556
632
  returnValue
557
- })
558
- }
559
-
560
- if (err) return reject(err)
561
- const result = {
562
- recordsets,
563
- recordset: recordsets && recordsets[0],
564
- output,
565
- rowsAffected,
566
- returnValue
567
- }
568
- if (this.arrayRowMode) result.columns = columns
569
- resolve(result)
633
+ }
634
+ if (this.arrayRowMode) result.columns = columns
635
+ resolve(result)
636
+ })
570
637
  })
571
638
  })
572
639
  }
@@ -598,6 +665,11 @@ class Request extends EventEmitter {
598
665
 
599
666
  cancel () {
600
667
  this._cancel()
668
+ if (!this._internal) {
669
+ publish(CHANNELS.REQUEST_CANCEL, () => ({
670
+ requestId: IDS.get(this)
671
+ }))
672
+ }
601
673
  return true
602
674
  }
603
675
 
@@ -2,11 +2,16 @@
2
2
 
3
3
  const debug = require('debug')('mssql:base')
4
4
  const { EventEmitter } = require('node:events')
5
- const { IDS } = require('../utils')
5
+ const { IDS, getPoolId } = require('../utils')
6
6
  const globalConnection = require('../global-connection')
7
7
  const { TransactionError } = require('../error')
8
8
  const shared = require('../shared')
9
9
  const ISOLATION_LEVEL = require('../isolationlevel')
10
+ const { CHANNELS, publish } = require('../diagnostics')
11
+
12
+ const ISOLATION_LEVEL_NAMES = Object.fromEntries(
13
+ Object.entries(ISOLATION_LEVEL).map(([name, value]) => [value, name])
14
+ )
10
15
 
11
16
  /**
12
17
  * Class Transaction.
@@ -101,6 +106,12 @@ class Transaction extends EventEmitter {
101
106
  if (typeof callback === 'function') {
102
107
  this._begin(isolationLevel, err => {
103
108
  if (!err) {
109
+ publish(CHANNELS.TRANSACTION_BEGIN, () => ({
110
+ transactionId: IDS.get(this),
111
+ isolationLevel: this.isolationLevel,
112
+ isolationLevelName: ISOLATION_LEVEL_NAMES[this.isolationLevel],
113
+ poolId: getPoolId(this)
114
+ }))
104
115
  this.emit('begin')
105
116
  }
106
117
  callback(err)
@@ -111,6 +122,12 @@ class Transaction extends EventEmitter {
111
122
  return new shared.Promise((resolve, reject) => {
112
123
  this._begin(isolationLevel, err => {
113
124
  if (err) return reject(err)
125
+ publish(CHANNELS.TRANSACTION_BEGIN, () => ({
126
+ transactionId: IDS.get(this),
127
+ isolationLevel: this.isolationLevel,
128
+ isolationLevelName: ISOLATION_LEVEL_NAMES[this.isolationLevel],
129
+ poolId: getPoolId(this)
130
+ }))
114
131
  this.emit('begin')
115
132
  resolve(this)
116
133
  })
@@ -155,6 +172,9 @@ class Transaction extends EventEmitter {
155
172
  if (typeof callback === 'function') {
156
173
  this._commit(err => {
157
174
  if (!err) {
175
+ publish(CHANNELS.TRANSACTION_COMMIT, () => ({
176
+ transactionId: IDS.get(this)
177
+ }))
158
178
  this.emit('commit')
159
179
  }
160
180
  callback(err)
@@ -165,6 +185,9 @@ class Transaction extends EventEmitter {
165
185
  return new shared.Promise((resolve, reject) => {
166
186
  this._commit(err => {
167
187
  if (err) return reject(err)
188
+ publish(CHANNELS.TRANSACTION_COMMIT, () => ({
189
+ transactionId: IDS.get(this)
190
+ }))
168
191
  this.emit('commit')
169
192
  resolve()
170
193
  })
@@ -214,6 +237,10 @@ class Transaction extends EventEmitter {
214
237
  if (typeof callback === 'function') {
215
238
  this._rollback(err => {
216
239
  if (!err) {
240
+ publish(CHANNELS.TRANSACTION_ROLLBACK, () => ({
241
+ transactionId: IDS.get(this),
242
+ aborted: this._aborted
243
+ }))
217
244
  this.emit('rollback', this._aborted)
218
245
  }
219
246
  callback(err)
@@ -224,6 +251,10 @@ class Transaction extends EventEmitter {
224
251
  return new shared.Promise((resolve, reject) => {
225
252
  return this._rollback(err => {
226
253
  if (err) return reject(err)
254
+ publish(CHANNELS.TRANSACTION_ROLLBACK, () => ({
255
+ transactionId: IDS.get(this),
256
+ aborted: this._aborted
257
+ }))
227
258
  this.emit('rollback', this._aborted)
228
259
  resolve()
229
260
  })
@@ -0,0 +1,153 @@
1
+ 'use strict'
2
+
3
+ const dc = require('node:diagnostics_channel')
4
+
5
+ // TracingChannel names
6
+ const TRACE_QUERY = 'mssql:query'
7
+ const TRACE_BATCH = 'mssql:batch'
8
+ const TRACE_EXECUTE = 'mssql:execute'
9
+ const TRACE_BULK = 'mssql:bulk'
10
+ const TRACE_CONNECT = 'mssql:connect'
11
+ const TRACE_POOL_ACQUIRE = 'mssql:pool:acquire'
12
+ const TRACE_PREPARED_STATEMENT_PREPARE = 'mssql:prepared-statement:prepare'
13
+ const TRACE_PREPARED_STATEMENT_EXECUTE = 'mssql:prepared-statement:execute'
14
+
15
+ // Point-event channel names
16
+ const CONNECTION_ACQUIRE = 'mssql:connection:acquire'
17
+ const CONNECTION_RELEASE = 'mssql:connection:release'
18
+ const CONNECTION_CREATE = 'mssql:connection:create'
19
+ const CONNECTION_DESTROY = 'mssql:connection:destroy'
20
+ const POOL_CLOSE = 'mssql:pool:close'
21
+ const TRANSACTION_BEGIN = 'mssql:transaction:begin'
22
+ const TRANSACTION_COMMIT = 'mssql:transaction:commit'
23
+ const TRANSACTION_ROLLBACK = 'mssql:transaction:rollback'
24
+ const REQUEST_CANCEL = 'mssql:request:cancel'
25
+ const PREPARED_STATEMENT_UNPREPARE = 'mssql:prepared-statement:unprepare'
26
+
27
+ const CHANNELS = Object.freeze({
28
+ TRACE_QUERY,
29
+ TRACE_BATCH,
30
+ TRACE_EXECUTE,
31
+ TRACE_BULK,
32
+ TRACE_CONNECT,
33
+ TRACE_POOL_ACQUIRE,
34
+ TRACE_PREPARED_STATEMENT_PREPARE,
35
+ TRACE_PREPARED_STATEMENT_EXECUTE,
36
+ CONNECTION_ACQUIRE,
37
+ CONNECTION_RELEASE,
38
+ CONNECTION_CREATE,
39
+ CONNECTION_DESTROY,
40
+ POOL_CLOSE,
41
+ TRANSACTION_BEGIN,
42
+ TRANSACTION_COMMIT,
43
+ TRANSACTION_ROLLBACK,
44
+ REQUEST_CANCEL,
45
+ PREPARED_STATEMENT_UNPREPARE
46
+ })
47
+
48
+ // Pre-create TracingChannel instances at module load time
49
+ const tracingChannels = {
50
+ [TRACE_QUERY]: dc.tracingChannel(TRACE_QUERY),
51
+ [TRACE_BATCH]: dc.tracingChannel(TRACE_BATCH),
52
+ [TRACE_EXECUTE]: dc.tracingChannel(TRACE_EXECUTE),
53
+ [TRACE_BULK]: dc.tracingChannel(TRACE_BULK),
54
+ [TRACE_CONNECT]: dc.tracingChannel(TRACE_CONNECT),
55
+ [TRACE_POOL_ACQUIRE]: dc.tracingChannel(TRACE_POOL_ACQUIRE),
56
+ [TRACE_PREPARED_STATEMENT_PREPARE]: dc.tracingChannel(TRACE_PREPARED_STATEMENT_PREPARE),
57
+ [TRACE_PREPARED_STATEMENT_EXECUTE]: dc.tracingChannel(TRACE_PREPARED_STATEMENT_EXECUTE)
58
+ }
59
+
60
+ // Pre-create point-event channel instances at module load time
61
+ const pointChannels = {
62
+ [CONNECTION_ACQUIRE]: dc.channel(CONNECTION_ACQUIRE),
63
+ [CONNECTION_RELEASE]: dc.channel(CONNECTION_RELEASE),
64
+ [CONNECTION_CREATE]: dc.channel(CONNECTION_CREATE),
65
+ [CONNECTION_DESTROY]: dc.channel(CONNECTION_DESTROY),
66
+ [POOL_CLOSE]: dc.channel(POOL_CLOSE),
67
+ [TRANSACTION_BEGIN]: dc.channel(TRANSACTION_BEGIN),
68
+ [TRANSACTION_COMMIT]: dc.channel(TRANSACTION_COMMIT),
69
+ [TRANSACTION_ROLLBACK]: dc.channel(TRANSACTION_ROLLBACK),
70
+ [REQUEST_CANCEL]: dc.channel(REQUEST_CANCEL),
71
+ [PREPARED_STATEMENT_UNPREPARE]: dc.channel(PREPARED_STATEMENT_UNPREPARE)
72
+ }
73
+
74
+ // TracingChannel.hasSubscribers was added in Node 22. On 18.19 / 20 the
75
+ // aggregate property is undefined, so we fall back to checking the
76
+ // sub-channels directly (these have existed since the original
77
+ // diagnostics_channel API). Preserves the zero-cost fast path across all
78
+ // supported runtimes.
79
+ function tracingChannelHasSubscribers (tc) {
80
+ if (typeof tc.hasSubscribers === 'boolean') return tc.hasSubscribers
81
+ return tc.start.hasSubscribers ||
82
+ tc.end.hasSubscribers ||
83
+ tc.asyncStart.hasSubscribers ||
84
+ tc.asyncEnd.hasSubscribers ||
85
+ tc.error.hasSubscribers
86
+ }
87
+
88
+ /**
89
+ * Trace an async operation using a TracingChannel.
90
+ *
91
+ * When subscribers are active, wraps `fn` with TracingChannel.tracePromise().
92
+ * When no subscribers are active, calls `fn` directly with zero overhead
93
+ * (no context allocation).
94
+ *
95
+ * @param {string} name - TracingChannel name (one of CHANNELS.TRACE_*)
96
+ * @param {Function} fn - The function to trace (must return a Promise)
97
+ * @param {Function} contextFactory - Factory function returning the context object
98
+ * @returns {Promise} The return value of fn
99
+ */
100
+ function tracePromise (name, fn, contextFactory) {
101
+ const channel = tracingChannels[name]
102
+ if (tracingChannelHasSubscribers(channel)) {
103
+ return channel.tracePromise(fn, contextFactory())
104
+ }
105
+ return fn()
106
+ }
107
+
108
+ /**
109
+ * Trace a callback-style async operation using a TracingChannel.
110
+ *
111
+ * When subscribers are active, delegates to TracingChannel.traceCallback,
112
+ * which replaces the callback at `position` in `args` with a wrapped
113
+ * version that publishes to start/end/asyncStart/asyncEnd/error. When
114
+ * no subscribers are active, calls `fn` directly with zero overhead.
115
+ *
116
+ * @param {string} name - TracingChannel name (one of CHANNELS.TRACE_*)
117
+ * @param {Function} fn - The function to call (receives callback at `position`)
118
+ * @param {number} position - Index of the callback within `args`
119
+ * @param {Function} contextFactory - Factory function returning the context object
120
+ * @param {*} thisArg - `this` binding for fn
121
+ * @param {Array} args - Arguments to pass to fn (includes the callback at `position`)
122
+ * @returns {*} The return value of fn
123
+ */
124
+ function traceCallback (name, fn, position, contextFactory, thisArg, args) {
125
+ const channel = tracingChannels[name]
126
+ if (tracingChannelHasSubscribers(channel)) {
127
+ return channel.traceCallback(fn, position, contextFactory(), thisArg, ...args)
128
+ }
129
+ return fn.apply(thisArg, args)
130
+ }
131
+
132
+ /**
133
+ * Publish a point event on a named channel.
134
+ *
135
+ * Only allocates the message object when subscribers are active.
136
+ *
137
+ * @param {string} name - Point-event channel name (one of CHANNELS.*)
138
+ * @param {Function} factory - Factory function that returns the message object
139
+ */
140
+ function publish (name, factory) {
141
+ const channel = pointChannels[name]
142
+ if (channel.hasSubscribers) {
143
+ channel.publish(factory())
144
+ }
145
+ }
146
+
147
+ module.exports = {
148
+ CHANNELS,
149
+ tracingChannels,
150
+ tracePromise,
151
+ traceCallback,
152
+ publish
153
+ }
@@ -8,6 +8,7 @@ const shared = require('../shared')
8
8
  const ConnectionError = require('../error/connection-error')
9
9
  const { platform } = require('node:os')
10
10
  const { build } = require('@tediousjs/connection-string')
11
+ const { CHANNELS, publish } = require('../diagnostics')
11
12
 
12
13
  const DEFAULT_CONNECTION_DRIVER = ['darwin', 'linux'].includes(platform()) ? 'ODBC Driver 17 for SQL Server' : 'SQL Server Native Client 11.0'
13
14
 
@@ -58,6 +59,12 @@ class ConnectionPool extends BaseConnectionPool {
58
59
  IDS.add(tds, 'Connection', connedtionId)
59
60
  tds.setUseUTC(this.config.options.useUTC)
60
61
  debug('connection(%d): established', IDS.get(tds))
62
+ publish(CHANNELS.CONNECTION_CREATE, () => ({
63
+ connectionId: IDS.get(tds),
64
+ poolId: IDS.get(this),
65
+ server: this.config.server,
66
+ database: this.config.database
67
+ }))
61
68
  resolve(tds)
62
69
  })
63
70
  })
@@ -80,9 +87,15 @@ class ConnectionPool extends BaseConnectionPool {
80
87
  resolve()
81
88
  return
82
89
  }
83
- debug('connection(%d): destroying', IDS.get(tds))
90
+ const connectionId = IDS.get(tds)
91
+ const poolId = IDS.get(this)
92
+ debug('connection(%d): destroying', connectionId)
84
93
  tds.close(() => {
85
- debug('connection(%d): destroyed', IDS.get(tds))
94
+ debug('connection(%d): destroyed', connectionId)
95
+ publish(CHANNELS.CONNECTION_DESTROY, () => ({
96
+ connectionId,
97
+ poolId
98
+ }))
86
99
  resolve()
87
100
  })
88
101
  })
@@ -6,6 +6,7 @@ const BaseConnectionPool = require('../base/connection-pool')
6
6
  const { IDS } = require('../utils')
7
7
  const shared = require('../shared')
8
8
  const ConnectionError = require('../error/connection-error')
9
+ const { CHANNELS, publish } = require('../diagnostics')
9
10
 
10
11
  class ConnectionPool extends BaseConnectionPool {
11
12
  _config () {
@@ -88,6 +89,12 @@ class ConnectionPool extends BaseConnectionPool {
88
89
 
89
90
  debug('connection(%d): established', IDS.get(tedious))
90
91
  this.collation = tedious.databaseCollation
92
+ publish(CHANNELS.CONNECTION_CREATE, () => ({
93
+ connectionId: IDS.get(tedious),
94
+ poolId: IDS.get(this),
95
+ server: this.config.server,
96
+ database: this.config.database
97
+ }))
91
98
  resolveOnce(tedious)
92
99
  })
93
100
  IDS.add(tedious, 'Connection')
@@ -156,6 +163,8 @@ class ConnectionPool extends BaseConnectionPool {
156
163
  return
157
164
  }
158
165
  debug('connection(%d): destroying', IDS.get(tedious))
166
+ const connectionId = IDS.get(tedious)
167
+ const poolId = IDS.get(this)
159
168
 
160
169
  if (tedious.closed) {
161
170
  debug('connection(%d): already closed', IDS.get(tedious))
@@ -163,6 +172,10 @@ class ConnectionPool extends BaseConnectionPool {
163
172
  } else {
164
173
  tedious.once('end', () => {
165
174
  debug('connection(%d): destroyed', IDS.get(tedious))
175
+ publish(CHANNELS.CONNECTION_DESTROY, () => ({
176
+ connectionId,
177
+ poolId
178
+ }))
166
179
  resolve()
167
180
  })
168
181