The Chart System
1. Overview
The first thing to understand is that the charts displayed in this dashboard are built using pChart (http://www.pchart.net/). So let's give them a big thanks for working hard to create such a nice charting interface.
The OSSEC Dashboard wraps around the pChart interface using data from OSSEC logs. I say this because not every type of chart has been implemented in this app. The following are supported:
- 2D Pie
- 3D Pie
- Line
- Plot
- Line Plot
- Bar
I will additionally be adding a table "chart" which does nothing more than build a table for display.
2. Adding/Removing Displayed Charts
Charts are stored in resources/Charts as Order_ClassName.php. Any file that does not end with .php is ignored.
Order - This is a number that tells the dashboard the order in which to display the charts. Lower numbers are displayed first. Failure to put a number here should result in the chart being placed last.
ClassName - Each of these chart files should be a class; the file name should contain the class name so that the dashboard knows how to call it.
Each class needs to be constructed with a minimum set of information:
- Type of chart
- A pData object (Reference: http://wiki.pchart.net/)
- A picture name
- Chop requirements and values
- A data array
- The genChartData method
- The parseData method
- The preProc method
- A constructor
Classes may optionally define:
- Image width
- Image height
An example follows:
<?PHP
# Important Notes:
# - The file name needs to match your class name. Example: MyEventChart.php --> $obj = new MyEventChart
# - All methods and class attributes shown here are required; these are the bare minimums that the dashboard script looks for
# - Adding a number to the beginning of the file will change the file order... Example: 01_file.php will come before 02_file.php
class NumEventsBySev {
/* The constructor should accept one value, the name of the picture, and set all of your default values that are later
called on by the dashboard script
*/
public function __construct( $pic ) {
$this->picName = $pic;
$this->ChartTitle = "Events by Severity";
$this->chopRequired = true;
$this->chopLimit = 9;
$this->chopOther = true;
$this->type = 'bar';
}
/* Each line of the generated cache is parsed and sent to this method as a CSV array as follows:
Array
(
[0] => Timestamp
[1] => Alert Group
[2] => Alert System Source
[3] => Alert Log Source
[4] => Alert Message
[5] => Alert Severity
[6] => Original syslog event
[7] => Alert Rule ID
)
Example:
Array
(
[0] => 1320070999.5192
[1] => syslog,adduse
[2] => localhost
[3] => /var/log/secure
[4] => New group added to the system
[5] => 8
[6] => Oct 31 10:23:18 localhost groupadd[7043]: new group: name=apache, GID=48
[7] => 235223
)
So whatever you want to pull out for parsing needs to happen here.
*/
public function parseData($csv) {
$this->myData[$csv[5]]++;
}
/*
This function creates the pData object (reference pChart.net documentation) that is utilized to create the charts you want to see
*/
public function genChartData() {
$this->ChartData = new pData();
$this->ChartData->addPoints(array_values($this->myData), "NumberEvents");
$this->ChartData->addPoints(array_keys($this->myData), "Labels");
$this->ChartData->setSerieDescription("Labels","Event Severity");
$this->ChartData->setAxisName(0,"Number of Events");
$this->ChartData->setAbscissa("Labels");
}
/*
This function is called after we finish reading all cache data and before the dashboard runs ChartChop on your data
(if ChartChop is required)
It's just an easy way to make sure any processing you require is done before the chart image is rendered.
*/
public function preProc() {
ksort($this->myData);
}
/*
This method will display details when someone clicks through a chart image to see the data behind it. This method, in combination with parseDetails, is required if you want to have the
detailed view. Otherwise, they are both unnecessary.
On the web page, it will look like this:
#html header area
<div id=mainpage>
<div id=dashboard>
## Output of showDetails()
</div>
</div>
# footer area
*/
public function showDetails() {
echo "<pre>";
print_r($this->myData);
echo "</pre>";
}
/*
The parseDetails method is called instead of the parseData method when a user clicks through a chart to see details. The data passed to this method is the same - it is every line of data from the alert logs
matching our given date range. Here, you can parse it as required for later use in showDetails.
*/
public function parseDetails($csv) {
$this->myData[] = $csv;
}
public $type; # The chart type we want to generate
public $ChartData; # The pData object to use when creating the chart
public $picName; # The name of the chart (should be passed in from the calling script)
public $ChartTitle; # The title of our chart
public $chopRequired; # True/false: Is a chop required
public $chopLimit; # Limit for the chop
public $chopOther; # True/false: Include other column
public $myData; # Storage for the base data
public $imageWidth; # Image width, if different from default
public $imageHeight; # Image height, if different from default
}
?>
Anything else can be placed in the class, but it will be for your use only.
3. Order of Class Calls
This is the order in which each of the above are used:
1. The object is created; calling the constructor which sets the values seen above
2. Data is added while alert files are parsed via the parseData() method
3. When all alerts are parsed, call the preProc() method
4. Check if a "ChartChop" is required, and perform it
5. Call the genChartData() method
6. Check if the image height and/or width need to be reset
7. Create the image and save in cache
4. Detailed View
You can support a 'detailed view' of your chart by adding the "parseDetails()"and "showDetails()" method to your chart class. The parseDetails method will be passed an array of data from the Alerts class that you can parse however you see fit. These methods are not required and you can have a non-clickable chart without them.
The array passed looks like this:
Array
(
[0] => Timestamp
[1] => Alert Group
[2] => Alert System Source
[3] => Alert Log Source
[4] => Alert Message
[5] => Alert Severity
[6] => Original syslog event
[7] => Alert Rule ID
)
You can store this data however you see fit; once all data has been parsed, the "showDetails" method is called and you can show the data however you need to meet your needs. This will show up in the dashboard "div" html element; also, you will need to add your own CSS formatting.