diff --git a/doc/api/diagnostics_channel.md b/doc/api/diagnostics_channel.md index 6ea1d0c112805d..b35390f39c2b07 100644 --- a/doc/api/diagnostics_channel.md +++ b/doc/api/diagnostics_channel.md @@ -425,6 +425,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 3ded7e3be9c9ad..3477f28377b316 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 6125adff0b5a82..246649ad65c21a 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 233c551212c56d..01e85292d4f3b1 100644 --- a/lib/dns.js +++ b/lib/dns.js @@ -110,7 +110,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 } }); } } @@ -131,7 +131,7 @@ function onlookupall(err, addresses) { this.callback(null, addresses); if (this[kPerfHooksDnsLookupContext] && hasObserver('dns')) { - stopPerf(this, kPerfHooksDnsLookupContext); + stopPerf(this, kPerfHooksDnsLookupContext, { detail: { addresses } }); } } @@ -227,7 +227,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 } }); } } @@ -280,7 +280,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 062753c0430ff2..1dcf78d92ea21e 100644 --- a/lib/internal/dns/promises.js +++ b/lib/internal/dns/promises.js @@ -86,7 +86,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 } }); } } @@ -109,7 +109,7 @@ function onlookupall(err, addresses) { this.resolve(addresses); if (this[kPerfHooksDnsLookupContext] && hasObserver('dns')) { - stopPerf(this, kPerfHooksDnsLookupContext); + stopPerf(this, kPerfHooksDnsLookupContext, { detail: { addresses } }); } } @@ -191,7 +191,7 @@ function onlookupservice(err, hostname, service) { this.resolve({ hostname, service }); if (this[kPerfHooksDnsLookupServiceContext] && hasObserver('dns')) { - stopPerf(this, kPerfHooksDnsLookupServiceContext); + stopPerf(this, kPerfHooksDnsLookupServiceContext, { detail: { hostname, service } }); } } @@ -247,7 +247,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 282a361e403eb3..5f2aa9c5de1ed8 100644 --- a/lib/net.js +++ b/lib/net.js @@ -133,6 +133,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, @@ -204,7 +209,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); } @@ -1714,6 +1723,11 @@ function onconnection(err, clientHandle) { DTRACE_NET_SERVER_CONNECTION(socket); 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 c5da4d386f9ffe..d108b9a6cf5286 100644 --- a/test/parallel/test-bootstrap-modules.js +++ b/test/parallel/test-bootstrap-modules.js @@ -160,6 +160,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 00000000000000..c03078a12659ac --- /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 00000000000000..79869c6d807926 --- /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 d90b7dfe3dea95..7636020bf6fe31 100644 --- a/test/parallel/test-dns-perf_hooks.js +++ b/test/parallel/test-dns-perf_hooks.js @@ -6,21 +6,55 @@ const dns = require('dns'); const { PerformanceObserver } = require('perf_hooks'); const entries = []; -const obs = new PerformanceObserver(common.mustCallAtLeast((items) => { +const obs = new PerformanceObserver((items) => { entries.push(...items.getEntries()); -})); +}); obs.observe({ type: 'dns' }); -dns.lookup('localhost', () => {}); +let count = 0; + +function inc() { + count++; +} + +// If DNS resolution fails, skip it +// https://github.com/nodejs/node/issues/44003 +dns.lookup('localhost', common.mustCall((err) => { !err && inc(); })); +dns.lookupService('127.0.0.1', 80, common.mustCall((err) => { !err && inc(); })); +dns.resolveAny('localhost', common.mustCall((err) => { !err && inc(); })); + +dns.promises.lookup('localhost').then(inc).catch(() => {}); +dns.promises.lookupService('127.0.0.1', 80).then(inc).catch(() => {}); +dns.promises.resolveAny('localhost').then(inc).catch(() => {}); process.on('exit', () => { - assert.strictEqual(entries.length, 1); + assert.strictEqual(entries.length, count); 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; + } }); });