While waiting at the airport this past weekend, I worked on a little utility to help me retrieve information about my OpenWhisk actions. As you know (hopefully know!), Bluemix provides a "stats" page for your OpenWhisk stuff but it is a bit limited in terms of how far it goes back and doesn't yet provide good aggregate data about your action. So for example, I really wanted to see how well my action was responding in a simple tabular fashion. With that in mind, I built a command line tool that provides a report:

Screen shot

You'll notice in the screen shot above that the action I tested has exactly 2000 activations. That's because I put an upper limit on the total number of activations returned by the code. This was somewhat arbitrary and could be tweaked of course. This particular action, getTraffic, has been running for months and probably has around 20k activations. Currently there isn't way to get the total number of activations though. (I've filed a bug report on that though.)

The code in question is relatively simple, although a bit ugly in terms of how I progressively load the data. I tried a Promise-based approach but had difficulties figuring out how to make that work with the API. Note that the code expects your credentials in a file called creds.json. This needs to include two values, apihost and api_key, both of which you can get from the OpenWhisk CLI.


#!/usr/bin/env node
const openwhisk = require('openwhisk');
const creds = require('./creds.json');

const ow = openwhisk({
    apihost: creds.apihost, 
    api_key: creds.api_key}
);

//used to max out the number of activations we fetch
const MAX_ACTS = 2000;

const chalk = require('chalk');

if(process.argv.length == 2) {
    process.stdout.write(chalk.blue('Usage: ./index.js <<actionname>>\n'));
    process.exit();
}

const action = process.argv[2];
process.stdout.write(chalk.blue('Fetching data for action '+action+'..'));

let results = {
    total:0,
    duration:0,
    fastduration:99999999,
    slowduration:0,
    successful:0,
    firstInvocation:'',
    lastInvocation:''
};

/*
Going to store dates in an array and sort. Right now the package is returning
items reverse date sorted, but its not documented and may change in the future.
*/
let dates = [];

let activations = [];
function getAllActivations(cb,acts,skip) {
    if(!acts) acts=[];
    if(!skip) skip=0;
    process.stdout.write(chalk.blue('.'));
    ow.activations.list({limit:200, name:action, docs:true, skip:skip}).then(result => {
        if(result.length === 0 || acts.length >= MAX_ACTS) return cb(acts);
        acts = acts.concat(result);
        getAllActivations(cb,acts,skip+200);
    });
}

getAllActivations((result) => {
    
    results.total = result.length;
    result.forEach((act) => {
        results.duration += act.duration
        if(act.duration < results.fastduration) results.fastduration = act.duration;
        if(act.duration > results.slowduration) results.slowduration = act.duration;
        if(act.response.success) results.successful++;
        dates.push(act.start);  
    });

    dates.sort((a,b) => {
        if(a < b) return -1;
        if(a === b) return 0;
        if(a > b) return 1;
    });

    results.firstInvocation = new Date(dates[0]);
    results.lastInvocation = new Date(dates[dates.length-1]);
       
    results.avgduration = Number((results.duration/results.total).toFixed(2));
    results.successfulperc = Number((results.successful/results.total*100).toFixed(2));

    let finalResult = `
Total Number of Invocations:    ${results.total}
Total Successful:               ${results.successful} (${results.successfulperc}%)
First Invocation:               ${results.firstInvocation}
Last Invocation:                ${results.lastInvocation}
Total Duration (ms):            ${results.duration}
Quickest Duration (ms):         ${results.fastduration}
Slowest Duration (ms):          ${results.slowduration}
Average Duration (ms):          ${results.avgduration}
`;
    process.stdout.write(chalk.green(finalResult));
    //console.log(results);

});

You can find this code (and make improvements!) here in my GitHub repo:

https://github.com/cfjedimaster/Serverless-Examples/blob/master/stats2/getstats.js