Skip to content

Commit

Permalink
http: add diagnostics channel for http client
Browse files Browse the repository at this point in the history
  • Loading branch information
theanarkh committed Jun 28, 2022
1 parent 42ad967 commit e2c069a
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 6 deletions.
40 changes: 34 additions & 6 deletions doc/api/diagnostics_channel.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ pipeline. It is use to track subscribers and to publish messages when there
are subscribers present. It exists as a separate object to avoid channel
lookups at publish time, enabling very fast publish speeds and allowing
for heavy use while incurring very minimal cost. Channels are created with
[`diagnostics_channel.channel(name)`][], constructing a channel directly
\[`diagnostics_channel.channel(name)`]\[], constructing a channel directly
with `new Channel(name)` is not supported.

#### `channel.hasSubscribers`
Expand Down Expand Up @@ -236,7 +236,8 @@ added:

Register a message handler to subscribe to this channel. This message handler
will be run synchronously whenever a message is published to the channel. Any
errors thrown in the message handler will trigger an [`'uncaughtException'`][].
errors thrown in the message handler will trigger an
\[`'uncaughtException'`]\[].

```mjs
import diagnostics_channel from 'node:diagnostics_channel';
Expand Down Expand Up @@ -277,7 +278,7 @@ changes:
* Returns: {boolean} `true` if the handler was found, `false` otherwise.

Remove a message handler previously registered to this channel with
[`channel.subscribe(onMessage)`][].
\[`channel.subscribe(onMessage)`]\[].

```mjs
import diagnostics_channel from 'node:diagnostics_channel';
Expand Down Expand Up @@ -307,6 +308,33 @@ channel.subscribe(onMessage);
channel.unsubscribe(onMessage);
```

[`'uncaughtException'`]: process.md#event-uncaughtexception
[`channel.subscribe(onMessage)`]: #channelsubscribeonmessage
[`diagnostics_channel.channel(name)`]: #diagnostics_channelchannelname
### Built-in Channels

#### HTTP

`http.client.request.start`: Emited with arguments `request` when client
starts a request.

* `request` {http.ClientRequest}

`http.client.response.finish`: Emited with arguments `request`, `response`
when client receives a response.

* `request` {http.ClientRequest}
* `response` {http.IncomingMessage}

`http.server.request.start`: Emited with arguments `request`, `response`,
`socket`, `server` when server receives a request.

* `request` {http.IncomingMessage}
* `response` {http.ServerResponse}
* `socket` {net.Socket}
* `server` {http.Server}

`http.server.response.finish`: Emited with arguments `request`, `response`,
`socket`, `server` when server sends a response.

* `request` {http.IncomingMessage}
* `response` {http.ServerResponse}
* `socket` {net.Socket}
* `server` {http.Server}
15 changes: 15 additions & 0 deletions lib/_http_client.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ const {

const kClientRequestStatistics = Symbol('ClientRequestStatistics');

const dc = require('diagnostics_channel');
const onClientRequestStartChannel = dc.channel('http.client.request.start');
const onClientResponseFinishChannel = dc.channel('http.client.response.finish');

const { addAbortSignal, finished } = require('stream');

let debug = require('internal/util/debuglog').debuglog('http', (fn) => {
Expand Down Expand Up @@ -367,6 +371,11 @@ ClientRequest.prototype._finish = function _finish() {
},
});
}
if (onClientRequestStartChannel.hasSubscribers) {
onClientRequestStartChannel.publish({
request: this,
});
}
};

ClientRequest.prototype._implicitHeader = function _implicitHeader() {
Expand Down Expand Up @@ -645,6 +654,12 @@ function parserOnIncomingClient(res, shouldKeepAlive) {
},
});
}
if (onClientResponseFinishChannel.hasSubscribers) {
onClientResponseFinishChannel.publish({
request: req,
response: res,
});
}
req.res = res;
res.req = req;

Expand Down
63 changes: 63 additions & 0 deletions test/parallel/test-diagnostics-channel-http.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const http = require('http');
const net = require('net');
const dc = require('diagnostics_channel');

const onClientRequestStart = dc.channel('http.client.request.start');
const onClientResponseFinish = dc.channel('http.client.response.finish');
const onServerRequestStart = dc.channel('http.server.request.start');
const onServerResponseFinish = dc.channel('http.server.response.finish');

const isHTTPServer = (server) => server instanceof http.Server;
const isIncomingMessage = (object) => object instanceof http.IncomingMessage;
const isOutgoingMessage = (object) => object instanceof http.OutgoingMessage;
const isNetSocket = (socket) => socket instanceof net.Socket;

onClientRequestStart.subscribe(common.mustCall(({ request }) => {
assert.strictEqual(isOutgoingMessage(request), true);
}));

onClientResponseFinish.subscribe(common.mustCall(({ request, response }) => {
assert.strictEqual(isOutgoingMessage(request), true);
assert.strictEqual(isIncomingMessage(response), true);
}));

onServerRequestStart.subscribe(common.mustCall(({
request,
response,
socket,
server,
}) => {
assert.strictEqual(isIncomingMessage(request), true);
assert.strictEqual(isOutgoingMessage(response), true);
assert.strictEqual(isNetSocket(socket), true);
assert.strictEqual(isHTTPServer(server), true);
}));

onServerResponseFinish.subscribe(common.mustCall(({
request,
response,
socket,
server,
}) => {
assert.strictEqual(isIncomingMessage(request), true);
assert.strictEqual(isOutgoingMessage(response), true);
assert.strictEqual(isNetSocket(socket), true);
assert.strictEqual(isHTTPServer(server), true);
}));

const server = http.createServer(common.mustCall((req, res) => {
res.end('done');
}));

server.listen(() => {
const { port } = server.address();
http.get(`http://localhost:${port}`, (res) => {
res.resume();
res.on('end', () => {
server.close();
});
});
});

0 comments on commit e2c069a

Please sign in to comment.