Chris Rasmussen · Photographer · Infrastructure Guy · Code Dabbler · Traveller

Using VB.NET to display Cacti & RTG graphs – Part 1

At the moment I’m working on an application that will eventually run on one of our plasma screens to show statistics and the current status of a number of things on our network and infrastructure. We use Cacti and RTG to map this data at the moment but they only produce static data, i.e. web pages with a whole load of graphs embedded in them. To get the latest data you have to manually refresh the pages. The requirement for the monitoring application is for it to be displayed on a wall-mounted screen, in our case a 42″ plasma TV. Nice. :)

This article will summarise how the application works. It’ll cover form control, the key .NET controls that are used and what happens when the application runs. In part 2 I’ll go into a little more detail about how the Cacti and RTG graph data is evaluated.

I imagine that a few people reading this will also be readers of Rowan Simpson’s blog, ex-Development Team Leader at Trade Me. From there you’ll probably know that Trade Me is written using VB.NET, currently version 2.0. For various reasons all of our current add-on applications, including the one I’m going to write about here, are also written using VB.NET.

Ok, so the app is going to run on a plasma TV. That means a couple of things.

1. The app has to be full-screen.
2. No part of the display can be completely static due to plasma screens being susceptible to burn-in (you’d think they would’ve solved this by now but oh well).

A while ago, while researching this project, I wrote a post entitled “How to make a full-screen Windows app using VB.NET“. The techniques and methods etc described there are what I’ve used in this monitoring application so I won’t repeat them here.

Now that my application can run full-screen whenever required, it also needs to be able to display URLs within the app’s form. The reason for this is simple : the graphs produced by both Cacti and RTG are generated on-the-fly, i.e. there wouldn’t be any point embedding a static in the application would there. :) The best way to do this is to use the built-in .NET control called System.Windows.Forms.WebBrowser. It has a number of methods to do cool web-browser stuff. This application is pretty simple as far as this goes and only needs to use one of the methods exposed by the WebBrowser control – Navigate.

So, what happens when the app runs? This particular application has the ability to run in 3 modes – Summary, Stats and Homepage. Stats is a custom-written webpage that shows a summary of critical data from our site, Homepage is the Trade Me homepage and Summary is the individual graphs. I’ll only be covering Summary in this article. When the app starts it does the following things.

1. Enables full-screen mode.
2. Sets up the UI. This is a method that resizes the various controls on the form based on calculations made after working out the screen width and height. Part of the SetupUI method is shown below this list of steps.
3. Navigates to a static loading page called Loading.html that simply shows a basic message saying “Loading … please wait”.
4. Loads the list of URLs that the app will cycle through. How you store these URLs is up to you so I’ll only cover how the URLs are put together. In my case I’m using an XML file to store the data.
5. Loads the app configuration.
6. Refreshes the screen view. This is the method that actually displays the graphs. It reads a variable called CurrentGraphNumber that indicates which graph is currently being shown.

Here is some of SetupUI(). Note that Me.Width and Me.Height refer the width & height of the form respectively.

Private Sub SetupUI()
Const GroupLeft = 5
Const GroupTop = 35
Dim GroupWidth As Integer = Me.Width – 10
Dim GroupHeight As Integer = Me.Height – 40
grpWeb0.Left = GroupLeft
grpWeb0.Top = GroupTop
grpWeb0.Width = GroupWidth
grpWeb0.Height = GroupHeight
grpWeb0.BringToFront()
End Sub

Step 4 loads the list of URLs to display. This step does basically the same thing as step 5 below – you should be able to retro-fit this code so that it also loads URLs from an XML file. Let me know if you need help with this and I’ll see what I can do.

Step 5 loads the configuration from the XML file. Below is part of the method that does this although it’s specific to this application so you’ll need to modify it substantially before it will work for you. Note that ConfigLocation refers to the location of the XML file – you can pass a string to this if you don’t want to pass a parameter to the method.

Public Function LoadConfig(ByVal ConfigLocation As String) As Config
Dim configTemp As Config = Nothing
Dim m_xmlr As XmlTextReader = New XmlTextReader(ConfigLocation)
Try
configTemp = New Config
m_xmlr.WhitespaceHandling = WhitespaceHandling.None
m_xmlr.Read()
m_xmlr.Read()
While Not m_xmlr.EOF
m_xmlr.Read()
If Not m_xmlr.IsStartElement() Then
Exit While
End If
m_xmlr.Read()
configTemp.GraphTimeout = m_xmlr.ReadElementString(“graphTimeout”)
End While
Catch
configTemp = Nothing
Finally
m_xmlr.Close()
m_xmlr = Nothing
End Try
Return configTemp
End Function

When step 6 runs it also checks to see a list of URLs is available otherwise it navigates to a file called GeneralError.html that displays … you guessed it, an appropriate error message. If an error occurs all the form’s timers are disabled to prevent the errors happening over and over.

If the list of URLs is available it then starts cycling through the list of URLs. At this stage it’s important to note that both Cacti and RTG display information from a specified time period that is based on a Unix time variable. This means that when you specify the start and end times for the period you want to graph you need to convert .NET time values to Unix time values. Below is the method to do this, along with an extra method to convert the other way in case you need it.

Private Function DotNetTimeToUnixTime(ByVal dotNetTimestamp As System.DateTime) As Integer
Dim Span As System.TimeSpan = New System.TimeSpan(System.DateTime.Parse(“1/1/1970″).Ticks)
Dim Time As System.DateTime = dotNetTimestamp.Subtract(Span)
Dim T As Integer = Time.Ticks / 10000000
Return T
End Function
Private Function UnixTimeToDotNetTime(ByVal unixTimeStamp As Integer) As System.DateTime
Dim DateInput As System.DateTime = System.DateTime.Parse(“1/1/1970″)
Return DateInput.AddSeconds(unixTimeStamp)
End Function

This application is also going to display time between the current time and the time 24 hours before. For this reason the code below calculates the start time as Now() minus 24 hours and the EndTime as Now(). Below is the code that handles this. Note that all the code snippets from here on in form the method called RefreshView() referenced by step 6 above.

Dim BeginTime As System.DateTime = DateAdd(DateInterval.Hour, -24, Now())
BeginTime = BeginTime.ToUniversalTime
Dim EndTime As System.DateTime = Now()
EndTime = EndTime.ToUniversalTime
EndTime = EndTime.AddSeconds(59)

The app then sets the title of groupbox that holds the WebBrowser control and displays Loading.html while the URL is being loaded. The app also has the ability to display either CUSTOM graphs or Cacti/RTG graphs. If the current URL is a CUSTOM graph it simply displays the URL in one of the current URL’s properties and if it’s Cacti/RTG it calls out another method called BuildRTGImageURL that constructs a Cacti/RTG graph URL. I’ll go through this method in part 2 of this article as it’s quite involved.

Once the URL has been constructed it is displayed in the WebBrowser control otherwise an error is displayed.

I’ll start working on part 2 shortly and have it online as soon as I can. :)

Leave a Reply

Powered by Wordpress | Designed by Elegant Themes