Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lib: add diagnostics channel and perf hooks detail #43984

Merged
merged 1 commit into from
Jul 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions doc/api/diagnostics_channel.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 5 additions & 3 deletions doc/api/perf_hooks.md
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
Expand Up @@ -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 } });
}
}

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

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

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

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

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

Expand Down
17 changes: 15 additions & 2 deletions lib/net.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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,
});
}
}

/**
Expand Down
1 change: 1 addition & 0 deletions test/parallel/test-bootstrap-modules.js
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
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;
}
});
});