Skip to content

Commit

Permalink
Merge remote-tracking branch 'etsy/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
jeff-minard-ck committed Jun 22, 2012
2 parents 4e4ed79 + 42ff275 commit 3f6b96b
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 49 deletions.
8 changes: 7 additions & 1 deletion README.md
Expand Up @@ -225,6 +225,11 @@ Inspiration
StatsD was inspired (heavily) by the project (of the same name) at Flickr. Here's a post where Cal Henderson described it in depth:
[Counting and timing](http://code.flickr.com/blog/2008/10/27/counting-timing/). Cal re-released the code recently: [Perl StatsD](https://github.com/iamcal/Flickr-StatsD)

Meta
---------
- IRC channel: `#statsd` on freenode
- Mailing list: `statsd@librelist.com`


Contribute
---------------------
Expand All @@ -242,6 +247,7 @@ fork StatsD from here: http://github.com/etsy/statsd

We'll do our best to get your changes in!


[graphite]: http://graphite.wikidot.com
[etsy]: http://www.etsy.com
[blog post]: http://codeascraft.etsy.com/2011/02/15/measure-anything-measure-everything/
Expand All @@ -254,4 +260,4 @@ Contributors
-----------------

In lieu of a list of contributors, check out the commit history for the project:
http://github.com/etsy/statsd/commits/master
https://github.com/etsy/statsd/graphs/contributors
22 changes: 14 additions & 8 deletions backends/graphite.js
Expand Up @@ -72,6 +72,12 @@ var flush_stats = function graphite_flush(ts, metrics) {
var min = values[0];
var max = values[count - 1];

var cumulativeValues = [min];
for (var i = 1; i < count; i++) {
cumulativeValues.push(values[i] + cumulativeValues[i-1]);
}

var sum = min;
var mean = min;
var maxAtThreshold = max;

Expand All @@ -84,27 +90,27 @@ var flush_stats = function graphite_flush(ts, metrics) {
if (count > 1) {
var thresholdIndex = Math.round(((100 - pct) / 100) * count);
var numInThreshold = count - thresholdIndex;
var pctValues = values.slice(0, numInThreshold);
maxAtThreshold = pctValues[numInThreshold - 1];

// average the remaining timings
var sum = 0;
for (var i = 0; i < numInThreshold; i++) {
sum += pctValues[i];
}

maxAtThreshold = values[numInThreshold - 1];
sum = cumulativeValues[numInThreshold - 1];
mean = sum / numInThreshold;
}

var clean_pct = '' + pct;
clean_pct.replace('.', '_');
message += 'stats.timers.' + key + '.mean_' + clean_pct + ' ' + mean + ' ' + ts + "\n";
message += 'stats.timers.' + key + '.upper_' + clean_pct + ' ' + maxAtThreshold + ' ' + ts + "\n";
message += 'stats.timers.' + key + '.sum_' + clean_pct + ' ' + sum + ' ' + ts + "\n";
}

sum = cumulativeValues[count-1];
mean = sum / count;

message += 'stats.timers.' + key + '.upper ' + max + ' ' + ts + "\n";
message += 'stats.timers.' + key + '.lower ' + min + ' ' + ts + "\n";
message += 'stats.timers.' + key + '.count ' + count + ' ' + ts + "\n";
message += 'stats.timers.' + key + '.sum ' + sum + ' ' + ts + "\n";
message += 'stats.timers.' + key + '.mean ' + mean + ' ' + ts + "\n";
statString += message;

numStats += 1;
Expand Down
4 changes: 2 additions & 2 deletions examples/Etsy/StatsD.pm
Expand Up @@ -99,7 +99,7 @@ sub send {

my $sampled_data;
if ( defined($sample_rate) and $sample_rate < 1 ){
while (my($stat,$value) = each %$sampled_data) {
while (my($stat,$value) = each %$data) {
$sampled_data->{$stat} = "$value|\@$sample_rate" if rand() <= $sample_rate;
}
} else {
Expand All @@ -124,4 +124,4 @@ Steve Sanbeg L<http://www.buzzfeed.com/stv>
=cut

1;
1;
1 change: 1 addition & 0 deletions examples/README.md
Expand Up @@ -11,6 +11,7 @@ Here's a bunch of example code contributed by the communinty for interfacing wit
python_example.py - Python
ruby_example.rb - Ruby
statsd.erl - Erlang
statsd-client.sh - Bash

Third Party StatsD Libraries
============================
Expand Down
4 changes: 2 additions & 2 deletions examples/python_example.py
Expand Up @@ -72,7 +72,7 @@ def send(data, sample_rate=1):
import random
if random.random() <= sample_rate:
for stat in data.keys():
value = sampled_data[stat]
value = data[stat]
sampled_data[stat] = "%s|@%s" %(value, sample_rate)
else:
sampled_data=data
Expand All @@ -81,7 +81,7 @@ def send(data, sample_rate=1):
udp_sock = socket(AF_INET, SOCK_DGRAM)
try:
for stat in sampled_data.keys():
value = data[stat]
value = sampled_data[stat]
send_data = "%s:%s" % (stat, value)
udp_sock.sendto(send_data, addr)
except:
Expand Down
25 changes: 25 additions & 0 deletions examples/statsd-client.sh
@@ -0,0 +1,25 @@
#!/bin/bash
#
# Very simple bash client to send metrics to a statsd server
# Example with gauge: ./statsd-client.sh 'my_metric:100|g'
#
# Alexander Fortin <alexander.fortin@gmail.com>
#
STATSD="statsd-ip-address"
PORT="8125"

if [ $# -ne 1 ]
then
echo "Syntax: $0 '<gauge_data_for_statsd>'"
exit 1
fi

# Setup UDP socket with statsd server
exec 3<> /dev/udp/${STATSD}/${PORT}

# Send data
echo "$1" >&3

# Close UDP socket
exec 3<&-
exec 3>&-
76 changes: 40 additions & 36 deletions stats.js
Expand Up @@ -85,47 +85,51 @@ config.configFile(process.argv[2], function (config, oldConfig) {
var keyFlushInterval = Number((config.keyFlush && config.keyFlush.interval) || 0);

server = dgram.createSocket('udp4', function (msg, rinfo) {
if (config.dumpMessages) { util.log(msg.toString()); }
var bits = msg.toString().split(':');
var key = bits.shift()
.replace(/\s+/g, '_')
.replace(/\//g, '-')
.replace(/[^a-zA-Z_\-0-9\.]/g, '');

if (keyFlushInterval > 0) {
if (! keyCounter[key]) {
keyCounter[key] = 0;
var metrics = msg.toString().split("\n");

for (midx in metrics) {
if (config.dumpMessages) { util.log(metrics[midx].toString()); }
var bits = metrics[midx].toString().split(':');
var key = bits.shift()
.replace(/\s+/g, '_')
.replace(/\//g, '-')
.replace(/[^a-zA-Z_\-0-9\.]/g, '');

if (keyFlushInterval > 0) {
if (! keyCounter[key]) {
keyCounter[key] = 0;
}
keyCounter[key] += 1;
}
keyCounter[key] += 1;
}

if (bits.length == 0) {
bits.push("1");
}

for (var i = 0; i < bits.length; i++) {
var sampleRate = 1;
var fields = bits[i].split("|");
if (fields[1] === undefined) {
util.log('Bad line: ' + fields);
stats['messages']['bad_lines_seen']++;
continue;
if (bits.length == 0) {
bits.push("1");
}
if (fields[1].trim() == "ms") {
if (! timers[key]) {
timers[key] = [];
}
timers[key].push(Number(fields[0] || 0));
} else if (fields[1].trim() == "g") {
gauges[key] = Number(fields[0] || 0);
} else {
if (fields[2] && fields[2].match(/^@([\d\.]+)/)) {
sampleRate = Number(fields[2].match(/^@([\d\.]+)/)[1]);

for (var i = 0; i < bits.length; i++) {
var sampleRate = 1;
var fields = bits[i].split("|");
if (fields[1] === undefined) {
util.log('Bad line: ' + fields);
stats['messages']['bad_lines_seen']++;
continue;
}
if (! counters[key]) {
counters[key] = 0;
if (fields[1].trim() == "ms") {
if (! timers[key]) {
timers[key] = [];
}
timers[key].push(Number(fields[0] || 0));
} else if (fields[1].trim() == "g") {
gauges[key] = Number(fields[0] || 0);
} else {
if (fields[2] && fields[2].match(/^@([\d\.]+)/)) {
sampleRate = Number(fields[2].match(/^@([\d\.]+)/)[1]);
}
if (! counters[key]) {
counters[key] = 0;
}
counters[key] += Number(fields[0] || 1) * (1 / sampleRate);
}
counters[key] += Number(fields[0] || 1) * (1 / sampleRate);
}
}

Expand Down

0 comments on commit 3f6b96b

Please sign in to comment.