DEV Community

Bruce Axtens
Bruce Axtens

Posted on

A simple metrics (invocation count, run-time) tool in JavaScript/TypeScript/GoogleAppsScript

I was wanting a simple way of keeping invocation/usage counts and function run-times. The example below also demonstrates the use of the Me() function that I wrote about recently in A Me() function for JavaScript and Google Apps Script.

The TypeScript code is very similar to the JavaScript so I'll just post the JavaScript and you can annotate it as necessary should you want to use it in a TypeScript project.

var metrics = {
    Counts: {},
    Times: {},
    count: function (func) {
        if (void 0 === this.Counts[func]) {
            this.Counts[func] = 1;
        }
        else {
            this.Counts[func] = this.Counts[func] + 1;
        }
    },
    report: function (func) {
        if (void 0 !== this.Counts[func]) {
            console.log("%s: %s Times", func, this.Counts[func]);
        }
        if (void 0 !== this.Times[func]) {
            console.log("%s: %s msec", func, this.Times[func][1] - this.Times[func][0]);
        }
    },
    start: function (func) {
        this.Times[func] = [new Date().valueOf(), 0];
    },
    stop: function (func) {
        this.Times[func][1] = new Date().valueOf();
    },
    reportAll: function () {
        var _this = this;
        var keys = new Set();
        Object.keys(this.Counts).forEach(function (key) { return keys.add(key); });
        Object.keys(this.Times).forEach(function (key) { return keys.add(key); });
        keys.forEach(function (key) { return _this.report(key); });
    }
};
Enter fullscreen mode Exit fullscreen mode

So from this metrics object we expose the following methods: count, report, start, stop and reportAll. We also expose two dictionaries but we leave the above methods to interact with them. By encapsulating them in the metrics object we save ourselves having to pollute the global namespace.

start and stop are used to record the start and stop times of a given function or block of code. count is used to log that a particular function or block has been executed.

report reports a named run-time and/or named count, and reportAll reports all the run-times and named counts.

On the assumption that the Me() function is also available, a possible usage might be:

function foo() {
    var me = Me();
    metrics.count(me);
    metrics.start(me);
    var accum = 0;
    for (var i_1 = 0; i_1 < 100; i_1++) {
        accum += Math.pow(2, i_1);
    }
    metrics.stop(me);
}
function bar() {
    var me = Me();
    metrics.count(me);
    metrics.start(me);
    foo();
    metrics.stop(me);
}
foo();
for (var i = 0; i < 10; i++)
    bar();
metrics.reportAll();
Enter fullscreen mode Exit fullscreen mode

This might then show something like this:

foo: 11 Times
foo: 0 msec
bar: 10 Times
bar: 2 msec
Enter fullscreen mode Exit fullscreen mode

Some weaknesses with this approach are immediately visible, most notably that the run-time is the last run, not (perhaps more helpfully) an average of all runs.

The other weakness, and this is also an acknowledged issue with Me() is that this isn't particularly performant code. However, it was put together as a Development tool to help me find performance bottle-necks.

Top comments (0)