UNPKG

ca-apm-probe

Version:

CA APM Node.js Agent monitors real-time health and performance of Node.js applications

262 lines (218 loc) 7.68 kB
/** * Copyright (c) 2015 CA. All rights reserved. * * This software and all information contained therein is confidential and proprietary and * shall not be duplicated, used, disclosed or disseminated in any way except as authorized * by the applicable license agreement, without the express written permission of CA. All * authorized reproductions must be marked with this language. * * EXCEPT AS SET FORTH IN THE APPLICABLE LICENSE AGREEMENT, TO THE EXTENT * PERMITTED BY APPLICABLE LAW, CA PROVIDES THIS SOFTWARE WITHOUT WARRANTY * OF ANY KIND, INCLUDING WITHOUT LIMITATION, ANY IMPLIED WARRANTIES OF * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL CA BE * LIABLE TO THE END USER OR ANY THIRD PARTY FOR ANY LOSS OR DAMAGE, DIRECT OR * INDIRECT, FROM THE USE OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, LOST * PROFITS, BUSINESS INTERRUPTION, GOODWILL, OR LOST DATA, EVEN IF CA IS * EXPRESSLY ADVISED OF SUCH LOSS OR DAMAGE. */ const util = require('util'); const METRIC_OP_CODE = 'm'; var metricTypes = require('./metric-types'); var metricSendHandler = null; var metrics = null; function Metric(name, value) { this.name = name; this.value = value; } Metric.prototype.toString = function () { return util.format('name: %s, value: %s', this.name, this.value); } Metric.prototype.toData = function () { return { op: METRIC_OP_CODE, mid: this.name, val: roundToInt(this.value), pid: process.pid }; } // string event metric type function StringMetric(name, value) { this.base = Metric; this.base(name, value); } StringMetric.prototype = Object.create(Metric.prototype); StringMetric.prototype.toData = function () { return { op: METRIC_OP_CODE, mid: this.name, val: this.value, mtype: metricTypes.STRING_EVENT, pid: process.pid }; } StringMetric.prototype.toString = function () { return util.format('StringMetric - %s', Metric.prototype.toString.call(this)); } // string constant metric type function StringConstantMetric(name, value) { this.base = StringMetric; this.base(name, value); } StringConstantMetric.prototype = Object.create(StringMetric.prototype); StringConstantMetric.prototype.toData = function () { return { op: METRIC_OP_CODE, mid: this.name, val: this.value, mtype: metricTypes.STRING_CONSTANT, pid: process.pid }; } StringConstantMetric.prototype.toString = function () { return util.format('StringConstantMetric - %s', Metric.prototype.toString.call(this)); } // long interval counter metric type function LongIntervalCounterMetric(name, value) { this.base = Metric; this.base(name, value); } LongIntervalCounterMetric.prototype = Object.create(Metric.prototype); LongIntervalCounterMetric.prototype.toData = function () { var data = Metric.prototype.toData.call(this); data.mtype = metricTypes.LONG_INTERVAL_COUNTER; return data; } LongIntervalCounterMetric.prototype.toString = function () { return util.format('IntervalCounterMetric - %s', Metric.prototype.toString.call(this)); } // long fluctuating counter metric type function LongFluctuatingCounterMetric(name, value) { this.base = Metric; this.base(name, value); } LongFluctuatingCounterMetric.prototype = Object.create(Metric.prototype); LongFluctuatingCounterMetric.prototype.toData = function () { var data = Metric.prototype.toData.call(this); data.mtype = metricTypes.LONG_FLUCTUATING_COUNTER; return data; } LongFluctuatingCounterMetric.prototype.toString = function () { return util.format('FluctuatingCounterMetric - %s', Metric.prototype.toString.call(this)); } // long duration average metric type function LongDurationMetric(name, value) { this.base = Metric; this.base(name, value); } LongDurationMetric.prototype = Object.create(Metric.prototype); LongDurationMetric.prototype.toData = function () { var data = Metric.prototype.toData.call(this); data.mtype = metricTypes.LONG_DURATION; return data; } LongDurationMetric.prototype.toString = function () { return util.format('DurationMetric - %s', Metric.prototype.toString.call(this)); } // average duration value to be set directly function AvgDurationDirectMetric(name, value, min, max, count) { this.base = Metric; this.base(name, value); this.min = min; this.max = max; this.count = count; this.timeStart = 0; this.timeEnd = 0; } AvgDurationDirectMetric.prototype = new Metric; AvgDurationDirectMetric.prototype.toString = function () { return util.format('AvgDurationDirectMetric - name: %s, value: %d, min: %d, max: %d, count: %d', this.name, this.value, this.min, this.max, this.count); } AvgDurationDirectMetric.prototype.toData = function (metric) { return { op: METRIC_OP_CODE, mid: this.name, mtype: metricTypes.LONG_DURATION_DIRECT, ct: this.count ? parseInt(this.count) : 0, val: roundToInt(this.value), mn: roundToInt(this.min), mx: roundToInt(this.max), ts: this.timeStart, te: this.timeEnd, pid: this.pid }; } function roundToInt(n) { return Math.round(Number(n)); }; function sendMetric(metric) { if (metricSendHandler) { return metricSendHandler(metric); } }; var setMetricEventHandler = function (handler) { metricSendHandler = handler; }; var reportStringConstantMetric = function (name, value) { sendMetric(new StringConstantMetric(name, value).toData()); }; var reportStringMetric = function (name, value) { sendMetric(new StringMetric(name, value).toData()); }; var reportIntervalCounterMetric = function (name, value) { sendMetric(new LongIntervalCounterMetric(name, value).toData()); }; var reportFluctuatingCounterMetric = function (name, value) { sendMetric(new LongFluctuatingCounterMetric(name, value).toData()); }; var reportAvgDurationMetric = function (name, value) { sendMetric(new LongDurationMetric(name, value).toData()); }; var reportAvgDurationDirectMetric = function (name, value, min, max, count) { sendMetric(new AvgDurationDirectMetric(name, value, min, max, count).toData()); }; var poll = function () { var snapshot = metrics; metrics = null; return snapshot; }; var add = function (scope, name, value, unit, op, session) { if (!scope) scope = 'default-scope'; var key = scope + ':' + name; if (metrics == null) { // Users can add their own metrics; we need a prototype-less dictionary // to store them or a metric like '__proto__' would cause issues. metrics = Object.create(null); } else { var obj = metrics[key]; if (obj) { obj.value = value; return; } } metrics[key] = { name: name, op: op, scope: scope, session: session, unit: unit, value: value, }; }; var reporter = { reportStringConstantMetric: reportStringConstantMetric, reportStringMetric: reportStringMetric, reportIntervalCounterMetric: reportIntervalCounterMetric, reportFluctuatingCounterMetric: reportFluctuatingCounterMetric, reportAvgDurationMetric: reportAvgDurationMetric } module.exports = { poll: poll, add: add, setMetricEventHandler: setMetricEventHandler, // it is hack for reporting average metrics directly // we don't want to expose this to customer. therefore not part of reporter object reportAvgDurationDirectMetric: reportAvgDurationDirectMetric, getReporter: function () { return reporter; } }