New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More

ca-apm-probe

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ca-apm-probe - npm Package Compare versions

Comparing version

to
1.10.20

@@ -0,0 +0,0 @@

@@ -24,2 +24,3 @@

var fs = require('fs');
var util = require('util');
var logger = require("./logger.js");

@@ -32,2 +33,3 @@ var config = require('../config.json');

var pid = process.pid;
var instanceId = util.format('%s-%s', os.hostname(), pid);
var maxPingDelay = config.maxPingDelay || 15000;

@@ -70,3 +72,3 @@ var lastPingResponseTime = new Date().getTime();

pid: pid,
instid: pid
instid: instanceId
};

@@ -81,3 +83,3 @@ return object;

ver: 1,
instid: pid,
instid: instanceId,
pgm: currentProbeName

@@ -84,0 +86,0 @@ };

@@ -0,0 +0,0 @@

@@ -42,3 +42,4 @@ /**

var path = obj.path;
var method = (obj.stack[0].method).toUpperCase();
var req = args[0];
var res = args[1];

@@ -51,3 +52,3 @@ var eventNameFormatted = 'route.dispatch';

route: path,
http_method: method
http_method: req.method
});

@@ -57,4 +58,2 @@ storage.set('ctx', ctx);

var req = args[0];
var res = args[1];
var errorObject = new Object();

@@ -61,0 +60,0 @@

@@ -51,4 +51,3 @@

// CA code end
proxy.callback(args, -1,
function(obj, args, extra, graph, currentNode, storage) {
proxy.callback(args, -1, function(obj, args, storage) {
//var errorObject = agent.checkAndSetErrorObject(args, 'FSError');

@@ -63,3 +62,3 @@

},
function(obj, args, extra, graph, currentNode) {
function(obj, args) {
if (ctx != null) agent.asynchEventFinish(ctx);

@@ -66,0 +65,0 @@ }); // CA code end

@@ -40,294 +40,274 @@

module.exports = function(http) {
targetModule.http = http;
targetModule.methodMap = getMethodsWithProbes();
var methodMap = targetModule.methodMap;
// server probe
targetModule.http = http;
targetModule.methodMap = getMethodsWithProbes();
var methodMap = targetModule.methodMap;
// server probe
proxy.after(http, 'createServer', function(module, args, server) {
server['__CA_id'] = serverNum++;
logger.debug('HTTP server %d created', server['__CA_id']);
var stackTrace = (new Error('Location')).stack.substring(6);
logger.debug(stackTrace);
});
proxy.after(http, 'createServer', function(module, args, server) {
server['__CA_id'] = serverNum++;
logger.debug('HTTP server %d created', server['__CA_id']);
var stackTrace = (new Error('Location')).stack.substring(6);
logger.debug(stackTrace);
});
proxy.before(http.Server.prototype, ['on', 'addListener'],
function caHTTPBeforeHook(server, args) {
proxy.before(http.Server.prototype, ['on', 'addListener'],
function caHTTPBeforeHook(server, args) {
if (logger.isDebug) {
logger.debug('HTTP server ' + server['__CA_id'] + ': ' + args[0] + ' listener added.');
logger.debug((new Error('Location')).stack.substring(6));
}
if (logger.isDebug()) {
logger.debug('HTTP server ' + server['__CA_id'] + ': ' + args[0] + ' listener added.');
logger.debug((new Error('Location')).stack.substring(6));
}
if (methodMap[0] == "skip_instrument") {
return;
}
if (methodMap[0] == "skip_instrument") {
return;
}
// store ref to server so we can pull current connections
agent.httpServer = server;
// store ref to server so we can pull current connections
agent.httpServer = server;
// agent provides data such as protocol, default port
// it differs across http vs https
var httpAgent = http.globalAgent;
// agent provides data such as protocol, default port
// it differs across http vs https
var httpAgent = http.globalAgent;
var kContextPropertyName = '__CA_APM_PROBE_HTTP_CONTEXT__';
var context = server[kContextPropertyName];
if (context == null) {
// Index [0] is current connection counter, [1] is the previous one.
context = {connectionCounts: [0, 0]};
Object.defineProperty(server, kContextPropertyName, {value: context});
}
var kContextPropertyName = '__CA_APM_PROBE_HTTP_CONTEXT__';
var context = server[kContextPropertyName];
if (context == null) {
// Index [0] is current connection counter, [1] is the previous one.
context = {connectionCounts: [0, 0]};
Object.defineProperty(server, kContextPropertyName, {value: context});
}
function getEventNameFormatted(req) {
var name = 'http.' + req.method;
return name;
function getEventNameFormatted(req) {
var name = 'http.' + req.method;
return name;
}
function getEventArgs(req) {
var eargs = {
url: req.url
};
var corHeaderValue = req.headers[CORRELATION_HEADER_KEY_LOWERCASE];
if (corHeaderValue) {
if (logger.isDebug()) {
logger.debug('Noticed correlation header in incoming http request, corid: %s'
, corHeaderValue);
}
eargs.corId = corHeaderValue;
}
function getEventArgs(req) {
var eargs = {
url: req.url
};
var corHeaderValue = req.headers[CORRELATION_HEADER_KEY_LOWERCASE];
if (corHeaderValue) {
if (logger.isDebug()) {
logger.debug('Noticed correlation header in incoming http request, corid: %s'
, corHeaderValue);
}
eargs.corId = corHeaderValue;
}
var hostHeader = req.headers['host'];
var hostHeader = req.headers['host'];
if(hostHeader) {
var hostPort = hostHeader.split(':');
eargs.hostName = hostPort[0] || DEFAULT_HOST;
eargs.hostPort = hostPort[1] || (httpAgent.defaultPort && httpAgent.defaultPort.toString()) || DEFAULT_PORT;
} else {
eargs.hostName = DEFAULT_HOST;
eargs.hostPort = (httpAgent.defaultPort && httpAgent.defaultPort.toString()) || DEFAULT_PORT;
}
if(hostHeader) {
var hostPort = hostHeader.split(':');
eargs.hostName = hostPort[0] || DEFAULT_HOST;
eargs.hostPort = hostPort[1] || (httpAgent.defaultPort && httpAgent.defaultPort.toString()) || DEFAULT_PORT;
} else {
eargs.hostName = DEFAULT_HOST;
eargs.hostPort = (httpAgent.defaultPort && httpAgent.defaultPort.toString()) || DEFAULT_PORT;
}
return eargs;
}
return eargs;
}
function logHttpUrl(req, eargs) {
if (logger.isDebug()) {
var protocol = httpAgent.protocol || DEFAULT_PROTOCOL;
var url = protocol + '//' + eargs.hostName + ':' + eargs.hostPort + req.url;
logger.debug('http requested url: %s', url);
}
}
function logHttpUrl(req, eargs) {
if (logger.isDebug()) {
var protocol = httpAgent.protocol || DEFAULT_PROTOCOL;
var url = protocol + '//' + eargs.hostName + ':' + eargs.hostPort + req.url;
logger.debug('http requested url: %s', url);
}
}
function processRequest(req, storage) {
var eventNameFormatted = getEventNameFormatted(req);
function processRequest(req, storage) {
var eventNameFormatted = getEventNameFormatted(req);
var eventArgs = getEventArgs(req);
var ctx = agent.asynchEventStart(null, eventNameFormatted, eventArgs);
storage.set('ctx', ctx);
logHttpUrl(req, eventArgs);
ctx.eventNameFormatted = eventNameFormatted;
return ctx;
}
var eventArgs = getEventArgs(req);
var ctx = agent.asynchEventStart(null, eventNameFormatted, eventArgs);
storage.set('ctx', ctx);
logHttpUrl(req, eventArgs);
ctx.eventNameFormatted = eventNameFormatted;
return ctx;
}
if (args[0] !== 'request' && args[0] !== 'upgrade') return;
if (args[0] === 'connection') {
proxy.callback(args, -1, function caHTTPConnectionHook(obj, args, _, _, _, storage) {
logger.debug('TCP connection.');
}, function (obj, args, _, _, _, storage) {
var socket = args[0];
if (socket.parser.onIncoming) {
if (socket.parser.onIncoming.__CA_patched) {
return;
}
logger.debug('HTTP parser attached to connection has been instrumented.');
var onOnIncoming_save = socket.parser.onIncoming;
socket.parser.onIncoming = function() {
logger.debug('HTTP request incoming.');
if (agent.paused) return;
var request = arguments[0];
request.__CA_ctx = processRequest(request, storage);
onOnIncoming_save.apply(socket.parser, arguments);
};
socket.parser.onIncoming.__CA_patched = true;
}
});
return;
}
if (args[0] !== 'request' && args[0] !== 'upgrade') return;
proxy.callback(args, -1, function caHTTPCallbackHook(obj, args, storage) {
context.connectionCounts[0] += 1;
proxy.callback(args, -1, function caHTTPCallbackHook(obj, args, _, _, _, storage) {
context.connectionCounts[0] += 1;
if (agent.paused) return;
if (agent.paused) return;
var request = args[0];
var res = args[1];
var ctx = null;
var eventNameFormatted = '';
var request = args[0];
var res = args[1];
var ctx = null;
var eventNameFormatted = '';
if (request.__CA_ctx) {
ctx = request.__CA_ctx;
eventNameFormatted = ctx.eventNameFormatted;
}
else {
ctx = processRequest(request, storage);
eventNameFormatted = ctx.eventNameFormatted;
}
// handle multiple request listeners scenario
// process request only once to send start event
if (request.__CA_ctx) {
ctx = request.__CA_ctx;
storage.set('ctx', ctx);
} else {
ctx = processRequest(request, storage);
request.__CA_ctx = ctx;
}
if (res.__CA_patched) {
return;
}
// response already patched to send finish event
if (res.__CA_patched) {
return;
}
var errorObject = null;
eventNameFormatted = ctx.eventNameFormatted;
var errorObject = null;
res.__CA_patched = true;
res.__CA_patched = true;
var end_save = res.end;
res.end = function () {
var isFinished = res.finished;
end_save.apply(res, arguments);
var end_save = res.end;
res.end = function() {
var isFinished = res.finished;
end_save.apply(res, arguments);
if (isFinished === false) {
if (res.statusCode >= 400) {
errorObject = new Object();
errorObject['class'] = "Http " + res.statusCode;
errorObject['msg'] = res.statusMessage;
}
if (isFinished === false) {
if (res.statusCode >= 400) {
errorObject = new Object();
errorObject['class'] = "Http " + res.statusCode;
errorObject['msg'] = res.statusMessage;
}
ctx = agent.asynchEventDone(ctx, eventNameFormatted, null, errorObject);
if (ctx != null) {
agent.asynchEventFinish(ctx);
}
}
};
ctx = agent.asynchEventDone(ctx, eventNameFormatted, null, errorObject);
if (ctx != null) {
agent.asynchEventFinish(ctx);
}
}
};
});
});
});
// probe into outgoing client request instance
proxy.after(http, 'request', function(obj, args, rval, storage) {
if (agent.paused) return;
// probe into outgoing client request instance
proxy.after(http, 'request', function(obj, args, rval, storage) {
if (agent.paused) return;
if (methodMap[0] == "skip_instrument") {
return;
}
if (methodMap[0] == "skip_instrument") {
return;
}
var clientReq = rval;
var clientReq = rval;
if (isHttpReqDecEnabled && clientReq && typeof clientReq === 'object') {
var ctx = storage.get('ctx');
if (isHttpReqDecEnabled && clientReq && typeof clientReq === 'object') {
var ctx = storage.get('ctx');
if (ctx && ctx.corIdObj) {
var corid = ctx.corIdObj.getOutgoingCorId();
clientReq.setHeader(CORRELATION_HEADER_KEY, corid);
logger.debug('Decorated outgoing http request with correlation header %s: %s',
CORRELATION_HEADER_KEY, corid);
}
}
});
if (ctx && ctx.corIdObj) {
var corid = ctx.corIdObj.getOutgoingCorId();
clientReq.setHeader(CORRELATION_HEADER_KEY, corid);
logger.debug('Decorated outgoing http request with correlation header %s: %s',
CORRELATION_HEADER_KEY, corid);
}
}
});
if (http.ClientRequest && http.ClientRequest.prototype) {
// request.end() is used to signify that one is done with making request out
proxy.after(http.ClientRequest.prototype, 'end', function caHTTPClientReqHook(obj, args, rval, storage) {
if (http.ClientRequest && http.ClientRequest.prototype) {
// request.end() is used to signify that one is done with making request out
proxy.after(http.ClientRequest.prototype, 'end', function caHTTPClientReqHook(obj, args, rval, storage) {
var clientReq = obj;
var hostHeader = clientReq.getHeader('host');
var host;
var port;
var protocol = (clientReq.agent && clientReq.agent.protocol) || DEFAULT_PROTOCOL;
var path = clientReq.path;
var url = path;
if(hostHeader) {
var hostPort = hostHeader.split(':');
host = hostPort[0] || DEFAULT_HOST;
port = hostPort[1] || (clientReq.agent && clientReq.agent.defaultPort && clientReq.agent.defaultPort.toString()) || DEFAULT_PORT;
} else {
host = DEFAULT_HOST;
port = (clientReq.agent && clientReq.agent.defaultPort && clientReq.agent.defaultPort.toString()) || DEFAULT_PORT;
}
var clientReq = obj;
var hostHeader = clientReq.getHeader('host');
var host;
var port;
var protocol = (clientReq.agent && clientReq.agent.protocol) || DEFAULT_PROTOCOL;
var path = clientReq.path;
var url = path;
if(hostHeader) {
var hostPort = hostHeader.split(':');
host = hostPort[0] || DEFAULT_HOST;
port = hostPort[1] || (clientReq.agent && clientReq.agent.defaultPort && clientReq.agent.defaultPort.toString()) || DEFAULT_PORT;
} else {
host = DEFAULT_HOST;
port = (clientReq.agent && clientReq.agent.defaultPort && clientReq.agent.defaultPort.toString()) || DEFAULT_PORT;
}
if (!path.startsWith(protocol + '//')) {
url = protocol + '//' + host + ':' + port + path;
}
if (!path.startsWith(protocol + '//')) {
url = protocol + '//' + host + ':' + port + path;
}
var eventArgs = {
host: host,
port: port,
method: clientReq.method,
path: path,
url: url
};
var eventArgs = {
host: host,
port: port,
method: clientReq.method,
path: path,
url: url
};
var eventNameFormatted = 'httpclient.request';
var ctx = storage.get('ctx');
if (logger.isDebug()) {
if (ctx) {
logger.debug('%s[%d %d %d]: $s', eventNameFormatted, ctx.txid, ctx.lane, ctx.evtid, eventArgs.url);
}
else {
logger.debug('%s - no context', eventNameFormatted);
logger.debug((new Error('No context')).stack);
}
}
ctx = agent.asynchEventStart(storage.get('ctx'), eventNameFormatted, eventArgs);
storage.set('ctx', ctx);
var eventNameFormatted = 'httpclient.request';
var ctx = storage.get('ctx');
if (logger.isDebug()) {
if (ctx) {
logger.debug('%s[%d %d %d]: $s', eventNameFormatted, ctx.txid, ctx.lane, ctx.evtid, eventArgs.url);
}
else {
logger.debug('%s - no context', eventNameFormatted);
logger.debug((new Error('No context')).stack);
}
}
ctx = agent.asynchEventStart(storage.get('ctx'), eventNameFormatted, eventArgs);
storage.set('ctx', ctx);
// patch emit method
var originalEmit = clientReq.emit;
// patch emit method
var originalEmit = clientReq.emit;
clientReq.emit = function() {
beforeClientResponseHook(clientReq, arguments, ctx);
var returnValue = originalEmit.apply(this, arguments);
if (ctx != null) agent.asynchEventFinish(ctx);
return returnValue;
};
clientReq.emit = function() {
beforeClientResponseHook(clientReq, arguments, ctx);
var returnValue = originalEmit.apply(this, arguments);
if (ctx != null) agent.asynchEventFinish(ctx);
return returnValue;
};
});
};
});
};
// one time response event is emitted by ClientRequest instance when it is
// gets response back from server
var beforeClientResponseHook = function(obj, args, ctx) {
if (methodMap[0] == "skip_instrument") {
return;
}
// one time response event is emitted by ClientRequest instance when it is
// gets response back from server
var beforeClientResponseHook = function(obj, args, ctx) {
if (methodMap[0] == "skip_instrument") {
return;
}
if (args[0] !== 'response') {
return;
}
if (args[0] !== 'response') {
return;
}
var res = args[1];
var res = args[1];
if (res) {
var clientReq = obj;
var resCode = res.statusCode;
var resMsg = res.statusMessage;
if (res) {
var clientReq = obj;
var resCode = res.statusCode;
var resMsg = res.statusMessage;
var eventArgs = {
resCode: resCode,
resMsg: resMsg
};
var eventArgs = {
resCode: resCode,
resMsg: resMsg
};
var errorObject = null;
if (res.statusCode >= 400 && res.statusCode <= 599) {
errorObject = {};
errorObject['class'] = "Http " + resCode;
errorObject['msg'] = resMsg;
}
var errorObject = null;
if (res.statusCode >= 400 && res.statusCode <= 599) {
errorObject = {};
errorObject['class'] = "Http " + resCode;
errorObject['msg'] = resMsg;
}
var eventNameFormatted = 'httpclient.request';
var eventNameFormatted = 'httpclient.request';
if (ctx) {
if (logger.isDebug()) {
logger.debug('%s[%d %d %d]: callback', eventNameFormatted, ctx.txid, ctx.lane, ctx.evti);
}
ctx = agent.asynchEventDone(ctx, eventNameFormatted, eventArgs, errorObject);
}
else {
if (logger.isDebug()) {
logger.debug('%s - no context: callback', eventNameFormatted);
logger.debug((new Error('No context')).stack);
}
}
if (ctx) {
if (logger.isDebug()) {
logger.debug('%s[%d %d %d]: callback', eventNameFormatted, ctx.txid, ctx.lane, ctx.evti);
}
};
ctx = agent.asynchEventDone(ctx, eventNameFormatted, eventArgs, errorObject);
}
else {
if (logger.isDebug()) {
logger.debug('%s - no context: callback', eventNameFormatted);
logger.debug((new Error('No context')).stack);
}
}
}
};

@@ -338,12 +318,12 @@ };

function getMethodsWithProbes() {
if (!targetModule.methodMap) {
var mt = new Object;
mt[0] = 'http#all';
targetModule.methodMap = mt;
}
return targetModule.methodMap;
if (!targetModule.methodMap) {
var mt = new Object;
mt[0] = 'http#all';
targetModule.methodMap = mt;
}
return targetModule.methodMap;
}
function instrument(methodMap) {
targetModule.methodMap = methodMap;
targetModule.methodMap = methodMap;
}

@@ -350,0 +330,0 @@

@@ -76,4 +76,3 @@

storage.set('ctx', ctx);
proxy.callback(args, -1,
function(obj, args, _, _, _, storage) {
proxy.callback(args, -1, function(obj, args, storage) {
var errorObject = agent.checkAndSetErrorObject(args, 'MySQLError');

@@ -80,0 +79,0 @@ // CA code start

@@ -142,4 +142,3 @@ /**

if (callbackIndex !== -1) {
proxy.callback(args, callbackIndex,
function(obj, args, extra, graph, currentNode, storage) {
proxy.callback(args, callbackIndex, function(obj, args, storage) {

@@ -146,0 +145,0 @@ //var errorObject = agent.checkAndSetErrorObject(args, 'MongodbError');

@@ -81,3 +81,3 @@

proxy.callback(args, -1, function(obj, args, _, _, _, storage) {
proxy.callback(args, -1, function(obj, args, storage) {
var errorObject = agent.checkAndSetErrorObject(args, 'MySQLError');

@@ -124,3 +124,3 @@ if (ctx != null) {

var newArgs = [args[0]._callback];
proxy.callback(newArgs, -1, function(obj, args, extra, graph, currentNode, storage) {
proxy.callback(newArgs, -1, function(obj, args, storage) {
storage.set('ctx', ctx);

@@ -127,0 +127,0 @@ if (debug) {

@@ -55,3 +55,3 @@

function handle(obj, args, extra, _, _, storage) {
function handle(obj, args, storage) {
// var errorObject = agent.checkAndSetErrorObject(args, 'RedisError');

@@ -68,3 +68,3 @@

}
function afterHandle(obj, args,extra) {
function afterHandle(obj, args) {
// if (ctx != null) agent.asynchEventFinish(ctx);

@@ -71,0 +71,0 @@ }

@@ -86,14 +86,8 @@

}
var target = args[index];
var extra = agent.extra;
var graph = agent.graph;
var currentNode = agent.currentNode;
var proxy = wrap(target, function(recv, args, context) {
// TODO(bnoordhuis) Get rid of these globals.
if (extra) agent.extra = extra;
if (graph) agent.graph = graph;
if (currentNode) agent.currentNode = currentNode;
if (before) {
try {
before(recv, args, extra, graph, currentNode, context.storage);
before(recv, args, context.storage);
} catch (e) {

@@ -103,6 +97,7 @@ logProbeErrorMessage(e, recv, context.target, true);

}
var rval = target.apply(recv, args);
if (after) {
try {
after(recv, args, extra, graph, currentNode, context.storage);
after(recv, args, rval, context.storage);
} catch (e) {

@@ -112,6 +107,2 @@ logProbeErrorMessage(e, recv, context.target, null, true);

}
// TODO(bnoordhuis) Get rid of these globals.
if (currentNode) agent.currentNode = undefined;
if (graph) agent.graph = undefined;
if (extra) agent.extra = undefined;
return rval;

@@ -118,0 +109,0 @@ }, true);

@@ -21,3 +21,17 @@ /**

module.exports.findCallbackIndex = function (args) {
var agent = require('../agent');
var proxy = require('../proxy');
var logger = require("../logger.js");
var traceUtil = require("./trace-util");
var util = require('util');
var DEFAULT_EVENT_CLASS_NAME = 'Object';
/**
* Find index of callback function in arguments array.
* @method
* @param {array} args array of arguments
* @returns {number}
*/
var findCallbackIndex = function (args) {
var callbackIndex = args.length - 1;

@@ -29,2 +43,233 @@

return callbackIndex;
}
}
/**
* Instrument callback based asynchronous non-blocking functions
* @method
* @param {object} object Object selected for instrumentation
* @param {array} fnNames Names of functions to instrument
* @param {string} eventClassName Class name used for creating trace events
* @param {function} startEventParamsCallback Callback function to fetch parameters for start trace event.
* Arguments passed to this callback are:
* -obj object being traced
* -args arguments passed to function under execution
* @param finishEventParamsCallback Callback function to fetch parameters for finish trace event
* Arguments passed to this callback are:
* -obj callback object being traced
* -args arguments passed to callback. Usually non null args[0] indicates error, args[1] refers to returned value
*/
var instrumentAsync = function (object, fnNames, eventClassName, startEventParamsCallback, finishEventParamsCallback) {
var eventClassName = eventClassName || (object.constructor.name && object.constructor.name.toLowerCase()) || DEFAULT_EVENT_CLASS_NAME;
var fnNames = fnNames || [];
if (!(fnNames instanceof Array)) {
fnNames = [fnNames];
}
fnNames.forEach(function (fnName) {
var eventNameFormatted = util.format('%s.%s', eventClassName, fnName);
proxy.before(object, fnName, function (obj, args, storage) {
var callbackIndex = findCallbackIndex(args);
// if callback in not available, skip tracing
if (callbackIndex == -1) {
return;
}
var ctx = storage.get('ctx');
var eventArgs = startEventParamsCallback ? startEventParamsCallback(obj, args) : {};
if (logger.isDebug()) {
logger.debug('%s - execution started', eventNameFormatted);
if (!ctx) {
logger.debug('%s - no context', eventNameFormatted);
}
}
//on start of execution, send 'start-trace' event
ctx = agent.asynchEventStart(ctx, eventNameFormatted, eventArgs);
storage.set('ctx', ctx);
proxy.callback(args, -1, function (obj, args, storage) {
if (ctx != null) {
if (logger.isDebug()) {
logger.debug('%s - execution finished', eventNameFormatted);
}
var eventArgs = finishEventParamsCallback ? finishEventParamsCallback(obj, args) : {};
var errorObject = traceUtil.checkCallbackArgsForError(args);
//on callback invocation, send 'end-trace' event
ctx = agent.asynchEventDone(ctx, eventNameFormatted, eventArgs, errorObject);
storage.set('ctx', ctx);
}
}, function (obj, args) {
agent.asynchEventFinish(ctx);
});
});
});
};
/**
* Instrument promise based asynchronous non-blocking functions
* @method
* @param {object} object Object selected for instrumentation
* @param {array} fnNames Names of functions to instrument
* @param {string} eventClassName Class name used for creating trace events
* @param {function} startEventParamsCallback Callback function to fetch parameters for start trace event.
* Arguments passed to this callback are:
* -obj object being traced
* -args arguments passed to function under execution
* @param finishEventParamsCallback Callback function to fetch parameters for finish trace event
* Arguments passed to this callback are:
* -val result of async operation when promise is successfully resolved
*/
var instrumentAsyncPromise = function (object, fnNames, eventClassName, startEventParamsCallback, finishEventParamsCallback) {
var eventClassName = eventClassName || (object.constructor.name && object.constructor.name.toLowerCase()) || DEFAULT_EVENT_CLASS_NAME;
var fnNames = fnNames || [];
if (!(fnNames instanceof Array)) {
fnNames = [fnNames];
}
fnNames.forEach(function (fnName) {
var eventNameFormatted = util.format('%s.%s', eventClassName, fnName);
proxy.around(object, fnName, function (obj, args, storage) {
var ctx = storage.get('ctx');
var eventArgs = startEventParamsCallback ? startEventParamsCallback(obj, args) : {};
if (logger.isDebug()) {
logger.debug('%s - execution started', eventNameFormatted);
if (!ctx) {
logger.debug('%s - no context', eventNameFormatted);
}
}
//on start of execution, send 'start-trace' event
ctx = agent.asynchEventStart(ctx, eventNameFormatted, eventArgs);
storage.set('ctx', ctx);
},
function (obj, args, rval, storage) {
var promise = rval;
var ctx = storage.get('ctx');
if (ctx) {
// register promise handlers
promise.then(getPromiseSuccessHandler(storage, ctx, eventNameFormatted, finishEventParamsCallback),
getPromiseRejectionHandler(storage, ctx, eventNameFormatted, finishEventParamsCallback));
}
});
});
};
function getPromiseSuccessHandler(storage, ctx, eventNameFormatted, finishEventParamsCallback) {
return function caMongodbPromiseSuccessHandler(value) {
if (logger.isDebug()) {
logger.debug('%s - execution finished - promise resolved successfully', eventNameFormatted);
}
if (ctx) {
var eventArgs = finishEventParamsCallback ? finishEventParamsCallback(value) : {};
ctx = agent.asynchEventDone(ctx, eventNameFormatted, eventArgs);
storage.set('ctx', ctx);
agent.asynchEventFinish(ctx);
}
};
}
function getPromiseRejectionHandler(storage, ctx, eventNameFormatted, finishEventParamsCallback) {
return function caMongodbPromiseRejectionHandler(value) {
if (logger.isDebug()) {
logger.debug('%s - execution finished - promise rejected', eventNameFormatted);
}
if (ctx) {
var eventArgs = {};
var errorObject = traceUtil.getFormattedErrorObject(value);
ctx = agent.asynchEventDone(ctx, eventNameFormatted, eventArgs, errorObject);
storage.set('ctx', ctx);
agent.asynchEventFinish(ctx);
}
};
}
/**
* Instrument synchronous blocking functions
* @method
* @param {object} object selected for instrumentation
* @param {array} fnNames Names of functions to instrument
* @param {string} eventClassName Class name used for creating trace events
* @param {function} startEventParamsCallback Callback function to fetch parameters for start trace event.
* Arguments passed to this callback are:
* -obj object being traced
* -args arguments passed to function under execution
* @param finishEventParamsCallback Callback function to fetch parameters for finish trace event
* Arguments passed to this callback are:
* -obj callback object being traced
* -args arguments passed to function under execution
* -rval value returned by function
*/
var instrumentSync = function (object, fnNames, eventClassName, startEventParamsCallback, finishEventParamsCallback) {
var eventClassName = eventClassName || (object.constructor.name && object.constructor.name.toLowerCase()) || DEFAULT_EVENT_CLASS_NAME;
var fnNames = fnNames || [];
if (!(fnNames instanceof Array)) {
fnNames = [fnNames];
}
fnNames.forEach(function (fnName) {
var eventNameFormatted = util.format('%s.%s', eventClassName, fnName);
proxy.around(object, fnName, function (obj, args, storage) {
var ctx = storage.get('ctx');
var eventArgs = startEventParamsCallback ? startEventParamsCallback(obj, args) : {};
if (logger.isDebug()) {
logger.debug('%s - execution started', eventNameFormatted);
if (!ctx) {
logger.debug('%s - no context', eventNameFormatted);
}
}
//on start of execution, send 'start-trace' event
ctx = agent.asynchEventStart(ctx, eventNameFormatted, eventArgs);
storage.set('ctx', ctx);
},
function (obj, args, rval, storage) {
var ctx = storage.get('ctx');
if (ctx != null) {
if (logger.isDebug()) {
logger.debug('%s - execution finished', eventNameFormatted);
}
var eventArgs = finishEventParamsCallback ? finishEventParamsCallback(obj, args, rval) : {};
ctx = agent.asynchEventDone(ctx, eventNameFormatted, eventArgs);
agent.asynchEventFinish(ctx);
}
});
});
};
module.exports = {
findCallbackIndex: findCallbackIndex,
instrumentAsync: instrumentAsync,
instrumentAsyncPromise: instrumentAsyncPromise,
instrumentSync: instrumentSync
};

