diff --git a/README.md b/README.md index 98808c7..07da45b 100644 --- a/README.md +++ b/README.md @@ -174,6 +174,30 @@ server.listen(port, (err) => { }); ``` +## prometheus.addMetric(metricInfo, onDataEvent) + +this method allow you to add custom monitoring for metrics. +the first parameter should have `name`, which represent the name of the appmetrics monitoring event. `data`, the dynamic data which will be saved on each event, and a `toString` which will be printed as part of the `metrics` route. +the last function is the listener for the monitoring and it will `this` as the metric info, which allow to save the data differently on each metric monitoring event. + +```js + require('appmetrics-prometheus') + .attach() + .addMetric({ + name: 'socketio', + data: null, + toString() { + if(this.data) { + return `socketio_last_event ${JSON.stringify(this.data)}`; + } + + return ''; + } + }, function(data) { + this.data = data; + }); +``` + ## Performance overhead Our testing has shown that the performance overhead in terms of processing is minimal, adding less than 0.5 % to the CPU usage of your application. diff --git a/lib/appmetrics-prometheus.js b/lib/appmetrics-prometheus.js index 12367f3..1e3e66e 100644 --- a/lib/appmetrics-prometheus.js +++ b/lib/appmetrics-prometheus.js @@ -35,7 +35,8 @@ var save = { http: {}, https: {}, }; - +var extendedMetrics = {}; +var globalOptions = {}; exports.attach = function(options) { if (save.http.Server) { @@ -43,12 +44,12 @@ exports.attach = function(options) { return exports; } // Protect our options from modification. - options = util._extend({}, options); + globalOptions = util._extend({}, options); // if the user hasn't supplied appmetrics, require // here so we get http probe data - if (!options.appmetrics) { - options.appmetrics = require('appmetrics'); + if (!globalOptions.appmetrics) { + globalOptions.appmetrics = require('appmetrics'); } patch(save.http, require('http')); @@ -59,21 +60,50 @@ exports.attach = function(options) { save.Server = http.Server; http.Server = function() { const server = save.Server.apply(this, arguments); - options.server = server; - monitor(options); + globalOptions.server = server; + monitor(globalOptions); return server; }; save.createServer = http.createServer; http.createServer = function() { const server = save.createServer.apply(this, arguments); - options.server = server; - monitor(options); + globalOptions.server = server; + monitor(globalOptions); return server; }; } return exports; }; +/** + * this method allow you to add customized metrics that will be visible through prometheus + * metrics endpoint + * + * @param {Object} metricInfo + * @param {string} metricInfo.name the listener monitored metric + * @param {any} metricInfo.data the changing data of the metric + * @param {function} metricInfo.toString the string representation of this object. will be showed as new line in the metrics endpoint + * @param {function} onMetricData function that represent what to do when receiving metric data, + * usually will set the data in order to print the data on metrics endpoint. + * + * @returns exports the exports object for chaining + */ +exports.addMetric = function(metricInfo, onMetricData) { + var appmetrics = globalOptions.appmetrics || require('appmetrics'); + var monitoring = appmetrics.monitor(); + + if (typeof onMetricData !== 'function') { + onMetricData = function(data) { + extendedMetrics[metricInfo.name].data = data; + }; + } + + extendedMetrics[metricInfo.name] = metricInfo; + monitoring.on(metricInfo.name, onMetricData.bind(extendedMetrics[metricInfo.name])); + + return exports; +}; + // Start monitoring process and subscribe to the data. // Don't export monitor var monitor = function(options) { @@ -131,6 +161,11 @@ var monitor = function(options) { res.write(httpRequestTotal); res.write(httpRequestDuration); } + + for (var metric in extendedMetrics) { + res.write(extendedMetrics[metric].toString() + '\n'); + } + res.end(); } @@ -292,3 +327,4 @@ var monitor = function(options) { }); return server; }; +