Skip to content

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

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

Merged
Merged
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
@@ -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`
@@ -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
@@ -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,
@@ -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;
}
@@ -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,
@@ -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;

@@ -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);
}
92 changes: 79 additions & 13 deletions test/parallel/test-diagnostics-channel-net.js
Original file line number Diff line number Diff line change
@@ -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();