apminsight
Version:
monitor nodejs applications
328 lines (294 loc) • 9.92 kB
JavaScript
var transaction = require("./transaction");
var libUtil = require("util");
var utils = require("./../util/utils");
var metricstore = require("./metricstore");
var constants = require("./../constants");
function WebTxn(reqInfo, req) {
transaction.call(this, reqInfo);
this._url = reqInfo.uri;
this._exactUrl = reqInfo.uri;
this._method = req ? req.method : "";
this._queryParam = reqInfo.queryParam;
this._inputParam = reqInfo.inputParam;
this._httpHeaders = reqInfo.httpHeaders;
(this._apdex = 0), (this._satisfied = 0);
(this._errorCodeDetails = {}), (this._tolerated = 0);
(this._frustrated = 0), (this._resCode = 0);
this._bytesInInfo = getBytesIn(req);
this._bytesOutInfo = {};
this._syntheticKey = "";
}
libUtil.inherits(WebTxn, transaction);
WebTxn.prototype.endTransaction = function (res) {
if (this.isTxnIgnored(res.statusCode)) {
return;
}
var allChildTrackers = this.getRootTracker().getChildTrackers();
for (var index = 0; index < allChildTrackers.length; index++) {
var curChildTracker = allChildTrackers[index];
traverseChildTrackers(curChildTracker, this);
}
this.updateRtMetric();
this.updateApdexMetric();
this.updateReqCount(res.statusCode);
this.markCompleted();
this.updateInDataStore();
};
function traverseChildTrackers(baseChildTracker, txnObj) {
if (!baseChildTracker) {
return;
}
if (!baseChildTracker.isCompleted()) {
apmInsightAgentInstance.endTracker(baseChildTracker, txnObj);
}
var allChilds = baseChildTracker.getChildTrackers();
for (var index = 0; index < allChilds.length; index++) {
var currChild = allChilds[index];
traverseChildTrackers(currChild, txnObj);
}
}
WebTxn.prototype.endApiTxn = function (err) {
if (this.isCreatedByApi() && !this.isTxnIgnored(this._resCode)) {
this.updateRtMetric();
this.updateApdexMetric();
this.updateReqCountByErr(err);
this.markCompleted();
this.updateInDataStore();
}
};
WebTxn.prototype.updateApdexMetric = function () {
var threshold = utils.getGenericThreshold(this.getUrl());
if (this._responseTime <= threshold.getApdexTh() * 1000) {
this._satisfied = 1;
} else if (this._responseTime <= threshold.getApdexTh() * 4 * 1000) {
this._tolerating = 1;
} else {
this._frustrated = 1;
}
};
WebTxn.prototype.updateReqCount = function (statusCode) {
this._resCode = statusCode;
if (utils.isPositiveNumber(statusCode) && statusCode >= 400) {
this._errorCount = 1;
this._errorCodeDetails[statusCode] = 1;
} else {
this._count = 1;
}
};
WebTxn.prototype.aggregate = function (txn) {
this._url = txn.getUrl();
this._resCode = txn.getResCode();
this.checkAndAggregateBytes(txn);
if (txn.isErrorTxn()) {
this._errorCount += txn.getErrorCount();
this._errorRt += txn.getRt();
this.aggregateErrorCode(txn.getErrorCodeDetails());
}
this.aggregateTxnSubResources(txn);
if (txn.getCount() > 0) {
this.aggregateNonErrorTxn(txn);
this._satisfied += txn.getSatisfied();
this._tolerated += txn.getTolerated();
this._frustrated += txn.getFrustrated();
}
};
WebTxn.prototype.checkAndAggregateBytes = function (txn) {
aggregateBytes(this._bytesInInfo, txn.getBytesInInfo());
aggregateBytes(this._bytesOutInfo, txn.getBytesOutInfo());
};
WebTxn.prototype.aggregateErrorCode = function (aggregatedErrorCodes) {
var allErrorCode = Object.keys(aggregatedErrorCodes);
var curTxn = this;
allErrorCode.forEach(function (eachErrorCode) {
if (curTxn._errorCodeDetails[eachErrorCode]) {
curTxn._errorCodeDetails[eachErrorCode] +=
aggregatedErrorCodes[eachErrorCode];
return;
}
curTxn._errorCodeDetails[eachErrorCode] =
aggregatedErrorCodes[eachErrorCode];
});
};
WebTxn.prototype.updateInDataStore = function () {
var txnMetric = metricstore.getWebTxnMetric();
var samplingFac = utils
.getGenericThreshold(this.getUrl())
.getWebTxnSamplingFactor();
var metricLimit = utils
.getGenericThreshold(this.getUrl())
.getApdexMetricSize();
this.checkAndupdateInDataStore(txnMetric, WebTxn, samplingFac, metricLimit);
};
WebTxn.prototype.getFormattedRtData = function () {
var apdexScore = 0;
if (this.getCount() > 0) {
apdexScore =
(this.getSatisfied() + this.getTolerated() / 2) / this.getCount();
}
var apdexRtData = [
this.getRt(),
this.getMinRt(),
this.getMaxRt(),
this.getCount(),
apdexScore,
this.getSatisfied(),
this.getTolerated(),
this.getFrustrated(),
this.getErrorCount()
];
var additinalMetric = {
httpcode: this.getErrorCodeDetails(),
components: this.getComponentDetails(),
logmetric: this.getErrorDetails(),
error_rt: this.getErrorRt(),
bytes_in: [0, 0, 0, 0],
bytes_out: [0, 0, 0, 0]
};
if (this.getBytesInInfo().bytes) {
var bytesInInfo = this.getBytesInInfo();
additinalMetric.bytes_in = [
bytesInInfo.bytes,
bytesInInfo.min,
bytesInInfo.max,
bytesInInfo.count
];
}
if (this.getBytesOutInfo().bytes) {
var bytesOutInfo = this.getBytesOutInfo();
additinalMetric.bytes_out = [
bytesOutInfo.bytes,
bytesOutInfo.min,
bytesOutInfo.max,
bytesOutInfo.count
];
}
return [apdexRtData, additinalMetric];
};
WebTxn.prototype.getTraceInfo = function () {
var traceInfo = {};
traceInfo.t_name = constants.webTxnPrefix + this.getUrl();
traceInfo.exact_url = this.getExactUrl();
traceInfo.http_method_name = this.getMethod();
traceInfo.s_time = this.getStartTime();
traceInfo.r_time = this.getRt();
traceInfo.http_query_str = this.getQueryParam();
traceInfo.http_input_params = this.getInputParam();
traceInfo.http_headers = this.getHttpHeaders();
traceInfo.trace_reason = 4;
traceInfo.db_opn = [];
traceInfo.loginfo = [];
traceInfo.method_count = 1;
traceInfo.dt_count = 0;
traceInfo.custom_params = this.getCustomParamsAsStr();
Object.assign(traceInfo, this.getTrackerCountInfo());
traceInfo.drop_threshold = utils
.getGenericThreshold(this.getUrl())
.getTxnTrackerDropThreshold();
this.appendCompInfoInTrace(traceInfo);
if (this.getBytesInInfo().bytes) {
traceInfo.hbytesin = this.getBytesInInfo().bytes;
}
if (this.getBytesOutInfo().bytes) {
traceInfo.hbytes = this.getBytesOutInfo().bytes;
}
if (this.getResCode() > 0) {
traceInfo.httpcode = this.getResCode();
}
if (this.getRumTraceId()) {
traceInfo.trace_id = this.getRumTraceId();
}
if (this.getSyntheticKey()) {
traceInfo[constants.syntheticMonitoringKey] = this.getSyntheticKey();
}
if (!utils.isEmpty(this.getError())) {
traceInfo.err_st = this.getError().getErrorStackFrames();
}
return traceInfo;
};
WebTxn.prototype.getExactUrl = function () {
return this._exactUrl;
};
WebTxn.prototype.getErrorCodeDetails = function () {
return this._errorCodeDetails;
};
WebTxn.prototype.getMethod = function () {
return this._method;
};
WebTxn.prototype.getResCode = function () {
return this._resCode;
};
WebTxn.prototype.getSatisfied = function () {
return this._satisfied;
};
WebTxn.prototype.getTolerated = function () {
return this._tolerated;
};
WebTxn.prototype.getFrustrated = function () {
return this._frustrated;
};
WebTxn.prototype.getQueryParam = function () {
return this._queryParam;
};
WebTxn.prototype.getInputParam = function () {
return this._inputParam;
};
WebTxn.prototype.getHttpHeaders = function () {
return this._httpHeaders;
};
WebTxn.prototype.getBytesInInfo = function () {
return this._bytesInInfo;
};
WebTxn.prototype.setBytesIn = function (bytes) {
this._bytesInInfo = { bytes: bytes };
};
WebTxn.prototype.getBytesOutInfo = function () {
return this._bytesOutInfo;
};
WebTxn.prototype.setBytesOut = function (bytes) {
this._bytesOutInfo = { bytes: bytes };
};
WebTxn.prototype.getSyntheticKey = function () {
return this._syntheticKey;
};
WebTxn.prototype.setSyntheticKey = function (key) {
this._syntheticKey = key;
};
WebTxn.prototype.getTxnType = function () {
return "webtxn";
};
function getNormalisedUri(uri) {
return uri ? uri.replace(constants.txnNormalizationRegex, "/*") : "";
}
function getBytesIn(req) {
var bytesInfo = {};
if (!req) {
return bytesInfo;
}
if (req && req.headers) {
var bytesIn = parseInt(req.headers[constants.contentLengthHeader]);
return utils.isPositiveNumber(bytesIn) ? { bytes: bytesIn } : bytesInfo;
}
return bytesInfo;
}
function aggregateBytes(curTxnBytesInfo, txnBytesInfo) {
if (txnBytesInfo.bytes) {
if (curTxnBytesInfo.bytes) {
curTxnBytesInfo.bytes += txnBytesInfo.bytes;
curTxnBytesInfo.min =
curTxnBytesInfo.min < txnBytesInfo.bytes
? curTxnBytesInfo.min
: txnBytesInfo.bytes;
curTxnBytesInfo.max =
curTxnBytesInfo.max > txnBytesInfo.bytes
? curTxnBytesInfo.max
: txnBytesInfo.bytes;
curTxnBytesInfo.count++;
} else {
curTxnBytesInfo.bytes = txnBytesInfo.bytes;
curTxnBytesInfo.min = txnBytesInfo.bytes;
curTxnBytesInfo.max = txnBytesInfo.bytes;
curTxnBytesInfo.count = 1;
}
}
}
module.exports = WebTxn;