GeezerVison is showing github.com — http: trace http request / response · nodejs/node@ed36b0d
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/tracing.md +1Lines changed: 1 addition & 0 deletions - Display the source diff
- Display the rich diff
| Original file line number | Diff line number | Diff line change |
|---|
@@ -36,6 +36,7 @@ The available categories are: | 36 | 36 | * `node.vm.script`: Enables capture of trace data for the `node:vm` module's | 37 | 37 | `runInNewContext()`, `runInContext()`, and `runInThisContext()` methods. | 38 | 38 | * `v8`: The [V8][] events are GC, compiling, and execution related. | | 39 | +* `node.http`: Enables capture of trace data for http request / response. | 39 | 40 |
| 40 | 41 | By default the `node`, `node.async_hooks`, and `v8` categories are enabled. | 41 | 42 |
| |
Collapse file Copy file name to clipboardExpand all lines: lib/_http_client.js +20-1Lines changed: 20 additions & 1 deletion | Original file line number | Diff line number | Diff line change |
|---|
@@ -64,7 +64,14 @@ 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 } = require('internal/http'); | | 67 | +const { | | 68 | + kOutHeaders, | | 69 | + kNeedDrain, | | 70 | + isTraceHTTPEnabled, | | 71 | + traceBegin, | | 72 | + traceEnd, | | 73 | + getNextTraceEventId, | | 74 | +} = require('internal/http'); | 68 | 75 | const { connResetException, codes } = require('internal/errors'); | 69 | 76 | const { | 70 | 77 | ERR_HTTP_HEADERS_SENT, | @@ -106,6 +113,8 @@ const kError = Symbol('kError'); | 106 | 113 | const kLenientAll = HTTPParser.kLenientAll | 0; | 107 | 114 | const kLenientNone = HTTPParser.kLenientNone | 0; | 108 | 115 |
| | 116 | +const HTTP_CLIENT_TRACE_EVENT_NAME = 'http.client.request'; | | 117 | + | 109 | 118 | function validateHost(host, name) { | 110 | 119 | if (host !== null && host !== undefined && typeof host !== 'string') { | 111 | 120 | throw new ERR_INVALID_ARG_TYPE(`options.${name}`, | @@ -376,6 +385,10 @@ ClientRequest.prototype._finish = function _finish() { | 376 | 385 | request: this, | 377 | 386 | }); | 378 | 387 | } | | 388 | + if (isTraceHTTPEnabled()) { | | 389 | + this._traceEventId = getNextTraceEventId(); | | 390 | + traceBegin(HTTP_CLIENT_TRACE_EVENT_NAME, this._traceEventId); | | 391 | + } | 379 | 392 | }; | 380 | 393 |
| 381 | 394 | ClientRequest.prototype._implicitHeader = function _implicitHeader() { | @@ -660,6 +673,12 @@ function parserOnIncomingClient(res, shouldKeepAlive) { | 660 | 673 | response: res, | 661 | 674 | }); | 662 | 675 | } | | 676 | + if (isTraceHTTPEnabled() && typeof req._traceEventId === 'number') { | | 677 | + traceEnd(HTTP_CLIENT_TRACE_EVENT_NAME, req._traceEventId, { | | 678 | + path: req.path, | | 679 | + statusCode: res.statusCode, | | 680 | + }); | | 681 | + } | 663 | 682 | req.res = res; | 664 | 683 | res.req = req; | 665 | 684 |
| |
Collapse file Copy file name to clipboardExpand all lines: lib/_http_server.js +17Lines changed: 17 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -55,6 +55,10 @@ const { | 55 | 55 | const { | 56 | 56 | kOutHeaders, | 57 | 57 | kNeedDrain, | | 58 | + isTraceHTTPEnabled, | | 59 | + traceBegin, | | 60 | + traceEnd, | | 61 | + getNextTraceEventId, | 58 | 62 | } = require('internal/http'); | 59 | 63 | const { | 60 | 64 | defaultTriggerAsyncIdScope, | @@ -174,6 +178,8 @@ const kLenientNone = HTTPParser.kLenientNone | 0; | 174 | 178 | const kConnections = Symbol('http.server.connections'); | 175 | 179 | const kConnectionsCheckingInterval = Symbol('http.server.connectionsCheckingInterval'); | 176 | 180 |
| | 181 | +const HTTP_SERVER_TRACE_EVENT_NAME = 'http.server.request'; | | 182 | + | 177 | 183 | class HTTPServerAsyncResource { | 178 | 184 | constructor(type, socket) { | 179 | 185 | this.type = type; | @@ -210,6 +216,10 @@ function ServerResponse(req) { | 210 | 216 | }, | 211 | 217 | }); | 212 | 218 | } | | 219 | + if (isTraceHTTPEnabled()) { | | 220 | + this._traceEventId = getNextTraceEventId(); | | 221 | + traceBegin(HTTP_SERVER_TRACE_EVENT_NAME, this._traceEventId); | | 222 | + } | 213 | 223 | } | 214 | 224 | ObjectSetPrototypeOf(ServerResponse.prototype, OutgoingMessage.prototype); | 215 | 225 | ObjectSetPrototypeOf(ServerResponse, OutgoingMessage); | @@ -228,6 +238,13 @@ ServerResponse.prototype._finish = function _finish() { | 228 | 238 | }); | 229 | 239 | } | 230 | 240 | OutgoingMessage.prototype._finish.call(this); | | 241 | + if (isTraceHTTPEnabled() && typeof this._traceEventId === 'number') { | | 242 | + const data = { | | 243 | + url: this.req?.url, | | 244 | + statusCode: this.statusCode, | | 245 | + }; | | 246 | + traceEnd(HTTP_SERVER_TRACE_EVENT_NAME, this._traceEventId, data); | | 247 | + } | 231 | 248 | }; | 232 | 249 |
| 233 | 250 |
| |
Collapse file Copy file name to clipboardExpand all lines: lib/internal/http.js +29Lines changed: 29 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 8 | 8 | } = primordials; | 9 | 9 |
| 10 | 10 | const { setUnrefTimeout } = require('internal/timers'); | | 11 | +const { trace, isTraceCategoryEnabled } = internalBinding('trace_events'); | | 12 | +const { | | 13 | + CHAR_LOWERCASE_B, | | 14 | + CHAR_LOWERCASE_E, | | 15 | +} = require('internal/constants'); | 11 | 16 |
| 12 | 17 | let utcCache; | 13 | 18 |
| @@ -26,8 +31,32 @@ function resetCache() { | 26 | 31 | utcCache = undefined; | 27 | 32 | } | 28 | 33 |
| | 34 | +let traceEventId = 0; | | 35 | + | | 36 | +function getNextTraceEventId() { | | 37 | + return ++traceEventId; | | 38 | +} | | 39 | + | | 40 | +function isTraceHTTPEnabled() { | | 41 | + return isTraceCategoryEnabled('node.http'); | | 42 | +} | | 43 | + | | 44 | +const traceEventCategory = 'node,node.http'; | | 45 | + | | 46 | +function traceBegin(...args) { | | 47 | + trace(CHAR_LOWERCASE_B, traceEventCategory, ...args); | | 48 | +} | | 49 | + | | 50 | +function traceEnd(...args) { | | 51 | + trace(CHAR_LOWERCASE_E, traceEventCategory, ...args); | | 52 | +} | | 53 | + | 29 | 54 | module.exports = { | 30 | 55 | kOutHeaders: Symbol('kOutHeaders'), | 31 | 56 | kNeedDrain: Symbol('kNeedDrain'), | 32 | 57 | utcDate, | | 58 | + traceBegin, | | 59 | + traceEnd, | | 60 | + getNextTraceEventId, | | 61 | + isTraceHTTPEnabled, | 33 | 62 | }; |
Collapse file Copy file name to clipboard +44Lines changed: 44 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| | 1 | +'use strict'; | | 2 | +const common = require('../common'); | | 3 | +const assert = require('assert'); | | 4 | +const cp = require('child_process'); | | 5 | +const fs = require('fs'); | | 6 | +const path = require('path'); | | 7 | +const tmpdir = require('../common/tmpdir'); | | 8 | + | | 9 | +const CODE = ` | | 10 | + const http = require('http'); | | 11 | + const server = http.createServer((req, res) => { | | 12 | + res.end('ok'); | | 13 | + server.close(); | | 14 | + }).listen(0, () => { | | 15 | + http.get({port: server.address().port}); | | 16 | + }); | | 17 | +`; | | 18 | + | | 19 | +tmpdir.refresh(); | | 20 | +const FILE_NAME = path.join(tmpdir.path, 'node_trace.1.log'); | | 21 | + | | 22 | +const proc = cp.spawn(process.execPath, | | 23 | + [ '--trace-events-enabled', | | 24 | + '--trace-event-categories', 'node.http', | | 25 | + '-e', CODE ], | | 26 | + { cwd: tmpdir.path }); | | 27 | + | | 28 | +proc.once('exit', common.mustCall(() => { | | 29 | + assert(fs.existsSync(FILE_NAME)); | | 30 | + fs.readFile(FILE_NAME, common.mustCall((err, data) => { | | 31 | + assert(!err); | | 32 | + const traces = JSON.parse(data.toString()).traceEvents; | | 33 | + assert(traces.length > 0); | | 34 | + let count = 0; | | 35 | + traces.forEach((trace) => { | | 36 | + if (trace.cat === 'node,node.http' && | | 37 | + ['http.server.request', 'http.client.request'].includes(trace.name)) { | | 38 | + count++; | | 39 | + } | | 40 | + }); | | 41 | + // Two begin, two end | | 42 | + assert.strictEqual(count, 4); | | 43 | + })); | | 44 | +})); |
|