diff --git a/lib/statsFunctions.js b/lib/statsFunctions.js index 6a667470..bd82a2b9 100644 --- a/lib/statsFunctions.js +++ b/lib/statsFunctions.js @@ -48,6 +48,42 @@ function applyStatsFns (Client) { }; }; + /** + * Decorates an async function with timing recording behaviour. + * + * This version of `timer` will record the time take for the asyncronus action returned by `func` + * not just the execution time of `func` itself. + * + * @param func {(...A):Promise} The function to run + * @param stat {String|Array} The stat(s) to send + * @param sampleRate {Number=} The Number of times to sample (0 to 1). Optional. + * @param tags {Array=} The Array of tags to add to metrics. Optional. + * @param callback {Function=} Callback when message is done being delivered. Optional. + */ + Client.prototype.asyncTimer = function (func, stat, sampleRate, tags, callback) { + var self = this; + return function() { + var end = hrtimer(); + var p = func.apply(null, arguments); + var recordStat = function() { self.timing(stat, end(), sampleRate, tags, callback); }; + p.then(recordStat, recordStat); + return p; + }; + }; + + function hrtimer() { + var start = process.hrtime(); + + return function () { + var durationComponents = process.hrtime(start); + var seconds = durationComponents[0]; + var nanoseconds = durationComponents[1]; + var duration = seconds * 1000 + nanoseconds / 1E6; + return duration; + }; + } + + /** * Increments a stat by a specified amount * @param stat {String|Array} The stat(s) to send @@ -267,4 +303,4 @@ function applyStatsFns (Client) { }; } -module.exports = applyStatsFns; \ No newline at end of file +module.exports = applyStatsFns; diff --git a/test/timer.js b/test/timer.js index d3813280..24cae592 100644 --- a/test/timer.js +++ b/test/timer.js @@ -1,5 +1,5 @@ 'use strict'; - +var StatsD = require('../lib/statsd'); var assert = require('assert'); var createStatsdClient = require('./helpers').createStatsdClient; @@ -105,5 +105,32 @@ module.exports = function runTimerTestSuite() { }); }); }); + + it('should record "user time" of promise', function () { + /* globals Promise */ + var statsd = new StatsD({mock:true}); + + var onehundredMsFunc = function () { return delay(100); }; + + var instrumented = statsd.asyncTimer(onehundredMsFunc, 'name-thingy'); + + return instrumented().then(function() { + + var stat = statsd.mockBuffer[0]; + var name = stat.split(/:|\|/)[0]; + var time = stat.split(/:|\|/)[1]; + + assert.equal(name, 'name-thingy'); + assert.ok(parseFloat(time) >= 100); + assert.ok(parseFloat(time) < 200); + }); + }); }); }; + + +function delay(n) { + return new Promise(function (resolve, reject) { + setTimeout(resolve, n); + }); +}