PageRenderTime 43ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/vendor/simplesamlphp/simplesamlphp/modules/statistics/lib/Aggregator.php

https://bitbucket.org/kigugama/simplesamlphp
PHP | 311 lines | 245 code | 47 blank | 19 comment | 39 complexity | 8ec6e989d4e8c2a0d4583712f791e3e0 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1
  1. <?php
  2. /*
  3. * @author Andreas Åkre Solberg <andreas.solberg@uninett.no>
  4. * @package SimpleSAMLphp
  5. */
  6. class sspmod_statistics_Aggregator
  7. {
  8. private $statconfig;
  9. private $statdir;
  10. private $inputfile;
  11. private $statrules;
  12. private $offset;
  13. private $metadata;
  14. private $fromcmdline;
  15. private $starttime;
  16. /**
  17. * Constructor
  18. */
  19. public function __construct($fromcmdline = false)
  20. {
  21. $this->fromcmdline = $fromcmdline;
  22. $this->statconfig = SimpleSAML_Configuration::getConfig('module_statistics.php');
  23. $this->statdir = $this->statconfig->getValue('statdir');
  24. $this->inputfile = $this->statconfig->getValue('inputfile');
  25. $this->statrules = $this->statconfig->getValue('statrules');
  26. $this->timeres = $this->statconfig->getValue('timeres');
  27. $this->offset = $this->statconfig->getValue('offset', 0);
  28. $this->metadata = null;
  29. $this->starttime = time();
  30. }
  31. public function dumpConfig()
  32. {
  33. echo 'Statistics directory : ' . $this->statdir . "\n";
  34. echo 'Input file : ' . $this->inputfile . "\n";
  35. echo 'Offset : ' . $this->offset . "\n";
  36. }
  37. public function debugInfo()
  38. {
  39. echo 'Memory usage : ' . number_format(memory_get_usage() / (1024*1024), 2) . " MB\n";
  40. }
  41. public function loadMetadata()
  42. {
  43. $filename = $this->statdir . '/.stat.metadata';
  44. $metadata = null;
  45. if (file_exists($filename)) {
  46. $metadata = unserialize(file_get_contents($filename));
  47. }
  48. $this->metadata = $metadata;
  49. }
  50. public function getMetadata()
  51. {
  52. return $this->metadata;
  53. }
  54. public function saveMetadata()
  55. {
  56. $this->metadata['time'] = time() - $this->starttime;
  57. $this->metadata['memory'] = memory_get_usage();
  58. $this->metadata['lastrun'] = time();
  59. $filename = $this->statdir . '/.stat.metadata';
  60. file_put_contents($filename, serialize($this->metadata), LOCK_EX);
  61. }
  62. public function aggregate($debug = false) {
  63. $this->loadMetadata();
  64. if (!is_dir($this->statdir)) {
  65. throw new Exception('Statistics module: output dir do not exists [' . $this->statdir . ']');
  66. }
  67. if (!file_exists($this->inputfile)) {
  68. throw new Exception('Statistics module: input file do not exists [' . $this->inputfile . ']');
  69. }
  70. $file = fopen($this->inputfile, 'r');
  71. if ($file === false) {
  72. throw new Exception('Statistics module: unable to open file [' . $this->inputfile . ']');
  73. }
  74. $logparser = new sspmod_statistics_LogParser(
  75. $this->statconfig->getValue('datestart', 0), $this->statconfig->getValue('datelength', 15), $this->statconfig->getValue('offsetspan', 44)
  76. );
  77. $datehandler = array(
  78. 'default' => new sspmod_statistics_DateHandler($this->offset),
  79. 'month' => new sspmod_statistics_DateHandlerMonth($this->offset),
  80. );
  81. $notBefore = 0;
  82. $lastRead = 0;
  83. $lastlinehash = '-';
  84. if (isset($this->metadata)) {
  85. $notBefore = $this->metadata['notBefore'];
  86. $lastlinehash = $this->metadata['lastlinehash'];
  87. }
  88. $lastlogline = 'sdfsdf';
  89. $lastlineflip = false;
  90. $results = array();
  91. $i = 0;
  92. // Parse through log file, line by line
  93. while (!feof($file)) {
  94. $logline = fgets($file, 4096);
  95. // Continue if STAT is not found on line
  96. if (!preg_match('/STAT/', $logline)) {
  97. continue;
  98. }
  99. $i++;
  100. $lastlogline = $logline;
  101. // Parse log, and extract epoch time and rest of content.
  102. $epoch = $logparser->parseEpoch($logline);
  103. $content = $logparser->parseContent($logline);
  104. $action = trim($content[5]);
  105. if ($this->fromcmdline && ($i % 10000) == 0) {
  106. echo("Read line " . $i . "\n");
  107. }
  108. if ($debug) {
  109. echo("----------------------------------------\n");
  110. echo('Log line: ' . $logline . "\n");
  111. echo('Date parse [' . substr($logline, 0, $this->statconfig->getValue('datelength', 15)) . '] to [' . date(DATE_RFC822, $epoch) . ']' . "\n");
  112. echo htmlentities(print_r($content, true));
  113. if ($i >= 13) {
  114. exit;
  115. }
  116. }
  117. if ($epoch > $lastRead) {
  118. $lastRead = $epoch;
  119. }
  120. if ($epoch === $notBefore) {
  121. if (!$lastlineflip) {
  122. if (sha1($logline) === $lastlinehash) {
  123. $lastlineflip = true;
  124. }
  125. continue;
  126. }
  127. }
  128. if ($epoch < $notBefore) {
  129. continue;
  130. }
  131. // Iterate all the statrules from config.
  132. foreach ($this->statrules as $rulename => $rule) {
  133. $type = 'aggregate';
  134. if (array_key_exists('type', $rule)) {
  135. $type = $rule['type'];
  136. }
  137. if ($type !== 'aggregate') {
  138. continue;
  139. }
  140. foreach ($this->timeres AS $tres => $tresconfig ) {
  141. $dh = 'default';
  142. if (isset($tresconfig['customDateHandler'])) {
  143. $dh = $tresconfig['customDateHandler'];
  144. }
  145. $timeslot = $datehandler['default']->toSlot($epoch, $tresconfig['slot']);
  146. $fileslot = $datehandler[$dh]->toSlot($epoch, $tresconfig['fileslot']);
  147. if (isset($rule['action']) && ($action !== $rule['action'])) {
  148. continue;
  149. }
  150. $difcol = self::getDifCol($content, $rule['col']);
  151. if (!isset($results[$rulename][$tres][$fileslot][$timeslot]['_'])) {
  152. $results[$rulename][$tres][$fileslot][$timeslot]['_'] = 0;
  153. }
  154. if (!isset($results[$rulename][$tres][$fileslot][$timeslot][$difcol])) {
  155. $results[$rulename][$tres][$fileslot][$timeslot][$difcol] = 0;
  156. }
  157. $results[$rulename][$tres][$fileslot][$timeslot]['_']++;
  158. $results[$rulename][$tres][$fileslot][$timeslot][$difcol]++;
  159. }
  160. }
  161. }
  162. $this->metadata['notBefore'] = $lastRead;
  163. $this->metadata['lastline'] = $lastlogline;
  164. $this->metadata['lastlinehash'] = sha1($lastlogline);
  165. return $results;
  166. }
  167. private static function getDifCol($content, $colrule)
  168. {
  169. if (is_int($colrule)) {
  170. return trim($content[$colrule]);
  171. } elseif (is_array($colrule)) {
  172. $difcols = array();
  173. foreach ($colrule as $cr) {
  174. $difcols[] = trim($content[$cr]);
  175. }
  176. return join('|', $difcols);
  177. } else {
  178. return 'NA';
  179. }
  180. }
  181. private function cummulateData($previous, $newdata)
  182. {
  183. $dataset = array();
  184. foreach ($previous as $slot => $dataarray) {
  185. if (!array_key_exists($slot, $dataset)) {
  186. $dataset[$slot] = array();
  187. }
  188. foreach ($dataarray as $key => $data) {
  189. if (!array_key_exists($key, $dataset[$slot])) {
  190. $dataset[$slot][$key] = 0;
  191. }
  192. $dataset[$slot][$key] += $data;
  193. }
  194. }
  195. foreach ($newdata as $slot => $dataarray) {
  196. if (!array_key_exists($slot, $dataset)) {
  197. $dataset[$slot] = array();
  198. }
  199. foreach ($dataarray as $key => $data) {
  200. if (!array_key_exists($key, $dataset[$slot])) {
  201. $dataset[$slot][$key] = 0;
  202. }
  203. $dataset[$slot][$key] += $data;
  204. }
  205. }
  206. return $dataset;
  207. }
  208. public function store($results)
  209. {
  210. $datehandler = array(
  211. 'default' => new sspmod_statistics_DateHandler($this->offset),
  212. 'month' => new sspmod_statistics_DateHandlerMonth($this->offset),
  213. );
  214. // Iterate the first level of results, which is per rule, as defined in the config.
  215. foreach ($results as $rulename => $timeresdata) {
  216. // Iterate over time resolutions
  217. foreach ($timeresdata as $tres => $resres) {
  218. $dh = 'default';
  219. if (isset($this->timeres[$tres]['customDateHandler'])) {
  220. $dh = $this->timeres[$tres]['customDateHandler'];
  221. }
  222. $filenos = array_keys($resres);
  223. $lastfile = $filenos[count($filenos) - 1];
  224. // Iterate the second level of results, which is the fileslot.
  225. foreach ($resres as $fileno => $fileres) {
  226. // Slots that have data.
  227. $slotlist = array_keys($fileres);
  228. // The last slot.
  229. $maxslot = $slotlist[count($slotlist) - 1];
  230. // Get start and end slot number within the file, based on the fileslot.
  231. $start = (int)$datehandler['default']->toSlot(
  232. $datehandler[$dh]->fromSlot($fileno, $this->timeres[$tres]['fileslot']),
  233. $this->timeres[$tres]['slot']
  234. );
  235. $end = (int)$datehandler['default']->toSlot(
  236. $datehandler[$dh]->fromSlot($fileno+1, $this->timeres[$tres]['fileslot']),
  237. $this->timeres[$tres]['slot']
  238. );
  239. // Fill in missing entries and sort file results
  240. $filledresult = array();
  241. for ($slot = $start; $slot < $end; $slot++) {
  242. if (array_key_exists($slot, $fileres)) {
  243. $filledresult[$slot] = $fileres[$slot];
  244. } else {
  245. if ($lastfile == $fileno && $slot > $maxslot) {
  246. $filledresult[$slot] = array('_' => null);
  247. } else {
  248. $filledresult[$slot] = array('_' => 0);
  249. }
  250. }
  251. }
  252. $filename = $this->statdir . '/' . $rulename . '-' . $tres . '-' . $fileno . '.stat';
  253. if (file_exists($filename)) {
  254. $previousData = unserialize(file_get_contents($filename));
  255. $filledresult = $this->cummulateData($previousData, $filledresult);
  256. }
  257. // store file
  258. file_put_contents($filename, serialize($filledresult), LOCK_EX);
  259. }
  260. }
  261. }
  262. $this->saveMetadata();
  263. }
  264. }