Skip to content

Commit f05fd1a

Browse files
theanarkhtargos
authored andcommitted
http: add perf_hooks detail for http request and client
PR-URL: #43361 Reviewed-By: Paolo Insogna <[email protected]> Reviewed-By: Matteo Collina <[email protected]>
1 parent 588a84e commit f05fd1a

File tree

5 files changed

+73
-39
lines changed

5 files changed

+73
-39
lines changed

doc/api/perf_hooks.md

+18
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,24 @@ property will be an {Object} with two properties:
521521
* `perf_hooks.constants.NODE_PERFORMANCE_GC_FLAGS_ALL_EXTERNAL_MEMORY`
522522
* `perf_hooks.constants.NODE_PERFORMANCE_GC_FLAGS_SCHEDULE_IDLE`
523523

524+
### HTTP ('http') Details
525+
526+
When `performanceEntry.type` is equal to `'http'`, the `performanceEntry.detail`
527+
property will be an {Object} containing additional information.
528+
529+
If `performanceEntry.name` is equal to `HttpClient`, the `detail`
530+
will contain the following properties: `req`, `res`. And the `req` property
531+
will be an {Object} containing `method`, `url`, `headers`, the `res` property
532+
will be an {Object} containing `statusCode`, `statusMessage`, `headers`.
533+
534+
If `performanceEntry.name` is equal to `HttpRequest`, the `detail`
535+
will contain the following properties: `req`, `res`. And the `req` property
536+
will be an {Object} containing `method`, `url`, `headers`, the `res` property
537+
will be an {Object} containing `statusCode`, `statusMessage`, `headers`.
538+
539+
This could add additional memory overhead and should only be used for
540+
diagnostic purposes, not left turned on in production by default.
541+
524542
### HTTP/2 ('http2') Details
525543

526544
When `performanceEntry.type` is equal to `'http2'`, the

lib/_http_client.js

