GeezerVison is showing github.com — http: add perf_hooks detail for http request and client · nodejs/node@f05fd1a
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: doc/api/perf_hooks.md +18Lines changed: 18 additions & 0 deletions - Display the source diff
- Display the rich diff
| Original file line number | Diff line number | Diff line change |
|---|
@@ -521,6 +521,24 @@ property will be an {Object} with two properties: | 521 | 521 | * `perf_hooks.constants.NODE_PERFORMANCE_GC_FLAGS_ALL_EXTERNAL_MEMORY` | 522 | 522 | * `perf_hooks.constants.NODE_PERFORMANCE_GC_FLAGS_SCHEDULE_IDLE` | 523 | 523 |
| | 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 | + | 524 | 542 | ### HTTP/2 ('http2') Details | 525 | 543 |
| 526 | 544 | When `performanceEntry.type` is equal to `'http2'`, the | |
Collapse file Copy file name to clipboardExpand all lines: lib/_http_client.js +25-8Lines changed: 25 additions & 8 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -64,7 +64,7 @@ const Agent = require('_http_agent'); | 64 | 64 | const { Buffer } = require('buffer'); | 65 | 65 | const { defaultTriggerAsyncIdScope } = require('internal/async_hooks'); | 66 | 66 | const { URL, urlToHttpOptions, searchParamsSymbol } = require('internal/url'); | 67 | | -const { kOutHeaders, kNeedDrain, emitStatistics } = require('internal/http'); | | 67 | +const { kOutHeaders, kNeedDrain } = require('internal/http'); | 68 | 68 | const { connResetException, codes } = require('internal/errors'); | 69 | 69 | const { | 70 | 70 | ERR_HTTP_HEADERS_SENT, | @@ -84,10 +84,10 @@ const { | 84 | 84 |
| 85 | 85 | const { | 86 | 86 | hasObserver, | | 87 | + startPerf, | | 88 | + stopPerf, | 87 | 89 | } = require('internal/perf/observe'); | 88 | 90 |
| 89 | | -const { now } = require('internal/perf/utils'); | 90 | | - | 91 | 91 | const kClientRequestStatistics = Symbol('ClientRequestStatistics'); | 92 | 92 |
| 93 | 93 | const { addAbortSignal, finished } = require('stream'); | @@ -355,10 +355,17 @@ ClientRequest.prototype._finish = function _finish() { | 355 | 355 | DTRACE_HTTP_CLIENT_REQUEST(this, this.socket); | 356 | 356 | FunctionPrototypeCall(OutgoingMessage.prototype._finish, this); | 357 | 357 | 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 | + }); | 362 | 369 | } | 363 | 370 | }; | 364 | 371 |
| @@ -627,7 +634,17 @@ function parserOnIncomingClient(res, shouldKeepAlive) { | 627 | 634 | } | 628 | 635 |
| 629 | 636 | 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 | + } | 631 | 648 | req.res = res; | 632 | 649 | res.req = req; | 633 | 650 |
| |
Collapse file Copy file name to clipboardExpand all lines: lib/_http_server.js +24-8Lines changed: 24 additions & 8 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -54,7 +54,6 @@ const { | 54 | 54 | const { | 55 | 55 | kOutHeaders, | 56 | 56 | kNeedDrain, | 57 | | - emitStatistics | 58 | 57 | } = require('internal/http'); | 59 | 58 | const { | 60 | 59 | defaultTriggerAsyncIdScope, | @@ -98,10 +97,10 @@ const kServerResponseStatistics = Symbol('ServerResponseStatistics'); | 98 | 97 |
| 99 | 98 | const { | 100 | 99 | hasObserver, | | 100 | + startPerf, | | 101 | + stopPerf, | 101 | 102 | } = require('internal/perf/observe'); | 102 | 103 |
| 103 | | -const { now } = require('internal/perf/utils'); | 104 | | - | 105 | 104 | const STATUS_CODES = { | 106 | 105 | 100: 'Continue', // RFC 7231 6.2.1 | 107 | 106 | 101: 'Switching Protocols', // RFC 7231 6.2.2 | @@ -198,18 +197,35 @@ function ServerResponse(req) { | 198 | 197 | } | 199 | 198 |
| 200 | 199 | 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 | + }); | 205 | 211 | } | 206 | 212 | } | 207 | 213 | ObjectSetPrototypeOf(ServerResponse.prototype, OutgoingMessage.prototype); | 208 | 214 | ObjectSetPrototypeOf(ServerResponse, OutgoingMessage); | 209 | 215 |
| 210 | 216 | ServerResponse.prototype._finish = function _finish() { | 211 | 217 | 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 | + } | 213 | 229 | OutgoingMessage.prototype._finish.call(this); | 214 | 230 | }; | 215 | 231 |
| |
Collapse file Copy file name to clipboardExpand all lines: lib/internal/http.js -23Lines changed: 0 additions & 23 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 9 | 9 |
| 10 | 10 | const { setUnrefTimeout } = require('internal/timers'); | 11 | 11 |
| 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 | | - | 21 | 12 | let utcCache; | 22 | 13 |
| 23 | 14 | function utcDate() { | @@ -35,22 +26,8 @@ function resetCache() { | 35 | 26 | utcCache = undefined; | 36 | 27 | } | 37 | 28 |
| 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 | | - | 51 | 29 | module.exports = { | 52 | 30 | kOutHeaders: Symbol('kOutHeaders'), | 53 | 31 | kNeedDrain: Symbol('kNeedDrain'), | 54 | 32 | utcDate, | 55 | | - emitStatistics, | 56 | 33 | }; |
Collapse file Copy file name to clipboardExpand all lines: test/parallel/test-http-perf_hooks.js +6Lines changed: 6 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -66,6 +66,12 @@ process.on('exit', () => { | 66 | 66 | } else if (entry.name === 'HttpRequest') { | 67 | 67 | numberOfHttpRequests++; | 68 | 68 | } | | 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'); | 69 | 75 | }); | 70 | 76 | assert.strictEqual(numberOfHttpClients, 2); | 71 | 77 | assert.strictEqual(numberOfHttpRequests, 2); | |
|