Click here to Skip to main content
Click here to Skip to main content

SarBox

, 21 Sep 2012 CPOL
Rate this:
Please Sign up or sign in to vote.
SarBox helps user to parse or analyze sar data. It shows data in graphical format which can be exported in CSV

Introduction

SarBox helps user to parse or analyze sar data. SarBox show selected counter data in graphical format which can be exported in CSV.

About sar: The sar command writes to standard output the contents of selected cumulative activity counters in the operating system, usually in Unix or equivalent OS.

In computing, sar (system activity monitor) is a Solaris-derived system monitor command used to report on various system loads, including CPU activity, memory/paging, device load, network. Linux distributions provide sar through the sysstat package.

Usage or how to get sar data and redirect to log file from an OS: user@localhost:$ sar -A 5 > sar.log

Background

Sample sar data is provided below to understand what SarBox does and how it is going to help end user who uses sar data from the log file.

Linux 2.6.39-100.5.1.el6uek.x86_64 (unixserver01) 	08/16/2012 	_x86_64_	(1 CPU)

11:59:11 PM CPU %usr %nice %sys %iowait %steal %irq %soft %guest %idle
11:59:16 PM all 1.07 0.00 0.52 0.06 0.00 0.00 0.05 0.00 98.30
11:59:16 PM 0 2.40 0.00 0.80 0.40 0.00 0.00 0.20 0.00 96.21

11:59:11 PM proc/s cswch/s
11:59:16 PM 22.16 2708.78

11:59:11 PM INTR intr/s
11:59:16 PM sum 5328.74
11:59:16 PM  0 0.00
11:59:16 PM  1 0.00
11:59:16 PM  2 0.00

11:59:16 PM CPU %usr %nice %sys %iowait %steal %irq %soft %guest %idle
11:59:21 PM all 1.08 0.00 0.87 0.08 0.00 0.00 0.04 0.00 97.92
11:59:21 PM 0 3.60 0.00 2.80 0.20 0.00 0.00 0.00 0.00 93.40

11:59:16 PM proc/s cswch/s
11:59:21 PM 21.20 3476.40

11:59:16 PM INTR intr/s
11:59:21 PM sum 5793.20
11:59:21 PM  0 0.00
11:59:21 PM  1 0.00
11:59:21 PM  2 0.00

11:59:21 PM CPU %usr %nice %sys %iowait %steal %irq %soft %guest %idle
11:59:26 PM all 1.08 0.00 0.87 0.08 0.00 0.00 0.04 0.00 97.92
11:59:26 PM 0 3.60 0.00 2.80 0.20 0.00 0.00 0.00 0.00 93.40

11:59:21 PM proc/s cswch/s
11:59:26 PM 96.20 3476.40

11:59:21 PM INTR intr/s
11:59:26 PM sum 5793.20
11:59:26 PM  0 0.00
11:59:26 PM  1 0.00
11:59:26 PM  2 0.00 

Let us understand a bit about sar data obtained from usually unix like OS. This will also help us to understand what SarBox will do for us. There are various version of sar available for different OS. But this is a general format and most of sar data will looks similar.

As we can see for the above example log, the first line is always a info line for sar which has nothing to do with sar data. SarBox can be configured for this to remove the line.

Each line starts with timetsamp to denote the duration of the counter value and also what is the interval for each set of counter value. Here the interval can be easily seen as 5 sec because 11:59:16 PM minus 11:59:11 PM at the beginning of above example. SarBox has the capability to set any date time format and also can be set with any interval duration.

As we see from above example that it contains 3 set of counter collection, namely CPU, Processes and Interrupts which can be differentiate with their counter names e.g. %usr or proc/s or intr/sec. Originally sar contains 30+ counter collections which has not been demonstrated here and to keep the article simple. These counter names will be displayed as tree view in SarBox. Each counter collection can also have series which will be displayed as subnode in tree view in SarBox (e.g. CPU has series like all or 0). There could also be counter collection which does not have any series and there won't be any sub node for the same (e.g. Process does not have series). This can be very easily seen in left side tree view of the SarBox.

SarBox will help user to parse or analyze the sar data into various counters and series (if it is available) and display in tree view format which then can be viewed in graphical format or export in csv format.

Screenshot

SarBox Main Window 

This is the main window of SarBox which will parse or analyze sar data based on user selected sar log file. Counter collection and associated series names will be shown in left hand side tree view. Once user selected any counter or its associated series from the tree view, SarBox will parse the data and represent the data in graphical format on bottom right hand side and also calculate metric values for each counter like %usr, %nice, etc and display on right top hand side. These data can be exported in CSV format.

SarBox User Setting

