<?php
include ("plotter/jpgraph/src/jpgraph.php");
include ("plotter/jpgraph/src/jpgraph_log.php");
include ("plotter/jpgraph/src/jpgraph_line.php");
include ("plotter/jpgraph/src/jpgraph_pie.php");
include ("plotter/jpgraph/src/jpgraph_bar.php");
include ("plotter/jpgraph/src/jpgraph_pie3d.php");
//this class use posttime from data base
//not really a plotter.. i picked wrong classname
//instead of interval that must be in 5 minutes granularity
//i revisit the sql query for selecting data from database
//if thereis no warning threshold and critical threshold it should be shown as green pie chart
Class Plotter{
//tons of data dictionary
private $starttime;
private $finishtime;
//determine active window monitoring
private $startwindow;
private $finishwindow;
private $table;
private $dba;
//the line graph to plot the actual data
private $graph;
private $bgraph;
//the pie graph to plot availability
private $pieGraph;
private $data;
private $availdata;
private $legend;
//interval determine what the granularity should be presented
//12*5 = 1 hour
private $interval;
private $redvalue;
private $greenvalue;
private $map;
//average (graphtype==avg) or full rough data (graphtype==full)
//or undefined/null if you want button average or detail disabled
private $graphtype;
private $caller; //actual class that invoke plotter, to determine href for image maps
private $post; //caller post
private $title;
private $graphAvail;
//statistic
private $maxstat;
private $minstat;
private $averagestat;
private $lateststat;
//return the downtime/totalcheckpoint
private $availability;
public function __construct(){
// Setup the graph
$this->dba = DBAccess::getInstance();
// default for interval
$this->interval = 10;
//defaul is line graph
$this->graphAvail = false;
}
public function setGraph($table,$st,$ft){
$this->starttime = $st;
$this->finishtime = $ft;
$stts = strtotime($this->starttime);
$ftts = strtotime($this->finishtime);
//calculate how much we will be iterate
$diff = ($ftts - $stts)/(60*5*$this->interval);
//table determine the monitoring id
//plotter self aware
$this->table = $table;
$obj = '';
if($table[0]=='p'){
$obj = new Ping();
$obj->selectByID($table);
$this->setLegend('Ping');
}
else
if($table[0]=='s'){
$obj = new ServiceMon();
$obj->selectByID($table);
$objservdef = new ServicesDef();
$objservdef->selectByID($obj->getService());
$this->setLegend('Service '.$objservdef->getName());
}
else
if($table[0]=='m'){
$obj = new SNMPMon();
$obj->selectByID($table);
$objservdef = new SNMPDef();
$objservdef->selectByID($obj->getSNMPDef());
$this->setLegend('Monitoring '.$objservdef->getName());
}
else{
die('Plotter: currently not support for monitoring with priority id '.$table);
}
$this->redvalue = $obj->getRedLine();
$this->greenvalue = $obj->getGreenLine();
$this->startwindow = $obj->getStartTime();
$this->finishwindow = $obj->getFinishTime();
$peak = 0;
//magic number here make sure it's big enough
$valley = 10000;
$gap = 5*60*$this->interval;
$downcount = 0;
$criticalcount = 0;
$warningcount = 0;
$okcount = 0;
$result = array();
$inactive = array();
$datay = array();
$posttime = array();
$redline = array();
$greenline = array();
$lastcaption = '';
$offset = $stts;
$bigtotal = 0;
for($i=0;$i<$diff;$i++){
//building time query
$q_start_time = " AND posttime >= \"".date('Y-m-d G:i:s',($offset+($i*$gap)))."\"";
$q_finish_time = " AND posttime <= \"".date('Y-m-d G:i:s',($offset+(($i+1)*$gap)))."\"";
$sql = "SELECT value FROM ".$this->table." WHERE value>=0 ".$q_start_time." ".$q_finish_time;
$tempresult = $this->dba->query($sql);
//calculate data within
$total = 0;
$tmpobj = new StdClass();
$count = 0;
$downcounttemp = 0;
$criticalcounttemp = 0;
$warningcounttemp = 0;
$okcounttemp = 0;
for($j=0;$j<sizeof($tempresult);$j++){
$total+=$tempresult[$j]->value;
$count++;
if($tempresult[$j]->value==0){
$downcounttemp++;
}
else
if($tempresult[$j]->value < $this->greenvalue){
$okcounttemp++;
}
else
if($tempresult[$j]->value>=$this->redvalue){
$criticalcounttemp++;
}
else
if(($tempresult[$j]->value <= $this->redvalue)&&($tempresult[$j]->value > $this->greenvalue)){
$warningcounttemp++;
}
}
if(($this->redvalue==0)&&($this->greenvalue==0)){
$okcounttemp += $criticalcounttemp;
$criticalcounttemp = 0;
}
$downcount += $downcounttemp;
$criticalcount += $criticalcounttemp;
$warningcount += $warningcounttemp;
$okcount += $okcounttemp;
$bigtotal += $total;
//take the data to the container
if($this->interval<288){
if($lastcaption==date('Y-m-d',$offset+($i*$gap))){
$posttime[$i] = date('G:i',$offset+($i*$gap));
}else{
$lastcaption = date('Y-m-d',$offset+($i*($gap)));
$posttime[$i] = ' '.date('G:i',$offset+($i*($gap)))."\n".date('Y-m-d',$offset+($i*$gap));
}
$tmpobj->itemid = date('Y-m-d G:i',$offset+($i*$gap));
}
else
if($this->interval>=288){
if($lastcaption==date('Y-m',$offset+($i*$gap))){
$posttime[$i] = date('d',$offset+($i*$gap));
}else{
$lastcaption = date('Y-m',$offset+($i*($gap)));
$posttime[$i] = ' '.date('d',$offset+($i*($gap)))."\n".date('Y-m',$offset+($i*$gap));
}
$tmpobj->itemid = date('Y-m-d',$offset+($i*$gap));
}
$tmpobj->posttime = $tmpobj->itemid;
$tmpdate = date('G:i:s',strtotime($tmpobj->posttime));
//if graphavail = false then datay is average value
if($this->graphAvail){
$avail=0;
if($count!=0){
$avail = round(($okcounttemp+$warningcounttemp)/$count*10000)/100;
}
if((strtotime($tmpdate)<strtotime($this->startwindow))||(strtotime($tmpdate)>strtotime($this->finishwindow))){
$inactive[] = $avail;
}else{
$datay[] = $avail;
}
$tmpobj->value = $avail;
}
else{
$average = null;
if($count>0){
$average=round($total/$count*100)/100;
}
$datay[] = $average;
$redline[] = $this->redvalue;
$greenline[] = $this->greenvalue;
if($peak < $average){
$peak = $average;
}
if($valley > $average){
$valley = $average;
}
if($this->startwindow!=$this->finishwindow){
if((strtotime($tmpdate)<strtotime($this->startwindow))||(strtotime($tmpdate)>strtotime($this->finishwindow))){
$inactive[] = $average;
}else{
$inactive[] = null;
}
}else{
$inactive[] = null;
}
$tmpobj->value = $average;
}
$result[] = $tmpobj;
}
$this->data = $result;
//calculate the peak and valley to give better presentation
$this->maxstat = $peak;
if($valley==10000){
$this->minstat = 0;
}
else{
$this->minstat = $valley;
}
if($downcount>0){
$valley = 0;
}
else
if($valley>$this->greenvalue){
$valley = $this->greenvalue;
}
if($peak<$this->redvalue){
$peak = $this->redvalue;
}
$peak += ($peak-$valley)*0.15;
$valley -= ($peak-$valley)*0.05;
//if negatif pick zero as valley
if($valley<0){
$valley=0;
}
// Setup the graph
$this->graph = new Graph(510,305);
$this->graph->SetMarginColor('white');
$this->graph->SetFrame(false);
$this->graph->SetMargin(30,50,30,35);
$this->bgraph = new Graph(800,600);
$this->bgraph->SetMarginColor('white');
$this->bgraph->SetFrame(false);
$this->bgraph->SetMargin(30,50,30,35);
//set up pie graph
$this->pieGraph = new PieGraph(500,200,"auto");
$this->pieGraph->SetMarginColor('white');
$this->pieGraph->SetFrame(false);
$this->pieGraph->SetMargin(30,50,30,30);
//if greenvalue and redvalue == 0, its mean that threshold unset
//treat it as green pie chart
$totalcheckpoint = $downcount+$criticalcount+$warningcount+$okcount;
if($totalcheckpoint<2){
die('Data not big enought to be plotted. Please wait while system is collecting the data');
}
$this->availability = round(($okcount+$warningcount)/$totalcheckpoint*10000)/100;
$this->averagestat = (round($bigtotal/$totalcheckpoint*100)/100);
//calculate the availability in percentage
//NOTE: critical is excluded for availability definition
$datapie = array();
$legendpie = array();
$slicecolor = array();
//for good presentation only show non-null value
if($downcount!=0){
$datapie[] = $downcount;
$legendpie[] = 'down';
$slicecolor[] = '#f2f2fc';
}
if($criticalcount!=0){
$datapie[] = $criticalcount;
$legendpie[] = 'critical';
$slicecolor[] = '#ff8c8f';
}
if($warningcount!=0){
$datapie[] = $warningcount;
$legendpie[] = 'warning';
$slicecolor[] = '#ffff8f';
}
if($okcount!=0){
$datapie[] = $okcount;
$legendpie[] = 'ok';
$slicecolor[] = '#befff5';
}
$pie = new PiePlot3D($datapie);
$pie->setLegends($legendpie);
$pie->SetSliceColors($slicecolor);
//always explode the first pie chunk ;)
//to give clear presentation what is critical
$pie->explodeSlice(0);
$this->pieGraph->add($pie);
if($this->graphAvail==false){
// Create the first line
$p1 = new LinePlot($datay);
$p1->SetColor("navy");
$p1->SetLegend($this->legend);
$this->graph->Add($p1);
$this->bgraph->Add($p1);
if(isset($this->redvalue)){
// Create red line
$p3 = new LinePlot($redline);
$p3->SetColor("red");
$this->graph->Add($p3);
$this->bgraph->Add($p3);
}
if(isset($this->greenvalue)){
$p2 = new LinePlot($greenline);
$p2->SetColor("yellow");
$this->graph->Add($p2);
$this->bgraph->Add($p2);
}
//build gray line to show active window size
$p5 = new LinePlot($inactive);
$p5->SetColor("gray");
$this->graph->Add($p5);
$this->bgraph->Add($p5);
$this->graph->SetScale("textlin",$valley,$peak);
$this->bgraph->SetScale("textlin",$valley,$peak);
}
else{
$datay = array();
for($i=0;$i<sizeof($this->data);$i++){
$datay[] = $this->data[$i]->value;
}
$p1 = new BarPlot($datay);
$p1->SetColor("navy");
$p1->SetFillGradient("#99ccff","white",GRAD_HOR);
$p1->SetLegend('availability (%)');
$this->graph->Add($p1);
$this->bgraph->Add($p1);
$this->graph->SetScale("textlin",0,105);
$this->bgraph->SetScale("textlin",0,105);
}
//average and detail button panel embeded in graph
$txt=new Text("[A]");
$txt->SetPos(492,85);
$txt->SetFont(FF_FONT1,FS_NORMAL);
//average button is enabled if graphtype = full
if($this->graphtype=='full'){
//image maps for detail control button
$url = 'javascript:sndReqPOST(\''.$this->caller.'\',\''.$this->post.'&graphtype=avg\')';
$this->map .= '<AREA SHAPE="rect" COORDS="492,85,510,97" HREF="'.$url.'">';
$txt->SetColor("black");
}
else{
$txt->SetColor("gray");
}
$this->graph->AddText($txt);
$txt=new Text("[D]");
$txt->SetPos(492,105);
$txt->SetFont(FF_FONT1,FS_NORMAL);
//detail button is enabled if graphtype = avg
if($this->graphtype=='avg'){
//image maps for detail control button
$url = 'javascript:sndReqPOST(\''.$this->caller.'\',\''.$this->post.'&graphtype=full\')';
$this->map .= '<AREA SHAPE="rect" COORDS="492,105,510,117" HREF="'.$url.'">';
$txt->SetColor("black");
}
else{
$txt->SetColor("gray");
}
$this->graph->AddText($txt);
$txt=new Text("[F]");
$txt->SetPos(492,135);
$txt->SetFont(FF_FONT1,FS_NORMAL);
//full screen
$url = 'javascript:sndReqPOST(\''.$this->caller.'\',\''.$this->post.'&graphtype=full\')';
$this->map .= '<AREA SHAPE="rect" title="show full screen" COORDS="492,135,510,147" HREF="javascript:popup(\'tmp/bigfile.png\',\'big\',\'notes\')">';
$txt->SetColor("black");
$this->graph->AddText($txt);
$this->graph->xaxis->SetTickLabels($posttime);
$this->graph->xaxis->SetTextTickInterval(1);
$this->graph->title->Set($this->title);
$this->bgraph->xaxis->SetTickLabels($posttime);
$this->bgraph->xaxis->SetTextTickInterval(1);
$this->bgraph->title->Set($this->title);
}
//similar with getrecent
public function getLatestStat(){
return $this->lateststat;
}
public function getMaxStat(){
return $this->maxstat;
}
public function getMinStat(){
return $this->minstat;
}
public function getAverageStat(){
return $this->averagestat;
}
public function getImageMaps(){
return '<MAP NAME="MyMap">'.$this->map.'</MAP>';
}
public function attachLine(){
//set graph
$file = rand(2,20000).'plotline.png';
$this->graph->Stroke('/www/htdocs/ajaxmonyet/tmp/'.$file);
$this->bgraph->Stroke('/www/htdocs/ajaxmonyet/tmp/bigfile.png');
return $file;
}
public function attachPie(){
//set graph
$file = rand(2,20000).'plotpie.png';
$this->pieGraph->Stroke('/www/htdocs/ajaxmonyet/tmp/'.$file);
return $file;
}
public function setTitle($title){
$this->title = $title;
}
public function getData(){
return $this->data;
}
public function setLegend($legend){
$this->legend = $legend;
}
//boolean value. determine wether graph should be displayed as bar availability or line detail line
public function setGraphAvail($graphavail){
$this->graphAvail = $graphavail;
}
public function setCaller($caller,$post){
$this->caller = $caller;
$this->post = $post;
}
public function setRedLine($red){
$this->redvalue = $red;
}
public function setGreenLine($green){
$this->greenvalue = $green;
}
//set the graph graphtype. avg for average and full for full rough data
//null or undefined if you want average and detail button disabled
public function setGraphType($graphtype){
$this->graphtype = $graphtype;
}
public function setInterval($interval){
$this->interval = $interval;
}
//please invoke after setGraph
public function getAvailability(){
return $this->availability;
}
}
?>