Skip to content

Commit f861733

Browse files
Qardtargos
authored andcommitted
http: report request start and end with diagnostics_channel
PR-URL: #34895 Reviewed-By: Bryan English <bryan@bryanenglish.com> Reviewed-By: Gerhard Stöbich <deb2001-github@yahoo.de> Reviewed-By: Vladimir de Turckheim <vlad2t@hotmail.com> Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Gabriel Schulhof <gabriel.schulhof@intel.com> Reviewed-By: Michael Dawson <midawson@redhat.com>
1 parent b38a43d commit f861733

3 files changed

Lines changed: 183 additions & 0 deletions

File tree

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
'use strict';
2+
constcommon=require('../common.js');
3+
constdc=require('diagnostics_channel');
4+
const{ AsyncLocalStorage }=require('async_hooks');
5+
consthttp=require('http');
6+
7+
constbench=common.createBenchmark(main,{
8+
apm: ['none','diagnostics_channel','patch'],
9+
type: 'buffer',
10+
len: 1024,
11+
chunks: 4,
12+
connections: [50,500],
13+
chunkedEnc: 1,
14+
duration: 5
15+
});
16+
17+
functionmain({ apm, connections, duration, type, len, chunks, chunkedEnc }){
18+
constdone={ none, patch, diagnostics_channel }[apm]();
19+
20+
constserver=require('../fixtures/simple-http-server.js')
21+
.listen(common.PORT)
22+
.on('listening',()=>{
23+
constpath=`/${type}/${len}/${chunks}/normal/${chunkedEnc}`;
24+
bench.http({
25+
path,
26+
connections,
27+
duration
28+
},()=>{
29+
server.close();
30+
if(done)done();
31+
});
32+
});
33+
}
34+
35+
functionnone(){}
36+
37+
functionpatch(){
38+
constals=newAsyncLocalStorage();
39+
consttimes=[];
40+
41+
const{ emit }=http.Server.prototype;
42+
functionwrappedEmit(...args){
43+
const[name,req,res]=args;
44+
if(name==='request'){
45+
als.enterWith({
46+
url: req.url,
47+
start: process.hrtime.bigint()
48+
});
49+
50+
res.on('finish',()=>{
51+
times.push({
52+
...als.getStore(),
53+
statusCode: res.statusCode,
54+
end: process.hrtime.bigint()
55+
});
56+
});
57+
}
58+
returnemit.apply(this,args);
59+
}
60+
http.Server.prototype.emit=wrappedEmit;
61+
62+
return()=>{
63+
http.Server.prototype.emit=emit;
64+
};
65+
}
66+
67+
functiondiagnostics_channel(){
68+
constals=newAsyncLocalStorage();
69+
consttimes=[];
70+
71+
conststart=dc.channel('http.server.request.start');
72+
constfinish=dc.channel('http.server.response.finish');
73+
74+
functiononStart(req){
75+
als.enterWith({
76+
url: req.url,
77+
start: process.hrtime.bigint()
78+
});
79+
}
80+
81+
functiononFinish(res){
82+
times.push({
83+
...als.getStore(),
84+
statusCode: res.statusCode,
85+
end: process.hrtime.bigint()
86+
});
87+
}
88+
89+
start.subscribe(onStart);
90+
finish.subscribe(onFinish);
91+
92+
return()=>{
93+
start.unsubscribe(onStart);
94+
finish.unsubscribe(onFinish);
95+
};
96+
}

‎lib/_http_server.js‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,10 @@ const { observerCounts, constants } = internalBinding('performance');
8484
const{ setTimeout, clearTimeout }=require('timers');
8585
const{NODE_PERFORMANCE_ENTRY_TYPE_HTTP}=constants;
8686

87+
constdc=require('diagnostics_channel');
88+
constonRequestStartChannel=dc.channel('http.server.request.start');
89+
constonResponseFinishChannel=dc.channel('http.server.response.finish');
90+
8791
constkServerResponse=Symbol('ServerResponse');
8892
constkServerResponseStatistics=Symbol('ServerResponseStatistics');
8993

@@ -775,6 +779,15 @@ function clearRequestTimeout(req) {
775779
}
776780

777781
functionresOnFinish(req,res,socket,state,server){
782+
if(onResponseFinishChannel.hasSubscribers){
783+
onResponseFinishChannel.publish({
784+
request: req,
785+
response: res,
786+
socket,
787+
server
788+
});
789+
}
790+
778791
// Usually the first incoming element should be our request. it may
779792
// be that in the case abortIncoming() was called that the incoming
780793
// array will be empty.
@@ -862,6 +875,15 @@ function parserOnIncoming(server, socket, state, req, keepAlive) {
862875
res.shouldKeepAlive=keepAlive;
863876
DTRACE_HTTP_SERVER_REQUEST(req,socket);
864877

878+
if(onRequestStartChannel.hasSubscribers){
879+
onRequestStartChannel.publish({
880+
request: req,
881+
response: res,
882+
socket,
883+
server
884+
});
885+
}
886+
865887
if(socket._httpMessage){
866888
// There are already pending outgoing res, append.
867889
state.outgoing.push(res);
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
'use strict';
2+
3+
constcommon=require('../common');
4+
const{ AsyncLocalStorage }=require('async_hooks');
5+
constdc=require('diagnostics_channel');
6+
constassert=require('assert');
7+
consthttp=require('http');
8+
9+
constincomingStartChannel=dc.channel('http.server.request.start');
10+
constoutgoingFinishChannel=dc.channel('http.server.response.finish');
11+
12+
constals=newAsyncLocalStorage();
13+
letcontext;
14+
15+
// Bind requests to an AsyncLocalStorage context
16+
incomingStartChannel.subscribe(common.mustCall((message)=>{
17+
als.enterWith(message);
18+
context=message;
19+
}));
20+
21+
// When the request ends, verify the context has been maintained
22+
// and that the messages contain the expected data
23+
outgoingFinishChannel.subscribe(common.mustCall((message)=>{
24+
constdata={
25+
request,
26+
response,
27+
server,
28+
socket: request.socket
29+
};
30+
31+
// Context is maintained
32+
compare(als.getStore(),context);
33+
34+
compare(context,data);
35+
compare(message,data);
36+
}));
37+
38+
letrequest;
39+
letresponse;
40+
41+
constserver=http.createServer(common.mustCall((req,res)=>{
42+
request=req;
43+
response=res;
44+
45+
setTimeout(()=>{
46+
res.end('done');
47+
},1);
48+
}));
49+
50+
server.listen(()=>{
51+
const{ port }=server.address();
52+
http.get(`http://localhost:${port}`,(res)=>{
53+
res.resume();
54+
res.on('end',()=>{
55+
server.close();
56+
});
57+
});
58+
});
59+
60+
functioncompare(a,b){
61+
assert.strictEqual(a.request,b.request);
62+
assert.strictEqual(a.response,b.response);
63+
assert.strictEqual(a.socket,b.socket);
64+
assert.strictEqual(a.server,b.server);
65+
}

0 commit comments

Comments
 (0)