statsd/backends/graphite.js

209 строки
6.5 KiB
JavaScript

/*
* Flush stats to graphite (http://graphite.wikidot.com/).
*
* To enable this backend, include 'graphite' in the backends
* configuration array:
*
* backends: ['graphite']
*
* This backend supports the following config options:
*
* graphiteHost: Hostname of graphite server.
* graphitePort: Port to contact graphite server at.
*/
var net = require('net'),
util = require('util');
var debug;
var flushInterval;
var graphiteHost;
var graphitePort;
// prefix configuration
var globalPrefix;
var prefixPersecond;
var prefixCounter;
var prefixTimer;
var prefixGauge;
var prefixSet;
// set up namespaces
var legacyNamespace = true;
var globalNamespace = [];
var counterNamespace = [];
var timerNamespace = [];
var gaugesNamespace = [];
var setsNamespace = [];
var graphiteStats = {};
var post_stats = function graphite_post_stats(statString) {
var last_flush = graphiteStats.last_flush || 0;
var last_exception = graphiteStats.last_exception || 0;
if (graphiteHost) {
try {
var graphite = net.createConnection(graphitePort, graphiteHost);
graphite.addListener('error', function(connectionException){
if (debug) {
util.log(connectionException);
}
});
graphite.on('connect', function() {
var ts = Math.round(new Date().getTime() / 1000);
var namespace = globalNamespace.concat('statsd');
statString += namespace.join(".") + '.graphiteStats.last_exception ' + last_exception + ' ' + ts + "\n";
statString += namespace.join(".") + '.graphiteStats.last_flush ' + last_flush + ' ' + ts + "\n";
this.write(statString);
this.end();
graphiteStats.last_flush = Math.round(new Date().getTime() / 1000);
});
} catch(e){
if (debug) {
util.log(e);
}
graphiteStats.last_exception = Math.round(new Date().getTime() / 1000);
}
}
}
var flush_stats = function graphite_flush(ts, metrics) {
var starttime = Date.now();
var statString = '';
var numStats = 0;
var key;
var timer_data_key;
var counters = metrics.counters;
var gauges = metrics.gauges;
var timers = metrics.timers;
var sets = metrics.sets;
var counter_rates = metrics.counter_rates;
var timer_data = metrics.timer_data;
var statsd_metrics = metrics.statsd_metrics;
for (key in counters) {
var namespace = counterNamespace.concat(key);
var value = counters[key];
var valuePerSecond = value / (flushInterval / 1000); // calculate "per second" rate
if (legacyNamespace === true) {
statString += namespace.join(".") + ' ' + valuePerSecond + ' ' + ts + "\n";
statString += 'stats_counts.' + key + ' ' + value + ' ' + ts + "\n";
} else {
statString += namespace.concat('rate').join(".") + ' ' + valuePerSecond + ' ' + ts + "\n";
statString += namespace.concat('count').join(".") + ' ' + value + ' ' + ts + "\n";
}
numStats += 1;
}
for (key in timer_data) {
if (Object.keys(timer_data).length > 0) {
for (timer_data_key in timer_data[key]) {
var namespace = timerNamespace.concat(key);
var the_key = namespace.join(".");
statString += the_key + '.' + timer_data_key + ' ' + timer_data[key][timer_data_key] + ' ' + ts + "\n";
}
numStats += 1;
}
}
for (key in gauges) {
var namespace = gaugesNamespace.concat(key);
statString += namespace.join(".") + ' ' + gauges[key] + ' ' + ts + "\n";
numStats += 1;
}
for (key in sets) {
var namespace = setsNamespace.concat(key);
statString += namespace.join(".") + '.count ' + sets[key].values().length + ' ' + ts + "\n";
numStats += 1;
}
var namespace = globalNamespace.concat('statsd');
if (legacyNamespace === true) {
statString += 'statsd.numStats ' + numStats + ' ' + ts + "\n";
statString += 'stats.statsd.graphiteStats.calculationtime ' + (Date.now() - starttime) + ' ' + ts + "\n";
for (key in statsd_metrics) {
statString += 'stats.statsd.' + key + ' ' + statsd_metrics[key] + ' ' + ts + "\n";
}
} else {
statString += namespace.join(".") + '.numStats ' + numStats + ' ' + ts + "\n";
statString += namespace.join(".") + '.graphiteStats.calculationtime ' + (Date.now() - starttime) + ' ' + ts + "\n";
for (key in statsd_metrics) {
var the_key = namespace.concat(key);
statString += the_key.join(".") + ' ' + statsd_metrics[key] + ' ' + ts + "\n";
}
}
post_stats(statString);
};
var backend_status = function graphite_status(writeCb) {
for (stat in graphiteStats) {
writeCb(null, 'graphite', stat, graphiteStats[stat]);
}
};
exports.init = function graphite_init(startup_time, config, events) {
debug = config.debug;
graphiteHost = config.graphiteHost;
graphitePort = config.graphitePort;
config.graphite = config.graphite || {};
globalPrefix = config.graphite.globalPrefix;
prefixCounter = config.graphite.prefixCounter;
prefixTimer = config.graphite.prefixTimer;
prefixGauge = config.graphite.prefixGauge;
prefixSet = config.graphite.prefixSet;
legacyNamespace = config.graphite.legacyNamespace;
// set defaults for prefixes
globalPrefix = globalPrefix !== undefined ? globalPrefix : "stats";
prefixCounter = prefixCounter !== undefined ? prefixCounter : "counters";
prefixTimer = prefixTimer !== undefined ? prefixTimer : "timers";
prefixGauge = prefixGauge !== undefined ? prefixGauge : "gauges";
prefixSet = prefixSet !== undefined ? prefixSet : "sets";
legacyNamespace = legacyNamespace !== undefined ? legacyNamespace : true;
if (legacyNamespace === false) {
if (globalPrefix !== "") {
globalNamespace.push(globalPrefix);
counterNamespace.push(globalPrefix);
timerNamespace.push(globalPrefix);
gaugesNamespace.push(globalPrefix);
setsNamespace.push(globalPrefix);
}
if (prefixCounter !== "") {
counterNamespace.push(prefixCounter);
}
if (prefixTimer !== "") {
timerNamespace.push(prefixTimer);
}
if (prefixGauge !== "") {
gaugesNamespace.push(prefixGauge);
}
if (prefixSet !== "") {
setsNamespace.push(prefixSet);
}
} else {
globalNamespace = ['stats'];
counterNamespace = ['stats'];
timerNamespace = ['stats', 'timers'];
gaugesNamespace = ['stats', 'gauges'];
setsNamespace = ['stats', 'sets'];
}
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;
};