appdynamics
Version:
Performance Profiler and Monitor
159 lines (127 loc) • 4.49 kB
JavaScript
/*
Copyright (c) AppDynamics, Inc., and its affiliates
2015
All Rights Reserved
*/
'use strict';
function TimePromise(agent, transactionInfo) {
this.agent = agent;
this.info = transactionInfo;
this.stackTrace = undefined;
this.time = undefined;
// optional callbacks:
this.beforeExitCall = null;
this.exitCallCompleted = null;
this.onSnapshotCaptured = null;
this.onResponseComplete = null;
}
exports.TimePromise = TimePromise;
TimePromise.fromRequest = function (agent, req, txn) {
if (txn.api)
return txn.api;
var tp = new TimePromise(agent, req),
profiler = agent.profiler;
tp.time = txn.time;
tp.stackTrace = profiler.stackTrace();
tp.transaction = txn;
txn.api = tp;
return tp;
};
TimePromise.prototype.start = function (cb) {
if (!this.info)
return;
var self = this;
var profiler = self.agent.profiler;
self.agent.context.run(function () {
self.time = profiler.time(true);
self.stackTrace = profiler.stackTrace();
self.transaction = profiler.startTransaction(
self.time, self.info, 'NODEJS_API');
self.agent.context.set('threadId', self.transaction.threadId);
self.transaction.api = self;
if (cb && typeof (cb) == 'function')
cb(self);
});
};
TimePromise.prototype.resume = function () {
if (!this.time) {
throw new Error('transaction not started');
}
this.agent.thread.resume(this.time.threadId);
this.transaction.touched = this.agent.system.millis();
};
TimePromise.prototype.markError = function (err, statusCode) {
this.transaction.error = err;
this.transaction.stackTrace = this.agent.profiler.formatStackTrace(err);
this.transaction.statusCode = statusCode !== undefined ? statusCode :
err.statusCode !== undefined ? err.statusCode :
500;
};
TimePromise.prototype.end = function (err, statusCode) {
var self = this;
var profiler = self.agent.profiler;
if (!self.time.done()) return;
if (err) this.markError(err, statusCode);
profiler.endTransaction(self.time, self.transaction, self.info);
};
TimePromise.prototype.startExitCall = function (exitCallInfo) {
var self = this;
var profiler = self.agent.profiler;
var callback = self.beforeExitCall;
var time = profiler.time();
try {
self.beforeExitCall = null; // bypass callback for explicit create
// libagent support
exitCallInfo.supportedProperties = exitCallInfo.identifyingProperties;
exitCallInfo.useBackendConfig = false;
// end libagent support
var ec = profiler.createExitCall(time, exitCallInfo);
if(!ec || ec.exitCallGuid == undefined) {
self.agent.logger.info('ExitCall not started correctly');
}
return ec;
} finally {
self.beforeExitCall = callback; // restore any callback
}
};
TimePromise.prototype.endExitCall = function (exitCall, error) {
var self = this;
if(!exitCall || exitCall.exitCallGuid == undefined) {
self.agent.logger.info('Cannot end exitCall as exitCall guid is not present');
return;
}
var time = exitCall.time;
if (time && !time.done()) return;
self.agent.profiler.addExitCall(exitCall.time, exitCall, error);
};
TimePromise.prototype.createCorrelationInfo = function (exitCall, doNotResolve) {
var self = this;
if(!exitCall || exitCall.exitCallGuid == undefined) {
self.agent.logger.info('Returning null Correlation Header as exitCall guid is not present');
return;
}
if (self.agent.backendConnector.libagent && doNotResolve) {
self.agent.libagentConnector.disableResolutionForExitCall(exitCall);
exitCall.correlationHeader = self.agent.libagentConnector.getCorrelationHeader(exitCall);
}
if (exitCall.correlationHeader) {
return exitCall.correlationHeader;
}
};
TimePromise.prototype.addSnapshotData = function (key, value) {
this.snapshotData = this.snapshotData || [];
this.snapshotData.push({ name: key, value: value });
};
TimePromise.prototype.addAnalyticsData = function (key, value) {
this.analyticsData = this.analyticsData || [];
/* The bindings layer will corretly preverse the type information on primitive types
* (bool, int, double, string), but complex types must be converted to their
* appropriate native representation otherwise the bindings layer will stringify
* the object through its toString method
*/
if (value instanceof Date) {
this.analyticsData.push({ name: key, value: value.toISOString() });
} else {
this.analyticsData.push({ name: key, value: value });
}
};