appdynamics
Version:
Performance Profiler and Monitor
175 lines (146 loc) • 5.08 kB
JavaScript
/*
Copyright (c) AppDynamics, Inc., and its affiliates
2015
All Rights Reserved
*/
;
var url = require("url");
function RedisProbe(agent) {
this.agent = agent;
this.packages = ['redis'];
this.relativePackages = ['../commander'];
}
exports.RedisProbe = RedisProbe;
function wrapExecutor(self, executor) {
return async function proxyExecutor(command, args, name) {
var profiler = self.agent.profiler;
var proxy = self.agent.proxy;
var locals = {};
locals.time = profiler.time();
locals.args = args;
var urlParsed = new url.URL(this.options.url);
var host = urlParsed.host;
locals.exitCall = self.createExitCall(host, name, args);
var val = executor.call(this, command, args, name);
var currentCtxt = self.agent.thread.current();
return proxy.promise(val, function(obj, args, ret, locals) {
self.agent.thread.resume(currentCtxt);
if (!locals.exitCall) return;
if (!locals.time.done()) return;
var error = proxy.getErrorObject(ret.error);
profiler.addExitCall(locals.time, locals.exitCall, error);
}, this, args, locals);
};
}
function proxyAttachCommands(self, originalObject) {
return function wrapperAttachCommands(argsObj) {
argsObj.executor = wrapExecutor(self, argsObj.executor);
return originalObject.attachCommands(argsObj);
};
}
RedisProbe.prototype.attachRelative = function(mod, args, obj) {
var self = this;
if(process.env.APPDYNAMICS_REDIS_PROBE_DISABLE == true || process.env.APPDYNAMICS_REDIS_PROBE_DISABLE == 'true') {
return;
}
if (args[0] == '../commander') {
var parentMod = mod.filename.split('@');
if (parentMod.length < 2
|| parentMod[1] != "redis/client/dist/lib/client/index.js") {
return;
}
if(obj.__appdynamicsProbeAttached__) return;
obj.__appdynamicsProbeAttached__ = true;
self.agent.on('destroy', function() {
if(obj.__appdynamicsProbeAttached__) {
delete obj.__appdynamicsProbeAttached__;
}
});
const originalObject = obj;
const overriddenObject = {};
overriddenObject.attachCommands = proxyAttachCommands(self, originalObject);
overriddenObject.__proto__ = originalObject;
return overriddenObject;
}
};
RedisProbe.prototype.attach = function(obj) {
var self = this;
if(obj.__appdynamicsProbeAttached__) return;
obj.__appdynamicsProbeAttached__ = true;
self.agent.on('destroy', function() {
if(obj.__appdynamicsProbeAttached__) {
delete obj.__appdynamicsProbeAttached__;
proxy.release(obj.createClient);
}
});
var proxy = self.agent.proxy;
var profiler = self.agent.profiler;
function proxyCommand(client) {
var method = client.internal_send_command
? "internal_send_command"
: "send_command";
proxy.around(client, method, before, after);
function before(obj, args, locals) {
locals.time = profiler.time();
var address = client.address || (client.host + ':' + client.port);
var command, params;
if (typeof(args[0]) == 'string') {
command = args[0];
params = args[1];
} else {
command = args[0].command;
params = args[0].args;
}
locals.exitCall = self.createExitCall(address, command, params);
if (typeof(args[0]) === 'object' && typeof(args[0].callback) === 'function') {
locals.methodHasCb = true;
proxy.before(args[0], 'callback', function(obj, args) {
complete(args, locals);
}, false, false, self.agent.thread.current());
} else if (typeof(args[2]) === 'function') {
locals.methodHasCb = true;
proxy.before(args, 2, function(obj, args) {
complete(args, locals);
}, false, false, self.agent.thread.current());
} else {
locals.methodHasCb = proxy.callback(args[1], -1, function(obj, args) {
complete(args, locals);
}, undefined, self.agent.thread.current());
}
}
function after(obj, args, ret, locals) {
if (locals.methodHasCb) return;
if (!ret || !ret.__appdynamicsIsPromiseResult__)
complete(null, locals);
else if (ret.error)
complete(ret.error, locals);
else
complete(null, locals);
}
function complete(err, locals) {
if (!locals.exitCall) return;
if (!locals.time.done()) return;
var error = proxy.getErrorObject(err);
profiler.addExitCall(locals.time, locals.exitCall, error);
}
}
proxy.after(obj, 'createClient', function(obj, args, ret) {
var client = ret;
proxyCommand(client);
});
};
RedisProbe.prototype.createExitCall = function(address, command, params) {
var self = this;
var profiler = self.agent.profiler;
var supportedProperties = {
'SERVER POOL': address,
'VENDOR': 'REDIS'
};
return profiler.createExitCall(profiler.time(), {
exitType: 'EXIT_CACHE',
supportedProperties: supportedProperties,
command: command,
commandArgs: profiler.sanitize(params),
stackTrace: profiler.stackTrace()
});
};