appdynamics
Version:
Performance Profiler and Monitor
184 lines (156 loc) • 5.64 kB
JavaScript
/*
Copyright (c) AppDynamics, Inc., and its affiliates
2015
All Rights Reserved
*/
;
var HttpOTUtils = require('./http-ot-utils.js');
module.exports.getHttpStatusCodeConfig = getHttpStatusCodeConfig;
module.exports.generateError = generateError;
module.exports.getHttpExitCallError = getHttpExitCallError;
module.exports.finalizeTransaction = finalizeTransaction;
module.exports.finalizeRequest = finalizeRequest;
module.exports.startTransactionHandler = startTransactionHandler;
function getHttpStatusCodeConfig(statusCode, statusCodesConfig) {
if (!statusCodesConfig) {
return undefined;
}
for (var i = 0, length = statusCodesConfig.length; i < length; ++i) {
var statusCodeConfig = statusCodesConfig[i];
if (statusCode >= statusCodeConfig.lowerBound &&
statusCode <= statusCodeConfig.upperBound) {
return statusCodeConfig;
}
}
return undefined;
}
function generateError(exception, statusCode, statusCodesConfig) {
var errorObject;
if (exception) {
if (exception instanceof Error) {
errorObject = {
name: "JS " + exception.name,
message: exception.message,
stack: exception.stack
};
}
} else {
var statusCodeConfig = getHttpStatusCodeConfig(statusCode, statusCodesConfig);
if (statusCodeConfig) {
if (statusCodeConfig.enabled) {
errorObject= { message: statusCodeConfig.description.toString(), name: "Error" };
}
}
else if ((statusCode < 200) || (statusCode >= 400)) {
var error, errorMsg;
if (statusCode >= 400 && statusCode <= 505) {
error = "HTTP response code " + statusCode;
} else {
error = "HTTP response code other";
}
errorMsg = "HTTP response code " + statusCode;
errorObject = { message: errorMsg, name: error };
}
}
return errorObject;
}
function getHttpExitCallError(statusCode, stack, locals) {
var error = {message: "Error code " + statusCode + " for URL " + locals.opts.hostname + ":" + locals.opts.port + locals.opts.path,
name: "Error",
stack: stack};
return error;
}
function finalizeRequest(err, profiler, time, transaction, req, res, span, sep) {
if (!time.done()) return;
finalizeTransaction(err, profiler, time, transaction, req, res, span);
finalizeServiceEndpoint(err, profiler, time, sep, res);
}
function finalizeServiceEndpoint (err, profiler, time, sep, res) {
if(!sep) return;
sep.error = sep.error || res.error || err;
sep.statusCode = sep.statusCode ||
(sep.error && sep.error.statusCode) ||
(res && res.statusCode) ||
500;
sep.stackTrace = sep.stackTrace || profiler.formatStackTrace(sep.error);
var error = generateError(sep.error, sep.statusCode);
if (error) {
sep.error = error;
}
profiler.endServiceEndpoint(time, sep);
}
function finalizeTransaction (err, profiler, time, transaction, req, res, span) {
transaction.error = transaction.error || res.error || err;
transaction.statusCode = transaction.statusCode ||
(transaction.error && transaction.error.statusCode) ||
(res && res.statusCode) ||
500;
transaction.stackTrace = transaction.stackTrace || profiler.formatStackTrace(transaction.error);
var error = generateError(transaction.error, transaction.statusCode);
if (error) {
transaction.error = error;
}
if (transaction.api && transaction.api.onResponseComplete) {
transaction.api.onResponseComplete.apply(transaction.api, [req, res]);
}
if (span) {
span.setAttributes(HttpOTUtils.getIncomingRequestAttributesOnResponse(res));
span.setStatus(HttpOTUtils.parseResponseStatus(res));
span.end();
}
profiler.endTransaction(time, transaction);
}
function startTransactionHandler(req, res, agent, isHTTPs, tracer, ot_api) {
var profiler = agent.profiler;
var proxy = agent.proxy;
var time = profiler.time(true);
agent.metricsManager.addMetric(
agent.metricsManager.HTTP_INCOMING_COUNT,
1
);
var span = undefined;
var baggageCorrHeader = undefined;
var otContext = undefined;
if (tracer) {
otContext = ot_api.propagation.extract(agent.TracerProvider.ot_api.ROOT_CONTEXT, req.headers);
var baggage = ot_api.propagation.getBaggage(otContext);
if (baggage && baggage.getEntry(agent.correlation.HEADER_NAME)) {
baggageCorrHeader = baggage.getEntry(agent.correlation.HEADER_NAME).value;
}
}
var transaction = profiler.startTransaction(time, req, "NODEJS_WEB", baggageCorrHeader);
if (tracer) {
ot_api.context.with(otContext, () => {
span = tracer.startSpan(transaction.name, {
kind: ot_api.SpanKind.SERVER,
attributes: HttpOTUtils.getIncomingRequestAttributes(req)
});
});
}
agent.context.set("threadId", transaction.threadId);
req.__appdThreadId = transaction.threadId;
transaction.url = req.url;
transaction.method = req.method;
transaction.requestHeaders = req.headers;
var eumEnabled = transaction.eumEnabled && !transaction.skip;
if (!transaction.corrHeader && eumEnabled) {
proxy.before(res, "writeHead", function (obj) {
if (!transaction.isFinished) {
var eumCookie = agent.eum.newEumCookie(
transaction,
req,
obj,
isHTTPs
);
eumCookie.build();
}
});
}
var serviceEndpoint = profiler.startServiceEndpoint(time, req, 'NODEJS_WEB');
proxy.after(res, "end", function () {
finalizeRequest(null, profiler, time, transaction, req, res, span, serviceEndpoint);
transaction = null;
serviceEndpoint = null;
});
return { transaction, span, otContext, serviceEndpoint };
}