loading...

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

bugmagnet profile image Bruce Axtens ・2 min read

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); });
    }
};

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();

This might then show something like this:

foo: 11 Times
foo: 0 msec
bar: 10 Times
bar: 2 msec

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.

Posted on by:

bugmagnet profile

Bruce Axtens

@bugmagnet

Programmed Canon Canola calculators in 1977. Assorted platforms and languages ever since. Assisting with HOPL.info. I am NOT looking for work -- I've got more than enough to do.

Discussion

markdown guide