@@ -36,3 +36,4 @@ /**

function formatEventArgValueObject (object) {
// always returns a string value
function formatEventArgValueObject(object) {
if (object) {

@@ -42,11 +43,9 @@ return truncateEventArgValue((JSON.stringify(object)));

return null;
return '';
}
function createErrorObject(err, errorClass) {
var errorObject = {};
errorObject = {
class : errorClass,
msg: formatEventArgValueObject(err)
function createErrorObject(errorClass, errMsg) {
var errorObject = {
class: errorClass,
msg: formatEventArgValueObject(errMsg)
}

@@ -57,7 +56,22 @@

function checkAndCreateErrorObject(args, errorClass) {
function getFormattedErrorObject(err) {
return (err instanceof Error) ? {
class: err.name,
msg: truncateEventArgValue(err.message)
} : null;
}
function checkCallbackArgsForError(args, defaultErrorClass) {
// based on callback calling conventions, first argument to callback is error
if (args[0] != null) {
return createErrorObject(args[0], errorClass);
var err = args[0];
if (err != null) {
var object = getFormattedErrorObject(err);
if (!object && defaultErrorClass) {
object = createErrorObject(defaultErrorClass, err);
}
return object;
}

@@ -72,2 +86,3 @@

module.exports.createErrorObject = createErrorObject;
module.exports.checkAndCreateErrorObject = checkAndCreateErrorObject;
module.exports.getFormattedErrorObject = getFormattedErrorObject;
module.exports.checkCallbackArgsForError = checkCallbackArgsForError;

@@ -1,2 +0,2 @@

/**

@@ -34,3 +34,3 @@ * Copyright (c) 2015 CA. All rights reserved.

function VirtualStack() {
events.EventEmitter.call(this);
events.EventEmitter.call(this);
}

@@ -58,9 +58,11 @@

var VirtualStackContext = function (parent, evtTypeNum, evtName, evtArgs) {
var VirtualStackContext = function (previous, evtTypeNum, evtName, evtArgs) {
this.evtTypeNum = evtTypeNum;
this.parent = parent;
this.previous = previous;
this.childLanes = 0;
this.name = evtName;
this.args = evtArgs;
if (parent == null) {
if (previous == null) {
this.parent = null;
this.txid = nextTxId++;

@@ -71,22 +73,22 @@ this.evtid = nextEventId++;

this.seq = 0;
this.corIdObj = coridgenerator.generateCorIdObj();
if (!this.args) {
this.args = {};
}
// in case, we have seen correlation header in request
// parse and reset the correlation instance
this.corIdObj = coridgenerator.generateCorIdObj();
if (!this.args) {
this.args = {};
}
// in case, we have seen correlation header in request
// parse and reset the correlation instance
if (this.args.corId) {
this.corIdObj.parseAndSet(this.args.corId);
}
this.corIdObj.parseAndSet(this.args.corId);
}
// create new Correlation id instance
this.args.corId = this.corIdObj.getCurrentCorId();
this.args.traceId = this.corIdObj.getTransactionTraceId();
this.args.corId = this.corIdObj.getCurrentCorId();
this.args.traceId = this.corIdObj.getTransactionTraceId();
return;
}
this.txid = parent.txid;
this.evtid = parent.evtid;
this.level = parent.level;
this.lane = parent.lane;
this.seq = parent.seq;
this.corIdObj = parent.corIdObj;
this.txid = previous.txid;
this.evtid = previous.evtid;
this.level = previous.level;
this.lane = previous.lane;
this.seq = previous.seq;
this.corIdObj = previous.corIdObj;

@@ -96,34 +98,55 @@ if (evtTypeNum == 0) {

this.evtid = nextEventId++;
if (parent.evtTypeNum == 0) {
if (previous.evtTypeNum == 0) {
// previous component is still executing,
// so previous context is parent for this context
this.parent = previous;
// Parent is start event, we go to next level and start new lane
this.level = parent.level + 1;
this.lane = parent.lane;
this.level = this.parent.level + 1;
this.lane = previous.lane;
this.seq = 0;
}
else {
// previous component has finished.
// so previous start context's parent is parent for this context
// startCtx == previous.parent
this.parent = previous.parent.parent;
// parent is finish event, so we just start new component in same lane and level
this.level = parent.level;
this.lane = parent.lane;
this.seq = parent.seq + 1;
this.level = previous.level;
this.lane = previous.lane;
this.seq = previous.seq + 1;
}
// If this not first child pick another lane and start a new fragment
if (parent.childLanes > 0) {
this.lane = nextLaneId++;
this.seq = 0;
//create fragment start event
//logger.debug("Parent: %s", util.inspect(parent, { showHidden: true, depth: 0 }));
logger.debug('create new lane [%d, %d]', this.txid, this.lane);
startNewLane(this);
if (this.parent) {
// If this not first child pick another lane and start a new fragment
if (this.parent.childLanes > 0) {
this.lane = nextLaneId++;
this.seq = 0;
//create fragment start event
//logger.debug("Parent: %s", util.inspect(parent, { showHidden: true, depth: 0 }));
if (logger.isDebug()) {
logger.debug('create new lane: %s', this.toString());
}
startNewLane(this);
}
this.parent.childLanes++;
}
parent.childLanes++;
} else
{
this.parent = previous;
}
};
VirtualStackContext.prototype.toString = function () {
return util.format('{txid: %d, lane: %d, level: %d, eventName: %s, eventType: %d}', this.txid, this.lane, this.level, this.name, this.evtTypeNum);
}
function getLogPrefix(ctx) {
var levelstr = '';
var levelstr = '';
for (var i = 0; i < ctx.level;i++) {
levelstr=levelstr + ' ';
}
}
var colorstr = '\x1b[1;3' + (ctx.lane%6 + 1) + 'm';

@@ -145,7 +168,7 @@ return levelstr + colorstr + '[' + ctx.txid + ',' + ctx.lane + ','+ ctx.seq + ','+ ctx.evtid + '] ';

if (!virtualStackMap.hasOwnProperty(txid)) {
// Create new transaction structure
// Create new transaction structure
virtualStackMap[txid] = {
fragments: {
count: 0
}
fragments: {
count: 0
}
};

@@ -155,12 +178,12 @@ }

if (ctx.parent) {
fragName = ctx.parent.name.replace("\.","_");
ctx.corIdObj = ctx.parent.corIdObj;
if (ctx.previous) {
fragName = ctx.previous.name.replace("\.","_");
ctx.corIdObj = ctx.previous.corIdObj;
};
virtualStackMap[txid].fragments[lane] = {
name: fragName,
evtid: fragmentCtx.evtid,
startlevel: fragmentCtx.level,
lane: fragmentCtx.lane
name: fragName,
evtid: fragmentCtx.evtid,
startlevel: fragmentCtx.level,
lane: fragmentCtx.lane
};

@@ -176,3 +199,3 @@ virtualStackMap[txid].fragments.count++;

ctx.args.corId = ctx.corIdObj.getCurrentCorId();
}
}

@@ -184,2 +207,3 @@ // Send out fragment start event to collector

ctx.evtid = nextEventId++;
ctx.parent = fragmentCtx;
return ctx;

@@ -202,2 +226,3 @@ }

virtualStackMap[txid].fragments.count--;
if (virtualStackMap[txid].fragments.count === 0) {

@@ -209,4 +234,4 @@ logger.debug("Transaction %d finished.", txid);

function pushAsyncTracerEvent(parentCtx, evtName, evtArgs) {
var ctx = new VirtualStackContext(parentCtx, 0, evtName, evtArgs);
function pushAsyncTracerEvent(previousCtx, evtName, evtArgs) {
var ctx = new VirtualStackContext(previousCtx, 0, evtName, evtArgs);
var txid = ctx.txid;

@@ -216,15 +241,15 @@ var lane = ctx.lane;

if (!virtualStackMap.hasOwnProperty(txid)) {
// Create new transaction structure
// Create new transaction structure
virtualStackMap[txid] = {
fragments: {
count: 0
}
fragments: {
count: 0
}
};
if (parentCtx == null && evtName.startsWith('http.')) {
if (previousCtx == null && evtName.startsWith('http.')) {
// This is brand new transaction, create new main fragment
virtualStackMap[txid].fragments.count = 1;
virtualStackMap[txid].fragments[lane] = {
evtid: ctx.evtid,
startlevel: ctx.level,
lane: ctx.lane
virtualStackMap[txid].fragments[lane] = {
evtid: ctx.evtid,
startlevel: ctx.level,
lane: ctx.lane
};

@@ -238,3 +263,3 @@ logger.debug('main fragment [%d, %d]', txid, lane);

}
}
}
logger.debug('fragment resume [%d, %d]', txid, lane);

@@ -249,3 +274,3 @@ if (!virtualStackMap[txid].fragments[lane]) {

virtualStackMap[txid].fragments[lane].active = true;
createTracerEvent(ctx, 'tracer-start', evtName, evtTs, ctx.args);

@@ -260,6 +285,6 @@ return ctx;

if (virtualStackMap[txid] == undefined) {
// This can happen for events that are not detected
// This can happen for events that are not detected
// as parallel fragments, but outlive the transaction
logger.debug('pop %s with unknown txid [%d]', evtName, txid);
// Send event to collector anyway, so that it can
// Send event to collector anyway, so that it can
createTracerEvent(ctx, 'tracer-finish', evtName, evtTs, evtArgs, errorObj);

@@ -273,4 +298,11 @@ return null;

}
virtualStackMap[txid].fragments[lane].active = false;
}
// on pop, update child lanes count of parent ctx
var parentCtx = startCtx.parent;
if (parentCtx) {
parentCtx.childLanes--;
}
}
createTracerEvent(ctx, 'tracer-finish', evtName, evtTs, evtArgs, errorObj);

@@ -288,9 +320,9 @@ return ctx;

if (virtualStackMap.hasOwnProperty(txid) &&
virtualStackMap[txid].fragments.hasOwnProperty(lane) &&
virtualStackMap[txid].fragments[lane].startlevel === level &&
virtualStackMap[txid].fragments[lane].active === false) {
if (virtualStackMap.hasOwnProperty(txid) &&
virtualStackMap[txid].fragments.hasOwnProperty(lane) &&
virtualStackMap[txid].fragments[lane].startlevel === level &&
virtualStackMap[txid].fragments[lane].active === false) {
finishLane(finishCtx);
}
}
}

@@ -304,3 +336,3 @@

if (logger.isDebug()) {
logger.debug('start: %s[%d %d %d] - ts:%d',evtName, ctx.txid, ctx.lane, ctx.evtid, evtTs);
logger.debug('start: %s[%d %d %d] - ts:%d',evtName, ctx.txid, ctx.lane, ctx.evtid, evtTs);
}

@@ -311,7 +343,7 @@ startTraceHandler(evtName, evtTs, txid, ctx.evtid, evtArgs);

if (evtType === 'tracer-finish' && endTraceHandler) {
// Fancy logging:
// Fancy logging:
//logger.info(getLogPrefix(ctx) + 'finish: ' + evtName + ' '+ durStr + '- ts:' + evtTs + getLogSuffix());
// More efficient logging
if (logger.isDebug()) {
logger.debug('finish: %s [%d %d %d] - ts:%d', evtName, ctx.txid, ctx.lane, ctx.evtid, evtTs);
logger.debug('finish: %s [%d %d %d] - ts:%d', evtName, ctx.txid, ctx.lane, ctx.evtid, evtTs);
}

@@ -321,3 +353,3 @@ endTraceHandler(evtName, evtTs, txid, ctx.evtid, evtArgs, errorObj);

}
}
}

@@ -351,3 +383,3 @@ function setTraceHandlers(startTrace, endTrace) {

if (logger.isDebug()) {
logger.debug('Deleting %d %s', txKeys[i],
logger.debug('Deleting %d %s', txKeys[i],
util.inspect(virtualStackMap[txKeys[i]], { showHidden: true, depth: 5 }) );

@@ -354,0 +386,0 @@ }

{
"name": "ca-apm-probe",
"version": "1.10.13",
"version": "1.10.20",
"description": "CA APM Node.js Agent monitors real-time health and performance of Node.js applications",

@@ -34,3 +34,3 @@ "keywords": "ca-apm-probe, apm, agent, instrumentation, monitoring, performance",

},
"engines" : { "node" : ">=0.10.x <=0.12.x" }
"engines" : { "node" : ">=0.10.x <=4.3.x" }
}

@@ -95,2 +95,5 @@ ## APM Node.js Agent

### Version History
- 1.10.20
- Published on: 04/25/2016
- Added support for node 4.3.x runtime
- 1.10.13

@@ -97,0 +100,0 @@ - Published on: 02/17/2016

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet