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
JavaScript
/**
* 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;
}
}