This window helps user to configure SarBox on how the log file will be parsed. The first thing is to truncate / remove the number of lines from top of sar log which is used for providing sar information and does not provide any counter related values and hence not required for SarBox.

The next is Date Time format. User needs to select the appropriate format based on matching sar Date Time format.

Last but not the least is the Interval duration for each set of sar data.

Note: SarBox will convert absolute timestamp to relative timestamp. E.g. In above example, it starts from 11:59:11 PM, 11:59:16 PM, etc. But SarBox will convert this and will start from 01/01/2000 00:00:00, 01/01/2000 00:00:05, etc. This will help SarBox to display graph properly and there are lot other usage which we will see in below topic.

SarBox Sar Duration

Here user can select whole duration of selected sar log file or selective duration of user choice. This gives user flexibility to view data of their choice and remove unwanted time frame data.

SarBox Sar Export

This helps user to export data in meanigful csv format which is not possible in raw sar data. User can select data of their choice duration.

SarBox Zoom Graph using mouse right or left click

This helps user to zoom in or zoom out or set default size of graph. This helps user to view the portion of graph which interest them the most. When mouse cursor is placed on a graph line mark, it displays the information of it.

Using the code

Code is very simple. It is segregated into below parts.

1. Read sar log file from user 

2. Get User Setting from user

3. Convert full sar data from absolute timestamp to relative timestamp. This will help to remove arbitrary timestamp like 21:38 and start from 01/01/2000 00:00:00

4. Get all the counters and associated series (if available) and display in tree.

5. Get all associated data for user selected counter 

6. Display the data in graph and display the metric in table.

7. These data can be exported in csv format for later usage.

There are 2 seperate package. One is for UI and another for background work. Under UI package, I have did everything which has to be part of UI and usually does less work in processing and more work to display information to user. In UI get the user interaction and get the associated values which is then passed to methods for processing. The method process the data and returns back meaningful data back to UI. The UI takes it and displays to user.

//
// Below menuitemOpenSarFileActionPerformed does 1 to 4 of above points
// 
private void menuitemOpenSarFileActionPerformed(java.awt.event.ActionEvent evt) {                                                    
        try
        {
            String strSelectedSarDirectory = "";
            boolean boolSuccess;
            
            /*Initialize All Values*/
            InitializeAllValues();
 
            /*Read from Sar Config to get the open dialog directory if it exists*/
            if(objCommonMethod.checkDirectoryFileExists(strSarConfigFilePath) == true)
            {
                ArrayList objALConfig = new ArrayList();
 
                objALConfig = objCommonMethod.readFile(strSarConfigFilePath, -1);
 
                for(int i=0; i<objALConfig.size(); i++)
                {
                    if(objALConfig.get(i).toString().startsWith("SelectedSarDirectory=") == true)
                    {
                        strSelectedSarDirectory = objALConfig.get(i).toString().replace("SelectedSarDirectory=", "");
                        
                        break;
                    }
                }
            }
            
            /*Show Open Sar File Dialog*/
            JFileChooser fileopen = new JFileChooser();
            FileFilter filterIni = new FileNameExtensionFilter("txt file", "txt");
            FileFilter filterLog = new FileNameExtensionFilter("log file", "log");
            fileopen.addChoosableFileFilter(filterIni);
            fileopen.addChoosableFileFilter(filterLog);
            
            fileopen.setCurrentDirectory(new File(strSelectedSarDirectory));
            fileopen.setDialogTitle("Open Sar File");
            
            int ret = fileopen.showDialog(this, "Open");
 
            if (ret == JFileChooser.APPROVE_OPTION)
            {
                /*Clear All Values*/
                menuitemCloseSarFileActionPerformed(null);
                
                /*Initialize All Values*/
                InitializeAllValues();
                
                File file = fileopen.getSelectedFile();
                strSelectedSarFilePath = file.toString();
                
                setTitle("SarBox : Sar Parser Tool " + strSelectedSarFilePath);
                
                boolSuccess = false;
                boolSuccess = objUiMethod.getUserSetting(strSelectedSarFilePath, strSarConfigFilePath);
                
                /*If User Settings was canceled then Close Sar File*/
                if(boolSuccess == false)
                {
                    menuitemCloseSarFileActionPerformed(null);
                }
                else
                {
                    intGlobalTruncate = objUiMethod.intGlobalTruncate;
                    intGlobalInterval = objUiMethod.intGlobalInterval;
                    intGlobalActualDateTimeLength = objUiMethod.intGlobalActualDateTimeLength;
                    
                    objALSarFileContent = objCommonMethod.readSarFile(strSelectedSarFilePath, intGlobalTruncate, intGlobalInterval, strGlobalRelativeDateTimeFormat, intGlobalActualDateTimeLength);
                    
                    objALPredefinedSarCounterCollection = objCommonMethod.readFile(strSarCounterCollectionFilePath, -1);
                    objALPredefinedSarCounterCollection = objCommonMethod.getSarCounterCollectionPredefinedInArrayList(objALPredefinedSarCounterCollection, strSarCounterCollectionHelpFilePath);
                    
                    objALSarCounterCollection = objCommonMethod.getSarCounterCollectionInArrayList(objALSarFileContent, objALPredefinedSarCounterCollection, strGlobalRelativeDateTimeFormat);
                    
                    objUiMethod.addSarCounterCollectionToTree(treeSarCounterCollection, objALSarCounterCollection);
                    
                    boolSuccess = false;
                    boolSuccess = objUiMethod.getUserSelectedSarDuration(objALSarFileContent, strGlobalRelativeDateTimeFormat);
                    
                    if(boolSuccess == false)
                    {
                        menuitemCloseSarFileActionPerformed(null);
                    }
                    else
                    {
                        String strUserSelectedSarStartTimeStamp = objUiMethod.strUserSelectedSarStartTimeStamp;
                        String strUserSelectedSarEndTimeStamp = objUiMethod.strUserSelectedSarEndTimeStamp;
                        
                        objALSelectedTimestampSarContent = objCommonMethod.getSelectedSarTimeStampContent(objALSarFileContent, strUserSelectedSarStartTimeStamp, strUserSelectedSarEndTimeStamp, strGlobalRelativeDateTimeFormat);
                    }
                }
            }
 
//            objCommonMethod = null;
//            objUiMethod = null;
        }
        catch (Exception ex)
        {
            JOptionPane.showMessageDialog(this, ex, "SarBox Error", JOptionPane.ERROR_MESSAGE);
            
            menuitemCloseSarFileActionPerformed(null);
        }
    }   
