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:
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