appdynamics
Version:
Performance Profiler and Monitor
147 lines (121 loc) • 4.51 kB
JavaScript
/*
Copyright (c) AppDynamics, Inc., and its affiliates
2015
All Rights Reserved
*/
;
var utility = require("../utility");
var HttpCommon = require("./http-common");
const bodyParser = require('body-parser');
var getGraphQLParams;
var parseRequestParams;
function HttpEntryProbe(agent) {
this.agent = agent;
}
exports.HttpEntryProbe = HttpEntryProbe;
HttpEntryProbe.prototype.init = function () {};
HttpEntryProbe.prototype.enableGraphQL = function (egql) {
getGraphQLParams = egql.getGraphQLParams;
};
HttpEntryProbe.prototype.enableGraphQLHttp = function (obj) {
parseRequestParams = obj.parseRequestParams;
};
HttpEntryProbe.prototype.attach = function (obj, moduleName) {
var self = this;
self.agent.timers.startTimer(100, true, function () {});
if (self.agent.tracer) {
self.ot_api = self.agent.TracerProvider.ot_api;
self.tracer = self.agent.tracer;
}
self.isHTTPs = obj.Agent && (obj.Agent.prototype.defaultPort == 443);
// server probe
self.agent.proxy.before(obj.Server.prototype, ['on', 'addListener'], function (obj, args) {
if (args[0] !== 'request') return;
if (obj.__httpProbe__) return;
obj.__httpProbe__ = true;
var cbIndex = args.length - 1;
args[cbIndex] = self.__createRequestHandler(args[cbIndex], moduleName === 'https');
});
};
function invokeOriginal(callback, self, args, ot_api, span, otCtx, req, res) {
if (ot_api) {
ot_api.context.with(ot_api.trace.setSpan(otCtx, span), () => {
ot_api.context.bind(ot_api.context.active(), req);
ot_api.context.bind(ot_api.context.active(), res);
return callback.apply(self, args);
});
} else {
return callback.apply(self, args);
}
}
HttpEntryProbe.prototype.__createRequestHandler = function (callback, isHTTPs) {
var self = this;
const handler = function (req, res) {
if (getGraphQLParams) {
getGraphQLParams(req).then(function (params) {
if (params.query !== null) {
req._body = true;
req.body = params;
req.graphqlop = params.operationName || "undefined";
}
self.agent.context.run(requestHandler, req, res);
});
} else if (parseRequestParams) {
const jsonParser = bodyParser.json();
jsonParser(req, res, (err) => {
if(err) {
self.agent.context.run(requestHandler, req, res);
} else {
parseRequestParams(req).then(function(params) {
if (params.query !== null) {
const { operationName } = params;
req.graphqlop = operationName || "undefined";
}
self.agent.context.run(requestHandler, req, res);
}).catch(function() {
self.agent.context.run(requestHandler, req, res);
});
}
});
} else {
if (
self.agent.opts.enableGraphQL
&& self.agent.libagentConnector.getBusinessTransactionQueryType(
"NODEJS_WEB",
utility.createBtNamingWrapper(req)
) == utility.constants.GRAPHQL_QUERY_TYPE
) {
self.agent.context.run(callback, req, res);
} else {
self.agent.context.run(requestHandler, req, res);
}
}
};
function requestHandler(req, res) {
let profiler = self.agent.profiler;
let time = profiler.time(true);
self.agent.metricsManager.addMetric(self.agent.metricsManager.HTTP_INCOMING_COUNT, 1);
let { transaction, span, otContext, serviceEndpoint } = HttpCommon.startTransactionHandler(req, res, self.agent, isHTTPs, self.tracer, self.ot_api);
var threadId = transaction.threadId;
self.agent.context.run(() => {
var oldThreadId = self.agent.thread.current();
self.agent.thread.resume(threadId);
try {
let threadProxyWrappedCb = self.agent.proxy.wrapWithThreadProxyIfEnabled(callback);
return invokeOriginal(threadProxyWrappedCb, this, arguments, self.ot_api, span, otContext, req, res);
} catch (e) {
HttpCommon.finalizeRequest(e, profiler, time, transaction, req, res, span, serviceEndpoint);
serviceEndpoint = null;
transaction = null;
throw e;
} finally {
self.agent.thread.resume(oldThreadId);
}
});
}
// Ensure any properties on callback are still accessible through handler.
// This is needed as Express attaches a bunch of extra properties and
// functionality, which may need to be accessed by other modules down stream.
handler.__proto__ = callback;
return handler;
};