apminsight
Version:
monitor nodejs applications
446 lines (404 loc) • 12.2 kB
JavaScript
var utils = require("./../util/utils");
var logger = require("./../util/logger");
var constants = require("./../constants");
var libUtil = require("util");
var errorinfo = require("./error");
function Tracker(trackerInfo) {
this._parent = trackerInfo.parent;
this._startTime = new Date().getTime();
this._name = trackerInfo.trackerName;
this._component = trackerInfo.component ? trackerInfo.component : "";
this._sync = trackerInfo.sync ? true : false;
this._byApi = trackerInfo.api ? true : false;
this._stale = trackerInfo.stale ? trackerInfo.stale : false;
this._compAppended = false;
this._endTime = 0;
this._time = 0;
this._childOverhead = 0;
this._info = {};
this._child = [];
this._error = null;
this._completed = false;
}
Tracker.prototype.getInfo = function () {
return this._info;
};
Tracker.prototype.updateInfo = function (additionalInfo) {
this._info = Object.assign(this._info, additionalInfo);
};
Tracker.prototype.getStartTime = function () {
return this._startTime;
};
Tracker.prototype.getTrackerName = function () {
return this._name;
};
Tracker.prototype.getTrackerNameForTrace = function () {
var name = this._name.indexOf(".prototype.")
? this._name.replace(".prototype", "")
: this._name;
var info = this.getInfo();
//reqPath will be available for next.js framework
if (info.reqPath) {
name += " - " + info.reqPath;
}
if (info.opn) {
name = this._component + " - " + info.opn;
}
if (info.method) {
name += " - " + info.method;
}
if (info.statusCode) {
name += " - " + info.statusCode;
}
if (info.host && info.port) {
name += " - " + info.host + ":" + info.port;
}
if (info.pathname) {
name += " - " + info.pathname;
}
if (this.isError()) {
return name + " : " + this.getErrorInfo().getType();
}
return name;
};
Tracker.prototype.getComponent = function () {
return this._component;
};
Tracker.prototype.getTime = function () {
return this._time;
};
Tracker.prototype.getChildOverhead = function () {
return this._childOverhead;
};
Tracker.prototype.checkAndUpdateExclusiveTime = function (childTracker) {
if (this._sync && childTracker && childTracker.isSync()) {
var overHead = childTracker.getTime() + childTracker.getChildOverhead();
this._childOverhead += overHead;
}
};
Tracker.prototype.getChildTrackers = function () {
return this._child;
};
Tracker.prototype.isAllowedInTrace = function (txn) {
if (this._stale || !this.isCompleted()) {
return false;
}
if (this.isError() || this.isCustomTracker()) {
return true;
}
if (
!utils.isEmpty(this.getComponent()) &&
constants.externalComponents.indexOf(this.getComponent()) >= 0
) {
return true;
}
return (
this._time >=
utils.getGenericThreshold(txn.getUrl()).getTxnTrackerDropThreshold()
);
};
Tracker.prototype.getAdditionalInfo = function () {
var info = {};
if (this.isError()) {
info.exception_st = this.getErrorInfo().getErrorStackFrames();
}
if (this._info.dtdata) {
info.dtdata = this._info.dtdata;
}
return info;
};
Tracker.prototype.updateEndTime = function () {
this._endTime = new Date().getTime();
this._time = this._endTime - this._startTime - this._childOverhead;
};
Tracker.prototype.setError = function (error, txn) {
if (error && !error.apmAgentHandled) {
this._error = new errorinfo(error);
error.apmAgentHandled = true;
txn.checkAndAddError(this._error.getType());
}
};
Tracker.prototype.setActive = function () {
if (this._stale && !this._compAppended) {
apmInsightAgentInstance.checkAndAddComponent(
apmInsightAgentInstance.getCurTxn(),
this
);
this._compAppended = true;
}
this._stale = false;
};
Tracker.prototype.isError = function () {
if (this._error) {
return true;
}
return false;
};
Tracker.prototype.getErrorInfo = function () {
return this._error;
};
Tracker.prototype.endTracker = function (txn, err) {
if (this.isCompleted()) {
return false;
}
if (!txn || txn.isCompleted()) {
return false;
}
this._completed = true;
this.setError(err, txn);
this.updateEndTime();
if (!this._stale && !this._compAppended) {
apmInsightAgentInstance.checkAndAddComponent(txn, this);
this._compAppended = true;
}
if (this._parent) {
this._parent.checkAndUpdateExclusiveTime(this);
}
return true;
};
Tracker.prototype.addChildTracker = function (child) {
this._child.push(child);
};
Tracker.prototype.isCompleted = function () {
return this._completed;
};
Tracker.prototype.isSync = function () {
return this._sync;
};
Tracker.prototype.isCustomTracker = function () {
return this._byApi;
};
Tracker.prototype.isDistributedTrace = function () {
return this._dtrace;
};
Tracker.prototype.setDistributedTrace = function () {
this._dtrace = true;
};
Tracker.prototype.updateDtInfo = function (dtInfo) {
this.updateInfo({ dtdata: dtInfo });
this.setDistributedTrace();
};
function DbTracker(trackerInfo) {
Tracker.call(this, trackerInfo);
this._minRt = 0;
this._maxRt = 0;
this._count = 0;
this._errorCount = 0;
this.isDbTracker = true;
}
libUtil.inherits(DbTracker, Tracker);
DbTracker.prototype.endTracker = function (txn) {
var processed = Tracker.prototype.endTracker.apply(this, arguments);
if (processed) {
txn.addDbCall(this);
}
};
DbTracker.prototype.isAllowedInTrace = function () {
return this.isCompleted() ? true : false;
};
DbTracker.prototype.getCount = function () {
return this._count;
};
DbTracker.prototype.getErrorCount = function () {
return this._errorCount;
};
DbTracker.prototype.getMinRt = function () {
return this._minRt;
};
DbTracker.prototype.getMaxRt = function () {
return this._maxRt;
};
DbTracker.prototype.getTrackerNameForTrace = function () {
if (!this._info.opn) {
return this._name.indexOf(".prototype.")
? this._name.replace(".prototype", "")
: this._name;
}
var trackerName = this._component + " - " + this._info.opn;
if (this._info.host && this._info.port) {
trackerName += " - " + this._info.host + ":" + this._info.port;
}
if (this.isError()) {
trackerName += " : " + this.getErrorInfo().getType();
}
return trackerName;
};
DbTracker.prototype.getAdditionalInfo = function (txn) {
var info = {};
if (this.isError()) {
info.stacktrace = this.getErrorInfo().getErrorStackFrames();
}
if (
(this.getComponent() === "MONGODB" || this.getComponent() === "ORACLEDB") &&
this._info.opn &&
this._info.object
) {
info.query = this._info.opn + " - " + this._info.object;
} else if (utils.getGenericThreshold(txn.getUrl()).isSqlParameterized()) {
info.query = getMaskedQuery(this._info.query);
} else {
info.query = this._info.query;
}
return info;
};
DbTracker.prototype.extractOperationInfo = function () {
if (this._info.opn && this._info.object) {
return this._info;
}
if (this._info.query) {
try {
var opnName = constants.firstSyllable.exec(this._info.query);
var regex = constants.dbOpnRegex[opnName[1].toLowerCase()];
if (regex) {
var groups = regex.exec(this._info.query);
if (groups) {
this._info.opn = groups[1].toUpperCase();
this._info.object = groups[2];
return this._info;
}
}
} catch (err) {
if (apmInsightAgentInstance.getConfig().isDebugModeEnabled()) {
logger.error(
"Error occured while processing the query - " +
this._info.query +
" :: " +
err
);
}
}
} else if (this.getComponent() === "MONGODB" || this.getComponent() === "ORACLEDB") {
var qualifiedName = this.getTrackerName().split(".");
this._info.opn = qualifiedName.pop().toUpperCase();
return this._info;
}
return {};
};
DbTracker.prototype.aggregate = function (dbtracker) {
var info = dbtracker.extractOperationInfo();
this._info.opn = info.opn;
this._info.object = info.object;
this._component = dbtracker.getComponent();
if (dbtracker.isError()) {
this._errorCount += 1;
return;
}
this._time += dbtracker.getTime();
this._count += 1;
if (this._minRt === 0 || dbtracker.getTime() < this._minRt) {
this._minRt = dbtracker.getTime();
}
if (this._maxRt === 0 || this._maxRt < dbtracker.getTime()) {
this._maxRt = dbtracker.getTime();
}
};
function getMaskedQuery(sql) {
if (!sql) {
return "";
}
var maskedQuery = "";
var length = sql.length;
for (var i = 0; i < length; i++) {
var c = sql.charAt(i);
if (c === "'" || c === '"' /*|| c == '`'*/) {
var c2 = c;
maskedQuery += "?";
for (i++; i < length; i++) {
c = sql.charAt(i);
if (c == "\\" && i < length - 1) {
i++;
} else {
if (c == c2) {
break;
}
}
}
if (i >= length) {
break;
}
} else {
if (
utils.isNumber(c) ||
(c === "." &&
i < length - 1 &&
utils.isNumber(sql.charAt(i + 1)))
) {
maskedQuery += "?";
while (i < length) {
c = sql.charAt(i);
if (!utils.isNumber(c) && c !== ".") {
break;
}
i++;
}
if (i >= length) {
break;
}
i--;
} else {
if (!utils.isLetter(c)) {
if (c !== "_") {
maskedQuery += c;
continue;
}
}
while (i < length) {
c = sql.charAt(i);
if (!utils.isLetter(c) && c != "_" && !utils.isNumber(c)) {
break;
}
maskedQuery += c;
i++;
}
if (i >= length) {
break;
}
i--;
}
}
}
return maskedQuery;
}
function EsTracker(trackerInfo) {
Tracker.call(this, trackerInfo);
this.isEsTracker = true;
}
libUtil.inherits(EsTracker, Tracker);
EsTracker.prototype.getTrackerNameForTrace = function () {
var trackerName = this._component;
if (
this._info.params &&
this._info.params[0] &&
this._info.params[0].method
) {
trackerName += " - " + this._info.params[0].method;
}
if (this._info.host && this._info.port) {
trackerName += " - " + this._info.host + ":" + this._info.port;
}
if (
this._info.params &&
this._info.params[0] &&
this._info.params[0].path
) {
trackerName += " - " + this._info.params[0].path;
}
if (this.isError()) {
trackerName += " : " + this.getErrorInfo().getType();
}
return trackerName;
};
function createRootTracker(rootListner) {
var trackerInfo = {
trackerName: rootListner,
sync: true,
component: "NODEJS-CORE"
};
return new Tracker(trackerInfo);
}
module.exports = {
Tracker: Tracker,
DbTracker: DbTracker,
EsTracker: EsTracker,
createRootTracker: createRootTracker
};