UNPKG

pmx

Version:

PM2/Keymetrics advanced API

288 lines (237 loc) 7.17 kB
var Counter = require('./utils/probes/Counter.js'); var Histogram = require('./utils/probes/Histogram.js'); var Meter = require('./utils/probes/Meter.js'); var Alert = require('./utils/alert.js'); var Transport = require('./utils/transport.js'); var debug = require('debug')('axm:probe'); var util = require('util'); var Probe = {}; Probe._started = false; Probe._var = {}; Probe.AVAILABLE_AGG_TYPES = ['avg', 'min', 'max', 'sum', 'none']; Probe.AVAILABLE_MEASUREMENTS = [ 'min', 'max', 'sum', 'count', 'variance', 'mean', 'stddev', 'median', 'p75', 'p95', 'p99', 'p999' ]; Probe.default_aggregation = 'avg'; Probe.default_type = 'user'; function getValue(value) { if (typeof(value) == 'function') return value(); return value; } /** * Data that will be sent to Keymetrics */ function cookData(data) { var cooked_data = {}; Object.keys(data).forEach(function(probe_name) { if (typeof(data[probe_name].value) == 'undefined') return false; cooked_data[probe_name] = { value: getValue(data[probe_name].value) }; /** * Attach aggregation mode */ if (data[probe_name].agg_type && data[probe_name].agg_type != 'none') cooked_data[probe_name].agg_type = data[probe_name].agg_type; cooked_data[probe_name].historic = data[probe_name].historic; cooked_data[probe_name].type = data[probe_name].type; //if (data[probe_name].unit) cooked_data[probe_name].unit = data[probe_name].unit; /** * Attach Alert configuration */ if (data[probe_name].alert) cooked_data[probe_name].alert = data[probe_name].alert.serialize(); else cooked_data[probe_name].alert = {}; }); return cooked_data; }; /** * Tick system for Alerts */ function checkIssues(data) { Object.keys(data).forEach(function(probe_name) { if (typeof(data[probe_name].alert) !== 'undefined') { data[probe_name].alert.tick(getValue(data[probe_name].value)); } }); }; function historicEnabled(historic) { if (historic === false) return false; if (typeof(historic) === 'undefined') return true; return true; } function attachAlert(opts, conf) { /** * pm2 set module-name:probes:probe_name:value 20 * pm2 set module-name:probes:probe_name:mode 'threshold-avg' * pm2 set module-name:probes:probe_name:cmp '<' * pm2 set module-name:probes:probe_name:interval 20 */ var alert_opts = {}; if (opts.alert) alert_opts = opts.alert; if (conf && conf.probes && conf.probes[opts.name]) { // Default mode if (!alert_opts.mode) alert_opts.mode = 'threshold'; alert_opts = Object.assign(alert_opts, conf.probes[opts.name]); } if (alert_opts && alert_opts.mode == 'none') return false; if (Object.keys(alert_opts).length > 0 && Probe._alert_activated == true) { Probe._var[opts.name].alert = new Alert(alert_opts, {name : opts.name}); } } Probe.probe = function() { var self = this; // Get module configuration to enable alerts if (this.getConf && this.getConf()) Probe._alert_activated = this.getConf().alert_enabled || true; else Probe._alert_activated = false; if (Probe._started == false) { Probe._started = true; var p_interval = setInterval(function() { Transport.send({ type : 'axm:monitor', data : cookData(Probe._var) }); checkIssues(Probe._var); }, 990); p_interval.unref(); } return { /** * This reflect data to keymetrics * pmx.transpose('prop name', fn) * * or * * pmx.transpose({ * name : 'variable name', * data : function() { return value } * }); */ transpose : function(variable_name, reporter) { if (typeof variable_name === 'object') { reporter = variable_name.data; variable_name = variable_name.name; } if (typeof reporter !== 'function') { return console.error('[PMX] reporter is not a function'); } Probe._var[variable_name] = { value: reporter }; }, metric : function(opts) { if (!opts.name) return console.error('[Probe][Metric] Name not defined'); Probe._var[opts.name] = { value : opts.value || 0, type : opts.type || opts.name, historic: historicEnabled(opts.historic), agg_type: opts.agg_type || Probe.default_aggregation, unit : opts.unit }; /** * Attach alert to: Probe._var[opts.name].alert */ if (self.getConf) attachAlert(opts, self.getConf()); return { val : function() { var value = Probe._var[opts.name].value; if (typeof(value) == 'function') value = value(); return value; }, set : function(dt) { Probe._var[opts.name].value = dt; } }; }, histogram : function(opts) { if (!opts.name) return console.error('[Probe][Histogram] Name not defined'); opts.measurement = opts.measurement || 'mean'; opts.unit = opts.unit || ''; if (Probe.AVAILABLE_MEASUREMENTS.indexOf(opts.measurement) == -1) return console.error('[Probe][Histogram] Measure type %s does not exists', opts.measurement); var histogram = new Histogram(opts); Probe._var[opts.name] = { value: function() { return (Math.round(histogram.val() * 100) / 100) + '' + opts.unit }, type : opts.type || opts.name, historic: historicEnabled(opts.historic), agg_type: opts.agg_type || Probe.default_aggregation, unit : opts.unit }; /** * Attach alert to: Probe._var[opts.name].alert */ if (self.getConf) attachAlert(opts, self.getConf()); return histogram; }, meter : function(opts) { if (!opts.name) return console.error('[Probe][Meter] Name not defined'); opts.unit = opts.unit || ''; var meter = new Meter(opts); Probe._var[opts.name] = { value: function() { return meter.val() + '' + opts.unit }, type : opts.type || opts.name, historic: historicEnabled(opts.historic), agg_type: opts.agg_type || Probe.default_aggregation, unit : opts.unit }; /** * Attach alert to: Probe._var[opts.name].alert */ if (self.getConf) attachAlert(opts, self.getConf()); return meter; }, counter : function(opts) { if (!opts.name) return console.error('[Probe][Counter] Name not defined'); var counter = new Counter(); Probe._var[opts.name] = { value: function() { return counter.val() }, type : opts.type || opts.name, historic: historicEnabled(opts.historic), agg_type: opts.agg_type || Probe.default_aggregation, unit : opts.unit }; /** * Attach alert to: Probe._var[opts.name].alert */ if (self.getConf) attachAlert(opts, self.getConf()); return counter; } } }; module.exports = Probe;