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;
15 static function getDatabaseHandle()
16 {
17 // Try to return last valid handle.
18 if(stats::$lastHandle != NULL && is_resource(stats::$lastHandle)){
19 return(stats::$lastHandle);
20 }
22 // Check if Logging is enabled
23 global $config;
24 if(!is_object($config) || ! $config instanceOf config){
25 return(NULL);
26 }
28 // Get statsFile property
29 stats::$tableFile = $config->get_cfg_value('core', 'statsDatabaseFile');
30 stats::$statsEnabled = $config->boolValueIsTrue('core', 'statsDatabaseEnabled');
31 if(!stats::$statsEnabled){
32 return;
33 }
35 // Check for SQLite extension
36 if(!stats::checkSQLiteExtension()){
37 return(NULL);
38 }
40 // Check if we are able to read/write the given database file.
41 if(!is_writeable(stats::$tableFile) && !is_writeable(dirname(stats::$tableFile))){
42 return(NULL);
43 }
45 // Try to create database, if it exists just open it.
46 $handle = sqlite_popen(stats::$tableFile, 0666, $error);
47 if($handle){
48 stats::createDatabaseOnDemand($handle);
49 }
50 stats::$lastHandle = $handle;
51 return($handle);
52 }
54 /*! \brief |
55 * @param |
56 * @return |
57 */
58 static function checkSQLiteExtension()
59 {
60 return(function_exists('sqlite_popen'));
61 }
64 /*! \brief |
65 * @param |
66 * @return |
67 */
68 static function dropTable($handle)
69 {
70 $TABLE_NAME = stats::$tableName;
71 $query = "DROP TABLE '{$TABLE_NAME}'";
72 $ret = sqlite_query($query, $handle);
73 }
76 /*! \brief |
77 * @param |
78 * @return |
79 */
80 static function get_memory_usage()
81 {
82 return(memory_get_usage());
83 }
86 /*! \brief |
87 * @param |
88 * @return |
89 */
90 static function get_cpu_load()
91 {
92 $cur = time();
93 if(empty(stats::$lastCpuLoad) || (($cur - stats::$lastCpuLoadTimestamp) >=2 )){
94 list($one, $five, $ten) =preg_split("/ /",shell_exec('cat /proc/loadavg'));
95 stats::$lastCpuLoad = $one;
96 stats::$lastCpuLoadTimestamp = $cur;
97 }
98 return(stats::$lastCpuLoad);
99 }
102 /*! \brief |
103 * @param |
104 * @return |
105 */
106 static function createDatabaseOnDemand($handle)
107 {
108 $TABLE_NAME = stats::$tableName;
110 // List Tables an check if there is already everything we need,
111 // if not create it.
112 $query = "SELECT name FROM sqlite_master WHERE type='table' and name='{$TABLE_NAME}'";
113 $ret = sqlite_query($query, $handle);
114 if(!count(sqlite_fetch_all($ret))){
115 $query = "
116 CREATE TABLE {$TABLE_NAME} (
117 ID INTEGER PRIMARY KEY,
118 ACTID INTEGER,
119 TYPE TEXT,
120 PLUGIN TEXT,
121 CATEGORY TEXT,
122 ACTION TEXT,
123 UUID TEXT,
124 TIMESTAMP INTEGER,
125 MTIMESTAMP REAL,
126 DURATION REAL,
127 RENDER_TIME REAL,
128 AMOUNT INTEGER,
129 MEMORY_USAGE INTEGER,
130 CPU_LOAD FLOAT,
131 INFO BLOB
132 )";
133 $ret = sqlite_query($query, $handle);
134 }
135 }
138 /*! \brief |
139 * @param |
140 * @return |
141 */
142 static function log($type, $plugin, $category, $action, $amount = 1, $duration = 0, $info ='')
143 {
144 global $config;
145 global $clicks;
146 global $overallRenderTimer;
148 // Get database handle, if it is invalid (NULL) return without creating stats
149 $res = stats::getDatabaseHandle();
150 if(!$res) return;
152 // Ensure that 'clicks' and 'overallRenderTimer' are present and set correctly,
153 // if not simply create them with dummy values...
154 // -- 'clicks' is a counter wich is set in main.php -> Number of page reloads
155 // -- 'overallRenderTimer' is set in main.php -> timestamp of rendering start.
156 if(!isset($clicks) || empty($clicks)) $clicks = 0;
157 if(!isset($overallRenderTimer) || empty($overallRenderTimer)){
158 $renderTime = 0;
159 }else{
160 $renderTime = microtime(TRUE) - $overallRenderTimer;
162 // Now set the overallRenderTimer to the current timestamp - else
163 // we will not be able to sum up the render time in a single SQL statement.
164 $overallRenderTimer = microtime(TRUE);
165 }
167 // Prepare values to be useable within a database
168 $uuid = $config->getGOsaUUID();
169 $type = sqlite_escape_string($type);
170 $plugin = sqlite_escape_string($plugin);
171 $action = sqlite_escape_string($action);
172 $timestamp = time();
173 $mtimestamp = microtime(TRUE);
174 $amount = sqlite_escape_string($amount);
175 $duration = sqlite_escape_string($duration);
176 $renderTime = sqlite_escape_string($renderTime);
177 $info = sqlite_escape_string($info);
178 $clicks = sqlite_escape_string($clicks);
179 $memory_usage = sqlite_escape_string(stats::get_memory_usage());
180 $cpu_load = sqlite_escape_string(stats::get_cpu_load());
182 // Clean up category, which usally comes from acl_category and may still contain
183 // some special chars like /
184 $tmp = array();
185 foreach($category as $cat){
186 $tmp[] = trim($cat, '\/,; ');
187 }
188 $category = sqlite_escape_string(implode($tmp, ', '));
190 // Create insert statement.
191 $TABLE_NAME = stats::$tableName;
192 $query = "
193 INSERT INTO {$TABLE_NAME}
194 (ACTID, TYPE, PLUGIN, CATEGORY, ACTION, UUID, MTIMESTAMP, TIMESTAMP,
195 AMOUNT, DURATION, RENDER_TIME, MEMORY_USAGE, CPU_LOAD, INFO)
196 VALUES
197 ('{$clicks}','{$type}','{$plugin}','{$category}','{$action}','{$uuid}',
198 '{$mtimestamp}','{$timestamp}','{$amount}','{$duration}','{$renderTime}',
199 '{$memory_usage}','{$cpu_load}','{$info}')";
200 sqlite_query($query, $res);
201 }
204 /*! \brief |
205 * @param |
206 * @return |
207 */
208 static function show()
209 {
210 $res = stats::getDatabaseHandle();
211 if(!$res) return;
213 $TABLE_NAME = stats::$tableName;
214 $query = "SELECT * FROM {$TABLE_NAME} ORDER BY MTIMESTAMP";
215 $query = "SELECT PLUGIN, ACTION, MAX(DURATION) as 'DURATION' FROM {$TABLE_NAME} WHERE ACTION='modify' GROUP BY PLUGIN,ACTION ";
216 $query = "SELECT * FROM {$TABLE_NAME} ORDER BY ID DESC LIMIT 30";
217 $query = "SELECT * FROM {$TABLE_NAME} WHERE plugin != 'LDAP' ORDER BY ID DESC LIMIT 30";
218 $ret = sqlite_query($query, $res);
219 echo "<pre>";
221 $colSize = 16;
223 $title = FALSE;
224 foreach(sqlite_fetch_all($ret) as $entry){
225 if(!$title){
226 foreach($entry as $key => $str) {
227 if(is_numeric($key)) continue;
228 echo str_pad($key,$colSize,' ')."|";
229 }
230 echo "\n";
231 foreach($entry as $key => $str) {
232 if(is_numeric($key)) continue;
233 echo str_pad('',$colSize,'-')."-";
234 }
235 echo "\n";
236 $title = TRUE;
237 }
239 foreach($entry as $key => $str){
240 if(is_numeric($key)) continue;
241 if($key == "DURATION" || $key == "MTIMESTAMP" || $key == "CPU_LOAD"){
242 $str = sprintf("%0.4f", preg_replace("/,/",".",$str));
243 echo str_pad($str,$colSize,' ', STR_PAD_LEFT)."|";
244 }else{
245 echo str_pad($str,$colSize,' ')."|";
246 }
247 }
248 echo "\n";
249 }
250 echo sqlite_error_string($ret);
252 echo "\n------ \n";
253 echo "Time spent per plugin-category \n";
254 echo "------ \n";
256 $query = "
257 SELECT SUM(DURATION) AS DUR, CATEGORY
258 FROM {$TABLE_NAME}
259 WHERE plugin != 'LDAP'
260 GROUP BY CATEGORY
261 ORDER BY DUR DESC LIMIT 10";
262 $ret = sqlite_query($query, $res);
264 $colSize = 16;
265 $title = FALSE;
266 foreach(sqlite_fetch_all($ret) as $entry){
267 foreach($entry as $key => $str){
268 if(is_numeric($key)) continue;
269 echo str_pad($str,$colSize,' ')."|";
270 }
271 echo "\n";
272 }
275 echo sqlite_error_string($ret);
277 echo "\n------ \n";
278 echo "Time spent per plugin \n";
279 echo "------ \n";
281 $query = "
282 SELECT SUM(DURATION) AS DUR, PLUGIN, UUID
283 FROM {$TABLE_NAME}
284 WHERE plugin != 'LDAP'
285 GROUP BY PLUGIN, UUID
286 ORDER BY DUR DESC LIMIT 10";
287 $ret = sqlite_query($query, $res);
289 $colSize = 16;
290 $title = FALSE;
291 foreach(sqlite_fetch_all($ret) as $entry){
292 foreach($entry as $key => $str){
293 if(is_numeric($key)) continue;
294 echo str_pad($str,$colSize,' ')."|";
295 }
296 echo "\n";
297 }
298 echo sqlite_error_string($ret);
300 # * Anzahl von Objekttypen
301 # * Anzahl der Löschungen pro Objekttyp
302 # * Anzahl der Erzeugungen pro Objekttyp
303 # * Anzahl der Bearbeitungen pro Objekttyp
304 # * Anzahl der Verschiebungen pro Objekttyp
305 # * Anzahl der Mehrfachbearbeitungen pro Objekttyp
306 # * Antwortzeiten pro aktion
307 # * Anzahl der Passwortänderungen
308 # * Anzahl der unterschiedlichen Anmeldungen
311 echo "\n------ \n";
312 echo "Actions done per plugin \n";
313 echo "------ \n";
315 $query = "
316 SELECT COUNT(ACTION) as CNT, ACTION, PLUGIN
317 FROM {$TABLE_NAME}
318 WHERE TYPE = 'plugin'
319 AND PLUGIN != 'LDAP'
320 GROUP BY ACTION,PLUGIN
321 ORDER BY CNT DESC LIMIT 30";
322 $ret = sqlite_query($query, $res);
324 $colSize = 16;
325 $title = FALSE;
326 foreach(sqlite_fetch_all($ret) as $entry){
327 foreach($entry as $key => $str){
328 if(is_numeric($key)) continue;
329 echo str_pad($str,$colSize,' ')."|";
330 }
331 echo "\n";
332 }
333 echo sqlite_error_string($ret);
335 echo "\n------ \n";
336 echo "'create' actions done per plugin (5 most)\n";
337 echo "------ \n";
339 $query = "
340 SELECT COUNT(ACTION) as CNT, ACTION, PLUGIN
341 FROM {$TABLE_NAME}
342 WHERE TYPE = 'plugin'
343 AND PLUGIN != 'LDAP'
344 AND ACTION = 'create'
345 GROUP BY ACTION,PLUGIN
346 ORDER BY CNT DESC LIMIT 5";
347 $ret = sqlite_query($query, $res);
349 $colSize = 16;
350 $title = FALSE;
351 foreach(sqlite_fetch_all($ret) as $entry){
352 foreach($entry as $key => $str){
353 if(is_numeric($key)) continue;
354 echo str_pad($str,$colSize,' ')."|";
355 }
356 echo "\n";
357 }
358 echo sqlite_error_string($ret);
360 echo "\n------ \n";
361 echo "'move' actions done per plugin (5 most)\n";
362 echo "------ \n";
364 $query = "
365 SELECT COUNT(ACTION) as CNT, ACTION, PLUGIN
366 FROM {$TABLE_NAME}
367 WHERE TYPE = 'plugin'
368 AND PLUGIN != 'LDAP'
369 AND ACTION = 'move'
370 GROUP BY ACTION,PLUGIN
371 ORDER BY CNT DESC LIMIT 5";
372 $ret = sqlite_query($query, $res);
374 $colSize = 16;
375 $title = FALSE;
376 foreach(sqlite_fetch_all($ret) as $entry){
377 foreach($entry as $key => $str){
378 if(is_numeric($key)) continue;
379 echo str_pad($str,$colSize,' ')."|";
380 }
381 echo "\n";
382 }
383 echo sqlite_error_string($ret);
385 echo "\n------ \n";
386 echo "'view' actions done per plugin (5 most)\n";
387 echo "------ \n";
389 $query = "
390 SELECT COUNT(ACTION) as CNT, ACTION, PLUGIN
391 FROM {$TABLE_NAME}
392 WHERE TYPE = 'plugin'
393 AND PLUGIN != 'LDAP'
394 AND ACTION = 'view'
395 GROUP BY ACTION,PLUGIN
396 ORDER BY CNT DESC LIMIT 5";
397 $ret = sqlite_query($query, $res);
399 $colSize = 16;
400 $title = FALSE;
401 foreach(sqlite_fetch_all($ret) as $entry){
402 foreach($entry as $key => $str){
403 if(is_numeric($key)) continue;
404 echo str_pad($str,$colSize,' ')."|";
405 }
406 echo "\n";
407 }
408 echo sqlite_error_string($ret);
410 echo "\n------ \n";
411 echo "'open' actions done per plugin (5 most)\n";
412 echo "------ \n";
414 $query = "
415 SELECT COUNT(ACTION) as CNT, ACTION, PLUGIN, UUID
416 FROM {$TABLE_NAME}
417 WHERE TYPE = 'plugin'
418 AND PLUGIN != 'LDAP'
419 AND ACTION = 'open'
420 GROUP BY ACTION,PLUGIN, UUID
421 ORDER BY CNT DESC LIMIT 5";
422 $ret = sqlite_query($query, $res);
424 $colSize = 16;
425 $title = FALSE;
426 foreach(sqlite_fetch_all($ret) as $entry){
427 foreach($entry as $key => $str){
428 if(is_numeric($key)) continue;
429 echo str_pad($str,$colSize,' ')."|";
430 }
431 echo "\n";
432 }
433 echo sqlite_error_string($ret);
435 echo "\n------ \n";
436 echo "Time per session\n";
437 echo "------ \n";
439 $query = "
440 SELECT SUM(DURATION) as DUR, UUID
441 FROM {$TABLE_NAME}
442 GROUP BY UUID
443 ORDER BY DUR DESC LIMIT 10";
444 $ret = sqlite_query($query, $res);
446 $colSize = 16;
447 $title = FALSE;
448 foreach(sqlite_fetch_all($ret) as $entry){
449 foreach($entry as $key => $str){
450 if(is_numeric($key)) continue;
451 echo str_pad($str,$colSize,' ')."|";
452 }
453 echo "\n";
454 }
455 echo sqlite_error_string($ret);
457 echo "\n------ \n";
458 echo "Most used password hashes\n";
459 echo "------ \n";
461 $query = "
462 SELECT DISTINCT(INFO), COUNT(INFO) as CNT
463 FROM {$TABLE_NAME}
464 WHERE ACTION = 'change_password'
465 GROUP BY INFO
466 ORDER BY INFO DESC LIMIT 10";
467 $ret = sqlite_query($query, $res);
469 $colSize = 16;
470 $title = FALSE;
471 foreach(sqlite_fetch_all($ret) as $entry){
472 foreach($entry as $key => $str){
473 if(is_numeric($key)) continue;
474 echo str_pad($str,$colSize,' ')."|";
475 }
476 echo "\n";
477 }
478 echo sqlite_error_string($ret);
480 echo "\n------ \n";
481 echo "Actions at all\n";
482 echo "------ \n";
484 $query = "
485 SELECT DISTINCT(ACTION), COUNT(ACTION) AS CNT
486 FROM {$TABLE_NAME}
487 GROUP BY ACTION
488 ORDER BY CNT DESC LIMIT 10";
489 $ret = sqlite_query($query, $res);
491 $colSize = 16;
492 $title = FALSE;
493 foreach(sqlite_fetch_all($ret) as $entry){
494 foreach($entry as $key => $str){
495 if(is_numeric($key)) continue;
496 echo str_pad($str,$colSize,' ')."|";
497 }
498 echo "\n";
499 }
500 echo sqlite_error_string($ret);
502 echo "\n------ \n";
503 echo "Time spent per action\n";
504 echo "------ \n";
506 $query = "
507 SELECT DISTINCT(ACTION), SUM(DURATION) AS DUR
508 FROM {$TABLE_NAME}
509 GROUP BY ACTION
510 ORDER BY DUR DESC LIMIT 10";
511 $ret = sqlite_query($query, $res);
513 $colSize = 16;
514 $title = FALSE;
515 foreach(sqlite_fetch_all($ret) as $entry){
516 foreach($entry as $key => $str){
517 if(is_numeric($key)) continue;
518 echo str_pad($str,$colSize,' ')."|";
519 }
520 echo "\n";
521 }
522 echo sqlite_error_string($ret);
524 echo "\n------ \n";
525 echo "Average time per action\n";
526 echo "------ \n";
528 $query = "
529 SELECT DISTINCT(ACTION), AVG(DURATION) AS DUR
530 FROM {$TABLE_NAME}
531 GROUP BY ACTION
532 ORDER BY DUR DESC LIMIT 10";
533 $ret = sqlite_query($query, $res);
535 $colSize = 16;
536 $title = FALSE;
537 foreach(sqlite_fetch_all($ret) as $entry){
538 foreach($entry as $key => $str){
539 if(is_numeric($key)) continue;
540 echo str_pad($str,$colSize,' ')."|";
541 }
542 echo "\n";
543 }
544 echo sqlite_error_string($ret);
546 echo "</pre>";
547 }
548 }
551 ?>