Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions doc/api/perf_hooks.md
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,24 @@ property will be an {Object} with two properties:
* `perf_hooks.constants.NODE_PERFORMANCE_GC_FLAGS_ALL_EXTERNAL_MEMORY`
* `perf_hooks.constants.NODE_PERFORMANCE_GC_FLAGS_SCHEDULE_IDLE`

### HTTP ('http') Details

When `performanceEntry.type` is equal to `'http'`, the `performanceEntry.detail`
property will be an {Object} containing additional information.

If `performanceEntry.name` is equal to `HttpClient`, the `detail`
will contain the following properties: `req`, `res`. And the `req` property
will be an {Object} containing `method`, `url`, `headers`, the `res` property
will be an {Object} containing `statusCode`, `statusMessage`, `headers`.

If `performanceEntry.name` is equal to `HttpRequest`, the `detail`
will contain the following properties: `req`, `res`. And the `req` property
will be an {Object} containing `method`, `url`, `headers`, the `res` property
will be an {Object} containing `statusCode`, `statusMessage`, `headers`.

This could add additional memory overhead and should only be used for
diagnostic purposes, not left turned on in production by default.

### HTTP/2 ('http2') Details

When `performanceEntry.type` is equal to `'http2'`, the
Expand Down
33 changes: 25 additions & 8 deletions lib/_http_client.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ const Agent = require('_http_agent');
const { Buffer } = require('buffer');
const { defaultTriggerAsyncIdScope } = require('internal/async_hooks');
const { URL, urlToHttpOptions, searchParamsSymbol } = require('internal/url');
const { kOutHeaders, kNeedDrain, emitStatistics } = require('internal/http');
const { kOutHeaders, kNeedDrain } = require('internal/http');
const { connResetException, codes } = require('internal/errors');
const {
ERR_HTTP_HEADERS_SENT,
Expand All @@ -84,10 +84,10 @@ const {

const {
hasObserver,
startPerf,
stopPerf,
} = require('internal/perf/observe');

const { now } = require('internal/perf/utils');

const kClientRequestStatistics = Symbol('ClientRequestStatistics');

const { addAbortSignal, finished } = require('stream');
Expand Down Expand Up @@ -355,10 +355,17 @@ ClientRequest.prototype._finish = function _finish() {
DTRACE_HTTP_CLIENT_REQUEST(this, this.socket);
FunctionPrototypeCall(OutgoingMessage.prototype._finish, this);
if (hasObserver('http')) {
this[kClientRequestStatistics] = {
startTime: now(),
type: 'HttpClient',
};
startPerf(this, kClientRequestStatistics, {
type: 'http',
name: 'HttpClient',
detail: {
req: {
method: this.method,
url: `${this.protocol}//${this.host}${this.path}`,
headers: typeof this.getHeaders === 'function' ? this.getHeaders() : {},
},
},
});
}
};

Expand Down Expand Up @@ -627,7 +634,17 @@ function parserOnIncomingClient(res, shouldKeepAlive) {
}

DTRACE_HTTP_CLIENT_RESPONSE(socket, req);
emitStatistics(req[kClientRequestStatistics]);
if (req[kClientRequestStatistics] && hasObserver('http')) {
stopPerf(req, kClientRequestStatistics, {
detail: {
res: {
statusCode: res.statusCode,
statusMessage: res.statusMessage,
headers: res.headers,
},
},
});
}
req.res = res;
res.req = req;

Expand Down
32 changes: 24 additions & 8 deletions lib/_http_server.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ const {
const {
kOutHeaders,
kNeedDrain,
emitStatistics
} = require('internal/http');
const {
defaultTriggerAsyncIdScope,
Expand Down Expand Up @@ -98,10 +97,10 @@ const kServerResponseStatistics = Symbol('ServerResponseStatistics');

const {
hasObserver,
startPerf,
stopPerf,
} = require('internal/perf/observe');

const { now } = require('internal/perf/utils');

const STATUS_CODES = {
100: 'Continue', // RFC 7231 6.2.1
101: 'Switching Protocols', // RFC 7231 6.2.2
Expand Down Expand Up @@ -199,18 +198,35 @@ function ServerResponse(req) {
}

if (hasObserver('http')) {
this[kServerResponseStatistics] = {
startTime: now(),
type: 'HttpRequest',
};
startPerf(this, kServerResponseStatistics, {
type: 'http',
name: 'HttpRequest',
detail: {
req: {
method: req.method,
url: req.url,
headers: req.headers,
},
},
});
}
}
ObjectSetPrototypeOf(ServerResponse.prototype, OutgoingMessage.prototype);
ObjectSetPrototypeOf(ServerResponse, OutgoingMessage);

ServerResponse.prototype._finish = function _finish() {
DTRACE_HTTP_SERVER_RESPONSE(this.socket);
emitStatistics(this[kServerResponseStatistics]);
if (this[kServerResponseStatistics] && hasObserver('http')) {
stopPerf(this, kServerResponseStatistics, {
detail: {
res: {
statusCode: this.statusCode,
statusMessage: this.statusMessage,
headers: typeof this.getHeaders === 'function' ? this.getHeaders() : {},
},
},
});
}
OutgoingMessage.prototype._finish.call(this);
};

Expand Down
23 changes: 0 additions & 23 deletions lib/internal/http.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,6 @@ const {

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

const { InternalPerformanceEntry } = require('internal/perf/performance_entry');

const {
enqueue,
hasObserver,
} = require('internal/perf/observe');

const { now } = require('internal/perf/utils');

let utcCache;

function utcDate() {
Expand All @@ -35,22 +26,8 @@ function resetCache() {
utcCache = undefined;
}

function emitStatistics(statistics) {
if (!hasObserver('http') || statistics == null) return;
const startTime = statistics.startTime;
const entry = new InternalPerformanceEntry(
statistics.type,
'http',
startTime,
now() - startTime,
undefined,
);
enqueue(entry);
}

module.exports = {
kOutHeaders: Symbol('kOutHeaders'),
kNeedDrain: Symbol('kNeedDrain'),
utcDate,
emitStatistics,
};
6 changes: 6 additions & 0 deletions test/parallel/test-http-perf_hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ process.on('exit', () => {
} else if (entry.name === 'HttpRequest') {
numberOfHttpRequests++;
}
assert.strictEqual(typeof entry.detail.req.method, 'string');
assert.strictEqual(typeof entry.detail.req.url, 'string');
assert.strictEqual(typeof entry.detail.req.headers, 'object');
assert.strictEqual(typeof entry.detail.res.statusCode, 'number');
assert.strictEqual(typeof entry.detail.res.statusMessage, 'string');
assert.strictEqual(typeof entry.detail.res.headers, 'object');
});
assert.strictEqual(numberOfHttpClients, 2);
assert.strictEqual(numberOfHttpRequests, 2);
Expand Down