ConnectionVisualization_1

Overview

This is the second article in a series around building a monitoring application with the Google Visualization APIs.  In my previous article BIG-IP CPU Visualization with the Google Visualization API, I illustrated how to build a C# WinForm application using  the Gauge Visualization to build a monitoring application to keep tabs on the system CPU usage.

In this article, I will look at a different visualization: the Area Chart to build a monitoring application to track connection statistics over a previous time interval.

The Application

As I did in the previous article, this application was developed as a WinForm application written in C#.  The application almost entirely consists of a WebBrowser control with a form, menu, and status bar to contain it, and a timer to trigger the poll intervals.

I’ve divided the application logic into several sections described below with some code samples.

Connecting To The BIG-IP

In this example, I used the iControl.Dialogs.ConnectionDialog, available from the iControl Assembly, to connect to the BIG-IP.  If you use the iRule Editor, this may look familiar…  The DoConnect() method will attempt to connect to the BIG-IP with the ConnectionDialog and, if it succeeds, then build the initial browser content for the WebBrowser control.

   1: private void DoConnect()
   2: {
   3:     if (timer1.Enabled)
   4:     {
   5:         timer1.Enabled = false;
   6:     }
   7:     else
   8:     {
   9:         DialogResult dr = _cd.ShowDialog();
  10:         if (dr == DialogResult.OK)
  11:         {
  12:             initializeBrowserControl();
  13:             timer1.Enabled = true;
  14:         }
  15:     }
  16:     updateMenus();
  17: }

Creating a HTML Page

The client side javascript content for the page is generated with the buildHTMLContent function.  This could have been a resource string, but I found that while developing it was easier to include it in the code.  For this application, we will just be looking at Global current and new connections so there is no need to query the device for more information.

The HTML page inserted into the browser control contains two DIV elements: conn_chart_open, and conn_chart_new to contain the visualizations.  There is also several JavaScript functions.  The set_conn_chart_size() method is used to set the variables that control the chart dimensions and the drawConnectionChart() method takes the input data for the chart, builds Javascript objects from that data, and calls the chart’s draw()  method to draw it on the page.

   1: private String buildHTMLContent()
   2: {
   3:     return @"
   4: <html>
   5:   <head>
   6:     <script type='text/javascript' src='https://www.google.com/jsapi'></script>
   7:     <script type='text/javascript'>
   8:       google.load('visualization', '1', {packages:['corechart']});
   9:       //google.setOnLoadCallback(drawChart);
  10:       
  11:       var conn_chart_width = 750;
  12:       var conn_chart_height = 200;
  13:       
  14:       function set_conn_chart_size(w, h)
  15:       {
  16:         conn_chart_width = w;
  17:         conn_chart_height = h;
  18:       }
  19:  
  20:       function findChart(elemId)
  21:       {
  22:         var chart = null;
  23:         var elem = document.getElementById(elemId);
  24:         if ( null != elem )
  25:         {
  26:             chart = new google.visualization.AreaChart(elem);
  27:         }
  28:         return chart;
  29:       }
  30:       
  31:       function drawConnectionChart(elemId, chartTitle, timelist, valuelist)
  32:       {
  33:         if ( (null != timelist) && (null != valuelist) )
  34:         {
  35:             var data = new google.visualization.DataTable();
  36:             data.addColumn('timeofday', 'Time');
  37:             data.addColumn('number', 'Connections');
  38:         
  39:             var timeArray = timelist.split(',');
  40:             var valueArray = valuelist.split(',');
  41:             for(i=0; i<timeArray.length; i++)
  42:             {
  43:               var time = timeArray[i];
  44:               var timeTokens = time.split(':');
  45:               var value = parseInt(valueArray[i]);
  46:           
  47:               var timeofday = [
  48:                 parseInt(timeTokens[0]),
  49:                 parseInt(timeTokens[1]),
  50:                 parseInt(timeTokens[2])
  51:               ];
  52:           
  53:               data.addRow([timeofday, value]);
  54:             }
  55:  
  56:             var chart = findChart(elemId);
  57:             if ( null != chart )
  58:             {
  59:               chart.draw(data,
  60:                 {
  61:                   width: conn_chart_width,
  62:                   height: conn_chart_height,
  63:                   title: chartTitle,
  64:                   hAxis: {
  65:                     title: 'Time (last 5 minutes)',
  66:                     titleTextStyle: {color: '#FF0000'},
  67:                     showTextEvery: 12
  68:                   },
  69:                   legend: 'none'
  70:                 });
  71:             }
  72:          } 
  73:       }
  74:       
  75:     </script>
  76:   </head>
  77:   <body>
  78:     <div id='chart_conn_open'></div>
  79:     <div id='chart_conn_new'></div>
  80:   </body>
  81: </html>
  82: ";
  83: }