//
// This treeSarCounterCollectionSelection is for point 5 to 7 as mentioned above
// 
private void treeSarCounterCollectionSelection(TreeSelectionEvent e)
    {
        boolean boolShowMetricfalg = false;
        String strSelectedCounter = "";
        String strSelectedCounterNames = "";
        String strSelectedSeriesName = "";
        
        objALSelectedCounterSarContent = null;
        strGlobalCounter = "";
        strGlobalCounterNames = "";
        strGlobalSeriesName = "";
        
        panelSarGraph.removeAll();
        panelSarGraph.updateUI();
        tableSarCounterName.setModel(new DefaultTableModel(
                new Object [][] { },
                new String [] 
                {
                    "CounterName", "Min", "Max", "Sum", "Avg"
                }
            ));
        
        try
        {
            if(treeSarCounterCollection.getSelectionPath() != null)
            {
                if(treeSarCounterCollection.getSelectionPath().getPathCount() == 2)
                {
                    strSelectedCounter = treeSarCounterCollection.getSelectionPath().getLastPathComponent().toString();
                    
                    for(int i=0; i<objALSarCounterCollection.size(); i++)
                    {
                        if(((ArrayList)objALSarCounterCollection.get(i)).get(0).toString().split(" ")[0].compareTo(strSelectedCounter) == 0)
                        {
                            if(((ArrayList)((ArrayList)objALSarCounterCollection.get(i)).get(1)).size() == 0)
                            {
                                strSelectedCounterNames = ((ArrayList)objALSarCounterCollection.get(i)).get(0).toString().substring(strSelectedCounter.length(), ((ArrayList)objALSarCounterCollection.get(i)).get(0).toString().length()).trim();
 
                                objALSelectedCounterSarContent = objCommonMethod.getSarContentForSelectedCounter(objALSelectedTimestampSarContent, strSelectedCounterNames);
                                
                                strGlobalCounter = strSelectedCounter;
                                strGlobalCounterNames = strSelectedCounterNames;
                                
                                objUiMethod.showGraphInPanel(panelSarGraph, jPanelChartPanel, objALSelectedCounterSarContent, strGlobalCounterNames, strGlobalRelativeDateTimeFormat, strGlobalRelativeDateTimeFormat.length(), strGlobalCounter, getSize().width, getSize().height);
                                
                                boolShowMetricfalg = true;
                            }
                            
                            break;
                        }
                    }
                }
                else if(treeSarCounterCollection.getSelectionPath().getPathCount() == 3)
                {
                    strSelectedCounter = treeSarCounterCollection.getSelectionPath().getPath()[1].toString();
                    strSelectedSeriesName = treeSarCounterCollection.getSelectionPath().getPath()[2].toString();
                    
                    for(int i=0; i<objALSarCounterCollection.size(); i++)
                    {
                        if(((ArrayList)objALSarCounterCollection.get(i)).get(0).toString().split(" ")[0].compareTo(strSelectedCounter) == 0)
                        {
                            strSelectedCounterNames = ((ArrayList)objALSarCounterCollection.get(i)).get(0).toString().substring(strSelectedCounter.length(), ((ArrayList)objALSarCounterCollection.get(i)).get(0).toString().length()).trim();
                            
                            objALSelectedCounterSarContent = objCommonMethod.getSarContentForSelectedCounter(objALSelectedTimestampSarContent, strSelectedCounterNames, strSelectedSeriesName, strGlobalRelativeDateTimeFormat);
                            
                            strGlobalSeriesName = strSelectedSeriesName;
                            strGlobalCounter = strSelectedCounter;
                            strGlobalCounterNames = strSelectedCounterNames.substring(strSelectedCounterNames.split(" ")[0].length(), strSelectedCounterNames.length()).trim();
                            
                            objUiMethod.showGraphInPanel(panelSarGraph, jPanelChartPanel, objALSelectedCounterSarContent, strGlobalCounterNames, strGlobalRelativeDateTimeFormat, strGlobalRelativeDateTimeFormat.length(), strGlobalCounter + " [" + strGlobalSeriesName + "]", getSize().width, getSize().height);
                            
                            boolShowMetricfalg = true;
                            
                            break;
                        }
                    }
                }
            }
            
            if((objUiMethod != null) && (boolShowMetricfalg == true))
            {
                boolShowMetricfalg = false;
                DecimalFormat objDecimalFormat = new DecimalFormat("#.###");
                String[] strArrayCounterName = objUiMethod.strArrayCounterName;
                double[] doubleArrayMin = objUiMethod.doubleArrayMin;
                double[] doubleArrayMax = objUiMethod.doubleArrayMax;
                double[] doubleArraySum = objUiMethod.doubleArraySum;
                double[] doubleArrayAvg = objUiMethod.doubleArrayAvg;
                Object[][] objectCounterMetric = new Object[strArrayCounterName.length][5];
 
                for(int i=0; i<strArrayCounterName.length; i++)
                {
                    objectCounterMetric[i][0] = strArrayCounterName[i];
                    objectCounterMetric[i][1] = objDecimalFormat.format(doubleArrayMin[i]);
                    objectCounterMetric[i][2] = objDecimalFormat.format(doubleArrayMax[i]);
                    objectCounterMetric[i][3] = objDecimalFormat.format(doubleArraySum[i]);
                    objectCounterMetric[i][4] = objDecimalFormat.format(doubleArrayAvg[i]);
                }
 
                tableSarCounterName.setModel(new DefaultTableModel(
                    objectCounterMetric,
                    new String [] {"CounterName", "Min", "Max", "Sum", "Avg"}));
            }
        }
        catch (Exception ex)
        {
            JOptionPane.showMessageDialog(this, ex, "SarBox Error", JOptionPane.ERROR_MESSAGE);
        }
    }

