-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Charlie
committed
Jul 1, 2012
0 parents
commit 1bff25c
Showing
2 changed files
with
186 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
# Hosted Graphite statsd plugin | ||
|
||
This is a plugin for [etsy's statsd](https://github.com/etsy/statsd) that sends your metric data to the [Hosted Graphite](http://www.hostedgraphite.com) service. | ||
|
||
## Installation | ||
|
||
Place **hostedgraphite.js** into the **backends/** directory of your **statsd** install. | ||
|
||
## Configuration | ||
|
||
### Enabling the plugin | ||
|
||
Add './backends/hostedgraphite' to the ```backends``` list. | ||
|
||
``` | ||
backends: ['./backends/hostedgraphite'] | ||
``` | ||
|
||
### Setting the Hosted Graphite key | ||
|
||
Set ```hostedGraphiteAPIKey``` to your key. This looks like a UUID and is available from your account details page on [hostedgraphite.com](hostedgraphite.com) | ||
|
||
``` | ||
hostedGraphiteAPIKey: 'deadbeef-dead-beef-dead-beefdeadbeef' | ||
``` | ||
|
||
## Example configuration | ||
|
||
``` | ||
{ | ||
port: 8125 | ||
, backends: ['./backends/hostedgraphite'] | ||
, hostedGraphiteAPIKey: 'deadbeef-dead-beef-dead-beefdeadbeef' | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
/* | ||
* Flush stats to hostedgraphite (http://www.hostedgraphite.com). | ||
* | ||
* To enable this backend, include './backends/hostedgraphite' in the backends | ||
* configuration array: | ||
* | ||
* backends: ['./backends/hostedgraphite'] | ||
* | ||
* This backend supports the following config options: | ||
* | ||
* hostedGraphiteAPIKey: A hostedgraphite.com API key. (a UUID) | ||
*/ | ||
|
||
var net = require('net'), | ||
util = require('util'), | ||
http = require('http'); | ||
|
||
var debug; | ||
var flushInterval; | ||
var APIKey; | ||
|
||
var graphiteStats = {}; | ||
|
||
var post_stats = function graphite_post_stats(statString) { | ||
var options = { | ||
host: 'www.hostedgraphite.com', | ||
port: 80, | ||
path: '/api/v1/sink', | ||
method: 'POST', | ||
auth: APIKey, | ||
headers: {'Content-Length': statString.length} | ||
}; | ||
|
||
var req = http.request(options, function(res) { | ||
if (res.statusCode == 202) { | ||
graphiteStats.last_flush = Math.round(new Date().getTime() / 1000); | ||
} | ||
}); | ||
|
||
req.on('error', function(ex) { | ||
graphiteStats.last_exception = Math.round(new Date().getTime() / 1000); | ||
if (debug) { | ||
util.log(ex); | ||
} | ||
}); | ||
|
||
req.write(statString); | ||
req.end(); | ||
} | ||
|
||
var flush_stats = function graphite_flush(ts, metrics) { | ||
var statString = ''; | ||
var numStats = 0; | ||
var key; | ||
|
||
var counters = metrics.counters; | ||
var gauges = metrics.gauges; | ||
var timers = metrics.timers; | ||
var pctThreshold = metrics.pctThreshold; | ||
|
||
for (key in counters) { | ||
var value = counters[key]; | ||
var valuePerSecond = value / (flushInterval / 1000); // calculate "per second" rate | ||
|
||
statString += 'stats.' + key + ' ' + valuePerSecond + ' ' + ts + "\n"; | ||
statString += 'stats_counts.' + key + ' ' + value + ' ' + ts + "\n"; | ||
|
||
numStats += 1; | ||
} | ||
|
||
for (key in timers) { | ||
if (timers[key].length > 0) { | ||
var values = timers[key].sort(function (a,b) { return a-b; }); | ||
var count = values.length; | ||
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; | ||
|
||
var message = ""; | ||
|
||
var key2; | ||
|
||
for (key2 in pctThreshold) { | ||
var pct = pctThreshold[key2]; | ||
if (count > 1) { | ||
var thresholdIndex = Math.round(((100 - pct) / 100) * count); | ||
var numInThreshold = count - thresholdIndex; | ||
|
||
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; | ||
} | ||
} | ||
|
||
for (key in gauges) { | ||
statString += 'stats.gauges.' + key + ' ' + gauges[key] + ' ' + ts + "\n"; | ||
numStats += 1; | ||
} | ||
|
||
statString += 'statsd.numStats ' + numStats + ' ' + ts + "\n"; | ||
post_stats(statString); | ||
}; | ||
|
||
var backend_status = function graphite_status(writeCb) { | ||
for (stat in graphiteStats) { | ||
writeCb(null, 'hostedgraphite', stat, graphiteStats[stat]); | ||
} | ||
}; | ||
|
||
exports.init = function graphite_init(startup_time, config, events) { | ||
debug = config.debug; | ||
APIKey = config.hostedGraphiteAPIKey; | ||
|
||
graphiteStats.last_flush = startup_time; | ||
graphiteStats.last_exception = startup_time; | ||
|
||
flushInterval = config.flushInterval; | ||
|
||
events.on('flush', flush_stats); | ||
events.on('status', backend_status); | ||
|
||
return true; | ||
}; |