appdynamics
Version:
Performance Profiler and Monitor
194 lines (164 loc) • 6.13 kB
JavaScript
/*
Copyright (c) AppDynamics, Inc., and its affiliates
2015
All Rights Reserved
*/
;
function SocketioProbe(agent) {
this.agent = agent;
this.packages = ['socket.io'];
this.attached = false;
}
exports.SocketioProbe = SocketioProbe;
SocketioProbe.prototype.attach = function(obj) {
var self = this;
var socketIOServer;
if(process.env.APPDYNAMICS_SOCKETIO_PROBE_DISABLE == true || process.env.APPDYNAMICS_SOCKETIO_PROBE_DISABLE == 'true') {
return;
}
if(obj.__appdynamicsProbeAttached__) return;
obj.__appdynamicsProbeAttached__ = true;
self.agent.on('destroy', function() {
if(obj.__appdynamicsProbeAttached__) {
delete obj.__appdynamicsProbeAttached__;
var socketIoObj = obj.prototype || obj.Server.prototype;
if(socketIoObj) {
proxy.release(socketIoObj.listen);
proxy.release(socketIoObj.attach);
}
if (socketIOServer) {
var nsps = socketIOServer.nsps || socketIOServer._nsps;
if(nsps instanceof Map) {
nsps.forEach(function(value, key) {
var namespace = nsps.get(key);
delete namespace.__appdynamicsProbeAttached__;
});
} else {
Object.keys(nsps).forEach(function(nameSpace) {
delete nsps[nameSpace].__appdynamicsProbeAttached__;
});
}
}
}
});
var proxy = self.agent.proxy;
var connectCount;
var totalConnectCount;
var metricsManager = self.agent.metricsManager;
metricsManager.addMetric(metricsManager.SOCKETIO_CONNECTIONS, function() {
if(connectCount === undefined) {
connectCount = 0;
}
return connectCount;
});
metricsManager.addMetric(metricsManager.SOCKETIO_CONNECTIONS_TOTAL, function() {
if(totalConnectCount === undefined) {
totalConnectCount = 0;
}
return totalConnectCount;
});
var sentCountMetric = metricsManager.createMetric(metricsManager.SOCKETIO_MESSAGES_SENT);
var receivedCountMetric = metricsManager.createMetric(metricsManager.SOCKETIO_MESSAGES_RECEIVED);
var sentSizeMetric = metricsManager.createMetric(metricsManager.SOCKETIO_SENT_MESSAGES_SIZE);
var receivedSizeMetric = metricsManager.createMetric(metricsManager.SOCKETIO_RECEIVED_MESSAGES_SIZE);
var socketIoObj = obj.prototype || obj.Server.prototype;
proxy.after(socketIoObj, ['listen','attach'], function(obj, args, ret) {
if(!ret.sockets) return;
socketIOServer = ret;
if(connectCount === undefined) {
connectCount = totalConnectCount = 0;
}
proxy.after(ret, 'of', function(obj, args, ret) {
if (ret.__appdynamicsProbeAttached__) return;
attachProbeToNameSpace(ret);
ret.__appdynamicsProbeAttached__ = true;
});
var nsps = ret.nsps || ret._nsps;
if(nsps instanceof Map) {
ret._nsps.forEach(function(value, key) {
var namespace = ret._nsps.get(key);
if (namespace.__appdynamicsProbeAttached__) return;
attachProbeToNameSpace(namespace);
namespace.__appdynamicsProbeAttached__ = true;
});
} else {
Object.keys(ret.nsps).forEach(function(nameSpace) {
if (ret.nsps[nameSpace].__appdynamicsProbeAttached__) return;
attachProbeToNameSpace(ret.nsps[nameSpace]);
ret.nsps[nameSpace].__appdynamicsProbeAttached__ = true;
});
}
function attachProbeToNameSpace(nameSpaceObj) {
proxy.before(nameSpaceObj, ['on', 'addListener'], function(obj, args) {
if(args[0] !== 'connection') return;
proxy.callback(args, -1, function(obj, args) {
if(!args[0]) return;
var socket = args[0];
// conenctions
connectCount++;
totalConnectCount++;
socket.on('disconnect', function() {
connectCount--;
});
// sent messages
proxy.before(socket, ['emit', 'send'], function(obj, args) {
// ignore internal events
if(args[0] === 'newListener') return;
try {
sentCountMetric.addValue(1);
if(args.length > 1) {
sentSizeMetric.addValue(JSON.stringify(args.slice(1)).length);
}
} catch (e) {
// ignored; unable to serialize socket.io message
}
});
proxy.getter(socket, ['broadcast'], function(obj, ret) {
proxy.before(ret, ['emit', 'send'], function(obj, args) {
// ignore internal events
if(args[0] === 'newListener') return;
try {
sentCountMetric.addValue(1);
if(args.length > 1) {
sentSizeMetric.addValue(JSON.stringify(args.slice(1)).length);
}
} catch (e) {
// ignored; unable to serialize socket.io message
}
});
});
proxy.after(socket, ['to', 'in', 'except'], function(obj, args, ret) {
proxy.before(ret, ['emit', 'send'], function(obj, args) {
// ignore internal events
if(args[0] === 'newListener') return;
try {
sentCountMetric.addValue(1);
if(args.length > 1) {
sentSizeMetric.addValue(JSON.stringify(args.slice(1)).length);
}
} catch (e) {
// ignored; unable to serialize socket.io message
}
});
});
// received messages
proxy.before(socket, ['on', 'addListener'], function(obj, args) {
// ignore internal events
if(args[0] === 'disconnect') return;
proxy.callback(args, -1, function(obj, args) {
try {
var msg = Array.from(args);
receivedCountMetric.addValue(1);
if(msg.length > 0) {
receivedSizeMetric.addValue(JSON.stringify(msg).length);
}
} catch (e) {
// ignored; unable to serialize socket.io message
}
});
});
});
});
}
});
};