Points of Interest

SarBox can be customized for any version of sar.

The customizable file resides under <SarBox Installed Directory>/Bin/SarCounterCollection.dat. It contains 3 columns seperated by "|". The first column is the CounterName which has to be unique. The second column can have -1 or 0 or 1. -1 is default and SarBox will determine whether the counter has any series or not. E.g. CPU has series like 0, 1, 2, 3 ... but Process does not have any series. 0 is maual setting forcing SarBox to not consider any series even if it is available and 1 is also manual setting forcing SarBox to consider series. Hence SarBox will try to get the series if it is available for that counter. The third column is the search criteria of the counter. Usually it has to be unique counter names to seperate it from other counter collection. E.g. NFS_Clinet can be identified with "access/s getatt/s" and NFS_Server can be identified with "saccess/s sgetatt/s". It can have any number of counter and seperated by single space.

If SarBox cannot find any predefined counter collection, then that will be named as "Unrecognized_1", "Unrecognized_2", etc. User can set it in SarCounterCollection.dat accordingly.

The SarBox has been developed by me keeping one point in mind that nothing should be hard coded and hence user has the flexibility to customiz the SarBox as they feel. But saying that, there are few things which SarBox will assume is that sar format remains constant

History

SarBox version 4.0 has been realsed on 19-Sep-2012.


License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Biswas, Sumit
Tester / Quality Assurance
India India
I am a Performance Engineer, but I like programming. i don't do it as a specialty, but because i love it. anyone who supports source code sharing on the same plane as me.
Anyone who wants to learn more about me can feel free to contact me. Meanwhile, i'd appreciate your feedback. Get in touch sumitsushil@gmail.com
 
* If this article is helpful, please give reputation points.
* Don't forget to tip the waiter with your appreciation.

Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.1411022.1 | Last Updated 21 Sep 2012
Article Copyright 2012 by Biswas, Sumit
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid