Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit c340344

Browse filesBrowse files
theanarkhruyadorno
authored andcommitted
http: trace http request / response
PR-URL: #44102 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Paolo Insogna <paolo@cowtech.it>
1 parent 86bbd5e commit c340344
Copy full SHA for c340344

File tree

Expand file treeCollapse file tree

5 files changed

+111
-1
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

5 files changed

+111
-1
lines changed
Open diff view settings
Collapse file

‎doc/api/tracing.md‎

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 numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ The available categories are:
3636
* `node.vm.script`: Enables capture of trace data for the `node:vm` module's
3737
`runInNewContext()`, `runInContext()`, and `runInThisContext()` methods.
3838
* `v8`: The [V8][] events are GC, compiling, and execution related.
39+
* `node.http`: Enables capture of trace data for http request / response.
3940

4041
By default the `node`, `node.async_hooks`, and `v8` categories are enabled.
4142

Collapse file

‎lib/_http_client.js‎

Copy file name to clipboardExpand all lines: lib/_http_client.js
+20-1Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,14 @@ 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 } = require('internal/http');
67+
const {
68+
kOutHeaders,
69+
kNeedDrain,
70+
isTraceHTTPEnabled,
71+
traceBegin,
72+
traceEnd,
73+
getNextTraceEventId,
74+
} = require('internal/http');
6875
const { connResetException, codes } = require('internal/errors');
6976
const {
7077
ERR_HTTP_HEADERS_SENT,
@@ -106,6 +113,8 @@ const kError = Symbol('kError');
106113
const kLenientAll = HTTPParser.kLenientAll | 0;
107114
const kLenientNone = HTTPParser.kLenientNone | 0;
108115

116+
const HTTP_CLIENT_TRACE_EVENT_NAME = 'http.client.request';
117+
109118
function validateHost(host, name) {
110119
if (host !== null && host !== undefined && typeof host !== 'string') {
111120
throw new ERR_INVALID_ARG_TYPE(`options.${name}`,
@@ -376,6 +385,10 @@ ClientRequest.prototype._finish = function _finish() {
376385
request: this,
377386
});
378387
}
388+
if (isTraceHTTPEnabled()) {
389+
this._traceEventId = getNextTraceEventId();
390+
traceBegin(HTTP_CLIENT_TRACE_EVENT_NAME, this._traceEventId);
391+
}
379392
};
380393

381394
ClientRequest.prototype._implicitHeader = function _implicitHeader() {
@@ -660,6 +673,12 @@ function parserOnIncomingClient(res, shouldKeepAlive) {
660673
response: res,
661674
});
662675
}
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+
}
663682
req.res = res;
664683
res.req = req;
665684

Collapse file

‎lib/_http_server.js‎

Copy file name to clipboardExpand all lines: lib/_http_server.js
+17Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ const {
5555
const {
5656
kOutHeaders,
5757
kNeedDrain,
58+
isTraceHTTPEnabled,
59+
traceBegin,
60+
traceEnd,
61+
getNextTraceEventId,
5862
} = require('internal/http');
5963
const {
6064
defaultTriggerAsyncIdScope,
@@ -174,6 +178,8 @@ const kLenientNone = HTTPParser.kLenientNone | 0;
174178
const kConnections = Symbol('http.server.connections');
175179
const kConnectionsCheckingInterval = Symbol('http.server.connectionsCheckingInterval');
176180

181+
const HTTP_SERVER_TRACE_EVENT_NAME = 'http.server.request';
182+
177183
class HTTPServerAsyncResource {
178184
constructor(type, socket) {
179185
this.type = type;
@@ -210,6 +216,10 @@ function ServerResponse(req) {
210216
},
211217
});
212218
}
219+
if (isTraceHTTPEnabled()) {
220+
this._traceEventId = getNextTraceEventId();
221+
traceBegin(HTTP_SERVER_TRACE_EVENT_NAME, this._traceEventId);
222+
}
213223
}
214224
ObjectSetPrototypeOf(ServerResponse.prototype, OutgoingMessage.prototype);
215225
ObjectSetPrototypeOf(ServerResponse, OutgoingMessage);
@@ -228,6 +238,13 @@ ServerResponse.prototype._finish = function _finish() {
228238
});
229239
}
230240
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+
}
231248
};
232249

233250

Collapse file

‎lib/internal/http.js‎

Copy file name to clipboardExpand all lines: lib/internal/http.js
+29Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ const {
88
} = primordials;
99

1010
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');
1116

1217
let utcCache;
1318

@@ -26,8 +31,32 @@ function resetCache() {
2631
utcCache = undefined;
2732
}
2833

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+
2954
module.exports = {
3055
kOutHeaders: Symbol('kOutHeaders'),
3156
kNeedDrain: Symbol('kNeedDrain'),
3257
utcDate,
58+
traceBegin,
59+
traceEnd,
60+
getNextTraceEventId,
61+
isTraceHTTPEnabled,
3362
};
Collapse file
+44Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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+
}));

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.