1 <?php
3 class stats
4 {
6 static protected $lastCpuLoad = "";
7 static protected $lastCpuLoadTimestamp = 0;
9 static protected $tableName = "stats";
10 static protected $tableFile = "/var/spool/gosa/stats";
12 static protected $lastHandle = NULL;
13 static protected $statsEnabled = FALSE;
16 static function prepareFloatForWriting($float){
17 return(floor($float * 1000));
18 }
20 static function prepareFloatForReading($int){
21 return($int / 1000);
22 }
24 static function getDatabaseHandle()
25 {
26 // Try to return last valid handle.
27 if(stats::$lastHandle != NULL && is_resource(stats::$lastHandle)){
28 return(stats::$lastHandle);
29 }
31 // Check if Logging is enabled
32 global $config;
33 if(!is_object($config) || ! $config instanceOf config){
34 return(NULL);
35 }
37 // Get statsFile property
38 stats::$tableFile = $config->get_cfg_value('core', 'statsDatabaseFile');
39 stats::$statsEnabled = $config->boolValueIsTrue('core', 'statsDatabaseEnabled');
40 if(!stats::$statsEnabled){
41 return;
42 }
44 // Check for SQLite extension
45 if(!stats::checkSQLiteExtension()){
46 return(NULL);
47 }
49 // Check if we are able to read/write the given database file.
50 if(!is_writeable(stats::$tableFile) && !is_writeable(dirname(stats::$tableFile))){
51 return(NULL);
52 }
54 // Try to create database, if it exists just open it.
55 $handle = sqlite_popen(stats::$tableFile, 0666, $error);
56 if($handle){
57 stats::createDatabaseOnDemand($handle);
58 }
59 stats::$lastHandle = $handle;
60 return($handle);
61 }
63 /*! \brief |
64 * @param |
65 * @return |
66 */
67 static function checkSQLiteExtension()
68 {
69 return(function_exists('sqlite_popen'));
70 }
73 /*! \brief |
74 * @param |
75 * @return |
76 */
77 static function dropTable($handle)
78 {
79 $TABLE_NAME = stats::$tableName;
80 $query = "DROP TABLE '{$TABLE_NAME}'";
81 $ret = sqlite_query($query, $handle);
82 stats::$lastHandle = NULL;
83 stats::getDatabaseHandle();
84 }
87 /*! \brief |
88 * @param |
89 * @return |
90 */
91 static function get_memory_usage()
92 {
93 return(memory_get_usage());
94 }
97 /*! \brief |
98 * @param |
99 * @return |
100 */
101 static function get_cpu_load()
102 {
103 $cur = time();
104 if(empty(stats::$lastCpuLoad) || (($cur - stats::$lastCpuLoadTimestamp) >=2 )){
105 list($one, $five, $ten) =preg_split("/ /",shell_exec('cat /proc/loadavg'));
106 stats::$lastCpuLoad = $one;
107 stats::$lastCpuLoadTimestamp = $cur;
108 }
109 return(stats::$lastCpuLoad);
110 }
113 /*! \brief |
114 * @param |
115 * @return |
116 */
117 static function createDatabaseOnDemand($handle)
118 {
119 $TABLE_NAME = stats::$tableName;
121 // List Tables an check if there is already everything we need,
122 // if not create it.
123 $query = "SELECT name FROM sqlite_master WHERE type='table' and name='{$TABLE_NAME}'";
124 $ret = sqlite_query($query, $handle);
125 if(!count(sqlite_fetch_all($ret))){
126 $query = "
127 CREATE TABLE {$TABLE_NAME} (
128 ID INTEGER PRIMARY KEY,
129 ACTID INTEGER,
130 TYPE TEXT,
131 PLUGIN TEXT,
132 CATEGORY TEXT,
133 ACTION TEXT,
134 UUID TEXT,
135 TIMESTAMP INTEGER,
136 MTIMESTAMP REAL,
137 DURATION REAL,
138 RENDER_TIME REAL,
139 AMOUNT INTEGER,
140 MEMORY_USAGE INTEGER,
141 CPU_LOAD FLOAT,
142 INFO BLOB
143 )";
144 $ret = sqlite_query($query, $handle);
145 }
146 }
149 /*! \brief |
150 * @param |
151 * @return |
152 */
153 static function log($type, $plugin, $category, $action, $amount = 1, $duration = 0, $info ='')
154 {
155 global $config;
156 global $clicks;
157 global $overallRenderTimer;
159 // Get database handle, if it is invalid (NULL) return without creating stats
160 $res = stats::getDatabaseHandle();
161 # stats::dropTable($res);
162 if(!$res) return;
164 // Ensure that 'clicks' and 'overallRenderTimer' are present and set correctly,
165 // if not simply create them with dummy values...
166 // -- 'clicks' is a counter wich is set in main.php -> Number of page reloads
167 // -- 'overallRenderTimer' is set in main.php -> timestamp of rendering start.
168 if(!isset($clicks) || empty($clicks)) $clicks = 0;
169 if(!isset($overallRenderTimer)){
170 $renderTime = 0;
171 }else{
172 $renderTime = microtime(TRUE) - $overallRenderTimer;
174 // Now set the overallRenderTimer to the current timestamp - else
175 // we will not be able to sum up the render time in a single SQL statement.
176 $overallRenderTimer = microtime(TRUE);
177 }
179 $duration = stats::prepareFloatForWriting($duration);
180 $renderTime = stats::prepareFloatForWriting($renderTime);
182 // Prepare values to be useable within a database
183 $uuid = $config->getGOsaUUID();
184 $type = sqlite_escape_string($type);
185 $plugin = sqlite_escape_string($plugin);
186 $action = sqlite_escape_string($action);
187 $timestamp = time();
188 $mtimestamp = microtime(TRUE);
189 $amount = sqlite_escape_string($amount);
190 $duration = sqlite_escape_string($duration);
191 $renderTime = sqlite_escape_string($renderTime);
192 $info = sqlite_escape_string($info);
193 $clicks = sqlite_escape_string($clicks);
194 $memory_usage = sqlite_escape_string(stats::get_memory_usage());
195 $cpu_load = sqlite_escape_string(sprintf("%0.6f",stats::get_cpu_load()));
197 // Clean up category, which usally comes from acl_category and may still contain
198 // some special chars like /
199 $tmp = array();
200 foreach($category as $cat){
201 $tmp[] = trim($cat, '\/,; ');
202 }
203 $category = sqlite_escape_string(implode($tmp, ', '));
205 // Create insert statement.
206 $TABLE_NAME = stats::$tableName;
207 $query = "
208 INSERT INTO {$TABLE_NAME}
209 (ACTID, TYPE, PLUGIN, CATEGORY, ACTION, UUID, MTIMESTAMP, TIMESTAMP,
210 AMOUNT, DURATION, RENDER_TIME, MEMORY_USAGE, CPU_LOAD, INFO)
211 VALUES
212 ('{$clicks}','{$type}','{$plugin}','{$category}','{$action}','{$uuid}',
213 '{$mtimestamp}','{$timestamp}','{$amount}','{$duration}','{$renderTime}',
214 '{$memory_usage}','{$cpu_load}','{$info}')";
215 sqlite_query($query, $res);
216 }
219 /*! \brief |
220 * @param |
221 * @return |
222 */
223 static function show()
224 {
225 $res = stats::getDatabaseHandle();
226 # stats::dropTable($res);
227 if(!$res) return;
229 $TABLE_NAME = stats::$tableName;
230 $query = "SELECT * FROM {$TABLE_NAME} ORDER BY MTIMESTAMP";
231 $query = "SELECT PLUGIN, ACTION, MAX(DURATION) as 'DURATION' FROM {$TABLE_NAME} WHERE ACTION='modify' GROUP BY PLUGIN,ACTION ";
232 $query = "SELECT * FROM {$TABLE_NAME} ORDER BY ID DESC LIMIT 30";
233 $query = "SELECT * FROM {$TABLE_NAME} WHERE plugin != 'LDAP' ORDER BY ID DESC LIMIT 30";
234 $ret = sqlite_query($query, $res);
235 echo "<pre>";
237 $colSize = 16;
239 $title = FALSE;
240 foreach(sqlite_fetch_all($ret) as $entry){
241 if(!$title){
242 foreach($entry as $key => $str) {
243 if(is_numeric($key)) continue;
244 echo str_pad($key,$colSize,' ')."|";
245 }
246 echo "\n";
247 foreach($entry as $key => $str) {
248 if(is_numeric($key)) continue;
249 echo str_pad('',$colSize,'-')."-";
250 }
251 echo "\n";
252 $title = TRUE;
253 }
255 foreach($entry as $key => $str){
256 if(is_numeric($key)) continue;
257 if($key == "DURATION" || $key == "MTIMESTAMP" || $key == "CPU_LOAD"){
258 $str = sprintf("%0.4f", preg_replace("/,/",".",$str));
259 echo str_pad($str,$colSize,' ', STR_PAD_LEFT)."|";
260 }else{
261 echo str_pad($str,$colSize,' ')."|";
262 }
263 }
264 echo "\n";
265 }
266 echo sqlite_error_string($ret);
268 echo "\n------ \n";
269 echo "Time spent per plugin-category \n";
270 echo "------ \n";
272 $query = "
273 SELECT SUM(DURATION) AS DUR, CATEGORY
274 FROM {$TABLE_NAME}
275 WHERE plugin != 'LDAP'
276 GROUP BY CATEGORY
277 ORDER BY DUR DESC LIMIT 10";
278 $ret = sqlite_query($query, $res);
280 $colSize = 16;
281 $title = FALSE;
282 foreach(sqlite_fetch_all($ret) as $entry){
283 foreach($entry as $key => $str){
284 if(is_numeric($key)) continue;
285 echo str_pad($str,$colSize,' ')."|";
286 }
287 echo "\n";
288 }
291 echo sqlite_error_string($ret);
293 echo "\n------ \n";
294 echo "Time spent per plugin \n";
295 echo "------ \n";
297 $query = "
298 SELECT SUM(DURATION) AS DUR, PLUGIN, UUID
299 FROM {$TABLE_NAME}
300 WHERE plugin != 'LDAP'
301 GROUP BY PLUGIN, UUID
302 ORDER BY DUR DESC LIMIT 10";
303 $ret = sqlite_query($query, $res);
305 $colSize = 16;
306 $title = FALSE;
307 foreach(sqlite_fetch_all($ret) as $entry){
308 foreach($entry as $key => $str){
309 if(is_numeric($key)) continue;
310 echo str_pad($str,$colSize,' ')."|";
311 }
312 echo "\n";
313 }
314 echo sqlite_error_string($ret);
316 # * Anzahl von Objekttypen
317 # * Anzahl der Löschungen pro Objekttyp
318 # * Anzahl der Erzeugungen pro Objekttyp
319 # * Anzahl der Bearbeitungen pro Objekttyp
320 # * Anzahl der Verschiebungen pro Objekttyp
321 # * Anzahl der Mehrfachbearbeitungen pro Objekttyp
322 # * Antwortzeiten pro aktion
323 # * Anzahl der Passwortänderungen
324 # * Anzahl der unterschiedlichen Anmeldungen
327 echo "\n------ \n";
328 echo "Actions done per plugin \n";
329 echo "------ \n";
331 $query = "
332 SELECT COUNT(ACTION) as CNT, ACTION, PLUGIN
333 FROM {$TABLE_NAME}
334 WHERE TYPE = 'plugin'
335 AND PLUGIN != 'LDAP'
336 GROUP BY ACTION,PLUGIN
337 ORDER BY CNT DESC LIMIT 30";
338 $ret = sqlite_query($query, $res);
340 $colSize = 16;
341 $title = FALSE;
342 foreach(sqlite_fetch_all($ret) as $entry){
343 foreach($entry as $key => $str){
344 if(is_numeric($key)) continue;
345 echo str_pad($str,$colSize,' ')."|";
346 }
347 echo "\n";
348 }
349 echo sqlite_error_string($ret);
351 echo "\n------ \n";
352 echo "'create' actions done per plugin (5 most)\n";
353 echo "------ \n";
355 $query = "
356 SELECT COUNT(ACTION) as CNT, ACTION, PLUGIN
357 FROM {$TABLE_NAME}
358 WHERE TYPE = 'plugin'
359 AND PLUGIN != 'LDAP'
360 AND ACTION = 'create'
361 GROUP BY ACTION,PLUGIN
362 ORDER BY CNT DESC LIMIT 5";
363 $ret = sqlite_query($query, $res);
365 $colSize = 16;
366 $title = FALSE;
367 foreach(sqlite_fetch_all($ret) as $entry){
368 foreach($entry as $key => $str){
369 if(is_numeric($key)) continue;
370 echo str_pad($str,$colSize,' ')."|";
371 }
372 echo "\n";
373 }
374 echo sqlite_error_string($ret);
376 echo "\n------ \n";
377 echo "'move' actions done per plugin (5 most)\n";
378 echo "------ \n";
380 $query = "
381 SELECT COUNT(ACTION) as CNT, ACTION, PLUGIN
382 FROM {$TABLE_NAME}
383 WHERE TYPE = 'plugin'
384 AND PLUGIN != 'LDAP'
385 AND ACTION = 'move'
386 GROUP BY ACTION,PLUGIN
387 ORDER BY CNT DESC LIMIT 5";
388 $ret = sqlite_query($query, $res);
390 $colSize = 16;
391 $title = FALSE;
392 foreach(sqlite_fetch_all($ret) as $entry){
393 foreach($entry as $key => $str){
394 if(is_numeric($key)) continue;
395 echo str_pad($str,$colSize,' ')."|";
396 }
397 echo "\n";
398 }
399 echo sqlite_error_string($ret);
401 echo "\n------ \n";
402 echo "'view' actions done per plugin (5 most)\n";
403 echo "------ \n";
405 $query = "
406 SELECT COUNT(ACTION) as CNT, ACTION, PLUGIN
407 FROM {$TABLE_NAME}
408 WHERE TYPE = 'plugin'
409 AND PLUGIN != 'LDAP'
410 AND ACTION = 'view'
411 GROUP BY ACTION,PLUGIN
412 ORDER BY CNT DESC LIMIT 5";
413 $ret = sqlite_query($query, $res);
415 $colSize = 16;
416 $title = FALSE;
417 foreach(sqlite_fetch_all($ret) as $entry){
418 foreach($entry as $key => $str){
419 if(is_numeric($key)) continue;
420 echo str_pad($str,$colSize,' ')."|";
421 }
422 echo "\n";
423 }
424 echo sqlite_error_string($ret);
426 echo "\n------ \n";
427 echo "'open' actions done per plugin (5 most)\n";
428 echo "------ \n";
430 $query = "
431 SELECT COUNT(ACTION) as CNT, ACTION, PLUGIN, UUID
432 FROM {$TABLE_NAME}
433 WHERE TYPE = 'plugin'
434 AND PLUGIN != 'LDAP'
435 AND ACTION = 'open'
436 GROUP BY ACTION,PLUGIN, UUID
437 ORDER BY CNT DESC LIMIT 5";
438 $ret = sqlite_query($query, $res);
440 $colSize = 16;
441 $title = FALSE;
442 foreach(sqlite_fetch_all($ret) as $entry){
443 foreach($entry as $key => $str){
444 if(is_numeric($key)) continue;
445 echo str_pad($str,$colSize,' ')."|";
446 }
447 echo "\n";
448 }
449 echo sqlite_error_string($ret);
451 echo "\n------ \n";
452 echo "Time per session\n";
453 echo "------ \n";
455 $query = "
456 SELECT SUM(DURATION) as DUR, UUID
457 FROM {$TABLE_NAME}
458 GROUP BY UUID
459 ORDER BY DUR DESC LIMIT 10";
460 $ret = sqlite_query($query, $res);
462 $colSize = 16;
463 $title = FALSE;
464 foreach(sqlite_fetch_all($ret) as $entry){
465 foreach($entry as $key => $str){
466 if(is_numeric($key)) continue;
467 echo str_pad($str,$colSize,' ')."|";
468 }
469 echo "\n";
470 }
471 echo sqlite_error_string($ret);
473 echo "\n------ \n";
474 echo "Most used password hashes\n";
475 echo "------ \n";
477 $query = "
478 SELECT DISTINCT(INFO), COUNT(INFO) as CNT
479 FROM {$TABLE_NAME}
480 WHERE ACTION = 'change_password'
481 GROUP BY INFO
482 ORDER BY INFO DESC LIMIT 10";
483 $ret = sqlite_query($query, $res);
485 $colSize = 16;
486 $title = FALSE;
487 foreach(sqlite_fetch_all($ret) as $entry){
488 foreach($entry as $key => $str){
489 if(is_numeric($key)) continue;
490 echo str_pad($str,$colSize,' ')."|";
491 }
492 echo "\n";
493 }
494 echo sqlite_error_string($ret);
496 echo "\n------ \n";
497 echo "Actions at all\n";
498 echo "------ \n";
500 $query = "
501 SELECT DISTINCT(ACTION), COUNT(ACTION) AS CNT
502 FROM {$TABLE_NAME}
503 GROUP BY ACTION
504 ORDER BY CNT DESC LIMIT 10";
505 $ret = sqlite_query($query, $res);
507 $colSize = 16;
508 $title = FALSE;
509 foreach(sqlite_fetch_all($ret) as $entry){
510 foreach($entry as $key => $str){
511 if(is_numeric($key)) continue;
512 echo str_pad($str,$colSize,' ')."|";
513 }
514 echo "\n";
515 }
516 echo sqlite_error_string($ret);
518 echo "\n------ \n";
519 echo "Time spent per action\n";
520 echo "------ \n";
522 $query = "
523 SELECT DISTINCT(ACTION), SUM(DURATION) AS DUR
524 FROM {$TABLE_NAME}
525 GROUP BY ACTION
526 ORDER BY DUR DESC LIMIT 10";
527 $ret = sqlite_query($query, $res);
529 $colSize = 16;
530 $title = FALSE;
531 foreach(sqlite_fetch_all($ret) as $entry){
532 foreach($entry as $key => $str){
533 if(is_numeric($key)) continue;
534 echo str_pad($str,$colSize,' ')."|";
535 }
536 echo "\n";
537 }
538 echo sqlite_error_string($ret);
540 echo "\n------ \n";
541 echo "Average time per action\n";
542 echo "------ \n";
544 $query = "
545 SELECT DISTINCT(ACTION), AVG(DURATION) AS DUR
546 FROM {$TABLE_NAME}
547 GROUP BY ACTION
548 ORDER BY DUR DESC LIMIT 10";
549 $ret = sqlite_query($query, $res);
551 $colSize = 16;
552 $title = FALSE;
553 foreach(sqlite_fetch_all($ret) as $entry){
554 foreach($entry as $key => $str){
555 if(is_numeric($key)) continue;
556 echo str_pad($str,$colSize,' ')."|";
557 }
558 echo "\n";
559 }
560 echo sqlite_error_string($ret);
563 echo "\n------ \n";
564 echo "Rendertime per plugin\n";
565 echo "------ \n";
567 $query = "
568 SELECT PLUGIN, RENDER_TIME AS RM
569 FROM {$TABLE_NAME}
570 GROUP BY PLUGIN
571 ";
572 $ret = sqlite_query($query, $res);
574 $colSize = 16;
575 $title = FALSE;
576 foreach(sqlite_fetch_all($ret) as $entry){
577 foreach($entry as $key => $str){
578 if(is_numeric($key)) continue;
579 echo str_pad($str,$colSize,' ')."|";
580 }
581 echo "\n";
582 }
583 echo sqlite_error_string($ret);
585 echo "</pre>";
586 }
587 }
590 ?>