var fs = require('fs'); var moment = require('moment'); var helper = require('../lib/helper'); var _ = require('lodash'); var alarm = require('./alarm'); /* * parameters: * dirname: string * rotation: interger (ms) * maxsize: interger (byte) * interval: interger (ms) * data: array (array of object) * alarm: object (alarm object) */ function stat(dirname, opts, alarmData) { opts = opts || {}; alarmData = alarmData || {}; this.dirname = dirname; this.rotation = opts.rotation || 15 * 60 * 1000; this.maxsize = opts.maxsize || 20000; this.currentsize = 0; this.timestamp = 0; this.foldername = 'stat/'; this.intervalId = undefined; this.interval = opts.interval || 60 * 1000; this.data = transformKeys(opts.data); this.rules = opts.data; this.alarm = new alarm(dirname, alarmData); helper.mkdirIfNotExist(`${this.dirname}/${this.foldername}`); }; function transformKeys(data) { keys = _.map(data, function(obj) { var fakey = {}; fakey[obj.key] = 0; return fakey; }); return _.reduce(keys, function(new_obj, obj) { return _.merge(new_obj, obj); }, {}); }; /* * parameters: * data: obj * rules: [obj] */ function alarmDataOutOfThreshold(data, rules) { _alarm = []; _.forEach(data, function(v, k) { rule = _.find(rules, ['key', k]); var alarmObj = {}; if(v < rule.threshold_inv) { _alarm.push({key: k, count: v, threshold_inv: rule.threshold_inv, message: `${k} count is below inverted threshold`}); } if(v > rule.threshold) { _alarm.push({key: k, count: v, threshold: rule.threshold, message: `${k} count is above threshold`}); } }); return _alarm }; /* * parameters: * data: any */ stat.prototype.appendStat = function(data) { data = this.formatData(data); this.currentsize = this.currentsize + helper.getLengthOfContent(data); fs.appendFile(this.getDir(), data, function(err) {}); }; /* * parameters: * none */ stat.prototype.start = function() { var self = this; this.intervalId = setInterval(function(){ var alarmData = alarmDataOutOfThreshold(self.data, self.rules); if(!_.isEmpty(alarmData)) { self.alarm.appendAlarm(alarmData); } self.appendStat(self.data); self.reset(); }, self.interval); }; /* * parameters: * none */ stat.prototype.stop = function() { clearInterval(this.intervalId); }; /* * parameters: * data: string */ stat.prototype.increment = function(data) { if(_.has(this.data, data)) { this.data[data]++; } else this.data[data] = 1; }; /* * parameters: * none */ stat.prototype.reset = function() { var self = this; _.forEach(this.data, function(v, k) { self.data[k] = 0; }); }; /* * parameters: * none */ stat.prototype.getDir = function() { var time = moment(Math.floor((+moment()) / this.rotation) * this.rotation); this.resetCurrentSize(time.unix()); time = time.format('YYYY-MM-DDTHH-mm-ss'); var count = this.getCount(); return `${this.dirname}${this.foldername}${time}_${count}.txt`; }; /* * parameters: * time_unix: string */ stat.prototype.resetCurrentSize = function(time_unix) { if(time_unix > this.timestamp) { this.currentsize = 0 this.timestamp = time_unix; } }; /* * parameters: * none */ stat.prototype.getCount = function() { var count = Math.floor((this.currentsize / this.maxsize) + 1); return ((count * 1e-5).toFixed(5)).split('.')[1]; }; /* * parameters: * data: any */ stat.prototype.formatData = function(data) { var date = moment().toISOString().trim(); var timestamp = moment().unix(); data = this._formatObject(data).trim(); return `${date} ${timestamp} ${data}\r\n`; }; /* * parameters: * data: any */ stat.prototype._formatObject = function(data) { return JSON.stringify(data); }; module.exports = stat;