File: //home/arjun/.pm2/modules/pm2-logrotate/node_modules/deep-metrics/probes/socketio-probe.js
/*******************************************************************************
* Copyright 2015 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
'use strict';
var Probe = require('../lib/probe.js');
var aspect = require('../lib/aspect.js');
var request = require('../lib/request.js');
var util = require('util');
var am = require('..');
function SocketioProbe() {
Probe.call(this, 'socket.io');
}
util.inherits(SocketioProbe, Probe);
SocketioProbe.prototype.attach = function(name, target) {
var that = this;
if (name != 'socket.io') return target;
/*
* Don't set __ddProbeAttached__ = true as we need to probe and return
* the constructor each time
*/
/*
* Patch the constructor so that we can patch io.sockets.emit() calls
* to broadcast to clients. This also picks up calls to io.emit() as
* they map down to io.socket.emit()
*/
var newtarget = aspect.afterConstructor(target, {}, function(target, methodName, methodArgs, context, server) {
var broadcast = 'broadcast';
aspect.around(
server.sockets,
'emit',
function(target, methodName, methodArgs, context) {
that.metricsProbeStart(context, broadcast, methodArgs);
that.requestProbeStart(context, broadcast, methodArgs);
},
function(target, methodName, methodArgs, context, rc) {
that.metricsProbeEnd(context, broadcast, methodArgs);
that.requestProbeEnd(context, broadcast, methodArgs);
}
);
return server;
});
/*
* Remap the listen API to point to new constructor
*/
newtarget.listen = newtarget;
/*
* We patch the constructor every time, but only want to patch prototype
* functions once otherwise we'll generate multiple events
*/
if (!target.__prototypeProbeAttached__) {
target.__prototypeProbeAttached__ = true;
aspect.before(target.prototype, ['on', 'addListener'], function(target, methodName, methodArgs, context) {
if (methodArgs[0] !== 'connection') return;
if (aspect.findCallbackArg(methodArgs) != undefined) {
aspect.aroundCallback(methodArgs, context, function(target, methodArgs, context) {
var socket = methodArgs[0];
/*
* Patch Socket#emit() calls
*/
aspect.around(
socket,
'emit',
function(target, methodName, methodArgs, context) {
that.metricsProbeStart(context, methodName, methodArgs);
that.requestProbeStart(context, methodName, methodArgs);
},
function(target, methodName, methodArgs, context, rc) {
that.metricsProbeEnd(context, methodName, methodArgs);
that.requestProbeEnd(context, methodName, methodArgs);
return rc;
}
);
/*
* Patch socket.on incoming events
*/
var receive = 'receive';
aspect.before(socket, ['on', 'addListener'], function(target, methodName, methodArgs, context) {
aspect.aroundCallback(
methodArgs,
context,
function(target, callbackArgs, context) {
that.metricsProbeStart(context, receive, methodArgs);
that.requestProbeStart(context, receive, methodArgs);
},
function(target, callbackArgs, context, rc) {
that.metricsProbeEnd(context, receive, methodArgs);
that.requestProbeEnd(context, receive, methodArgs);
return rc;
}
);
});
});
}
});
}
return newtarget;
};
/*
* Lightweight metrics probe for Socket.io websocket connections
*
* These provide:
* time: time event started
* method: the type of socket.io action
* event: the event broadcast/emitted/received
* duration: the time for the action to complete
*/
SocketioProbe.prototype.metricsEnd = function(context, methodName, methodArgs) {
if (context && context.timer) {
context.timer.stop();
am.emit('socketio', {
time: context.timer.startTimeMillis,
method: methodName,
event: methodArgs[0],
duration: context.timer.timeDelta,
});
}
};
/*
* Heavyweight request probes for Socket.io websocket connections
*/
SocketioProbe.prototype.requestStart = function(context, methodName, methodArgs) {
/*
* method names are "broadcast", "receive" and "emit"
*/
if (methodName !== 'receive') {
context.req = request.startRequest('socketio', methodName, false, context.timer);
} else {
context.req = request.startRequest('socketio', methodName, true, context.timer);
}
};
SocketioProbe.prototype.requestEnd = function(context, methodName, methodArgs) {
if (context && context.req) context.req.stop({ method: methodName, event: methodArgs[0] });
};
module.exports = SocketioProbe;