ca-apm-probe
Version:
CA APM Node.js Agent monitors real-time health and performance of Node.js applications
132 lines (111 loc) • 3.74 kB
JavaScript
/**
* Copyright (c) 2015 CA. All rights reserved.
*
* This software and all information contained therein is confidential and proprietary and
* shall not be duplicated, used, disclosed or disseminated in any way except as authorized
* by the applicable license agreement, without the express written permission of CA. All
* authorized reproductions must be marked with this language.
*
* EXCEPT AS SET FORTH IN THE APPLICABLE LICENSE AGREEMENT, TO THE EXTENT
* PERMITTED BY APPLICABLE LAW, CA PROVIDES THIS SOFTWARE WITHOUT WARRANTY
* OF ANY KIND, INCLUDING WITHOUT LIMITATION, ANY IMPLIED WARRANTIES OF
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL CA BE
* LIABLE TO THE END USER OR ANY THIRD PARTY FOR ANY LOSS OR DAMAGE, DIRECT OR
* INDIRECT, FROM THE USE OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, LOST
* PROFITS, BUSINESS INTERRUPTION, GOODWILL, OR LOST DATA, EVEN IF CA IS
* EXPRESSLY ADVISED OF SUCH LOSS OR DAMAGE.
*/
var path = require('path');
var agent = require('../agent');
var proxy = require('../proxy');
var logger = require("../logger.js");
var config = require('../configdata').getConfigData();
var showGraphQLQuery = config.graphql.showGraphQLQuery;
var targetModule = new Object;
module.exports = function (graphql) {
targetModule.graphql = graphql;
targetModule.Execution = findExecution(targetModule.graphql, require);
targetModule.methodMap = getMethodsWithProbes();
var methodMap = targetModule.methodMap;
if (methodMap[0] == "skip_instrument") {
return;
}
logger.info('Loading graphql probe');
proxy.before(targetModule.Execution, 'execute', queryHook);
};
function queryHook(obj, args, storage) {
var req = args[0];
if(!req.document){
return;
}
var operationDefinition = null
req.document.definitions.forEach(element => {
if(element.kind == "OperationDefinition"){
operationDefinition = element;
}
});
var operation = operationDefinition.operation;
var query = null;
operationDefinition.selectionSet.selections.forEach(element => {
if(!query){
query = element.name.value;
} else {
query += ',' + element.name.value;
}
});
var ctx = storage.get('ctx') || req.__CA_ctx;
var queryString = query;
if(ctx != null && showGraphQLQuery){
queryString = storage.get('gqlQuery');
queryString = JSON.stringify(queryString).replace(/\\n/g, '');
}
if(ctx != null){
if(!agent.graphQLUrl){
agent.graphQLUrl = ctx.args.url;
}
ctx.args.url = ctx.args.url + "/" + operation + "/" + query;
ctx.args.hdrs[0]="GraphQL";
}
var evtName = 'graphql.execute';
var gqlCtx = agent.asynchEventStart(ctx, evtName, {
operation: operation,
query: queryString,
tracePreviousCtx: true
});
if(ctx != null){
ctx.gqlCtx = gqlCtx;
gqlCtx.asyncCall = true;
gqlCtx.fragmentEntryPoint = ctx.args.url;
}
storage.set('ctx', gqlCtx);
}
function findExecution(parent, require) {
var cache = require.cache;
for (var key in cache) {
var candidate = cache[key];
if (candidate.exports !== parent) {
continue;
}
var dirname = path.dirname(candidate.filename);
var filename = path.join(dirname, 'execution', 'execute.js');
try {
return require(filename);
} catch (e) {
return null;
}
}
return null;
}
function getMethodsWithProbes() {
if (!targetModule.methodMap) {
var mt = new Object;
mt[0] = 'graphql#execute';
targetModule.methodMap = mt;
}
return targetModule.methodMap;
}
function instrument(methodMap) {
targetModule.methodMap = methodMap;
}
module.exports.getMethodsWithProbes = getMethodsWithProbes;
module.exports.instrument = instrument.bind(module);