Hi,
Can anybody share their technique explaining how you created your own graphs using the data from Apigee's "/stats" api?
I'm a bit embarrassed to admit I started out doing an ultra low tech method of copy/paste from the JSON response into excel. Technically it works, but it could become a full time job if I send the wrong person a report they love and then they want it every day.
I'm hoping somebody on here has a much smoother method that they can share?
Thanks!
Mark
Gah! Cut/paste?!?!! No, don't do that.
There are lots of options of course.
Most recently the option I have used, that I liked, was to run a nodejs Script that pulls /stats data, and then pushes that data into a Google Spreadsheet (via the API of course!). The sheets API also allows the client to insert formulas, charts, and so on. So you'd have all the raw data, plus the chart. See https://github.com/DinoChiesa/ApigeeEdge-API-Traffic-Summarizer
I have also used d3, the JavaScript framework to visualize results.
I'll flag a couple of my colleagues to see if they have any good examples to share.
@Keith Danekind, do you have anything in your bag of tricks?
@Cass Obregon, what about you?
Yes, as @Dino-at-Google wrote, there are a lot of great options! I like Google Charts (https://developers.google.com/chart/) for creating nice looking graphs on a web page.
You can create a simple line graph with a little Javascript and a call to the stats APIs:
Here is the code for a single page web application that draws that graph. You can save the code to an HTML file and run it in Chrome. It will request your Apigee user name and password so it can get an OAuth token for the call to stats API. Once it has a token it will ask for a org name and environment, for example "myorg" and "test". You can supply a date range of a few days to see how it works. This is a quick example that is not robust or extensively tested.
// Sample code, offered as is without any support <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>Analytics API Query Example</title> <script type="text/javascript" src="https://www.google.com/jsapi"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css"> <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script> <script type="text/javascript"> // OAuth token for Apigee Edge Management APIs var token = ""; // Load the Visualization API google.load('visualization', '1.0', {'packages':['corechart']}); // wait until the document loads $( document ).ready(function() { // if the query button was clicked $("#queryButton").click(getData); // if the login button was clicked $("#loginButton").click(getToken); }); // Get an access token for Apigee Edge managment APIs function getToken() { // get values from input fields var username = $('#username').val(); var password = $('#password').val(); var mfa = $('#mfa').val(); console.log("Getting token..."); // Call Apigee Edge managment authentication API jQuery.ajax({ url: "https://login.apigee.com/oauth/token", type: "POST", headers: { "Authorization": "Basic ZWRnZWNsaTplZGdlY2xpc2VjcmV0", "Content-Type": "application/x-www-form-urlencoded; charset=utf-8", }, contentType: "application/x-www-form-urlencoded", data: { "username": username, "password": password, "mfa_token": mfa, "grant_type": "password", }, }) .done(function(data, textStatus, jqXHR) { console.log("Login succeeded: " + jqXHR.status); token = data.access_token; $('#loginStatus').html(""); $('#auth').hide(); $('#application').show(); $('#password').val(''); $('#mfa').val(''); }) .fail(function(jqXHR, textStatus, errorThrown) { console.log("HTTP Request Failed"); if(jqXHR.status == 401) { $('#loginStatus').html("Invalid username/password"); } else { $('#loginStatus').html("Error (" + jqXHR.status + "): " + errorThrown); } }) .always(function() { /* ... */ }); } // Call Edge management API for analtyics and get data function getData() { // read values from HTML input fields var org = $('#org').val(); var environment = $('#environment').val(); var user = $('#user').val(); var password = $('#password').val(); var startDate = $('#datepickerStart').val(); var endDate = $('#datepickerEnd').val(); // update status, ui $('#chart_div').hide(); $('#statusMessage').html("Running query..."); $('#statusMessage').show(); console.log("Running query..."); // call management API and get analytics data jQuery.ajax({ url: "https://api.enterprise.apigee.com/v1/o/" + org + "/environments/" + environment + "/stats/apps/", type: "GET", data: { "select": "sum(message_count)", "timeRange": startDate + " 06:00~" + endDate + " 07:00", // adjust for your timezone offset from GMT "timeUnit": "hour", }, headers: { "Authorization": "Bearer " + token }, }) .done(function(data, textStatus, jqXHR) { $('#statusMessage').hide(); console.log("Query successful"); updateData(data); }) .fail(function(jqXHR, textStatus, errorThrown) { console.log("HTTP Request Failed"); $('#statusMessage').html(textStatus + ": " + errorThrown); $('#responsecode').html("Status: " + jqXHR.status); // if "unauthorized", show login UI if(jqXHR.status == 401) { onTokenExpiration(); } }); } // update HTML, draw graph function updateData(myData) { if(myData.environments[0].dimensions[0].metrics[0].values.length == 0) { // no results? tell the user $('#dateInfo').html("No data"); console.log("No data"); $('#chart_div').hide(); return; } // new variable, for convenience, to shorten the path var counts = myData.environments[0].dimensions[0].metrics[0].values; // sort data by timestamp counts.sort(function(a, b) {return a.timestamp - b.timestamp} ); // create the data structure for the graph var data = new google.visualization.DataTable(); data.addColumn('date', 'Time'); data.addColumn('number', 'Requests'); // Build data for graph for(var i=0; i < counts.length; i++) { temp = []; temp.push(new Date(counts[i].timestamp)); // convert timestamp string to a Date temp.push(Number(counts[i].value)); data.addRow(temp); } // Change format of tool-tip to show date and hours and minutes var date_formatter = new google.visualization.DateFormat({ pattern: "MMM dd, yyyy HH:mm"}); date_formatter.format(data, 0); // Set chart options var options = { chartArea: { top: 10, left: 70 }, width: 1200, height: 600, backgroundColor: '#1e1e1e', vAxis: { textStyle: { color: '#fff'}, titleTextStyle: { color: '#fff'} }, hAxis: { textStyle: { color: '#fff'}, titleTextStyle: { color: '#fff'}, baselineColor: { color: '#fff'} }, legend: { textStyle: { color: '#fff'}, titleTextStyle: { color: '#fff'}, }, animation: { startup: true, duration: 500, easing: 'out' }, series: { 0: { color: '#88C1F2' } } }; // Instantiate and draw chart, passing in chart options. var chart = new google.visualization.LineChart(document.getElementById('chart_div')); $('#chart_div').show(); chart.draw(data, options); } // set up UI for start and end date picker $(function() { $( "#datepickerStart" ).datepicker({ dateFormat: 'mm/dd/yy' }); $( "#datepickerEnd" ).datepicker({ dateFormat: 'mm/dd/yy' }); }); </script> </head> <body style="color: white; font-family: sans-serif; background-color: #1e1e1e"> <!-- login section --> <div id="auth" style="border: 1px solid #858585"> <p> <div style="font-family: sans-serif; font-size: 20px; font-weight: 400; color: white;"> Please log into Apigee Edge</div> <table border="0" cellpadding="10"> <tr> <td align="right">Username</td> <td><input type="text" value="" id="username"></td> <td></td> </tr> <tr> <td align="right">Password</td> <td><input type="password" value="" id="password"></td> <td><input type="submit" value="Log in" id="loginButton"></td> </tr> <tr> <td align="right">MFA token<br/><span style="font-size: x-small">(if required)</span></td> <td><input type="password" value="" id="mfa"></td> <td></td> </tr> </table> </p> <div id="loginStatus"></div> </div> <!-- application section --> <div id="application" style="display: none;"> <p>Org: <input type="text" value="org name here" id="org"> Environment: <input type="text" value="prod" id="environment"></p> <hr/> <br/> <p>Start date: <input type="text" id="datepickerStart" value="08/01/2018"> End date: <input type="text" id="datepickerEnd" value="08/15/2018"> <input type="submit" value="Run query" id="queryButton"> </p> <div style="font-family: sans-serif; font-size: 40px; font-weight: 400; color: white;">Requests Per Hour</div> <div id="statusMessage" style="font-family: sans-serif; font-size: 30px; font-weight: 300; color: white"></div><div> <!-- div for the graph --> <div id="chart_div"></div> <hr> <div id="responsecode"></div> </div> </body> </html>
Thank you very much! I will give this a try. My companies "edge" environment is secured with SSO so I think I'll change it to just accept a token that I get using a passcode and the "get_token" utility but this is a huge help!
Here is a simplified version that assumes you already have a token. I removed all of the token retrieval code and UI and replaced it with an input field for a token.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>Analytics API Query Example</title> <script type="text/javascript" src="https://www.google.com/jsapi"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css"> <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script> <script type="text/javascript"> // Load the Visualization API google.load('visualization', '1.0', {'packages':['corechart']}); // wait until the document loads $( document ).ready(function() { // if the query button was clicked $("#queryButton").click(getData); }); // Call Edge management API for analtyics and get data function getData() { // read values from HTML input fields var org = $('#org').val(); var environment = $('#environment').val(); var token = $('#token').val(); var startDate = $('#datepickerStart').val(); var endDate = $('#datepickerEnd').val(); // update status, ui $('#chart_div').hide(); $('#statusMessage').html("Running query..."); $('#statusMessage').show(); console.log("Running query..."); // call management API and get analytics data jQuery.ajax({ url: "https://api.enterprise.apigee.com/v1/o/" + org + "/environments/" + environment + "/stats/apps/", type: "GET", data: { "select": "sum(message_count)", "timeRange": startDate + " 06:00~" + endDate + " 07:00", // adjust for your timezone offset from GMT "timeUnit": "hour", }, headers: { "Authorization": "Bearer " + token }, }) .done(function(data, textStatus, jqXHR) { $('#statusMessage').hide(); console.log("Query successful"); updateData(data); }) .fail(function(jqXHR, textStatus, errorThrown) { console.log("HTTP Request Failed"); $('#statusMessage').html(textStatus + ": " + errorThrown); $('#responsecode').html("Status: " + jqXHR.status); // if "unauthorized", show login UI if(jqXHR.status == 401) { onTokenExpiration(); } }); } // update HTML, draw graph function updateData(myData) { if(myData.environments[0].dimensions[0].metrics[0].values.length == 0) { // no results? tell the user $('#dateInfo').html("No data"); console.log("No data"); $('#chart_div').hide(); return; } // new variable, for convenience, to shorten the path var counts = myData.environments[0].dimensions[0].metrics[0].values; // sort data by timestamp counts.sort(function(a, b) {return a.timestamp - b.timestamp} ); // create the data structure for the graph var data = new google.visualization.DataTable(); data.addColumn('date', 'Time'); data.addColumn('number', 'Requests'); // Build data for graph for(var i=0; i < counts.length; i++) { temp = []; temp.push(new Date(counts[i].timestamp)); // convert timestamp string to a Date temp.push(Number(counts[i].value)); data.addRow(temp); } // Change format of tool-tip to show date and hours and minutes var date_formatter = new google.visualization.DateFormat({ pattern: "MMM dd, yyyy HH:mm"}); date_formatter.format(data, 0); // Set chart options var options = { chartArea: { top: 10, left: 70 }, width: 1200, height: 600, backgroundColor: '#1e1e1e', vAxis: { textStyle: { color: '#fff'}, titleTextStyle: { color: '#fff'} }, hAxis: { textStyle: { color: '#fff'}, titleTextStyle: { color: '#fff'}, baselineColor: { color: '#fff'} }, legend: { textStyle: { color: '#fff'}, titleTextStyle: { color: '#fff'}, }, animation: { startup: true, duration: 500, easing: 'out' }, series: { 0: { color: '#88C1F2' } } }; // Instantiate and draw chart, passing in chart options. var chart = new google.visualization.LineChart(document.getElementById('chart_div')); $('#chart_div').show(); chart.draw(data, options); } // set up UI for start and end date picker $(function() { $( "#datepickerStart" ).datepicker({ dateFormat: 'mm/dd/yy' }); $( "#datepickerEnd" ).datepicker({ dateFormat: 'mm/dd/yy' }); }); </script> </head> <body style="color: white; font-family: sans-serif; background-color: #1e1e1e"> <!-- application section --> <div id="application" > <p>Org: <input type="text" value="org name here" id="org"> Environment: <input type="text" value="prod" id="environment"> Token: <input type="password" value="token" id="token"></p> <hr/> <br/> <p>Start date: <input type="text" id="datepickerStart" value="08/01/2018"> End date: <input type="text" id="datepickerEnd" value="08/15/2018"> <input type="submit" value="Run query" id="queryButton"> </p> <div style="font-family: sans-serif; font-size: 40px; font-weight: 400; color: white;">Requests Per Hour</div> <div id="statusMessage" style="font-family: sans-serif; font-size: 30px; font-weight: 300; color: white"></div><div> <!-- div for the graph --> <div id="chart_div"></div> <hr> <div id="responsecode"></div> </div> </body> </html>
Excellent, Can I embed this solution into the developer portal ?
with filtering for developer specific data
User | Count |
---|---|
7 | |
2 | |
2 | |
1 | |
1 |