Yet another client for Etsy's statsd


Node.js client for statsd.

var SDC = require('statsd-client'),
    sdc = new SDC({host: ''});
var timer = new Date();
sdc.increment('some.counter'); // Increment by one. 
sdc.gauge('some.gauge', 10); // Set gauge to 10 
sdc.timing('some.timer', timer); // Calculates time diff 
sdc.close(); // Optional - stop NOW 
var SDC = require('statsd-client'),
    sdc = new SDC({host: '', port: 8124, debug: true});

Global options:

  • prefix: Prefix all stats with this value (default "").
  • debug: Print what is being sent to stderr (default false).
  • tcp: User specifically wants to use tcp (default false).
  • socketTimeout: Dual-use timer. Will flush metrics every interval. For UDP, it auto-closes the socket after this long without activity (default 1000 ms; 0 disables this). For TCP, it auto-closes the socket after socketTimeoutsToClose number of timeouts have elapsed without activity.

UDP options:

  • host: Where to send the stats (default localhost).
  • port: Port to contact the statsd-daemon on (default 8125).

TCP options:

  • host: Where to send the stats (default localhost).
  • port: Port to contact the statsd-daemon on (default 8125).
  • socketTimeoutsToClose: Number of timeouts in which the socket auto-closes if it has been inactive. (default 10; 1 to auto-close after a single timeout).

HTTP options:

  • host: The URL to send metrics to (default: http://localhost).
  • headers: Additional headers to send (default {})
  • method: What HTTP method to use (default PUT)

Counters are supported, both as raw .counter(metric, delta) and with the shortcuts .increment(metric, [delta=1]) and .decrement(metric, [delta=-1]):

sdc.increment('systemname.subsystem.value'); // Increment by one 
sdc.decrement('systemname.subsystem.value', -10); // Decrement by 10 
sdc.counter('systemname.subsystem.value', 100); // Increment by 100 

Sends an arbitrary number to the back-end:

sdc.gauge('', 100);
sdc.gaugeDelta('', 20);  // Will now count 120 
sdc.gaugeDelta('', -70); // Will now count 50 
sdc.gauge('', 10);       // Will now count 10 

Send unique occurences of events between flushes to the back-end:

sdc.set('your.set', 200);

Keep track of how fast (or slow) your stuff is:

var start = new Date();
setTimeout(function () {
    sdc.timing('random.timeout', start);
}, 100 * Math.random());

If it is given a Date, it will calculate the difference, and anything else will be passed straight through.

And don't let the name (or nifty interface) fool you - it can measure any kind of number, where you want to see the distribution (content lengths, list items, query sizes, ...)

There's also a helper for measuring stuff in Express.js via middleware:

var app = express();
    sdc = new StatsDClient({...});
// or 
    function (reqresnext) { req.pipe(res); });

This will count responses by status-code (prefix.<statuscode>) and the overall response-times.

It can also measure per-URL (e.g. PUT to /:user/:thing will become PUT_user_thing by setting the timeByUrl: true in the options-object:

app.use(sdc.helpers.getExpressMiddleware('prefix', { timeByUrl: true }));

As the names can become rather odd in corner-cases (esp. regexes and non-REST interfaces), you can specify another value by setting res.locals.statsdUrlKey at a later point.

The / page will appear as root (e.g. GET_root) in metrics while any not found route will appear as {METHOD}_unknown_express_route. You can change that name by setting the notFoundRouteName in the middleware options.

By default, the socket is closed if it hasn't been used for a second (see socketTimeout in the init-options), but it can also be force-closed with .close():

var start = new Date();
setTimeout(function () {
    sdc.timing('random.timeout', start); // 2 - implicitly re-creates socket. 
    sdc.close(); // 3 - Closes socket after last use. 
}, 100 * Math.random());
sdc.close(); // 1 - Closes socket early. 

The call is idempotent, so you can call it "just to be sure". And if you submit new metrics later, the socket will automatically be re-created, and a new timeout-timer started.

The library supports getting "child" clients with extra prefixes, to help with making sane name-spacing in apps:

// Create generic client 
var sdc = new StatsDClient({host: '', prefix: 'systemname'});
sdc.increment('foo'); // Increments '' 
... do great stuff ...
// Subsystem A 
var sdcA = sdc.getChildClient('a');
sdcA.increment('foo'); // Increments '' 
// Subsystem B 
var sdcB = sdc.getChildClient('b');
sdcB.increment('foo'); // Increments '' 

Internally, they all use the same socket, so calling .close() on any of them will allow the entire program to stop gracefully.

Check the GitHub issues.