Skip to content

Commit

Permalink
net: add new net.server.listen tracing channel
Browse files Browse the repository at this point in the history
PR-URL: #53136
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Mohammed Keyvanzadeh <mohammadkeyvanzade94@gmail.com>
Reviewed-By: Santiago Gimeno <santiago.gimeno@gmail.com>
  • Loading branch information
ShogunPanda authored and targos committed Jun 1, 2024
1 parent 74cefa5 commit a0766bd
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 13 deletions.
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();

0 comments on commit a0766bd

Please sign in to comment.