/******************************************************************************* * 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('../'); // Riak methods can have different arguments. // Methods which only have a 'callback' parameter var callbackOnlyMethods = ['ping', 'shutdown', 'stop']; // Methods which have 'options' and 'callback' parameters var optionsAndCallbackMethods = [ 'deleteValue', 'deleteIndex', 'fetchBucketProps', 'fetchBucketTypeProps', 'fetchCounter', 'fetchIndex', 'fetchMap', 'fetchPreflist', 'fetchSchema', 'fetchSet', 'fetchValue', 'listBuckets', 'listKeys', 'search', 'secondaryIndexQuery', 'storeBucketProps', 'storeBucketTypeProps', 'storeIndex', 'storeSchema', 'storeValue', 'tsDelete', 'tsDescribe', 'tsGet', 'tsListKeys', 'tsQuery', 'tsStore', 'updateCounter', 'updateMap', 'updateSet', ]; // Methods which have a 'command' parameter, 'query' parameter and no parameters var commandMethods = ['execute']; var queryMethods = ['mapReduce']; var noParameterMethods = ['getRiakCluster']; function RiakProbe() { Probe.call(this, 'basho-riak-client'); } util.inherits(RiakProbe, Probe); RiakProbe.prototype.attach = function(name, target) { var that = this; if (name != 'basho-riak-client') return target; if (target.__ddProbeAttached__) return target; target.__ddProbeAttached__ = true; var data = {}; aspect.after(target, 'Client', data, function(clientTarget, methodName, args, probeData, rc) { // For all methods var methods = callbackOnlyMethods.concat( optionsAndCallbackMethods, commandMethods, queryMethods, noParameterMethods ); // Start probing before the method is executed aspect.around( clientTarget, methods, function(target, methodName, methodArgs, probeData) { that.metricsProbeStart(probeData, target, methodName, methodArgs); that.requestProbeStart(probeData, target, methodName, methodArgs); // If the method contains a callback, finish probing when the callback returns if (aspect.findCallbackArg(methodArgs) != undefined) { aspect.aroundCallback(methodArgs, probeData, function(target, args, probeData) { that.metricsProbeEnd(probeData, methodName, methodArgs); that.requestProbeEnd(probeData, methodName, methodArgs); }); } }, // Otherwise if there is no callback finish probing when the method returns function(target, methodName, methodArgs, probeData, rc) { if (aspect.findCallbackArg(methodArgs) == undefined) { that.metricsProbeEnd(probeData, methodName, methodArgs); that.requestProbeEnd(probeData, methodName, methodArgs); } return rc; } ); return rc; }); return target; }; /* * Lightweight metrics probe for Riak queries * * These provide: * time: Time event started * method: The name of the riak method used * options: The options parameter (if present) * command: The command parameter (if present) * query: The query parameter (if present) * duration: The time for the request to respond */ RiakProbe.prototype.metricsEnd = function(probeData, method, methodArgs) { if (probeData && probeData.timer) { probeData.timer.stop(); var eventTimer = probeData.timer; // Work out if options, command or query are needed. Defaults to just method var jsonToEmit = { time: eventTimer.startTimeMillis, method: method, duration: eventTimer.timeDelta, }; var key = ''; if (optionsAndCallbackMethods.indexOf(method) > -1) { key = 'options'; } else if (commandMethods.indexOf(method) > -1) { key = 'command'; } else if (queryMethods.indexOf(method) > -1) { key = 'query'; } if (key != '') { jsonToEmit[key] = methodArgs[0]; } am.emit('riak', jsonToEmit); } }; /* * Heavyweight request probes for Riak queries */ RiakProbe.prototype.requestStart = function(probeData, method, methodArgs) { probeData.req = request.startRequest('basho-riak-client', 'query', false, probeData.timer); }; RiakProbe.prototype.requestEnd = function(probeData, method, methodArgs) { if (probeData && probeData.req) probeData.req.stop({ method: method }); }; module.exports = RiakProbe;