Inserting The HTML Page Into The Browser Control

The initializeBrowserControl() method called in the connection initialization, references the previously generated page content and passes it along to the WebBrowser’s DocumentText property.  This is a nice easy way to populate the contents of the WebBrowser control with a string instead of a URL.

   1: private void initializeBrowserControl()
   2: {
   3:     loadBrowserContents(_browserContent);
   4:     _pollCount = 0;
   5: }
   6:  
   7: private void loadBrowserContents(String s)
   8: {
   9:     if (null != s)
  10:     {
  11:         webBrowser1.DocumentText = s;
  12:     }
  13: }

Refreshing The Charts

The timer triggers calls to the getData() method.  If a connection is initialized, a new size for the charts is determined and set with the DoResize() call that I will talk about below.  The current time is set, and the statistics are pulled from the System.Statistics.get_global_statistics() iControl method.  The current and total connections are extracted from the statistics array and appended to the current data set (see the source distribution if you are interested in seeing how the data array is managed).  Then the data array is generated and passed as a single string to the drawConnectionChart() JavaScript function via the WebBrowser’s InvokeScript method.

   1: private void getData()
   2: {
   3:     if (_cd.m_interfaces.initialized)
   4:     {
   5:         DoResize();
   6:  
   7:         DateTime dt = DateTime.Now;
   8:  
   9:         iControl.SystemStatisticsSystemStatistics sysStats =
  10:             _cd.m_interfaces.SystemStatistics.get_global_statistics();
  11:  
  12:         UInt64 cur = findStatistic(sysStats.statistics, 
  13:             iControl.CommonStatisticType.STATISTIC_CLIENT_SIDE_CURRENT_CONNECTIONS);
  14:         UInt64 tot = findStatistic(sysStats.statistics, 
  15:             iControl.CommonStatisticType.STATISTIC_CLIENT_SIDE_TOTAL_CONNECTIONS);
  16:  
  17:         addData(dt, cur, tot);
  18:         ConnectionDataItem[] dataArray = getDataArray();
  19:         if (null != dataArray)
  20:         {
  21:             String timeList = "";
  22:             String currList = "";
  23:             String newList = "";
  24:  
  25:             for (int i = 0; i < dataArray.Length; i++)
  26:             {
  27:                 String s = dataArray[i].ts.Hour + ":" + 
  28:                     dataArray[i].ts.Minute + ":" + dataArray[i].ts.Second;
  29:                 if ( timeList.Length > 0 ) { timeList += ","; }
  30:                 timeList += s;
  31:  
  32:                 if ( currList.Length > 0 ) { currList += ","; }
  33:                 currList += dataArray[i].connCurrent.ToString();
  34:  
  35:                 if (newList.Length > 0) { newList += ","; }
  36:                 newList += dataArray[i].connNew.ToString();
  37:             }
  38:             // update charts with timeline
  39:  
  40:             updateChart("chart_conn_open", "Open Connections", timeList, currList);
  41:             updateChart("chart_conn_new", "New Connections", timeList, newList);
  42:         }
  43:         _pollCount++;
  44:  
  45:         updateTimestamp(true);
  46:     }
  47: }
  48: private void updateChart(String id, String title, String timelist, String valuelist)
  49: {
  50:     if (null != webBrowser1.Document)
  51:     {
  52:         String[] args = new String[] { id, title, timelist, valuelist };
  53:         webBrowser1.Document.InvokeScript("drawConnectionChart", args);
  54:     }
  55: }

Resizing The Charts

By resizing the window, the next time the charts are drawn, they will be resized to fit into the new size of the WebBrowser control.  The new width and height are calculated and passed along to the set_conn_chart_size() JavaScript function in the WebBrowser’s page content.  The next time the charts are rendered, they will honor this new size.

   1: private void DoResize()
   2: {
   3:     if (timer1.Enabled)
   4:     {
   5:         // Calculate the new chart sizes;
   6:         long width = webBrowser1.Width;
   7:         long height = webBrowser1.Height;
   8:  
   9:         long newWidth = (width) - 20;
  10:         long newHeight = ((height/2)) - 40;
  11:  
  12:         resizeCharts(newWidth, newHeight);
  13:     }
  14: }
  15: private void resizeCharts(long width, long height)
  16: {
  17:     if (null != webBrowser1.Document)
  18:     {
  19:         String [] args = new String[] { width.ToString(), height.ToString() };
  20:         webBrowser1.Document.InvokeScript("set_conn_chart_size", args);
  21:     }
  22: }

I will continue on with this series building a few more visualizations into the BIG-IP statistics with the ultimate goal of building a larger, more encompassing dashboard application.

Get The Source

The source code for this application can be downloaded from the following link: ConnectionVisualization.zip

Related Links on DevCentral