Name: js-handler/node_modules/restify/bin/report-latency 
1:
#!/usr/bin/env node
2:
// -*- mode: js -*-
3:
 
4:
var fs = require('fs');
5:
var path = require('path');
6:
var spawn = require('child_process').spawn;
7:
var readline = require('readline');
8:
var sprintf = require('util').format;
9:
 
10:
var nopt = require('nopt');
11:
 
12:
 
13:
 
14:
 
15:
///--- Globals
16:
 
17:
var BUCKETS = {};
18:
var REQUEST_IDS = {};
19:
 
20:
var OPTS = {
21:
        'average': Boolean,
22:
        'help': Boolean,
23:
        'end': Date,
24:
        'max-latency': Number,
25:
        'max-requests': Number,
26:
        'output': String,
27:
        'percentile': [Number, Array],
28:
        'period': Number,
29:
        'requests': Boolean,
30:
        'start': Date
31:
};
32:
 
33:
var SHORT_OPTS = {
34:
        'a': ['--average'],
35:
        'h': ['--help'],
36:
        'i': ['--period'],
37:
        'e': ['--end'],
38:
        'l': ['--max-latency'],
39:
        'n': ['--max-requests'],
40:
        'o': ['--output'],
41:
        'p': ['--percentile'],
42:
        'r': ['--requests'],
43:
        's': ['--start']
44:
};
45:
 
46:
 
47:
 
48:
 
49:
///--- Functions
50:
 
51:
function percentile(p, vals) {
52:
        p = parseInt(p, 10);
53:
        return vals[(Math.round(((p/100) * vals.length) + 1/2) - 1)].latency;
54:
}
55:
 
56:
 
57:
function report(buckets, output) {
58:
        Object.keys(buckets).sort(function (a, b) {
59:
                return parseInt(a, 10) - parseInt(b, 10);
60:
        }).forEach(function (k) {
61:
                var avg = 0;
62:
                var perc = [];
63:
                var req = buckets[k].length;
64:
                var sum = 0;
65:
                var t = Math.round(buckets[k]._time);
66:
 
67:
                buckets[k] = buckets[k].sort(function (a, b) {
68:
                        return a.latency - b.latency;
69:
                });
70:
 
71:
                buckets[k].forEach(function (v) {
72:
                        sum += v.latency;
73:
                });
74:
 
75:
                if (sum > 0 && req > 0) {
76:
                        if (output.average)
77:
                                output.average.push([t, Math.round(sum/req)]);
78:
                        if (output.requests)
79:
                                output.requests.push([t, buckets[k].length]);
80:
                        Object.keys(output.percentile).forEach(function (p) {
81:
                                var _p = percentile(p, buckets[k]);
82:
                                output.percentile[p].push([t, _p]);
83:
                        });
84:
                }
85:
        });
86:
 
87:
        return output;
88:
}
89:
 
90:
 
91:
function usage(code, message) {
92:
        var str = '';
93:
        Object.keys(SHORT_OPTS).forEach(function(k) {
94:
                if (!Array.isArray(SHORT_OPTS[k]))
95:
                        return;
96:
 
97:
                var opt = SHORT_OPTS[k][0].replace('--', '');
98:
                var type = OPTS[opt].name || 'string';
99:
                if (type && type === 'boolean')
100:
                        type = '';
101:
                type = type.toLowerCase();
102:
 
103:
                str += ' [--' + opt + ' ' + type + ']';
104:
        });
105:
        str += ' [file ...]';
106:
 
107:
        if (message)
108:
                console.error(message);
109:
 
110:
        console.error('usage: ' + path.basename(process.argv[1]) + str);
111:
        process.exit(code);
112:
}
113:
 
114:
 
115:
 
116:
///--- Mainline
117:
 
118:
var parsed;
119:
 
120:
try {
121:
        parsed = nopt(OPTS, SHORT_OPTS, process.argv, 2);
122:
} catch (e) {
123:
        usage(1, e.toString());
124:
}
125:
 
126:
if (parsed.help)
127:
        usage(0);
128:
if (!parsed.average && !parsed.percentile)
129:
        usage(1, '--average or --percentile required');
130:
if (parsed.argv.remain.length < 1)
131:
        usage(1, 'log file required');
132:
 
133:
var config = {
134:
        average: parsed.average || false,
135:
        maxLatency: parsed['max-latency'] || 1000,
136:
        maxRequests: parsed['max-requests'] || 10000,
137:
        percentile: parsed.percentile || [],
138:
        period: parsed.period || 60,
139:
        requests: parsed.requests || false,
140:
        start: parsed.start ? (parsed.start.getTime() / 1000) : 0,
141:
        end: parsed.end ? (parsed.end.getTime() / 1000) : Number.MAX_VALUE
142:
};
143:
 
144:
var buckets = {};
145:
 
146:
var done = 0;
147:
parsed.argv.remain.forEach(function (f) {
148:
        var stream = readline.createInterface({
149:
                input: fs.createReadStream(f),
150:
                output: null
151:
        })
152:
        stream.on('line', function (l) {
153:
                var record;
154:
                var t = -1;
155:
 
156:
                try {
157:
                        record = JSON.parse(l);
158:
                } catch (e) {}
159:
 
160:
                if (!record)
161:
                        return;
162:
 
163:
                var t = -1;
164:
                if (record.time)
165:
                        t = (new Date(record.time).getTime() / 1000);
166:
 
167:
                if (record._audit !== true ||
168:
                    REQUEST_IDS[record.req_id] ||
169:
                    t < config.start ||
170:
                    t > config.end) {
171:
 
172:
                        console.error('Skipping %s', l);
173:
                }
174:
 
175:
                REQUEST_IDS[record.req_id] = true;
176:
                record.time = t;
177:
 
178:
                var b = Math.round(record.time / config.period) + '';
179:
                if (!buckets[b])
180:
                        buckets[b] = [];
181:
 
182:
                buckets[b].push(record);
183:
                buckets[b]._time = record.time // good enough
184:
        });
185:
 
186:
        stream.on('end', function () {
187:
                if (++done === parsed.argv.remain.length) {
188:
                        console.error('Generating report...');
189:
 
190:
                        var output = {
191:
                                average: config.average ? [] : false,
192:
                                requests: config.requests ? [] : false,
193:
                                percentile: {}
194:
                        };
195:
                        config.percentile.forEach(function (p) {
196:
                                output.percentile[p] = [];
197:
                        });
198:
 
199:
                        output = report(buckets, output);
200:
                        var finalOutput = [];
201:
                        if (output.average) {
202:
                                finalOutput.push({
203:
                                        name: 'avg',
204:
                                        values: output.average
205:
                                });
206:
                        }
207:
                        if (output.requests) {
208:
                                finalOutput.push({
209:
                                        name: 'n',
210:
                                        values: output.requests
211:
                                });
212:
                        }
213:
                        Object.keys(output.percentile).forEach(function (k) {
214:
                                finalOutput.push({
215:
                                        name: 'p' + k,
216:
                                        values: output.percentile[k]
217:
                                });
218:
                        });
219:
 
220:
                        console.log(JSON.stringify(finalOutput));
221:
                }
222:
        });
223:
});