Skip to content

Commit

Permalink
delete stats via management console: move to lib/, docs, generalize, …
Browse files Browse the repository at this point in the history
…tests
  • Loading branch information
carver committed Mar 22, 2013
1 parent d07b90e commit 2d9b0de
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 48 deletions.
68 changes: 68 additions & 0 deletions lib/mgmt_console.js
@@ -0,0 +1,68 @@

/**
* delete_stats - delete all matching statistics
*
* Side effect notes: this function works by altering stats_type in place,
* and calls stream.write(str) to display user feedback.
*
* @param stats_type array of all statistics of this type (eg~ timers) to delete from
* @param cmdline array of all requested deletions, which can be fully qualified,
* or end in a .* to delete a folder, like stats.temp.*
* @param stream buffer output for for all outgoing user feedback
*/
exports.delete_stats = function(stats_type, cmdline, stream) {

//for each metric requested on the command line
for (var index in cmdline) {

//get a list of deletable metrics that match the request
deletable = existing_stats(stats_type, cmdline[index]);

//warn if no matches
if (deletable.length == 0) {
stream.write("metric " + cmdline[index] + " not found\n");
}

//delete all requested metrics
for (var del_idx in deletable) {
delete stats_type[deletable[del_idx]];
stream.write("deleted: " + deletable[del_idx] + "\n");
}
}
stream.write("END\n\n");
}

/**
* existing_stats - find fully qualified matches for the requested stats bucket
*
* @param stats_type array of all statistics of this type (eg~ timers) to match
* @param bucket string to search on, which can be fully qualified,
* or end in a .* to search for a folder, like stats.temp.*
*
* @return array of fully qualified stats that match the specified bucket. if
* no matches, an empty array is a valid response
*/
function existing_stats(stats_type, bucket){
matches = []

//typical case: one-off, fully qualified
if (bucket in stats_type) {
matches.push(bucket);
}

//special case: match a whole 'folder' (and subfolders) of stats
if (bucket.slice(-2) == ".*") {
var folder = bucket.slice(0,-1);

for (var name in stats_type) {
//check if stat is in bucket, ie~ name starts with folder
if (name.substring(0, folder.length) == folder) {
matches.push(name);
}
}
}

return matches;
}

exports.existing_stats = existing_stats;
52 changes: 4 additions & 48 deletions stats.js
Expand Up @@ -7,6 +7,7 @@ var dgram = require('dgram')
, logger = require('./lib/logger')
, set = require('./lib/set')
, pm = require('./lib/process_metrics')
, mgmt = require('./lib/mgmt_console')


// initialize data structures with defaults for statsd stats
Expand Down Expand Up @@ -131,51 +132,6 @@ var stats = {
// Global for the logger
var l;

function delete_stats(stats_type, cmdline, stream) {

//for each metric requested on the command line
for (var index in cmdline) {

//get a list of deletable metrics that match the request
deletable = stats_to_delete(stats_type, cmdline[index]);

//warn if no matches
if (deletable.length == 0) {
stream.write("metric " + cmdline[index] + " not found\n");
}

//delete all requested metrics
for (var del_idx in deletable) {
delete stats_type[deletable[del_idx]];
stream.write("deleted: " + deletable[del_idx] + "\n");
}
}
stream.write("END\n\n");
}

function stats_to_delete(stats_type, bucket){
deletable = []

//typical case: one-off deletion
if (bucket in stats_type) {
deletable.push(bucket);
}

//special case: delete a whole 'folder' (and subfolders) of stats
if (bucket.slice(-2) == ".*") {
var folder = bucket.slice(0,-1);

for (var name in stats_type) {
//check if stat is in bucket, ie~ name starts with folder
if (name.substring(0, folder.length) == folder) {
deletable.push(name);
}
}
}

return deletable;
}

config.configFile(process.argv[2], function (config, oldConfig) {
conf = config;
l = new logger.Logger(config.log || {});
Expand Down Expand Up @@ -352,15 +308,15 @@ config.configFile(process.argv[2], function (config, oldConfig) {
break;

case "delcounters":
delete_stats(counters, cmdline, stream);
mgmt.delete_stats(counters, cmdline, stream);
break;

case "deltimers":
delete_stats(timers, cmdline, stream);
mgmt.delete_stats(timers, cmdline, stream);
break;

case "delgauges":
delete_stats(gauges, cmdline, stream);
mgmt.delete_stats(gauges, cmdline, stream);
break;

case "quit":
Expand Down
65 changes: 65 additions & 0 deletions test/mgmt_console_tests.js
@@ -0,0 +1,65 @@
var mgmt = require('../lib/mgmt_console');

module.exports = {
stat_matches: function(test) {
test.expect(8);
stat_vertical = {'a.b':1,'a.c':1,'c':1};

//test function
f = function (bucket) { return mgmt.existing_stats(stat_vertical, bucket) }

//empties
test.deepEqual(f('d'), []);
test.deepEqual(f('a'), []);
test.deepEqual(f('c.a'), []);
test.deepEqual(f('c.*'), []);
test.deepEqual(f(''), []);

//single matches
test.deepEqual(f('a.b'), ['a.b']);
test.deepEqual(f('c'), ['c']);

//multiple matches
test.deepEqual(f('a.*'), ['a.b', 'a.c']);

test.done();
},

stat_deletes: function(test) {
test.expect(6);

var stream = {
buffer : '',
clear : function() { this.buffer = '' },
write : function(to_write) { this.buffer += to_write },
};

stats_fixture =

//delete missing
stat_vertical = {'a.b':1,'a.c':1,'d':1};
stream.clear();
mgmt.delete_stats(stat_vertical, ['e'], stream);

test.deepEqual(stat_vertical, stats_fixture);
test.equal(stream.buffer, 'metric e not found\nEND\n\n');

//delete fully qualified
stat_vertical = {'a.b':1,'a.c':1,'d':1};
stream.clear();
mgmt.delete_stats(stat_vertical, ['a.b'], stream);

test.deepEqual(stat_vertical, {'a.c':1,'d':1});
test.equal(stream.buffer, 'deleted: a.b\nEND\n\n');

//delete folder
stat_vertical = {'a.b':1,'a.c':1,'d':1};
stream.clear();
mgmt.delete_stats(stat_vertical, ['a.*'], stream);

test.deepEqual(stat_vertical, {'d':1});
test.equal(stream.buffer, 'deleted: a.b\ndeleted: a.c\nEND\n\n');

test.done();
},
}

0 comments on commit 2d9b0de

Please sign in to comment.