Get metrics from codahale/metrics in realtime.
Requires obfuscurity/tasseo#64
Get metrics from codahale/metrics in realtime.
Requires obfuscurity/tasseo#64
function MetricsDatasource(metricsUrl, options) { | |
this.metricCache = new MetricCache(new MetricFetcher(metricsUrl)); | |
} | |
MetricsDatasource.prototype = { | |
refresh: function(metrics, period) { | |
var self = this; | |
self.metricCache.setPeriod(period * 60); | |
self.metricCache.refresh(function() { | |
_.each(metrics, function(metric) { | |
var dataset = self.metricCache.get(metric.target); | |
metric.update(_.map(dataset, function(datum) { | |
return { x: datum.time, y: datum.value } | |
})) | |
}) | |
}) | |
} | |
} | |
function MetricFetcher(url) { | |
this.url = url; | |
} | |
MetricFetcher.prototype = { | |
refresh: function(cb) { | |
$.ajax({ | |
dataType: 'json', | |
error: function(xhr, textStatus, errorThrown) { console.log(errorThrown); }, | |
url: this.url, | |
success: _.bind(function(data) { | |
this.latestMetrics = this.flattenMetrics(data) | |
cb.call(this.latestMetrics) | |
}, this) | |
}) | |
}, | |
flattenMetrics: function(data, prefix) { | |
var result = {}; | |
var hasType = _.has(data, 'type'); | |
_.each(data, function(value, key) { | |
var metricName = _.isUndefined(prefix) ? key : prefix + "." + key; | |
if (hasType) { | |
if (_.isNumber(value)) { | |
result[metricName] = value; | |
} | |
} else if (_.isObject(value)) { | |
_.extend(result, this.flattenMetrics(value, metricName)) | |
} | |
}, this); | |
return result; | |
} | |
} | |
function MetricCache(metricFetcher, options) { | |
this.metricFetcher = metricFetcher; | |
this.options = _.extend({}, { | |
period: 60 * 5 // 5 minutes | |
}, options) | |
this.period = this.options.period | |
this.cache = {} | |
this._metricNames = {} | |
} | |
MetricCache.prototype = { | |
refresh: function(callback) { | |
var self = this; | |
this.metricFetcher.refresh(function() { | |
self.update() | |
if (callback) { | |
callback.call() | |
} | |
}) | |
}, | |
setPeriod: function(period) { | |
this.period = period; | |
}, | |
get: function(name) { | |
if (!_.has(this.cache, name)) { | |
this.cache[name] = this.blankData(); | |
} | |
return this.cache[name]; | |
}, | |
metricNames: function() { | |
return _.keys(this._metricNames); | |
}, | |
update: function() { | |
var now = this.unixtime(); | |
var oldest = now - this.period; | |
var newMetric = false; | |
_.each(this.metricFetcher.latestMetrics, function(value, name) { | |
if (!this._metricNames[name]) { | |
this._metricNames[name] = true | |
newMetric = true; | |
} | |
// Only fill in metrics that we've had requests for | |
if (_.has(this.cache, name)) { | |
this.cache[name].push({ value: value, time: now }) | |
this.cache[name] = _.reject(this.cache[name], function(record) { | |
return record.time < oldest; | |
}) | |
} | |
}, this) | |
if (newMetric) { | |
$(this).trigger("metric:added") | |
} | |
}, | |
unixtime: function() { | |
return Math.floor(new Date() / 1000) | |
}, | |
blankData: function() { | |
var now = this.unixtime(); | |
var data = [] | |
for (var i = now - this.period; i < now; i += 5) { | |
data.push({ value: 0, time: i }) | |
} | |
return data; | |
} | |
} |