+25-8
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ const Agent = require('_http_agent');
6464
const { Buffer } = require('buffer');
6565
const { defaultTriggerAsyncIdScope } = require('internal/async_hooks');
6666
const { URL, urlToHttpOptions, searchParamsSymbol } = require('internal/url');
67-
const { kOutHeaders, kNeedDrain, emitStatistics } = require('internal/http');
67+
const { kOutHeaders, kNeedDrain } = require('internal/http');
6868
const { connResetException, codes } = require('internal/errors');
6969
const {
7070
ERR_HTTP_HEADERS_SENT,
@@ -84,10 +84,10 @@ const {
8484

8585
const {
8686
hasObserver,
87+
startPerf,
88+
stopPerf,
8789
} = require('internal/perf/observe');
8890

89-
const { now } = require('internal/perf/utils');
90-
9191
const kClientRequestStatistics = Symbol('ClientRequestStatistics');
9292

9393
const { addAbortSignal, finished } = require('stream');
@@ -355,10 +355,17 @@ ClientRequest.prototype._finish = function _finish() {
355355
DTRACE_HTTP_CLIENT_REQUEST(this, this.socket);
356356
FunctionPrototypeCall(OutgoingMessage.prototype._finish, this);
357357
if (hasObserver('http')) {
358-
this[kClientRequestStatistics] = {
359-
startTime: now(),
360-
type: 'HttpClient',
361-
};
358+
startPerf(this, kClientRequestStatistics, {
359+
type: 'http',
360+
name: 'HttpClient',
361+
detail: {
362+
req: {
363+
method: this.method,
364+
url: `${this.protocol}//${this.host}${this.path}`,
365+
headers: typeof this.getHeaders === 'function' ? this.getHeaders() : {},
366+
},
367+
},
368+
});
362369
}
363370
};
364371

@@ -627,7 +634,17 @@ function parserOnIncomingClient(res, shouldKeepAlive) {
627634
}
628635

629636
DTRACE_HTTP_CLIENT_RESPONSE(socket, req);
630-
emitStatistics(req[kClientRequestStatistics]);
637+
if (req[kClientRequestStatistics] && hasObserver('http')) {
638+
stopPerf(req, kClientRequestStatistics, {
639+
detail: {
640+
res: {
641+
statusCode: res.statusCode,
642+
statusMessage: res.statusMessage,
643+
headers: res.headers,
644+
},
645+
},
646+
});
647+
}
631648
req.res = res;
632649
res.req = req;
633650

lib/_http_server.js

+24-8
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ const {
5454
const {
5555
kOutHeaders,
5656
kNeedDrain,
57-
emitStatistics
5857
} = require('internal/http');
5958
const {
6059
defaultTriggerAsyncIdScope,
@@ -98,10 +97,10 @@ const kServerResponseStatistics = Symbol('ServerResponseStatistics');
9897

9998
const {
10099
hasObserver,
100+
startPerf,
101+
stopPerf,
101102
} = require('internal/perf/observe');
102103

103-
const { now } = require('internal/perf/utils');
104-
105104
const STATUS_CODES = {
106105
100: 'Continue', // RFC 7231 6.2.1
107106
101: 'Switching Protocols', // RFC 7231 6.2.2
@@ -198,18 +197,35 @@ function ServerResponse(req) {
198197
}
199198

200199
if (hasObserver('http')) {
201-
this[kServerResponseStatistics] = {
202-
startTime: now(),
203-
type: 'HttpRequest',
204-
};
200+
startPerf(this, kServerResponseStatistics, {
201+
type: 'http',
202+
name: 'HttpRequest',
203+
detail: {
204+
req: {
205+
method: req.method,
206+
url: req.url,
207+
headers: req.headers,
208+
},
209+
},
210+
});
205211
}
206212
}
207213
ObjectSetPrototypeOf(ServerResponse.prototype, OutgoingMessage.prototype);
208214
ObjectSetPrototypeOf(ServerResponse, OutgoingMessage);
209215

210216
ServerResponse.prototype._finish = function _finish() {
211217
DTRACE_HTTP_SERVER_RESPONSE(this.socket);
212-
emitStatistics(this[kServerResponseStatistics]);
218+
if (this[kServerResponseStatistics] && hasObserver('http')) {
219+
stopPerf(this, kServerResponseStatistics, {
220+
detail: {
221+
res: {
222+
statusCode: this.statusCode,
223+
statusMessage: this.statusMessage,
224+
headers: typeof this.getHeaders === 'function' ? this.getHeaders() : {},
225+
},
226+
},
227+
});
228+
}
213229
OutgoingMessage.prototype._finish.call(this);
214230
};
215231

lib/internal/http.js

-23
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,6 @@ const {
99

1010
const { setUnrefTimeout } = require('internal/timers');
1111

12-
const { InternalPerformanceEntry } = require('internal/perf/performance_entry');
13-
14-
const {
15-
enqueue,
16-
hasObserver,
17-
} = require('internal/perf/observe');
18-
19-
const { now } = require('internal/perf/utils');
20-
2112
let utcCache;
2213

2314
function utcDate() {
@@ -35,22 +26,8 @@ function resetCache() {
3526
utcCache = undefined;
3627
}
3728

38-
function emitStatistics(statistics) {
39-
if (!hasObserver('http') || statistics == null) return;
40-
const startTime = statistics.startTime;
41-
const entry = new InternalPerformanceEntry(
42-
statistics.type,
43-
'http',
44-
startTime,
45-
now() - startTime,
46-
undefined,
47-
);
48-
enqueue(entry);
49-
}
50-
5129
module.exports = {
5230
kOutHeaders: Symbol('kOutHeaders'),
5331
kNeedDrain: Symbol('kNeedDrain'),
5432
utcDate,
55-
emitStatistics,
5633
};

test/parallel/test-http-perf_hooks.js

+6
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,12 @@ process.on('exit', () => {
6666
} else if (entry.name === 'HttpRequest') {
6767
numberOfHttpRequests++;
6868
}
69+
assert.strictEqual(typeof entry.detail.req.method, 'string');
70+
assert.strictEqual(typeof entry.detail.req.url, 'string');
71+
assert.strictEqual(typeof entry.detail.req.headers, 'object');
72+
assert.strictEqual(typeof entry.detail.res.statusCode, 'number');
73+
assert.strictEqual(typeof entry.detail.res.statusMessage, 'string');
74+
assert.strictEqual(typeof entry.detail.res.headers, 'object');
6975
});
7076
assert.strictEqual(numberOfHttpClients, 2);
7177
assert.strictEqual(numberOfHttpRequests, 2);

0 commit comments

Comments
 (0)