Skip to content

Commit da42ffb

Browse files
theanarkhbengl
authored andcommitted
http: trace http client by perf_hooks
PR-URL: #42345 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Ricky Zhou <0x19951125@gmail.com>
1 parent 229fb40 commit da42ffb

5 files changed

Lines changed: 66 additions & 9 deletions

File tree

‎doc/api/perf_hooks.md‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1254,6 +1254,36 @@ obs.observe({ entryTypes: ['function'], buffered: true });
12541254
require('some-module');
12551255
```
12561256

1257+
### Measuring how long one HTTP round-trip takes
1258+
1259+
The following example is used to trace the time spent by HTTP client
1260+
(`OutgoingMessage`) and HTTP request (`IncomingMessage`). For HTTP client,
1261+
it means the time interval between starting the request and receiving the
1262+
response, and for HTTP request, it means the time interval between receiving
1263+
the request and sending the response:
1264+
1265+
```js
1266+
'use strict';
1267+
const { PerformanceObserver } =require('perf_hooks');
1268+
consthttp=require('http');
1269+
1270+
constobs=newPerformanceObserver((items) => {
1271+
items.getEntries().forEach((item) => {
1272+
console.log(item);
1273+
});
1274+
});
1275+
1276+
obs.observe({ entryTypes: ['http'] });
1277+
1278+
constPORT=8080;
1279+
1280+
http.createServer((req, res) => {
1281+
res.end('ok');
1282+
}).listen(PORT, () => {
1283+
http.get(`http://127.0.0.1:${PORT}`);
1284+
});
1285+
```
1286+
12571287
[Async Hooks]: async_hooks.md
12581288
[High Resolution Time]: https://www.w3.org/TR/hr-time-2
12591289
[Performance Timeline]: https://w3c.github.io/performance-timeline/

‎lib/_http_client.js‎

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ const Agent = require('_http_agent');
5757
const{ Buffer }=require('buffer');
5858
const{ defaultTriggerAsyncIdScope }=require('internal/async_hooks');
5959
const{URL, urlToHttpOptions, searchParamsSymbol }=require('internal/url');
60-
const{ kOutHeaders, kNeedDrain }=require('internal/http');
60+
const{ kOutHeaders, kNeedDrain, emitStatistics}=require('internal/http');
6161
const{ connResetException, codes }=require('internal/errors');
6262
const{
6363
ERR_HTTP_HEADERS_SENT,
@@ -75,6 +75,12 @@ const {
7575
DTRACE_HTTP_CLIENT_RESPONSE
7676
}=require('internal/dtrace');
7777

78+
const{
79+
hasObserver,
80+
}=require('internal/perf/observe');
81+
82+
constkClientRequestStatistics=Symbol('ClientRequestStatistics');
83+
7884
const{ addAbortSignal, finished }=require('stream');
7985

8086
letdebug=require('internal/util/debuglog').debuglog('http',(fn)=>{
@@ -337,6 +343,12 @@ ObjectSetPrototypeOf(ClientRequest, OutgoingMessage);
337343
ClientRequest.prototype._finish=function_finish(){
338344
DTRACE_HTTP_CLIENT_REQUEST(this,this.socket);
339345
FunctionPrototypeCall(OutgoingMessage.prototype._finish,this);
346+
if(hasObserver('http')){
347+
this[kClientRequestStatistics]={
348+
startTime: process.hrtime(),
349+
type: 'HttpClient',
350+
};
351+
}
340352
};
341353

342354
ClientRequest.prototype._implicitHeader=function_implicitHeader(){
@@ -604,6 +616,7 @@ function parserOnIncomingClient(res, shouldKeepAlive) {
604616
}
605617

606618
DTRACE_HTTP_CLIENT_RESPONSE(socket,req);
619+
emitStatistics(req[kClientRequestStatistics]);
607620
req.res=res;
608621
res.req=req;
609622

‎lib/_http_server.js‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,8 @@ function ServerResponse(req) {
193193

194194
if(hasObserver('http')){
195195
this[kServerResponseStatistics]={
196-
startTime: process.hrtime()
196+
startTime: process.hrtime(),
197+
type: 'HttpRequest',
197198
};
198199
}
199200
}

‎lib/internal/http.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ function emitStatistics(statistics) {
3838
conststartTime=statistics.startTime;
3939
constdiff=process.hrtime(startTime);
4040
constentry=newInternalPerformanceEntry(
41-
'HttpRequest',
41+
statistics.type,
4242
'http',
4343
startTime[0]*1000+startTime[1]/1e6,
4444
diff[0]*1000+diff[1]/1e6,

‎test/parallel/test-http-perf_hooks.js‎

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,9 @@ const assert = require('assert');
55
consthttp=require('http');
66

77
const{ PerformanceObserver }=require('perf_hooks');
8-
8+
constentries=[];
99
constobs=newPerformanceObserver(common.mustCallAtLeast((items)=>{
10-
items.getEntries().forEach((entry)=>{
11-
assert.strictEqual(entry.entryType,'http');
12-
assert.strictEqual(typeofentry.startTime,'number');
13-
assert.strictEqual(typeofentry.duration,'number');
14-
});
10+
entries.push(...items.getEntries());
1511
}));
1612

1713
obs.observe({type: 'http'});
@@ -57,3 +53,20 @@ server.listen(0, common.mustCall(async () => {
5753
]);
5854
server.close();
5955
}));
56+
57+
process.on('exit',()=>{
58+
letnumberOfHttpClients=0;
59+
letnumberOfHttpRequests=0;
60+
entries.forEach((entry)=>{
61+
assert.strictEqual(entry.entryType,'http');
62+
assert.strictEqual(typeofentry.startTime,'number');
63+
assert.strictEqual(typeofentry.duration,'number');
64+
if(entry.name==='HttpClient'){
65+
numberOfHttpClients++;
66+
}elseif(entry.name==='HttpRequest'){
67+
numberOfHttpRequests++;
68+
}
69+
});
70+
assert.strictEqual(numberOfHttpClients,2);
71+
assert.strictEqual(numberOfHttpRequests,2);
72+
});

0 commit comments

Comments
 (0)