UNPKG

apminsight

Version:

monitor nodejs applications

446 lines (404 loc) 12.2 kB
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 };