Skip to content

Instantly share code, notes, and snippets.

@chowse
Created June 22, 2011 20:34
Show Gist options
  • Save chowse/1041094 to your computer and use it in GitHub Desktop.
Save chowse/1041094 to your computer and use it in GitHub Desktop.
StatsD for Client-Side Interactions
if (!Date.now) {
Date.now = function() {
return (new Date()).getTime();
};
}
var StatsD = (function($, undefined) {
var activeTimers = { };
var queuedData = [ ];
var flushTimer = undefined;
var configOpts = {
url: '/statsd',
flushInterval: 1000
};
/**
* Update the client configuration of StatsD.
* @param opts an object containing new configuration values
*/
function config(opts) {
$.extend(configOpts, opts);
}
/**
* Update a stat by an arbitrary amount.
* @param {String} stat the name of the stat to update
* @param {Number} delta the amount to update the stat by
* @param {Number} [sampleRate] a number between 0 and 1 indicating what percentage of this stat to sample
*/
function update(stat, delta, sampleRate) {
queue(stat, delta+"|c", sampleRate);
}
/**
* Increment a stat by 1.
* @param {String} stat the name of the stat to update
* @param {Number} [sampleRate] a number between 0 and 1 indicating what percentage of this stat to sample
*/
function increment(stat, sampleRate) {
update(stat, 1, sampleRate);
}
/**
* Decrement a stat by 1.
* @param {String} stat the name of the stat to update
* @param {Number} [sampleRate] a number between 0 and 1 indicating what percentage of this stat to sample
*/
function decrement(stat, sampleRate) {
update(stat, -1, sampleRate);
}
/**
* Log timing information.
* @param {String} stat the name of the stat to update
* @param {Number} ms the time (in ms) to log
* @param {Number} [sampleRate] a number between 0 and 1 indicating what percentage of this stat to record
*/
function timing(stat, ms, sampleRate) {
send(stat, ms+"|ms", sampleRate);
}
/**
* Start a timer that, when completed with stopTiming(), will log timing information.
* @param {String} stat the name of the stat to update
*/
function startTiming(stat) {
activeTimers[stat] = Date.now();
}
/**
* Stop a running timer and log the amount of time (in ms) since it was started.
* @param {String} stat the name of the stat to update
* @param {Number} [sampleRate] a number between 0 and 1 indicating what percentage of this stat to sample
*/
function stopTiming(stat, sampleRate) {
var start = activeTimers[stat];
delete activeTimers[stat];
if (start) {
timing(stat, Date.now() - start);
}
}
/**
* Queues up a piece of StatsD data to be sent to the server.
* @param {String} method the type of data that is being queues
* @param {String} stat the name of the stat being queued
* @param {String} value the value of the stat being queued
* @param {Number} [sampleRate] a number between 0 and 1 indicating what percentage of this stat to sample
*/
function queue(stat, value, sampleRate) {
var data = stat+":"+value;
if (sampleRate !== undefined && sampleRate != 1) {
if (sampleRate < Math.random()) {
return;
}
data = data+"|@"+sampleRate;
}
queuedData.push(data);
if (configOpts.flushInterval <= 0) {
flush();
} else if (!flushTimer) {
flushTimer = setTimeout(flush, configOpts.flushInterval);
}
}
/**
* Send any queued StatsD data to the server. This data is
* automatically sent at a regular interval specificed by the
* flushInterval config setting.
*/
function flush() {
clearTimeout(flushTimer);
flushTimer = 0;
var data = queuedData.join('\n');
queuedData.splice(0, queuedData.length);
$.ajax({
type: "POST",
url: configOpts.url,
contentType: 'text/plain',
data: data
});
}
return {
config: config,
update: update,
increment: increment,
decrement: decrement,
timing: timing,
startTiming: startTiming,
stopTiming: stopTiming,
flush: flush
};
})(jQuery);
from django.http import HttpResponse
import re, socket
VALID_STAT_RE = re.compile(r'''
^ # beginning of the string
\w+(\.\w+)*: # the name of the stat
-?\d+ # the stat's value
\|(c|ms) # the type of stat
(|@\d+(\.\d+)?)? # the sample rate
$ # end of the string
''')
# TODO: init from config
VALID_KEYS = set()
# TODO: init from config
STATSD_HOST = 'somehost'
STATSD_PORT = 9000
STATSD_ADDR = (STATSD_HOST, STATSD_PORT)
def statsd_proxy(request):
for stat in request.read().split('\n'):
if not VALID_STAT_RE.match(stat):
continue
key, _, _ = stat.partition(':')
if key not in VALID_KEYS:
continue
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.sendto(stat, STATSD_ARRD)
except:
pass # Don't care
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment