UNPKG

mongo-metrics

Version:

Tracking Metrics with MongoDb

183 lines (143 loc) 4.17 kB
var qbox = require('qbox'); var mongo = require('mongodb'); function MongoMetrics (mongoUrl, collection) { collection = collection || 'metrics'; var mongoDatabase = qbox.create(); mongo.MongoClient.connect(mongoUrl, function(err, db) { if(err) { throw err; } mongoDatabase.db = db; mongoDatabase.start(); db.on('error', function(err) { console.error('mongodb error: ' + err.toString()); }); }); this.track = function track(name, value, source, date, callback) { if((typeof date) == 'function') { callback = date; date = null; } date = date || new Date(); var metric = { name: name, value: value, source: source, date: date.getTime(), resolution: getResolution(date) }; mongoDatabase.ready(function() { if(callback) { mongoDatabase.db.collection(collection).insert(metric, callback); } else { mongoDatabase.db.collection(collection).insert(metric, {w: 0}); } }); }; /* Aggregate metrics @param {String} name - name of the metric @param {Constant} resolution - resolution type possible values: "DAY", "HOUR", "MINUTE", "FIVE_SECS" @param {String} metricsAggregator - aggregation function to be used for aggregating metric of the each source possible values: "sum", "avg", "min", "max" @param {String} sourceAggregator - aggregation function to be used for the aggregating sources(value from metricsAggregation) possible values: "sum", "avg", "min", "max" @param {Object} query - mongodb query for filtering out metrics only supports date and source only @param {Function} callback - callback function callback(err, results) */ this.aggregate = function aggregate(name, resolution, metricsAggregator, sourceAggregator, query, callback) { if(typeof(query) == 'function') { callback = query; query = {}; } if(!MongoMetrics.RESOLUTION[resolution]) { return callback(new Error("invalid resolution")); } if(!MongoMetrics.AGGREGATORS[metricsAggregator]) { return callback(new Error("metricsAggregator is not supported")); } if(!MongoMetrics.AGGREGATORS[sourceAggregator]) { return callback(new Error("sourceAggregator is not supported")); } var filter = { name: name }; ['date', 'source'].forEach(function(field) { if(query[field]) { filter[field] = query[field]; } }); var aggreation = [ {$match: filter}, {$group: this._generateMetricsGrouping(resolution, metricsAggregator)}, {$group: this._generateSourceGrouping(sourceAggregator)}, {$sort: {"_id.y": 1, "_id.mo": 1, "_id.d": 1, "_id.h": 1, "_id.m": 1, "_id.s": 1}} ]; mongoDatabase.ready(function() { mongoDatabase.db.collection(collection).aggregate(aggreation, callback); }); }; this._generateMetricsGrouping = function _generateMetricsGrouping(resolution, aggregator) { var _id = { date: { y: "$resolution.y", mo: "$resolution.mo" }, source: "$source" }; var value = {}; value["$" + aggregator] = "$value"; switch(resolution) { case "five_secs": _id.date['s5'] = "$resolution.s5" case "minute": _id.date['m'] = "$resolution.m" case "hour": _id.date['h'] = "$resolution.h" case "day": _id.date['d'] = "$resolution.d"; } return { _id: _id, value: value }; }; this._generateSourceGrouping = function _generateSourceGrouping(aggregator) { var value = {}; value['$' + aggregator] = "$value"; return { _id: "$_id.date", value: value }; }; } MongoMetrics.RESOLUTION = { day: true, hour: true, minute: true, five_secs: true }; MongoMetrics.AGGREGATORS = { "sum": true, "avg": true, "min": true, "max": true }; function getResolution(date) { return { y: date.getUTCFullYear(), mo: date.getUTCMonth(), d: date.getUTCDate(), h: date.getUTCHours(), m: date.getUTCMinutes(), s5: roundToNear(date.getUTCSeconds(), 5), //with 5 sec resolution, s: date.getUTCSeconds() }; } function roundToNear (value, roundVal) { return ((value - (value % roundVal)) / roundVal) * roundVal; } module.exports = MongoMetrics; module.exports._roundToNear = roundToNear; module.exports._getResolution = getResolution;