From d03ef602e848338c6c1099aac083ddaa7532b9d3 Mon Sep 17 00:00:00 2001 From: theanarkh Date: Mon, 25 Jul 2022 23:51:13 +0800 Subject: [PATCH] lib: add diagnostics channel and perf hooks detail --- doc/api/diagnostics_channel.md | 18 ++++++++++++ doc/api/perf_hooks.md | 8 ++++-- lib/dgram.js | 8 ++++++ lib/dns.js | 8 +++--- lib/internal/dns/promises.js | 8 +++--- lib/net.js | 17 +++++++++-- test/parallel/test-diagnostics-channel-net.js | 28 +++++++++++++++++++ test/parallel/test-diagnostics-channel-udp.js | 16 +++++++++++ test/parallel/test-dns-perf_hooks.js | 28 ++++++++++++++++++- 9 files changed, 125 insertions(+), 14 deletions(-) create mode 100644 test/parallel/test-diagnostics-channel-net.js create mode 100644 test/parallel/test-diagnostics-channel-udp.js diff --git a/doc/api/diagnostics_channel.md b/doc/api/diagnostics_channel.md index 04a602195848a3..912c8ea63fc481 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 new a client socket. + +`net.server.socket` + +* `socket` {net.Socket} + +Emitted when receive a connection. + +`udp.socket` + +* `socket` {dgram.Socket} + +Emitted when call `'createSocket'`. + [`'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 a56b1f232a1b06..ea617199517a60 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 with the result of `queryxxx` or `getHostByAddr`. ## Class: `PerformanceNodeTiming` diff --git a/lib/dgram.js b/lib/dgram.js index 5f644d2a6c30e3..9a11a2287c6155 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 97793eb12aaf3a..5fe34b4b049358 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 334260923faa7b..ac40bc5541b997 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 a67dda1309c722..34e55dbe9e8bef 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); } @@ -1706,8 +1715,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-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..ae4a1fc981b08f --- /dev/null +++ b/test/parallel/test-diagnostics-channel-udp.js @@ -0,0 +1,16 @@ +'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..d1c7fb9b3c51ec 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; + } }); });