Skip to content

Commit

Permalink
lib: add diagnostics channel and perf hooks detail
Browse files Browse the repository at this point in the history
Co-Authored-By: theanarkh <theratliter@gmail.com>
PR-URL: #43984
Backport-PR-URL: #44256
Reviewed-By: Matteo Collina matteo.collina@gmail.com
Reviewed-By: Mohammed Keyvanzadeh mohammadkeyvanzade94@gmail.com
Reviewed-By: Minwoo Jung nodecorelab@gmail.com
  • Loading branch information
2 people authored and juanarbol committed Oct 11, 2022
1 parent 763a63c commit 9dad4b0
Show file tree
Hide file tree
Showing 10 changed files with 136 additions and 16 deletions.
18 changes: 18 additions & 0 deletions doc/api/diagnostics_channel.md
Expand Up @@ -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
Expand Down
8 changes: 5 additions & 3 deletions doc/api/perf_hooks.md
Expand Up @@ -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`

Expand Down
8 changes: 8 additions & 0 deletions lib/dgram.js
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
8 changes: 4 additions & 4 deletions lib/dns.js
Expand Up @@ -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 } });
}
}

Expand All @@ -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 } });
}
}

Expand Down Expand Up @@ -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 } });
}
}

Expand Down Expand Up @@ -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 } });
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions lib/internal/dns/promises.js
Expand Up @@ -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 } });
}
}

Expand All @@ -109,7 +109,7 @@ function onlookupall(err, addresses) {

this.resolve(addresses);
if (this[kPerfHooksDnsLookupContext] && hasObserver('dns')) {
stopPerf(this, kPerfHooksDnsLookupContext);
stopPerf(this, kPerfHooksDnsLookupContext, { detail: { addresses } });
}
}

Expand Down Expand Up @@ -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 } });
}
}

Expand Down Expand Up @@ -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 } });
}
}

Expand Down
16 changes: 15 additions & 1 deletion lib/net.js
Expand Up @@ -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,
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -1714,6 +1723,11 @@ function onconnection(err, clientHandle) {

DTRACE_NET_SERVER_CONNECTION(socket);
self.emit('connection', socket);
if (netServerSocketChannel.hasSubscribers) {
netServerSocketChannel.publish({
socket,
});
}
}

/**
Expand Down
1 change: 1 addition & 0 deletions test/parallel/test-bootstrap-modules.js
Expand Up @@ -160,6 +160,7 @@ const expectedModules = new Set([
'NativeModule v8',
'NativeModule internal/v8/startup_snapshot',
'NativeModule vm',
'NativeModule diagnostics_channel',
]);

if (!common.isMainThread) {
Expand Down
28 changes: 28 additions & 0 deletions 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);
});
15 changes: 15 additions & 0 deletions 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();
42 changes: 38 additions & 4 deletions test/parallel/test-dns-perf_hooks.js
Expand Up @@ -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;
}
});
});

0 comments on commit 9dad4b0

Please sign in to comment.