diff --git a/doc/api/diagnostics_channel.md b/doc/api/diagnostics_channel.md index 3bcf6b7966a21b8..cdce9d6b1c86a50 100644 --- a/doc/api/diagnostics_channel.md +++ b/doc/api/diagnostics_channel.md @@ -428,6 +428,24 @@ Emitted when server receives a request. Emitted when server sends a response. +`net.client.socket` + +* `socket` {net.Socket} + +Emitted when a new TCP or pipe client socket is created. + +`net.server.socket` + +* `socket` {net.Socket} + +Emitted when a new TCP or pipe connection is received. + +`udp.socket` + +* `socket` {dgram.Socket} + +Emitted when a new UDP socket is created. + [`'uncaughtException'`]: process.md#event-uncaughtexception [`channel.subscribe(onMessage)`]: #channelsubscribeonmessage [`diagnostics_channel.channel(name)`]: #diagnostics_channelchannelname diff --git a/doc/api/perf_hooks.md b/doc/api/perf_hooks.md index a56b1f232a1b06a..bb5648f0a744399 100644 --- a/doc/api/perf_hooks.md +++ b/doc/api/perf_hooks.md @@ -602,13 +602,15 @@ When `performanceEntry.type` is equal to `'dns'`, the additional information. If `performanceEntry.name` is equal to `lookup`, the `detail` -will contain the following properties: `hostname`, `family`, `hints`, `verbatim`. +will contain the following properties: `hostname`, `family`, `hints`, `verbatim`, +`addresses`. If `performanceEntry.name` is equal to `lookupService`, the `detail` will -contain the following properties: `host`, `port`. +contain the following properties: `host`, `port`, `hostname`, `service`. If `performanceEntry.name` is equal to `queryxxx` or `getHostByAddr`, the `detail` will -contain the following properties: `host`, `ttl`. +contain the following properties: `host`, `ttl`, `result`. The value of `result` is +same as the result of `queryxxx` or `getHostByAddr`. ## Class: `PerformanceNodeTiming` diff --git a/lib/dgram.js b/lib/dgram.js index 5f644d2a6c30e30..9a11a2287c61554 100644 --- a/lib/dgram.js +++ b/lib/dgram.js @@ -74,6 +74,9 @@ const { SendWrap } = internalBinding('udp_wrap'); +const dc = require('diagnostics_channel'); +const udpSocketChannel = dc.channel('udp.socket'); + const BIND_STATE_UNBOUND = 0; const BIND_STATE_BINDING = 1; const BIND_STATE_BOUND = 2; @@ -145,6 +148,11 @@ function Socket(type, listener) { this.once('close', () => signal.removeEventListener('abort', onAborted)); } } + if (udpSocketChannel.hasSubscribers) { + udpSocketChannel.publish({ + socket: this, + }); + } } ObjectSetPrototypeOf(Socket.prototype, EventEmitter.prototype); ObjectSetPrototypeOf(Socket, EventEmitter); diff --git a/lib/dns.js b/lib/dns.js index 97793eb12aaf3a5..5fe34b4b049358a 100644 --- a/lib/dns.js +++ b/lib/dns.js @@ -112,7 +112,7 @@ function onlookup(err, addresses) { } this.callback(null, addresses[0], this.family || isIP(addresses[0])); if (this[kPerfHooksDnsLookupContext] && hasObserver('dns')) { - stopPerf(this, kPerfHooksDnsLookupContext); + stopPerf(this, kPerfHooksDnsLookupContext, { detail: { addresses } }); } } @@ -133,7 +133,7 @@ function onlookupall(err, addresses) { this.callback(null, addresses); if (this[kPerfHooksDnsLookupContext] && hasObserver('dns')) { - stopPerf(this, kPerfHooksDnsLookupContext); + stopPerf(this, kPerfHooksDnsLookupContext, { detail: { addresses } }); } } @@ -251,7 +251,7 @@ function onlookupservice(err, hostname, service) { this.callback(null, hostname, service); if (this[kPerfHooksDnsLookupServiceContext] && hasObserver('dns')) { - stopPerf(this, kPerfHooksDnsLookupServiceContext); + stopPerf(this, kPerfHooksDnsLookupServiceContext, { detail: { hostname, service } }); } } @@ -304,7 +304,7 @@ function onresolve(err, result, ttls) { else { this.callback(null, result); if (this[kPerfHooksDnsLookupResolveContext] && hasObserver('dns')) { - stopPerf(this, kPerfHooksDnsLookupResolveContext); + stopPerf(this, kPerfHooksDnsLookupResolveContext, { detail: { result } }); } } } diff --git a/lib/internal/dns/promises.js b/lib/internal/dns/promises.js index 334260923faa7b7..ac40bc5541b9979 100644 --- a/lib/internal/dns/promises.js +++ b/lib/internal/dns/promises.js @@ -89,7 +89,7 @@ function onlookup(err, addresses) { const family = this.family || isIP(addresses[0]); this.resolve({ address: addresses[0], family }); if (this[kPerfHooksDnsLookupContext] && hasObserver('dns')) { - stopPerf(this, kPerfHooksDnsLookupContext); + stopPerf(this, kPerfHooksDnsLookupContext, { detail: { addresses } }); } } @@ -112,7 +112,7 @@ function onlookupall(err, addresses) { this.resolve(addresses); if (this[kPerfHooksDnsLookupContext] && hasObserver('dns')) { - stopPerf(this, kPerfHooksDnsLookupContext); + stopPerf(this, kPerfHooksDnsLookupContext, { detail: { addresses } }); } } @@ -205,7 +205,7 @@ function onlookupservice(err, hostname, service) { this.resolve({ hostname, service }); if (this[kPerfHooksDnsLookupServiceContext] && hasObserver('dns')) { - stopPerf(this, kPerfHooksDnsLookupServiceContext); + stopPerf(this, kPerfHooksDnsLookupServiceContext, { detail: { hostname, service } }); } } @@ -261,7 +261,7 @@ function onresolve(err, result, ttls) { this.resolve(result); if (this[kPerfHooksDnsLookupResolveContext] && hasObserver('dns')) { - stopPerf(this, kPerfHooksDnsLookupResolveContext); + stopPerf(this, kPerfHooksDnsLookupResolveContext, { detail: { result } }); } } diff --git a/lib/net.js b/lib/net.js index 47e263f3dbd069e..a1be06346b28a5b 100644 --- a/lib/net.js +++ b/lib/net.js @@ -129,6 +129,11 @@ const isWindows = process.platform === 'win32'; const noop = () => {}; const kPerfHooksNetConnectContext = Symbol('kPerfHooksNetConnectContext'); + +const dc = require('diagnostics_channel'); +const netClientSocketChannel = dc.channel('net.client.socket'); +const netServerSocketChannel = dc.channel('net.server.socket'); + const { hasObserver, startPerf, @@ -200,7 +205,11 @@ function connect(...args) { const options = normalized[0]; debug('createConnection', normalized); const socket = new Socket(options); - + if (netClientSocketChannel.hasSubscribers) { + netClientSocketChannel.publish({ + socket, + }); + } if (options.timeout) { socket.setTimeout(options.timeout); } @@ -1710,8 +1719,12 @@ function onconnection(err, clientHandle) { self._connections++; socket.server = self; socket._server = self; - self.emit('connection', socket); + if (netServerSocketChannel.hasSubscribers) { + netServerSocketChannel.publish({ + socket, + }); + } } /** diff --git a/test/parallel/test-bootstrap-modules.js b/test/parallel/test-bootstrap-modules.js index 374fb3eed623a14..8bbed50df892989 100644 --- a/test/parallel/test-bootstrap-modules.js +++ b/test/parallel/test-bootstrap-modules.js @@ -170,6 +170,7 @@ const expectedModules = new Set([ 'NativeModule v8', 'NativeModule internal/v8/startup_snapshot', 'NativeModule vm', + 'NativeModule diagnostics_channel', ]); if (!common.isMainThread) { diff --git a/test/parallel/test-diagnostics-channel-net.js b/test/parallel/test-diagnostics-channel-net.js new file mode 100644 index 000000000000000..c03078a12659ac7 --- /dev/null +++ b/test/parallel/test-diagnostics-channel-net.js @@ -0,0 +1,28 @@ +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const net = require('net'); +const dc = require('diagnostics_channel'); + +const netClientSocketChannel = dc.channel('net.client.socket'); +const netServerSocketChannel = dc.channel('net.server.socket'); + +const isNetSocket = (socket) => socket instanceof net.Socket; + +netClientSocketChannel.subscribe(common.mustCall(({ socket }) => { + assert.strictEqual(isNetSocket(socket), true); +})); + +netServerSocketChannel.subscribe(common.mustCall(({ socket }) => { + assert.strictEqual(isNetSocket(socket), true); +})); + +const server = net.createServer(common.mustCall((socket) => { + socket.destroy(); + server.close(); +})); + +server.listen(() => { + const { port } = server.address(); + net.connect(port); +}); diff --git a/test/parallel/test-diagnostics-channel-udp.js b/test/parallel/test-diagnostics-channel-udp.js new file mode 100644 index 000000000000000..79869c6d8079268 --- /dev/null +++ b/test/parallel/test-diagnostics-channel-udp.js @@ -0,0 +1,15 @@ +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const dgram = require('dgram'); +const dc = require('diagnostics_channel'); + +const udpSocketChannel = dc.channel('udp.socket'); + +const isUDPSocket = (socket) => socket instanceof dgram.Socket; + +udpSocketChannel.subscribe(common.mustCall(({ socket }) => { + assert.strictEqual(isUDPSocket(socket), true); +})); +const socket = dgram.createSocket('udp4'); +socket.close(); diff --git a/test/parallel/test-dns-perf_hooks.js b/test/parallel/test-dns-perf_hooks.js index d90b7dfe3dea955..d1c7fb9b3c51ec3 100644 --- a/test/parallel/test-dns-perf_hooks.js +++ b/test/parallel/test-dns-perf_hooks.js @@ -13,14 +13,40 @@ const obs = new PerformanceObserver(common.mustCallAtLeast((items) => { obs.observe({ type: 'dns' }); dns.lookup('localhost', () => {}); +dns.lookupService('127.0.0.1', 80, () => {}); +dns.resolveAny('localhost', () => {}); + +dns.promises.lookup('localhost'); +dns.promises.lookupService('127.0.0.1', 80); +dns.promises.resolveAny('localhost'); process.on('exit', () => { - assert.strictEqual(entries.length, 1); + assert.strictEqual(entries.length, 6); entries.forEach((entry) => { assert.strictEqual(!!entry.name, true); assert.strictEqual(entry.entryType, 'dns'); assert.strictEqual(typeof entry.startTime, 'number'); assert.strictEqual(typeof entry.duration, 'number'); assert.strictEqual(typeof entry.detail, 'object'); + switch (entry.name) { + case 'lookup': + assert.strictEqual(typeof entry.detail.hostname, 'string'); + assert.strictEqual(typeof entry.detail.family, 'number'); + assert.strictEqual(typeof entry.detail.hints, 'number'); + assert.strictEqual(typeof entry.detail.verbatim, 'boolean'); + assert.strictEqual(Array.isArray(entry.detail.addresses), true); + break; + case 'lookupService': + assert.strictEqual(typeof entry.detail.host, 'string'); + assert.strictEqual(typeof entry.detail.port, 'number'); + assert.strictEqual(typeof entry.detail.hostname, 'string'); + assert.strictEqual(typeof entry.detail.service, 'string'); + break; + case 'queryAny': + assert.strictEqual(typeof entry.detail.host, 'string'); + assert.strictEqual(typeof entry.detail.ttl, 'boolean'); + assert.strictEqual(Array.isArray(entry.detail.result), true); + break; + } }); });