diff --git a/modules/statistics/config-templates/statistics.php b/modules/statistics/config-templates/statistics.php index b42e692f00a0448b0b13a4ddeebcec7879ad752b..34627122f11529b49e141300324b5026ee62c08f 100644 --- a/modules/statistics/config-templates/statistics.php +++ b/modules/statistics/config-templates/statistics.php @@ -6,9 +6,12 @@ $config = array ( 'statdir' => '/tmp/stats/', - 'inputfile' => '/Users/andreas/Desktop/stat2.log', -# 'inputfile' => '/Users/andreas/Desktop/simplesamlphp.stat.1', - 'offset' => 60*60*1, // Two hours offset to match epoch and norwegian winter time. + 'inputfile' => '/var/log/simplesamlphp.stat', + 'offset' => 60*60*2, // Two hours offset to match epoch and norwegian winter time. + + 'datestart' => 1, + 'datelength' => 15, + 'offsetspan' => 21, /* * Do you want to generate statistics using the cron module? If so, specify which cron tag to use. @@ -31,14 +34,28 @@ $config = array ( 'dateformat-period' => 'j. M', // 4. Mars 'dateformat-intra' => 'j. M H:i', // 4. Mars 12:30 +# 'dateformat-intra' => 'j. H:i', // 4. Mars 12:30 + ), + 'sso_day80' => array( + 'name' => 'Number of SP logins (per day spanning 80 days)', + 'descr' => 'The number of Service Provider logins put into slots of one hour.', + + 'action' => 'saml20-sp-SSO', + 'col' => 5, // Service Provider EntityID + 'slot' => 60*60*24, // Slots of six hour + 'fileslot' => 60*60*24*80, // 7 days of data in each file + 'axislabelint' => 7, // Number of slots per label. 24 is one each day + + 'dateformat-period' => 'j. M', // 4. Mars + 'dateformat-intra' => 'j. M', # H:i', // 4. Mars 12:30 # 'dateformat-intra' => 'j. H:i', // 4. Mars 12:30 ), 'sso_hoursweek' => array( - 'name' => 'Numer of SP logins (per hour)', + 'name' => 'Numer of SP logins (per hour spanning 7 days)', 'descr' => 'The number of Service Provider logins put into slots of one hour.', 'action' => 'saml20-sp-SSO', - 'col' => 7, // Service Provider EntityID + 'col' => 5, // Service Provider EntityID 'slot' => 60*60, // Slots of one hour 'fileslot' => 60*60*24*7, // 7 days of data in each file 'axislabelint' => 24, // Number of slots per label. 24 is one each day @@ -52,7 +69,7 @@ $config = array ( 'descr' => 'The number of Service Provider logins put into slots of one day.', 'action' => 'saml20-sp-SSO', - 'col' => 7, // Service Provider EntityID + 'col' => 5, // Service Provider EntityID 'slot' => 60*60*24, // Slots of one day 'fileslot' => 60*60*24*30, // 30 days of data in each file 'axislabelint' => 7, // Number of slots per label. 24 is one each day @@ -61,6 +78,8 @@ $config = array ( 'dateformat-intra' => 'j. M', // 4. Mars 12:30 # 'dateformat-intra' => 'j. H:i', // 4. Mars 12:30 ), + + ), ); diff --git a/modules/statistics/extlibs/loganalyzer.php b/modules/statistics/extlibs/loganalyzer.php index 9be259e2eb001936abbf2968abcbb4ec309d5491..88f0aa367f6b3b5ca5d5459af1502e344c7c219f 100755 --- a/modules/statistics/extlibs/loganalyzer.php +++ b/modules/statistics/extlibs/loganalyzer.php @@ -1,92 +1,66 @@ <?php -#int mktime ([ int $hour [, int $minute [, int $second [, int $month [, int $day [, int $year [, int $is_dst ]]]]]]] ) -#http://chart.apis.google.com/chart?cht=lc&chs=200x125&chd=s:helloWorld&chxt=x,y&chxl=0:|Mar|Apr|May|June|July|1:||50+Kb - $config = SimpleSAML_Configuration::getInstance(); $statconfig = $config->copyFromBase('statconfig', 'statistics.php'); - $statdir = $statconfig->getValue('statdir'); -$offset = $statconfig->getValue('offset'); $inputfile = $statconfig->getValue('inputfile'); - $statrules = $statconfig->getValue('statrules'); $file = fopen($inputfile, 'r'); $logfile = file($inputfile, FILE_IGNORE_NEW_LINES ); -# Aug 27 12:54:25 ssp 5 STAT [5416262207] saml20-sp-SSO urn:mace:feide.no:services:no.uninett.wiki-feide sam.feide.no NA -# -#Oct 30 11:07:14 www1 simplesamlphp-foodle[12677]: 5 STAT [200b4679af] saml20-sp-SLO spinit urn:mace:feide.no:services:no.feide.foodle sam.feide.no -function parse15($str) { - $di = date_parse($str); - $datestamp = mktime($di['hour'], $di['minute'], $di['second'], $di['month'], $di['day']); - return $datestamp; -} - -function parse23($str) { - $timestamp = strtotime($str); - return $timestamp; -} +$logparser = new sspmod_statistics_LogParser( + $statconfig->getValue('datestart', 0), $statconfig->getValue('datelength', 15), $statconfig->getValue('offsetspan', 44) +); +$datehandler = new sspmod_statistics_DateHandler($statconfig->getValue('offset', 0)); $results = array(); -# Sat, 16 Feb 08 00:55:11 (23 chars) + +// Parse through log file, line by line foreach ($logfile AS $logline) { - $datenumbers = 19; - - if (!preg_match('/^[0-9]{4}/', $logline)) continue; - - $datestr = substr($logline,0,$datenumbers); - #$datestr = substr($logline,0,23); - $timestamp = parse15($datestr) + $offset; - $restofline = substr($logline,$datenumbers+1); - $restcols = split(' ', $restofline); - $action = $restcols[5]; - -// print_r($timestamp); -// print_r($restcols); if ($i++ > 5) exit; + + // Continue if STAT is not found on line. + if (!preg_match('/STAT/', $logline)) continue; + + // Parse log, and extract epoch time and rest of content. + $epoch = $logparser->parseEpoch($logline); + $content = $logparser->parseContent($logline); + $action = $content[4]; + // Iterate all the statrules from config. foreach ($statrules AS $rulename => $rule) { - $timeslot = floor($timestamp/$rule['slot']); - $fileslot = floor($timestamp/$rule['fileslot']); - - if (isset($rule['action'])) { - if ($action !== $rule['action']) continue; - } - - $difcol = $restcols[$rule['col']]; - $difcolsp = split('@', $difcol); - $difcol = $difcolsp[1]; - -// print(' foo: ' . $difcol . ' : ' . $rule['col']); exit; - + $timeslot = $datehandler->toSlot($epoch, $rule['slot']); + $fileslot = $datehandler->toSlot($epoch, $rule['fileslot']); //print_r($content); + if (isset($rule['action']) && ($action !== $rule['action'])) continue; + + $difcol = $content[$rule['col']]; // echo '[...' . $difcol . '...]'; + $results[$rulename][$fileslot][$timeslot]['_']++; $results[$rulename][$fileslot][$timeslot][$difcol]++; } } - +// Iterate the first level of results, which is per rule, as defined in the config. foreach ($results AS $rulename => $ruleresults) { + + // Iterate the second level of results, which is the fileslot. foreach ($ruleresults AS $fileno => $fileres) { $slotlist = array_keys($fileres); - $start = $slotlist[0]; - $start = $fileno*($statrules[$rulename]['fileslot'] / $statrules[$rulename]['slot']); - #echo 'Start was set to ' . $start . ' instead consider ' . $fileno*($statrules[$rulename]['fileslot'] / $statrules[$rulename]['slot']) . "\n"; - - $end = $slotlist[count($fileres)-1]; - $end = ($fileno+1)*($statrules[$rulename]['fileslot'] / $statrules[$rulename]['slot']); - #echo 'End was set to ' . $end . ' instead consider ' . ($fileno+1)*($statrules[$rulename]['fileslot'] / $statrules[$rulename]['slot']) . "\n"; -// exit; -// echo "From $start to $end \n"; - + + // Get start and end slot number within the file, based on the fileslot. + $start = $datehandler->toSlot($datehandler->fromSlot($fileno, $statrules[$rulename]['fileslot']), $statrules[$rulename]['slot']); + $end = $datehandler->toSlot($datehandler->fromSlot($fileno+1, $statrules[$rulename]['fileslot']), $statrules[$rulename]['slot']); + + // Fill in missing entries and sort file results $filledresult = array(); for ($slot = $start; $slot < $end; $slot++) { $filledresult[$slot] = (isset($fileres[$slot])) ? $fileres[$slot] : array('_' => 0); } - + + // store file file_put_contents($statdir . $rulename . '-' . $fileno . '.stat', serialize($filledresult) ); } } diff --git a/modules/statistics/lib/DateHandler.php b/modules/statistics/lib/DateHandler.php new file mode 100644 index 0000000000000000000000000000000000000000..fafde9e3a4bc10bbe5d472a50471cbac0949143b --- /dev/null +++ b/modules/statistics/lib/DateHandler.php @@ -0,0 +1,49 @@ +<?php +/* + * @author Andreas Ă…kre Solberg <andreas.solberg@uninett.no> + * @package simpleSAMLphp + * @version $Id$ + */ +class sspmod_statistics_DateHandler { + + private $offset; + + /** + * Constructor + * + * @param array $offset Date offset + */ + public function __construct($offset) { + $this->offset = $offset; + } + + public function toSlot($epoch, $slotsize) { + return floor( ($epoch + $this->offset) / $slotsize); + } + + public function fromSlot($slot, $slotsize) { + return $slot*$slotsize - $this->offset; + } + + public function prettyDateEpoch($epoch, $dateformat) { + return date($dateformat, $epoch); + } + + public function prettyDateSlot($slot, $slotsize, $dateformat) { + return $this->prettyDateEpoch($this->fromSlot($slot, $slotsize), $dateformat); + + } + +} + +// $datestr = substr($logline,0,$datenumbers); +// #$datestr = substr($logline,0,23); +// $timestamp = parse15($datestr) + $offset; +// $restofline = substr($logline,$datenumbers+1); +// $restcols = split(' ', $restofline); +// $action = $restcols[5]; + +// print_r($timestamp); +// print_r($restcols); if ($i++ > 5) exit; + +?> \ No newline at end of file diff --git a/modules/statistics/lib/Graph/GoogleCharts.php b/modules/statistics/lib/Graph/GoogleCharts.php new file mode 100644 index 0000000000000000000000000000000000000000..07321adc731cdc10ed86f32bb71b10a51e71dc9e --- /dev/null +++ b/modules/statistics/lib/Graph/GoogleCharts.php @@ -0,0 +1,58 @@ +<?php +/* + * @author Andreas Ă…kre Solberg <andreas.solberg@uninett.no> + * @package simpleSAMLphp + * @version $Id$ + */ +class sspmod_statistics_Graph_GoogleCharts { + + private $x, $y; + + /** + * Constructor + */ + public function __construct($x, $y) { + $this->x = $x; $this->y = $y; + } + + private function encodeaxis($axis) { + return join('|', $axis); + } + + # t:10.0,58.0,95.0 + private function encodedata($data) { + return 't:' . join(',', $data); + } + + public function show($axis, $axispos, $values, $max) { + + $nv = count($values); + $url = 'http://chart.apis.google.com/chart?' . + 'chs=800x350' . + '&chd=' . $this->encodedata($values) . + '&cht=lc' . + '&chxt=x,y' . + '&chxl=0:|' . $this->encodeaxis($axis) . # . $'|1:||top' . + '&chxp=0,' . join(',', $axispos) . +# '&chxp=0,0.3,0.4' . + '&chxr=0,0,1|1,0,' . $max . +# '&chm=R,CCCCCC,0,0.25,0.5' . + '&chg=' . (2400/(count($values)-1)) . ',20,3,3'; // lines + return $url; + } + + public static function roof($in) { + if ($in < 1) return 1; + $base = log10($in); + $r = ceil(5*$in / pow(10, ceil($base))); + return ($r/5)*pow(10, ceil($base)); + } + // $foo = array(0, 2, 2.3, 2.6, 6, 10, 15, 98, 198, 256, 487, 563, 763, 801, 899, 999, 987, 198234.485, 283746); + // foreach ($foo AS $f) { + // echo '<p>' . $f . ' => ' . roof($f); + // } + // exit; + +} + +?> \ No newline at end of file diff --git a/modules/statistics/lib/LogParser.php b/modules/statistics/lib/LogParser.php new file mode 100644 index 0000000000000000000000000000000000000000..80506b41a8c001410cd747650a2b139fe661b76d --- /dev/null +++ b/modules/statistics/lib/LogParser.php @@ -0,0 +1,58 @@ +<?php +/* + * @author Andreas Ă…kre Solberg <andreas.solberg@uninett.no> + * @package simpleSAMLphp + * @version $Id$ + */ +class sspmod_statistics_LogParser { + + private $datestart; + private $datelength; + private $offset; + + /** + * Constructor + * + * @param $datestart At which char is the date starting + * @param $datelength How many characters is the date (on the b + * @param $offset At which char is the rest of the entries starting + */ + public function __construct($datestart, $datelength, $offset) { + $this->datestart = $datestart; + $this->datelength = $datelength; + $this->offset = $offset; + } + + public function parseEpoch($line) { + $epoch = strtotime(substr($line, 0, $this->datelength)); + echo 'debug ' . $line . "\n"; + echo 'debug [' . substr($line, 0, $this->datelength) . '] => [' . $epoch . ']' . "\n"; + return $epoch; + } + + public function parseContent($line) { + $contentstr = substr($line, $this->offset); + $content = split(' ', $contentstr); + return $content; + } + + + # Aug 27 12:54:25 ssp 5 STAT [5416262207] saml20-sp-SSO urn:mace:feide.no:services:no.uninett.wiki-feide sam.feide.no NA + # + #Oct 30 11:07:14 www1 simplesamlphp-foodle[12677]: 5 STAT [200b4679af] saml20-sp-SLO spinit urn:mace:feide.no:services:no.feide.foodle sam.feide.no + + function parse15($str) { + $di = date_parse($str); + $datestamp = mktime($di['hour'], $di['minute'], $di['second'], $di['month'], $di['day']); + return $datestamp; + } + + function parse23($str) { + $timestamp = strtotime($str); + return $timestamp; + } + + +} + +?> \ No newline at end of file diff --git a/modules/statistics/www/showstats.php b/modules/statistics/www/showstats.php index 7048d5581f5a15c3a96cc3cb3619683d1b9bd73f..9c26c65aa0e7bf2c14b7d367311b3bcb3965d9cf 100644 --- a/modules/statistics/www/showstats.php +++ b/modules/statistics/www/showstats.php @@ -1,84 +1,41 @@ <?php - -function encodeaxis($axis) { - return join('|', $axis); -} -# t:10.0,58.0,95.0 -function encodedata($data) { - return 't:' . join(',', $data); -} - -function show($axis, $axispos, $values, $max) { - - $nv = count($values); - - $url = 'http://chart.apis.google.com/chart?' . - 'chs=800x350' . - '&chd=' . encodedata($values) . - '&cht=lc' . - '&chxt=x,y' . - '&chxl=0:|' . encodeaxis($axis) . # . $'|1:||top' . - '&chxp=0,' . join(',', $axispos) . -# '&chxp=0,0.3,0.4' . - '&chxr=0,0,1|1,0,' . $max . -# '&chm=R,CCCCCC,0,0.25,0.5' . - '&chg=' . (2400/(count($values)-1)) . ',20,3,3'; // lines - - return $url; -} - -function prettydate($timeslot, $granularity, $offset, $dateformat) { -# echo 'date: [' . $dateformat . date($dateformat, $timeslot*$granularity-$offset) . ']'; - return date($dateformat, $timeslot*$granularity-$offset); -} - -function roof($in) { - if ($in < 1) return 1; - $base = log10($in); - $r = ceil(5*$in / pow(10, ceil($base))); - return ($r/5)*pow(10, ceil($base)); -} - -// $foo = array(0, 2, 2.3, 2.6, 6, 10, 15, 98, 198, 256, 487, 563, 763, 801, 899, 999, 987, 198234.485, 283746); -// foreach ($foo AS $f) { -// echo '<p>' . $f . ' => ' . roof($f); -// } -// exit; - - $config = SimpleSAML_Configuration::getInstance(); $statconfig = $config->copyFromBase('statconfig', 'statistics.php'); - $statdir = $statconfig->getValue('statdir'); -$offset = $statconfig->getValue('offset'); $inputfile = $statconfig->getValue('inputfile'); - $statrules = $statconfig->getValue('statrules'); +$datehandler = new sspmod_statistics_DateHandler($statconfig->getValue('offset', 0)); + +/* + * Walk through file lists, and get available [rule][fileslot]... + */ if (!is_dir($statdir)) throw new Exception('Statisics output directory [' . $statdir . '] does not exists.'); $filelist = scandir($statdir); - $available = array(); foreach ($filelist AS $file) { - if (preg_match('/([a-z_]+)-([0-9]+)\.stat/', $file, $matches)) { - + if (preg_match('/([a-z0-9_]+)-([0-9]+)\.stat/', $file, $matches)) { if (array_key_exists($matches[1], $statrules)) { $available[$matches[1]][] = $matches[2]; } } } +/* + * Create array with information about available rules.. + */ $available_rules = array(); foreach ($available AS $key => $av) { $available_rules[$key] = array('name' => $statrules[$key]['name'], 'descr' => $statrules[$key]['descr']); } - $availrulenames = array_keys($available_rules); + +// Get selected rulename.... $rule = $availrulenames[0]; if(array_key_exists('rule', $_GET)) { if (array_key_exists($_GET['rule'], $available_rules)) { @@ -86,34 +43,29 @@ if(array_key_exists('rule', $_GET)) { } } +/* + * Get list of avaiable times in current file (rule) + */ $available_times = array(); foreach ($available[$rule] AS $slot) { - $available_times[$slot] = prettydate($slot, $statrules[$rule]['fileslot'], $offset, $statrules[$rule]['dateformat-period']) . ' to ' . - prettydate($slot+1, $statrules[$rule]['fileslot'], $offset, $statrules[$rule]['dateformat-period']); + $available_times[$slot] = $datehandler->prettyDateSlot($slot, $statrules[$rule]['fileslot'], $statrules[$rule]['dateformat-period']) . + ' to ' . $datehandler->prettyDateSlot($slot+1, $statrules[$rule]['fileslot'], $statrules[$rule]['dateformat-period']); } -#print_r($available_times); exit; - +// Get which time (fileslot) to use.. First get a default, which is the most recent one. $fileslot = $available[$rule][count($available[$rule])-1]; - +// Then check if the user have provided one. if (array_key_exists('time', $_GET)) { if (in_array($_GET['time'], $available[$rule])) { $fileslot = $_GET['time']; } } -#echo 'fileslot: ' . $fileslot; exit; -#echo '<pre>'; print_r($available_rules); exit; -#echo '<pre>'; print_r($available); exit; - - +// Get file and extract results. $resultfile = file_get_contents($statdir . $rule . '-' . $fileslot . '.stat'); $results = unserialize($resultfile); -// echo '<html><body><pre>'; -// print_r($results); -// echo '</pre>'; $dataset = array(); $axis = array(); @@ -134,58 +86,60 @@ if (isset($_REQUEST['d'])) { $delimiter = $_REQUEST['d']; } +/* + * Walk through dataset to get the max values. + */ $maxvalue = 0; $maxvaluetime = 0; $debugdata = array(); foreach($results AS $slot => $res) { - if ($res[$delimiter] > $maxvalue) { $maxvaluetime = prettydate($slot, $statrules[$rule]['slot'], $offset, $statrules[$rule]['dateformat-intra']); } + if ($res[$delimiter] > $maxvalue) { + $maxvaluetime = $datehandler->prettyDateSlot($slot, $slotsize, $dateformat_intra); + } $maxvalue = max($res[$delimiter],$maxvalue); - - $debugdata[] = array( - prettydate($slot, $statrules[$rule]['slot'], $offset, $statrules[$rule]['dateformat-intra']), - $res[$delimiter] - ); + $debugdata[] = array($datehandler->prettyDateSlot($slot, $slotsize, $dateformat_intra), $res[$delimiter] ); } -$max = roof($maxvalue); +$max = sspmod_statistics_Graph_GoogleCharts::roof($maxvalue); #echo 'Maxvalue [' . $maxvalue . '] at time ' . $maxvaluetime; exit; +#echo '<pre>'; print_r($debugdata); exit; -#echo '<pre>'; print_r($debugdata); exit; +/* + * Walk through dataset to get percent values from max into dataset[]. + */ $availdelimiters = array(); - -$lastslot = 0; $xentries = count($results); -$i = 0; -foreach($results AS $slot => $res) { +$lastslot = 0; $i = 0; - #echo '<p>' . date($dateformat, $slot*$granularity) . ': ' . (isset($results[$slot]) ? $results[$slot] : 0); +foreach($results AS $slot => $res) { $dataset[] = number_format(100*$res[$delimiter] / $max, 2); foreach(array_keys($res) AS $nd) $availdelimiters[$nd] = 1; - #$dataset[] = (isset($results[$slot]) ? round(($results[$slot]*$perseconds/($granularity*$max))*100) : 0); - if ($slot % $axislabelint == 0) { - $axis[] = date($dateformat_intra, $slot*$slotsize - $offset); + // check if there should be an axis here... + if ( $slot % $axislabelint == 0) { + $axis[] = $datehandler->prettyDateSlot($slot, $slotsize, $dateformat_intra); $axispos[] = (($i)/($xentries-1)); - #echo "<p> ". $slot . " = " . date($dateformat_intra, ($slot*$slotsize - $offset) ) . " "; + + #echo 'set axis on [' . $slot . ']'; } - #echo "<p> ". $slot . " = " . date($dateformat_intra, ($slot*$slotsize - $offset) ) . " "; $lastslot = $slot; $i++; } +#echo 'set axis on lastslot [' . $lastslot . ']'; $axis[] = date($dateformat_intra, ($lastslot*$slotsize) + $slotsize - $offset); #echo "<p> ". ($lastslot+1) . " = " . date($dateformat_intra, (($lastslot+1)*$slotsize - $offset) ) . " "; #print_r($axis); -// echo '<input value="' . htmlspecialchars(show($axis, $dataset, $max)) . '" />'; -// echo '<img src="' . htmlspecialchars() . '" />'; + +$grapher = new sspmod_statistics_Graph_GoogleCharts(800, 350); $t = new SimpleSAML_XHTML_Template($config, 'statistics:statistics-tpl.php'); $t->data['header'] = 'stat'; -$t->data['imgurl'] = show($axis, $axispos, $dataset, $max); +$t->data['imgurl'] = $grapher->show($axis, $axispos, $dataset, $max); $t->data['available.rules'] = $available_rules; $t->data['available.times'] = $available_times; $t->data['selected.rule']= $rule; @@ -195,28 +149,5 @@ $t->data['availdelimiters'] = array_keys($availdelimiters); $t->show(); -// $slotlist = array_keys($results); -// $start = $slotlist[0]; -// $end = $slotlist[count($results)-1]; -// -// #echo 'from slot ' . $start . ' to ' . $end; -// -// $dataset = array(); -// $axis = array(); -// $max = 10; -// -// $perseconds = 60; -// -// for ($slot = $start; $slot <= $end; $slot++) { -// #echo '<p>' . date($dateformat, $slot*$granularity) . ': ' . (isset($results[$slot]) ? $results[$slot] : 0); -// -// $dataset[] = (isset($results[$slot]) ? round(($results[$slot]*$perseconds/($granularity*$max))*100) : 0); -// if ($slot % 3 == 0) -// $axis[] = date($dateformat, $slot*$granularity); -// } -// -// echo '<input value="' . htmlspecialchars(show($axis, $dataset)) . '" />'; -// echo '<img src="' . htmlspecialchars(show($axis, $dataset, $max)) . '" />'; - ?> \ No newline at end of file