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

net: add new net.server.listen tracing channel #53136

Merged
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
21 changes: 21 additions & 0 deletions doc/api/diagnostics_channel.md
Original file line number Diff line number Diff line change
Expand Up @@ -1131,6 +1131,26 @@ Emitted when a new TCP or pipe client socket is created.

Emitted when a new TCP or pipe connection is received.

`tracing:net.server.listen:asyncStart`

* `server` {net.Server}
* `options` {Object}

Emitted when [`net.Server.listen()`][] is invoked, before the port or pipe is actually setup.

`tracing:net.server.listen:asyncEnd`

* `server` {net.Server}

Emitted when [`net.Server.listen()`][] has completed and thus the server is ready to accept connection.

`tracing:net.server.listen:error`

* `server` {net.Server}
* `error` {Error}

Emitted when [`net.Server.listen()`][] is returning an error.

#### UDP

`udp.socket`
Expand Down Expand Up @@ -1179,5 +1199,6 @@ Emitted when a new thread is created.
[`diagnostics_channel.unsubscribe(name, onMessage)`]: #diagnostics_channelunsubscribename-onmessage
[`end` event]: #endevent
[`error` event]: #errorevent
[`net.Server.listen()`]: net.md#serverlisten
[`start` event]: #startevent
[context loss]: async_context.md#troubleshooting-context-loss
19 changes: 19 additions & 0 deletions lib/net.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ const kPerfHooksNetConnectContext = Symbol('kPerfHooksNetConnectContext');
const dc = require('diagnostics_channel');
const netClientSocketChannel = dc.channel('net.client.socket');
const netServerSocketChannel = dc.channel('net.server.socket');
const netServerListen = dc.tracingChannel('net.server.listen');

const {
hasObserver,
Expand Down Expand Up @@ -1879,6 +1880,11 @@ function setupListenHandle(address, port, addressType, backlog, fd, flags) {

if (typeof rval === 'number') {
const error = new UVExceptionWithHostPort(rval, 'listen', address, port);

if (netServerListen.hasSubscribers) {
netServerListen.error.publish({ server: this, error });
}

process.nextTick(emitErrorNT, this, error);
return;
}
Expand All @@ -1898,6 +1904,11 @@ function setupListenHandle(address, port, addressType, backlog, fd, flags) {
const ex = new UVExceptionWithHostPort(err, 'listen', address, port);
this._handle.close();
this._handle = null;

if (netServerListen.hasSubscribers) {
netServerListen.error.publish({ server: this, error: ex });
}

defaultTriggerAsyncIdScope(this[async_id_symbol],
process.nextTick,
emitErrorNT,
Expand All @@ -1906,6 +1917,10 @@ function setupListenHandle(address, port, addressType, backlog, fd, flags) {
return;
}

if (netServerListen.hasSubscribers) {
netServerListen.asyncEnd.publish({ server: this });
}

// Generate connection key, this should be unique to the connection
this._connectionKey = addressType + ':' + address + ':' + port;

Expand Down Expand Up @@ -1993,6 +2008,10 @@ Server.prototype.listen = function(...args) {
throw new ERR_SERVER_ALREADY_LISTEN();
}

if (netServerListen.hasSubscribers) {
netServerListen.asyncStart.publish({ server: this, options });
}

if (cb !== null) {
this.once('listening', cb);
}
Expand Down
92 changes: 79 additions & 13 deletions test/parallel/test-diagnostics-channel-net.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,87 @@ const net = require('net');
const dc = require('diagnostics_channel');

const isNetSocket = (socket) => socket instanceof net.Socket;
const isNetServer = (server) => server instanceof net.Server;

dc.subscribe('net.client.socket', common.mustCall(({ socket }) => {
assert.strictEqual(isNetSocket(socket), true);
}));
function testDiagnosticChannel(subscribers, test, after) {
dc.tracingChannel('net.server.listen').subscribe(subscribers);

dc.subscribe('net.server.socket', common.mustCall(({ socket }) => {
assert.strictEqual(isNetSocket(socket), true);
}));
test(common.mustCall(() => {
dc.tracingChannel('net.server.listen').unsubscribe(subscribers);
after?.();
}));
}

const server = net.createServer(common.mustCall((socket) => {
socket.destroy();
server.close();
}));
const testSuccessfullListen = common.mustCall(() => {
let cb;
const server = net.createServer(common.mustCall((socket) => {
socket.destroy();
server.close();
cb();
}));

server.listen(() => {
const { port } = server.address();
net.connect(port);
dc.subscribe('net.client.socket', common.mustCall(({ socket }) => {
assert.strictEqual(isNetSocket(socket), true);
}));

dc.subscribe('net.server.socket', common.mustCall(({ socket }) => {
assert.strictEqual(isNetSocket(socket), true);
}));

testDiagnosticChannel(
{
asyncStart: common.mustCall(({ server: currentServer, options }) => {
assert.strictEqual(isNetServer(server), true);
assert.strictEqual(currentServer, server);
assert.strictEqual(options.customOption, true);
}),
asyncEnd: common.mustCall(({ server: currentServer }) => {
assert.strictEqual(isNetServer(server), true);
assert.strictEqual(currentServer, server);
}),
error: common.mustNotCall()
},
common.mustCall((callback) => {
cb = callback;
server.listen({ port: 0, customOption: true }, () => {
const { port } = server.address();
net.connect(port);
});
}),
testFailingListen
);
});

const testFailingListen = common.mustCall(() => {
const originalServer = net.createServer(common.mustNotCall());

originalServer.listen(() => {
const server = net.createServer(common.mustNotCall());

testDiagnosticChannel(
{
asyncStart: common.mustCall(({ server: currentServer, options }) => {
assert.strictEqual(isNetServer(server), true);
assert.strictEqual(currentServer, server);
assert.strictEqual(options.customOption, true);
}),
asyncEnd: common.mustNotCall(),
error: common.mustCall(({ server: currentServer }) => {
assert.strictEqual(isNetServer(server), true);
assert.strictEqual(currentServer, server);
}),
},
common.mustCall((callback) => {
server.on('error', () => {});
server.listen({ port: originalServer.address().port, customOption: true });
callback();
}),
common.mustCall(() => {
originalServer.close();
server.close();
})
);
});
});

testSuccessfullListen();