Skip to content
This repository was archived by the owner on Sep 25, 2020. It is now read-only.

Commit 4d5f833

Browse files
Emit stats from ringpop-test program (#271)
In preparation for automated performance and failure testing we want to be able to emit stats to a file or a network address from testpop. This commit add two new flags (--stats-udp, --stats-file) to `main.js` to control if and where stats should be emitted; if the flags are omitted, no stats are emitted.
1 parent 976355d commit 4d5f833

1 file changed

Lines changed: 93 additions & 2 deletions

File tree

main.js

Lines changed: 93 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2020
// THE SOFTWARE.
2121

22+
var fs = require('fs');
23+
var path = require('path');
24+
2225
var program = require('commander');
2326
var RingPop = require('./index');
2427
var TChannel = require('tchannel');
@@ -28,7 +31,7 @@ function main(args) {
2831
.version(require('./package.json').version)
2932

3033
.usage('[options]')
31-
34+
3235
.option('-l, --listen <listen>',
3336
'Host and port on which server listens (also node\'s identity in cluster)')
3437

@@ -47,6 +50,15 @@ function main(args) {
4750
'The lifetime of a tombstone member in ms. After that the member is removed from the membership.',
4851
parseInt10, 5000)
4952

53+
.option('--stats-file <stats-file>',
54+
'Enable stats emitting to a file. Stats-file can be a relative or absolute path. '+
55+
'Note: this flag is mutually exclusive with --stats-udp and you need to manually install "uber-statsd-client" to be able to emit stats')
56+
57+
.option('--stats-udp <stats-udp>',
58+
'Enable stats emitting over udp. Destination is in the host-port format (e.g. localhost:8125 or 127.0.0.1:8125) ' +
59+
'Note: this flag is mutually exclusive with --stats-file and you need to manually install "uber-statsd-client" to be able to emit stats',
60+
/^(.+):(\d+)$/)
61+
5062
.parse(args);
5163

5264
var listen = program.listen;
@@ -56,6 +68,8 @@ function main(args) {
5668
process.exit(1);
5769
}
5870

71+
var stats = createStatsClient(program);
72+
5973
var tchannel = new TChannel({
6074
});
6175

@@ -72,7 +86,8 @@ function main(args) {
7286
suspect: program.suspectPeriod,
7387
faulty: program.faultyPeriod,
7488
tombstone: program.tombstonePeriod,
75-
}
89+
},
90+
statsd: stats
7691
});
7792

7893
ringpop.setupChannel();
@@ -87,6 +102,82 @@ function main(args) {
87102
}
88103
}
89104

105+
function createStatsClient(program) {
106+
if (!program.statsUdp && !program.statsFile) {
107+
return null;
108+
}
109+
if (program.statsUdp && program.statsFile) {
110+
console.error("--stats-udp and --stats-file are mutually exclusive.");
111+
console.error("Please specify only one of the two options!");
112+
process.exit(1);
113+
}
114+
115+
var opts = null;
116+
if (program.statsUdp) {
117+
var matchesHostPort = program.statsUdp.match(/^(.+):(\d+)$/);
118+
opts = {
119+
host: matchesHostPort[1],
120+
port: parseInt(matchesHostPort[2])
121+
};
122+
} else if (program.statsFile) {
123+
var file = path.resolve(program.statsFile);
124+
opts = {
125+
// passing in our own 'socket' implementation here so we can write to file instead.
126+
// note: this is non-public api and could change without warning.
127+
_ephemeralSocket: new FileStatsLogger(file)
128+
};
129+
}
130+
131+
var createStatsdClient;
132+
133+
// Wrap the require in a try/catch so we're don't have to add uber-statsd-client
134+
// as a dependency but fail gracefully when not available.
135+
try {
136+
createStatsdClient = require('uber-statsd-client');
137+
} catch (e) {
138+
if (e.code !== "MODULE_NOT_FOUND") {
139+
throw e;
140+
}
141+
142+
console.error("To be able to emit stats you need to have uber-statsd-client installed.");
143+
console.error("Please run \"npm install uber-statsd-client\" and try again!");
144+
process.exit(1);
145+
}
146+
147+
return createStatsdClient(opts);
148+
}
149+
150+
function FileStatsLogger(file) {
151+
if (!(this instanceof FileStatsLogger)) {
152+
return new FileStatsLogger(file);
153+
}
154+
155+
this.file = file;
156+
this.stream = null;
157+
this.ensureStream();
158+
}
159+
160+
FileStatsLogger.prototype.ensureStream = function ensureStream() {
161+
if (this.stream) {
162+
return;
163+
}
164+
this.stream = fs.createWriteStream(this.file, {flags: 'a'});
165+
};
166+
167+
FileStatsLogger.prototype.close = function close() {
168+
if (this.stream) {
169+
this.stream.end();
170+
this.stream = null;
171+
}
172+
};
173+
174+
FileStatsLogger.prototype._writeToSocket = function _writeToSocket(data, cb) {
175+
this.ensureStream();
176+
this.stream.write(new Date().toISOString() + ': ' + data + '\n', cb);
177+
};
178+
179+
FileStatsLogger.prototype.send = FileStatsLogger.prototype._writeToSocket;
180+
90181
function parseInt10(str) {
91182
return parseInt(str, 10);
92183
}

0 commit comments

Comments
 (0)