1 | 'use strict';
|
2 |
|
3 | var Measured = require('measured');
|
4 |
|
5 | module.exports = Stats;
|
6 |
|
7 | function Stats(experiment) {
|
8 | var stats = {
|
9 | requestsPerSecond: new Measured.Meter(),
|
10 | latencyNs: new Measured.Histogram(),
|
11 | requests: {},
|
12 | statusCodes: {},
|
13 | errors: {},
|
14 | verificationErrors: {}
|
15 | };
|
16 |
|
17 | stats.requestsPerSecond.unref();
|
18 |
|
19 | experiment.on('request', function(req) {
|
20 | var start = process.hrtime();
|
21 | stats.requestsPerSecond.mark();
|
22 |
|
23 | var key = req.method + ' ' + req.uri.href;
|
24 | var stat = stats.requests[key];
|
25 | if (! stat) {
|
26 | stat = stats.requests[key] = {
|
27 | latencyNs: new Measured.Histogram(),
|
28 | statusCodes: {},
|
29 | errors: {},
|
30 | verificationErrors: {}
|
31 | };
|
32 | }
|
33 |
|
34 | req.once('response', function(response) {
|
35 | var diff = process.hrtime(start);
|
36 | var ns = diff[0] * 1e9 + diff[1];
|
37 | stats.latencyNs.update(ns);
|
38 | stat.latencyNs.update(ns);
|
39 |
|
40 | var statusCodeStat = stat.statusCodes[response.statusCode];
|
41 | if (! statusCodeStat) {
|
42 | statusCodeStat =
|
43 | stat.statusCodes[response.statusCode] =
|
44 | new Measured.Counter();
|
45 | }
|
46 | statusCodeStat.inc();
|
47 |
|
48 | var statusCode = response.statusCode;
|
49 | var statusCodeStats = stats.statusCodes[statusCode];
|
50 | if (! statusCodeStats) {
|
51 | statusCodeStats = stats.statusCodes[statusCode] = new Measured.Counter();
|
52 | }
|
53 | statusCodeStats.inc();
|
54 | });
|
55 | });
|
56 |
|
57 | experiment.on('request-error', function(req, err) {
|
58 | var code = err.code || err.message;
|
59 |
|
60 | var stat = stats.errors[code];
|
61 | if (! stat) {
|
62 | stat = stats.errors[code] = new Measured.Counter();
|
63 | }
|
64 | stat.inc();
|
65 |
|
66 | var key = req.method + ' ' + req.uri.href;
|
67 | var stat = stats.requests[key];
|
68 | if (! stat) {
|
69 | stat = stats.requests[key] = {
|
70 | latencyNs: new Measured.Histogram(),
|
71 | statusCodes: {},
|
72 | errors: {},
|
73 | verificationErrors: {}
|
74 | };
|
75 | }
|
76 |
|
77 | var errorStat = stat.errors[code];
|
78 | if (! errorStat) {
|
79 | errorStat = stat.errors[code] = new Measured.Counter();
|
80 | }
|
81 | errorStat.inc();
|
82 | });
|
83 |
|
84 | experiment.on('verify-error', function(err, req, res) {
|
85 | var code = err.code || err.message;
|
86 |
|
87 | var stat = stats.verificationErrors[code];
|
88 | if (! stat) {
|
89 | stat = stats.verificationErrors[code] = new Measured.Counter();
|
90 | }
|
91 | stat.inc();
|
92 |
|
93 | var key = req.method + ' ' + req.uri.href;
|
94 | var stat = stats.requests[key];
|
95 | if (! stat) {
|
96 | stat = stats.requests[key] = {
|
97 | latencyNs: new Measured.Histogram(),
|
98 | statusCodes: {},
|
99 | errors: {},
|
100 | verificationErrors: {}
|
101 | };
|
102 | }
|
103 |
|
104 | var errorStat = stat.verificationErrors[code];
|
105 | if (! errorStat) {
|
106 | errorStat = stat.verificationErrors[code] = new Measured.Counter();
|
107 | }
|
108 | errorStat.inc();
|
109 | });
|
110 |
|
111 | function toJSON() {
|
112 | var ret = {
|
113 | requestsPerSecond: stats.requestsPerSecond.toJSON(),
|
114 | latencyNs: stats.latencyNs.toJSON(),
|
115 | requests: {},
|
116 | statusCodes: {},
|
117 | errors: {},
|
118 | verificationErrors: {}
|
119 | };
|
120 |
|
121 | for(var req in stats.requests) {
|
122 |
|
123 | var statusCodes = {};
|
124 | for(var statusCode in stats.requests[req].statusCodes) {
|
125 | var count = stats.requests[req].statusCodes[statusCode].toJSON();
|
126 | statusCodes[statusCode] = {
|
127 | count: count,
|
128 | percentage: count / stats.requests[req].latencyNs.toJSON().count
|
129 | };
|
130 | }
|
131 |
|
132 | var errors = {};
|
133 | for(var error in stats.requests[req].errors) {
|
134 | var count = stats.requests[req].errors[error].toJSON();
|
135 | errors[error] = {
|
136 | count: count,
|
137 | percentage: count / stats.requests[req].latencyNs.toJSON().count
|
138 | };
|
139 | }
|
140 |
|
141 | var verificationErrors = {};
|
142 | for(var error in stats.requests[req].verificationErrors) {
|
143 | var count = stats.requests[req].verificationErrors[error].toJSON();
|
144 | verificationErrors[error] = {
|
145 | count: count,
|
146 | percentage: count / stats.requests[req].latencyNs.toJSON().count
|
147 | };
|
148 | }
|
149 |
|
150 | ret.requests[req] = {
|
151 | latencyNs: stats.requests[req].latencyNs.toJSON(),
|
152 | statusCodes: statusCodes,
|
153 | errors: errors,
|
154 | verificationErrors: verificationErrors
|
155 | };
|
156 | }
|
157 |
|
158 | for(var code in stats.statusCodes) {
|
159 | var count = stats.statusCodes[code].toJSON();
|
160 | ret.statusCodes[code] = {
|
161 | count: count,
|
162 | percentage: count / ret.requestsPerSecond.count
|
163 | };
|
164 | }
|
165 |
|
166 | for(var error in stats.errors) {
|
167 | var count = stats.errors[error].toJSON();
|
168 | ret.errors[error] = {
|
169 | count: count,
|
170 | percentage: count / ret.requestsPerSecond.count
|
171 | };
|
172 | }
|
173 |
|
174 | for(var error in stats.verificationErrors) {
|
175 | var count = stats.verificationErrors[error].toJSON();
|
176 | ret.errors[error] = {
|
177 | count: count,
|
178 | percentage: count / ret.requestsPerSecond.count
|
179 | };
|
180 | }
|
181 |
|
182 | return ret;
|
183 | };
|
184 |
|
185 | return {
|
186 | toJSON: toJSON
|
187 | };
|
188 | } |
\ | No newline at end of file |