Changeset 6767


Ignore:
Timestamp:
Feb 5, 2018, 2:19:57 PM (22 months ago)
Author:
mabarracus
Message:

Fix test suite
Consolidation daemon ported to python3
Avoid daemon running with multiple instances
Fixes indent,sizes in fonts and graphics
System stats visualization page
Minimized javascript files
New cache for visualization graphs minimizing overloading and DoS attacks
Improved scheduler with clients sending 10+ results

Location:
lliurex-analytics-server/trunk/fuentes
Files:
7 added
7 edited

Legend:

Unmodified
Added
Removed
  • lliurex-analytics-server/trunk/fuentes/debian/changelog

    r6508 r6767  
     1lliurex-analytics-server (0.2.4) unreleased; urgency=medium
     2
     3  * Fix test suite
     4  * Consolidation daemon ported to python3
     5  * Avoid daemon running with multiple instances
     6  * Fixes indent,sizes in fonts and graphics
     7  * System stats visualization page
     8  * Minimized javascript files
     9  * New cache for visualization graphs minimizing overloading and DoS attacks
     10  * Improved scheduler with clients sending 10+ results
     11
     12 -- M.Angel Juan <m.angel.juan@gmail.com>  Mon, 05 Feb 2018 13:56:27 +0100
     13
    114lliurex-analytics-server (0.2.3) xenial; urgency=medium
    215
  • lliurex-analytics-server/trunk/fuentes/debian/control

    r5560 r6767  
    99Depends: ${shlibs:Depends}, ${misc:Depends},
    1010        debconf (>= 0.5) | debconf-2.0, po-debconf,
    11         ucf, python, python-daemon, apache2, libapache2-mod-php7.0, php7.0-mysql, mysql-server, dialog, perl, python-mysqldb, python-psutil
    12 Recommends:
     11        ucf, python3, python3-daemon, apache2, libapache2-mod-php7.0, php7.0-mysql, mysql-server, dialog, perl, python3-mysqldb, python3-psutil
     12Recommends: libapache2-mod-evasive
    1313Suggests:
    1414Description: Statistics server for lliurex-analytics agent, this package contains the server part.
  • lliurex-analytics-server/trunk/fuentes/lliurex-analytics-server/usr/lib/analytics-server/analytics/db.php

    r5926 r6767  
    11<?php
     2class Cache{
     3    private $cache_file;
     4    private $cache_dir;
     5    private $data_file;
     6    private $data;
     7    private $cache_timeout=60*60;
     8
     9    function Cache(){
     10        $this->cache_dir = sys_get_temp_dir();
     11        $this->cache_file = "cache_analytics.db.tmp";
     12        $this->datafile=$this->cache_dir.'/'.$this->cache_file;
     13        $this->data = array();
     14    }
     15    function readFile(){
     16        if (is_file($this->datafile) and is_writable($this->datafile)){
     17            $this->filecontents = file_get_contents($this->datafile);
     18        }else{
     19            // do nothing or throw error
     20            return false;
     21        }
     22        return true;
     23    }
     24    function newFile($data=array()){
     25        // create new file
     26        $obj=$data;
     27        $json='';
     28        try{
     29            $json=json_encode($obj);
     30        }catch(Exception $e){
     31            return false;
     32        }
     33        file_put_contents($this->datafile,$json);
     34    }
     35    function parseJson(){
     36        try{
     37            $json=json_decode($this->filecontents,true);
     38            $this->data=$json;
     39        }catch(Exception $e){
     40            return false;
     41        }
     42        return true;
     43    }
     44    function process(){
     45        $continue = false;
     46        if ($this->readFile()){
     47            $continue = true;
     48        }else{
     49            $this->newFile();
     50            if ($this->readFile()){
     51                $continue=true;
     52            }
     53        }
     54        if (! $continue){
     55            return false;
     56        }
     57        if (! $this->parseJson()){
     58            return false;
     59        }
     60        return true;
     61    }
     62    function get($key){
     63        if (! $this->process()){
     64            return false;
     65        }
     66        try{
     67            $data=$this->data;
     68            if ($data == null or ! is_array($data) or ! array_key_exists($key,$data))
     69                return false;
     70            $data=$data[$key];
     71            if (time() - (int)$data['timestamp'] > $this->cache_timeout){
     72                return false; //'invalid';
     73            }else{
     74                return $data['value'];
     75            }
     76        }catch(Exception $e){
     77            return false;
     78        }
     79    }
     80    function store($obj,$key){
     81        if (! $this->process()){
     82            return false;
     83        }
     84        try{
     85            $this->data[$key]=['timestamp'=>time(),'value'=>$obj];
     86            return $this->newFile($this->data);
     87        }catch(Exception $e){
     88            return false;
     89        }
     90    }
     91}
     92
    293class DB{
    394
    4         private $dbhost;
    5         private $dbname;
    6         private $dbuser;
    7         private $dbpass;
    8         private $ka_file='/var/run/analyticsd.keepalive';
    9         private $alias;
    10         public $dbconn;
    11 
    12         function DB(){
    13                 require_once('config.php');
    14                 global $dbhost,$dbname,$dbpass,$dbuser,$distros;
    15                
    16                 $this->dbhost=$dbhost;
    17                 $this->dbname=$dbname;
    18                 $this->dbpass=$dbpass;
    19                 $this->dbuser=$dbuser;
    20                 $this->alias=array();
    21                 $this->info_distro=json_decode($distros,true);
    22                 if ($this->info_distro == NULL){
    23                     die('Error: Wrong json in Config.php');
    24                 }
    25                 $this->init_dates();
    26                 $this->times=0;
    27         }
    28         function init_dates(){
    29                 $this->dates=array();
    30                 $this->dates['today']=date("Y-m-d");
    31                 $this->dates['first_current']=date("Y-m-").'01';
    32                 $this->dates['last_old']=date("Y-m-d",strtotime($this->dates['first_current']." -1 days"));
    33                 $this->dates['first_old']=date("Y-m-",strtotime($this->dates['today']. "-1 months")).'01';
    34                 $this->dates['last_very_old']=date("Y-m-d",strtotime($this->dates['first_old']." -1 days"));
    35                 $this->dates['first_very_old']=date("Y-m-",strtotime($this->dates['first_old']." -1 days")).'01';
    36                 $this->dates['date_current']="(date between '".$this->dates['first_current']."' and '".$this->dates['today']."')";
    37                 $this->dates['date_old']="(date between '".$this->dates['first_old']."' and '".$this->dates['last_old']."')";
    38                 $this->dates['date_very_old']="(date between '".$this->dates['first_very_old']."' and '".$this->dates['last_very_old']."')";
    39                 $this->dates['date_range_last_three_months']="(date between '".$this->dates['first_very_old']."' and '".$this->dates['today']."')";
    40 
    41         }
    42         function connect(){
    43                 $this->dbconn=new mysqli($this->dbhost, $this->dbuser , $this->dbpass, $this->dbname);
    44                 if ($this->dbconn->connect_error) {
    45                     die('Connect Error:'. $this->dbconn->connect_error);
    46                 }
    47         }
    48         function disconnect(){
    49                 $this->dbconn->close();
    50         }
    51         function init_trans(){
    52                 $this->dbconn->autocommit(FALSE);
    53                 $this->dbconn->begin_transaction(MYSQLI_TRANS_START_READ_WRITE);
    54         }
     95     private $dbhost;
     96     private $dbname;
     97     private $dbuser;
     98     private $dbpass;
     99     private $ka_file='/var/run/analyticsd.keepalive';
     100     private $alias;
     101     public $dbconn;
     102
     103     function DB(){
     104         require_once('config.php');
     105         global $dbhost,$dbname,$dbpass,$dbuser,$distros;
     106
     107         $this->dbhost=$dbhost;
     108         $this->dbname=$dbname;
     109         $this->dbpass=$dbpass;
     110         $this->dbuser=$dbuser;
     111         $this->alias=array();
     112         $this->info_distro=json_decode($distros,true);
     113         if ($this->info_distro == NULL){
     114             die('Error: Wrong json in Config.php');
     115         }
     116         $this->init_dates();
     117         $this->times=0;
     118     }
     119     function init_dates(){
     120         $this->dates=array();
     121         $this->dates['today']=date("Y-m-d");
     122         $this->dates['first_current']=date("Y-m-").'01';
     123         $this->dates['last_old']=date("Y-m-d",strtotime($this->dates['first_current']." -1 days"));
     124         $this->dates['first_old']=date("Y-m-",strtotime($this->dates['today']. "-1 months")).'01';
     125         $this->dates['last_very_old']=date("Y-m-d",strtotime($this->dates['first_old']." -1 days"));
     126         $this->dates['first_very_old']=date("Y-m-",strtotime($this->dates['first_old']." -1 days")).'01';
     127         $this->dates['date_current']="(date between '".$this->dates['first_current']."' and '".$this->dates['today']."')";
     128         $this->dates['date_old']="(date between '".$this->dates['first_old']."' and '".$this->dates['last_old']."')";
     129         $this->dates['date_very_old']="(date between '".$this->dates['first_very_old']."' and '".$this->dates['last_very_old']."')";
     130         $this->dates['date_range_last_three_months']="(date between '".$this->dates['first_very_old']."' and '".$this->dates['today']."')";
     131     }
     132     function connect(){
     133        $this->dbconn=new mysqli($this->dbhost, $this->dbuser , $this->dbpass, $this->dbname);
     134        if ($this->dbconn->connect_error) {
     135            die('Connect Error:'. $this->dbconn->connect_error);
     136        }
     137     }
     138     function disconnect(){
     139         $this->dbconn->close();
     140     }
     141     function init_trans(){
     142         $this->dbconn->autocommit(FALSE);
     143         $this->dbconn->begin_transaction(MYSQLI_TRANS_START_READ_WRITE);
     144     }
    55145
    56146        function send_data($user,$version,$sabor,$apps,$date=''){
     
    136226        }
    137227
    138         private function load_alias(){
    139                 $sql="SELECT name,alias from Alias";
    140                 $result=$this->dbconn->query($sql);
    141                 while($row=$result->fetch_array(MYSQLI_ASSOC)){
    142                         $this->alias[$row['name']]=$row['alias'];
    143                 }
    144         }
    145         function get_extended_data($app){
    146             $today=date("Y-m-d");
    147             $min_date=date("Y-m",strtotime($today." -1 year")).'-01';
    148             $this->times=0;
    149             // CLIENTS DISTRIBUTION PER RELEASE/FLAVOUR
    150             $sql="select year(date) as year,month(date) as month,Releases_name,Flavours_name,count(*) as num_hosts from (select distinct Client_uid,date,Releases_name,Flavours_name from Client_Versions where date >= '$min_date' )t group by year,month,Releases_name,Flavours_name order by year Desc,month desc,Releases_name asc,num_hosts desc";
    151             $stime=microtime(true);
    152             $result=$this->dbconn->query($sql);
    153             if ($result){
    154                 $this->times+=microtime(true)-$stime;
    155                 $clients_month=[];
    156                 $tmp=[];
    157                 while($row=$result->fetch_array(MYSQLI_ASSOC)){
    158                     $date=$row['year'].'_'.$row['month'];
    159                     $tmp[$date][$row['Releases_name']][$row['Flavours_name']]=intval($row['num_hosts']);
    160                 }
    161                 foreach ($tmp as $date){
    162                     $clients_month[]=$date;
    163                 }
    164             }else{
    165                 $clients_month=$this->dbconn->error;
    166             }
    167             // CLIENT UPDATES
    168             $sql="select year,month,count(*) as nclients,sum(cnt)-count(*) as nclients_updated from (select Client_uid,count(Client_uid) as cnt,year(date) as year,month(date) as month from Client_Versions where date >= '$min_date' GROUP by Client_uid,year,month having count(Client_uid) >= 1 ) t group by year,month order by year desc,month desc";
    169             $sql="select year,month,count(*) as nclients,sum(cnt)-count(*) as nclients_updated,Releases_name as rel,Flavours_name as fla from (select Client_uid,count(Client_uid) as cnt,year(date) as year,month(date) as month,Releases_name,Flavours_name from Client_Versions where date >= '$min_date' GROUP by Client_uid,year,month,Releases_name,Flavours_name having count(Client_uid) >= 1 ) t group by year,month,Releases_name,Flavours_name order by year desc,month desc";
    170             $stime=microtime(true);
    171             $result=$this->dbconn->query($sql);
    172             if ($result){
    173                 $this->times+=microtime(true)-$stime;
    174                 $i=0;
    175                 $tmp=[];
    176                 while($row=$result->fetch_array(MYSQLI_ASSOC)){
    177                     $date=$row['year'].'_'.$row['month'];
    178                     $tmp[$date][$row['rel']][$row['fla']]=intval($row['nclients_updated']);
    179                 }
    180                 foreach($tmp as $date){
    181                     $num_updates_month[]=$date;
    182                 }
    183             }else{
    184                 $num_updates_month=$this->dbconn->error;
    185             }
    186             // CLIENT CHANGE RELEASE
    187             $sql="select year,month,count(*) as upgrades_en_mes from (select year,month,Client_uid as cliente_upgradeado from (select Client_uid,year(date) as year,month(date) as month from Client_Versions where date >= '$min_date' GROUP by Client_uid,Releases_name,year,month)t group by month,year,Client_uid having(count(*))>1)t group by year,month order by year desc,month desc limit 12";
    188             $stime=microtime(true);
    189             $result=$this->dbconn->query($sql);
    190             if ($result){
    191                 $this->times+=microtime(true)-$stime;
    192                 $change_releases=[0,0,0,0,0,0,0,0,0,0,0,0];
    193                 $i=0;
    194                 while($row=$result->fetch_array(MYSQLI_ASSOC)){
    195                     $change_releases[$i++]=intval($row['upgrades_en_mes']);
    196                 }
    197             }else{
    198                 $change_releases=$this->dbconn->error;
    199             }
    200             // CLIENT CHANGE FLAVOUR
    201             $sql="select year,month,count(*) as cambio_sabor_en_mes from (select year,month,Client_uid as cliente_upgradeado from (select Client_uid,year(date) as year,month(date) as month from Client_Versions where date >= '$min_date' GROUP by Client_uid,Flavours_name,year,month)t group by month,year,Client_uid having(count(*))>1)t group by year,month order by year desc,month desc limit 12";
    202             $stime=microtime(true);
    203             $result=$this->dbconn->query($sql);
    204             if ($result){
    205                 $this->times+=microtime(true)-$stime;
    206                 $i=0;
    207                 $change_flavour=[0,0,0,0,0,0,0,0,0,0,0,0];
    208                 while($row=$result->fetch_array(MYSQLI_ASSOC)){
    209                     $change_flavour[$i++]=intval($row['cambio_sabor_en_mes']);
    210                 }
    211             }else{
    212                 $change_flavour=$this->dbconn->error;
    213             }
    214            
    215             //sanitize input
    216             if ($app != NULL){
    217                 $app=preg_grep('/^[a-zA-Z0-9\-_]+$/',array($app));
    218                 if ($app != NULL and isset($app[0])){
    219                     $app=$this->dbconn->real_escape_string($app[0]);
    220                     $stats['apps']=[];
    221                     $stats['apps']['app']=$app;
    222                     $sql="select year(date) as year,month(date) as month,string,Releases_name as rel,Flavours_name as fla,sum(count) as count from RecvPackages where string='$app' and date >= '$min_date' group by year,month,Releases_name,Flavours_name order by year desc,month desc,sum(count) desc";
    223                     $stime=microtime(true);
    224                     $result=$this->dbconn->query($sql);
    225                     if ($result){
    226                         $this->times+=microtime(true)-$stime;
    227                         $tmp=[];
    228                         while($row=$result->fetch_array(MYSQLI_ASSOC)){
    229                             $date=$row['year'].'_'.$row['month'];
    230                             $tmp[$date][$row['rel']][$row['fla']]=intval($row['count']);
    231                         }
    232                         foreach($tmp as $date){
    233                             $app_use[]=$date;
    234                         }
    235                         $stats['apps']['app_use']=$app_use;
    236                     }else{
    237                         $app_use=$this->dbconn->error;
    238                     }
    239                 }
    240             }
    241             // FINALIZATION & WRITE STRUCTURE
    242             if (isset($clients_month)){
    243                 $stats['clients']['clients_per_month']=$clients_month;
    244             }
    245             if (isset($num_updates_month)){
    246                 $stats['clients']['freq_updates_per_month']=$num_updates_month;
    247             }
    248             if (isset($change_releases)){
    249                 $stats['clients']['change_releases']=$change_releases;
    250             }
    251             if (isset($change_flavour)){
    252                 $stats['clients']['change_flavours']=$change_flavour;
    253             }
    254             $stats['debug_query_time']=strval(number_format($this->times,5));
    255             if (file_exists($this->ka_file)){
    256                     $stats['debug_keep_alive']=date('Y-m-d H:i',file_get_contents($this->ka_file));
    257             }
    258             return json_encode($stats);
    259         }
    260 
    261         function get_historic_data(){
    262                 $this->load_alias();
    263                 $obj=[];
    264                 $this->times=0;
    265                 foreach ($this->info_distro['distros'] as $distro){
    266                         $dname=$distro['name'];
    267                         $dlike=$distro['like'];
    268                         $obj[$dname]=array();
    269                         foreach ($distro['sabor'] as $sabor){
    270                                 $sname=$sabor['name'];
    271                                 $slike=$sabor['like'];
    272                                 $obj[$dname][$sname][]=$this->get_chart($dlike,$slike,'current');
    273                                 $obj[$dname][$sname][]=$this->get_chart($dlike,$slike,'old');
    274                                 $obj[$dname][$sname][]=$this->get_chart($dlike,$slike,'very_old');
    275                         }
    276                 }
    277                 $obj['debug_query_time']=strval(number_format($this->times,3));
    278                
    279                 if (file_exists($this->ka_file)){
    280                     $obj['debug_keep_alive']=date('Y-m-d H:i',file_get_contents($this->ka_file));
    281                 }
    282                 return json_encode($obj);
    283         }
    284         function get_chart($version='',$sabor='',$type='current'){
    285                 if ($version != ''){
    286                     $version = " and Releases_name = '$version' ";
    287                 }
    288                 if ($sabor != ''){
    289                     $sabor = " and Flavours_name = '$sabor' ";
    290                 }
    291                 $order=" order by count desc limit 10 ";
    292                 $group=" group by app ";
    293                
    294                 $where=$this->dates['date_'.$type]." $version $sabor ";
    295                 $where_clients=$this->dates['date_'.$type]." $version $sabor ";
    296 
    297                 $sql="SELECT string as app,sum(count) as count from RecvPackages where $where $group $order";
    298                 $sql_clients = "select count(distinct Client_uid) as count from Client_Versions where $where_clients $order";
    299 
    300                 return array($this->get_result_from_sql($sql),$this->get_clients_from_sql($sql_clients));
    301         }
    302         function get_clients_from_sql($sql){
    303                 $stime=microtime(true);
    304                 if ($result=$this->dbconn->query($sql)){
    305                         $etime=microtime(true);
    306                         $this->times+=($etime-$stime);
    307                         while($row=$result->fetch_array(MYSQLI_ASSOC)){
    308                                 if (isset($row['count'])){
    309                                         return array('nclients'=>$row['count']);
    310                                 }
    311                         }
    312                         return array('nclients'=>'not available');
    313                 }else{
    314                         return array('nclients'=>$this->dbconn->error);
    315                 }
    316                
    317         }
    318         function get_result_from_sql($sql){
    319                 $stime=microtime(true);
    320                 if ($result=$this->dbconn->query($sql)){
    321                         $etime=microtime(true);
    322                         $this->times+=($etime-$stime);
    323                         $obj2=[];
    324                         $nobj=0;
    325                         while($row=$result->fetch_array(MYSQLI_ASSOC)){
    326                                 if (array_key_exists($row['app'],$this->alias)){
    327                                         if (! empty($this->alias[$row['app']])){
    328                                                 if ($nobj < 10)
    329                                                         $obj2[$this->alias[$row['app']]]=$row['count'];
    330                                                 $nobj++;
    331                                         }
    332                                 }else{
    333                                         if ($nobj < 10)
    334                                                 $obj2[$row['app']]=$row['count'];
    335                                         $nobj++;
    336                                 }
    337                         }
    338                         return $obj2;
    339                 }else{
    340                     return $this->dbconn->error;
    341                 }
    342         }
     228     private function load_alias(){
     229         $sql="SELECT name,alias from Alias";
     230         $result=$this->dbconn->query($sql);
     231         while($row=$result->fetch_array(MYSQLI_ASSOC)){
     232             $this->alias[$row['name']]=$row['alias'];
     233         }
     234     }
     235        function get_system_data(){
     236            $sql="select * from Config";
     237            $result=$this->dbconn->query($sql);
     238            if ($result){
     239                $tmp=[];
     240                foreach ($result->fetch_all(MYSQLI_ASSOC) as $value){
     241                    $tmp[$value['name']]=$value['value'];
     242                }
     243                return json_encode($tmp);
     244            }
     245        }
     246     function get_extended_data($app){
     247         $today=date("Y-m-d");
     248         $min_date=date("Y-m",strtotime($today." -1 year")).'-01';
     249         $this->times=0;
     250         // CLIENTS DISTRIBUTION PER RELEASE/FLAVOUR
     251         $sql="select year(date) as year,month(date) as month,Releases_name,Flavours_name,count(*) as num_hosts from (select distinct Client_uid,date,Releases_name,Flavours_name from Client_Versions where date >= '$min_date' )t group by year,month,Releases_name,Flavours_name order by year Desc,month desc,Releases_name asc,num_hosts desc";
     252
     253            $cache = new Cache;
     254            $cache_key='extended_1';
     255            $data = $cache->get($cache_key);
     256            $stime=microtime(true);
     257            if ($data != false){
     258                $clients_month=$data;
     259            }else{
     260             $result=$this->dbconn->query($sql);
     261                if ($result){
     262                 $this->times+=microtime(true)-$stime;
     263                 $clients_month=[];
     264                 $tmp=[];
     265                 while($row=$result->fetch_array(MYSQLI_ASSOC)){
     266                     $date=$row['year'].'_'.$row['month'];
     267                     $tmp[$date][$row['Releases_name']][$row['Flavours_name']]=intval($row['num_hosts']);
     268                 }
     269                 foreach ($tmp as $date){
     270                     $clients_month[]=$date;
     271                 }
     272                    $cache->store($clients_month,$cache_key);
     273             }else{
     274                 $clients_month=$this->dbconn->error;
     275             }
     276            }
     277
     278         
     279         // CLIENT UPDATES
     280         $sql="select year,month,count(*) as nclients,sum(cnt)-count(*) as nclients_updated from (select Client_uid,count(Client_uid) as cnt,year(date) as year,month(date) as month from Client_Versions where date >= '$min_date' GROUP by Client_uid,year,month having count(Client_uid) >= 1 ) t group by year,month order by year desc,month desc";
     281         $sql="select year,month,count(*) as nclients,sum(cnt)-count(*) as nclients_updated,Releases_name as rel,Flavours_name as fla from (select Client_uid,count(Client_uid) as cnt,year(date) as year,month(date) as month,Releases_name,Flavours_name from Client_Versions where date >= '$min_date' GROUP by Client_uid,year,month,Releases_name,Flavours_name having count(Client_uid) >= 1 ) t group by year,month,Releases_name,Flavours_name order by year desc,month desc";
     282
     283            $cache_key='extended_2';
     284            $data = $cache->get($cache_key);
     285            $stime=microtime(true);
     286            if ($data != false){
     287                $num_updates_month=$data;
     288            }else{
     289                $result=$this->dbconn->query($sql);
     290
     291             if ($result){
     292                 $this->times+=microtime(true)-$stime;
     293                 $i=0;
     294             $tmp=[];
     295                 while($row=$result->fetch_array(MYSQLI_ASSOC)){
     296                     $date=$row['year'].'_'.$row['month'];
     297                 $tmp[$date][$row['rel']][$row['fla']]=intval($row['nclients_updated']);
     298                 }
     299             foreach($tmp as $date){
     300                 $num_updates_month[]=$date;
     301             }
     302                    $cache->store($num_updates_month,$cache_key);
     303             }else{
     304                 $num_updates_month=$this->dbconn->error;
     305             }
     306            }
     307
     308
     309         // CLIENT CHANGE RELEASE
     310         $sql="select year,month,count(*) as upgrades_en_mes from (select year,month,Client_uid as cliente_upgradeado from (select Client_uid,year(date) as year,month(date) as month from Client_Versions where date >= '$min_date' GROUP by Client_uid,Releases_name,year,month)t group by month,year,Client_uid having(count(*))>1)t group by year,month order by year desc,month desc limit 12";
     311
     312
     313            $cache_key='extended_3';
     314            $data = $cache->get($cache_key);
     315            $stime=microtime(true);
     316            if ($data != false){
     317                $change_releases=$data;
     318            }else{
     319                $result=$this->dbconn->query($sql);
     320
     321                if ($result){
     322                 $this->times+=microtime(true)-$stime;
     323                 $change_releases=[0,0,0,0,0,0,0,0,0,0,0,0];
     324                 $i=0;
     325                 while($row=$result->fetch_array(MYSQLI_ASSOC)){
     326                     $change_releases[$i++]=intval($row['upgrades_en_mes']);
     327                 }
     328                    $cache->store($change_releases,$cache_key);
     329             }else{
     330                 $change_releases=$this->dbconn->error;
     331             }
     332            }
     333
     334         
     335         // CLIENT CHANGE FLAVOUR
     336         $sql="select year,month,count(*) as cambio_sabor_en_mes from (select year,month,Client_uid as cliente_upgradeado from (select Client_uid,year(date) as year,month(date) as month from Client_Versions where date >= '$min_date' GROUP by Client_uid,Flavours_name,year,month)t group by month,year,Client_uid having(count(*))>1)t group by year,month order by year desc,month desc limit 12";
     337
     338            $cache_key='extended_4';
     339            $data = $cache->get($cache_key);
     340            $stime=microtime(true);
     341            if ($data != false){
     342                $change_flavour=$data;
     343            }else{
     344                $result=$this->dbconn->query($sql);
     345
     346             if ($result){
     347                 $this->times+=microtime(true)-$stime;
     348                 $i=0;
     349                 $change_flavour=[0,0,0,0,0,0,0,0,0,0,0,0];
     350                 while($row=$result->fetch_array(MYSQLI_ASSOC)){
     351                     $change_flavour[$i++]=intval($row['cambio_sabor_en_mes']);
     352                 }
     353                    $cache->store($change_flavour,$cache_key);
     354             }else{
     355                 $change_flavour=$this->dbconn->error;
     356             }
     357            }
     358         
     359         //sanitize input
     360         if ($app != NULL){
     361             $app=preg_grep('/^[a-zA-Z0-9\-_]+$/',array($app));
     362             if ($app != NULL and isset($app[0])){
     363                 $app=$this->dbconn->real_escape_string($app[0]);
     364                 $stats['apps']=[];
     365                 $stats['apps']['app']=$app;
     366                 $sql="select year(date) as year,month(date) as month,string,Releases_name as rel,Flavours_name as fla,sum(count) as count from RecvPackages where string='$app' and date >= '$min_date' group by year,month,Releases_name,Flavours_name order by year desc,month desc,sum(count) desc";
     367
     368                    $cache_key="extended_app_$app";
     369                    $data = $cache->get($cache_key);
     370                    $stime=microtime(true);
     371                    if ($data != false){
     372                        $app_use=$data;
     373                        $stats['apps']['app_use']=$app_use;
     374                    }else{
     375                        $result=$this->dbconn->query($sql);
     376                        if ($result){
     377                         $this->times+=microtime(true)-$stime;
     378                         $tmp=[];
     379                         while($row=$result->fetch_array(MYSQLI_ASSOC)){
     380                             $date=$row['year'].'_'.$row['month'];
     381                         $tmp[$date][$row['rel']][$row['fla']]=intval($row['count']);
     382                         }
     383                     foreach($tmp as $date){
     384                         $app_use[]=$date;
     385                     }
     386                            $cache->store($app_use,$cache_key);
     387                         $stats['apps']['app_use']=$app_use;
     388                     }else{
     389                         $app_use=$this->dbconn->error;
     390                     }
     391                    }
     392
     393             }
     394         }
     395         // FINALIZATION & WRITE STRUCTURE
     396         if (isset($clients_month)){
     397             $stats['clients']['clients_per_month']=$clients_month;
     398         }
     399         if (isset($num_updates_month)){
     400             $stats['clients']['freq_updates_per_month']=$num_updates_month;
     401         }
     402         if (isset($change_releases)){
     403             $stats['clients']['change_releases']=$change_releases;
     404         }
     405         if (isset($change_flavour)){
     406             $stats['clients']['change_flavours']=$change_flavour;
     407         }
     408         $stats['debug_query_time']=strval(number_format($this->times,5));
     409         if (file_exists($this->ka_file)){
     410             $stats['debug_keep_alive']=date('Y-m-d H:i',file_get_contents($this->ka_file));
     411         }
     412         return json_encode($stats);
     413     }
     414
     415     function get_historic_data(){
     416         $this->load_alias();
     417         $obj=[];
     418         $this->times=0;
     419         foreach ($this->info_distro['distros'] as $distro){
     420             $dname=$distro['name'];
     421             $dlike=$distro['like'];
     422             $obj[$dname]=array();
     423             foreach ($distro['sabor'] as $sabor){
     424                 $sname=$sabor['name'];
     425                 $slike=$sabor['like'];
     426                 $obj[$dname][$sname][]=$this->get_chart($dlike,$slike,'current');
     427                 $obj[$dname][$sname][]=$this->get_chart($dlike,$slike,'old');
     428                 $obj[$dname][$sname][]=$this->get_chart($dlike,$slike,'very_old');
     429             }
     430         }
     431         $obj['debug_query_time']=strval(number_format($this->times,3));
     432         
     433         if (file_exists($this->ka_file)){
     434             $obj['debug_keep_alive']=date('Y-m-d H:i',file_get_contents($this->ka_file));
     435         }
     436         return json_encode($obj);
     437     }
     438    function get_chart($version='',$sabor='',$type='current'){
     439        $cache_key="$version"."_"."$sabor"."_"."$type";
     440        if ($version != ''){
     441            $version = " and Releases_name = '$version' ";
     442        }
     443        if ($sabor != ''){
     444            $sabor = " and Flavours_name = '$sabor' ";
     445        }
     446        $order=" order by count desc limit 10 ";
     447        $group=" group by app ";
     448
     449        $where=$this->dates['date_'.$type]." $version $sabor ";
     450        $where_clients=$this->dates['date_'.$type]." $version $sabor ";
     451
     452        $sql="SELECT string as app,sum(count) as count from RecvPackages where $where $group $order";
     453        $sql_clients = "select count(distinct Client_uid) as count from Client_Versions where $where_clients $order";
     454
     455        $cache = new Cache;
     456        $data = $cache->get($cache_key);
     457        if ($data != false){
     458            return $data;
     459        }else{
     460            $data=array($this->get_result_from_sql($sql),$this->get_clients_from_sql($sql_clients));
     461            $cache->store($data,$cache_key);
     462            return $data;
     463        }
     464     }
     465     function get_clients_from_sql($sql){
     466             $stime=microtime(true);
     467         if ($result=$this->dbconn->query($sql)){
     468                 $etime=microtime(true);
     469                 $this->times+=($etime-$stime);
     470             while($row=$result->fetch_array(MYSQLI_ASSOC)){
     471                 if (isset($row['count'])){
     472                     return array('nclients'=>$row['count']);
     473                 }
     474             }
     475             return array('nclients'=>'not available');
     476         }else{
     477             return array('nclients'=>$this->dbconn->error);
     478         }
     479
     480     }
     481     function get_result_from_sql($sql){
     482             $stime=microtime(true);
     483         if ($result=$this->dbconn->query($sql)){
     484                 $etime=microtime(true);
     485                 $this->times+=($etime-$stime);
     486             $obj2=[];
     487             $nobj=0;
     488             while($row=$result->fetch_array(MYSQLI_ASSOC)){
     489                 if (array_key_exists($row['app'],$this->alias)){
     490                     if (! empty($this->alias[$row['app']])){
     491                         if ($nobj < 10)
     492                             $obj2[$this->alias[$row['app']]]=$row['count'];
     493                         $nobj++;
     494                     }
     495                 }else{
     496                     if ($nobj < 10)
     497                         $obj2[$row['app']]=$row['count'];
     498                     $nobj++;
     499                 }
     500             }
     501             return $obj2;
     502         }else{
     503             return $this->dbconn->error;
     504         }
     505     }
    343506
    344507}
  • lliurex-analytics-server/trunk/fuentes/lliurex-analytics-server/usr/lib/analytics-server/analytics/functions.php

    r6508 r6767  
    4949}
    5050
     51function call_get_system_stats(){
     52    return function($request,$response,$service){
     53        $db = new DB;
     54        $db->connect();
     55        echo $db->get_system_data();
     56        $db->disconnect();
     57    };
     58}
     59
    5160function call_get_extended_stats(){
    5261        return function($request,$reponse,$service){
     
    6978    <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
    7079    <script type="text/javascript" src="jquery.min.js"></script>
    71     <script type="text/javascript" src="graph.js"></script>
     80    <script type="text/javascript" src="graph_min.js"></script>
    7281
    7382    <script type="text/javascript">
     
    7584        google.charts.setOnLoadCallback(doChart);
    7685    </script>
    77     <script type="text/javascript" src="jquery.min.js"></script>
    78     <script type="text/javascript" src="graph.js"></script>
    7986    <link href="ui/jquery-ui.css" rel="stylesheet">
    8087    <link href="graph.css" rel="stylesheet">
     
    9299}
    93100
     101function call_show_system_stats(){
     102
     103return function($request,$reponse,$service){
     104
     105echo '<html>
     106  <head>
     107    <!--Load the AJAX API-->
     108    <!--<script type="text/javascript" src="https://www.google.com/jsapi"></script>-->
     109    <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
     110    <script type="text/javascript" src="jquery.min.js"></script>
     111    <script type="text/javascript" src="sysstats_min.js"></script>
     112    <script type="text/javascript">
     113        google.charts.load("current", {packages: ["corechart"],"language":"es"});
     114        google.charts.setOnLoadCallback(initialize);
     115    </script>
     116    <link href="ui/jquery-ui.css" rel="stylesheet">
     117    <link href="graph.css" rel="stylesheet">
     118    <script type="text/javascript" src="ui/jquery-ui.js"></script>
     119  </head>
     120  <body>
     121  <div id="chart_div"></div>
     122  </body>
     123</html>
     124';
     125
     126};
     127
     128}
    94129function call_show_extended_stats(){
    95130
     
    102137    <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
    103138    <script type="text/javascript" src="jquery.min.js"></script>
    104     <script type="text/javascript" src="graph.js"></script>
     139    <script type="text/javascript" src="graph_min.js"></script>
    105140
    106141    <script type="text/javascript">
     
    108143        google.charts.setOnLoadCallback(doExtendedChart);
    109144    </script>
    110     <script type="text/javascript" src="jquery.min.js"></script>
    111     <script type="text/javascript" src="graph.js"></script>
    112145    <link href="ui/jquery-ui.css" rel="stylesheet">
    113146    <link href="graph.css" rel="stylesheet">
  • lliurex-analytics-server/trunk/fuentes/lliurex-analytics-server/usr/lib/analytics-server/analytics/graph.js

    r5926 r6767  
    11function drawChart(datos,title,id) {
    22  var custom_width=$('#'+id).parent().width()*0.95;
    3   var custom_height=$(window).height()/3*0.60;
     3  var custom_height=$(window).height()/3*0.75;
    44
    55  // Set chart options
     
    88                 height:custom_height,
    99                 fontSize: 10,
     10                 legend: 'none',
    1011                 hAxis: {
    1112                    viewWindow:{
     
    1314                    }
    1415                 },
    15                 chartArea:{left:'10%',right:'10%'},
     16                chartArea:{left:'5%',right:'1%'},
    1617                };
    1718
     
    3031
    3132function get_sizes(id){
    32     var custom_width=$('#'+id).parent().width()*0.90;
     33    var custom_width=$('#'+id).parent().width()*0.95;
    3334    var custom_height=$(window).height()*0.72/2;
    3435    return {'width':custom_width,'height':custom_height};
     
    8081                    isStacked: false,
    8182                    hAxis:{title:'Months',ticks:dates_axis,format:'MMM'},
    82                     vAxis:{title:'Num hosts'},
    83                     legend:{textStyle:{fontSize: 12}},
    84                     chartArea:{left:'10%',right:'10%'},
     83                    vAxis:{title:'Num hosts',viewWindow : {min:0}},
     84                    legend:{textStyle:{fontSize: 10}},
     85                    chartArea:{left:'5%',right:'10%'},
    8586                    focusTarget: 'category',
    8687                    colors:['blue','red','grey'],
     
    131132                    isStacked: false,
    132133                    hAxis:{title:'Months',ticks:dates_axis,format:'MMM'},
    133                     vAxis:{title:'Num hosts'},
    134                     legend:{textStyle:{fontSize: 12}},
    135                     chartArea:{left:'10%',right:'10%'},
     134                    vAxis:{title:'Num hosts',viewWindow : {min:0}},
     135                    legend:{textStyle:{fontSize: 10}},
     136                    chartArea:{left:'5%',right:'10%'},
    136137                    focusTarget: 'category',
    137138                    colors: ['purple','teal','gold','olive','grey'],
     
    161162                    hAxis:{title:'Months',ticks:dates_axis,format:'MMM'},
    162163                    vAxis:{title:'Num hosts',minValue: 0,maxValue:'automatic',viewWindowMode:'pretty',viewWindow:{min:0,max:'auto'}},
    163                     legend:{textStyle:{fontSize: 12}},
     164                    legend:{textStyle:{fontSize: 10}},
    164165                    chartArea:{left:'10%',right:'10%'},
    165166                    focusTarget: 'category',
     
    178179    $('#accordion').append('<div id="loading"></div>');
    179180    $.getJSON( "./GetExtendedStats"+parameter, function( json ) {
    180     $('#loading').remove();
    181181    end_get_time=get_time();
    182182    start_graph_time=end_get_time;
     
    281281    }
    282282
    283 
     283    $('#loading').remove();
    284284    $('#accordion').accordion({active:false,collapsible:true});
    285285    if (app != null){
     
    311311    $('#accordion').append('<div id="loading"></div>');
    312312    $.getJSON( "./GetStats", function( json ) {
    313         $('#loading').remove();
     313       
    314314        end_get_time=get_time();
    315315        start_graph_time=end_get_time;
     
    370370    num_ready++;
    371371    if (num_ready == max_graph){
     372        $('#accordion>#loading').remove()
    372373        $('#accordion').accordion({active:false,collapsible:true});
     374
    373375    }
    374376}
  • lliurex-analytics-server/trunk/fuentes/lliurex-analytics-server/usr/lib/analytics-server/analytics/reports.php

    r5560 r6767  
    1717$klein->respond('GET','/ShowExtendedStats',call_show_extended_stats());
    1818$klein->respond('GET','/GetExtendedStats',call_get_extended_stats());
     19$klein->respond('GET','/SystemStats',call_get_system_stats());
     20$klein->respond('GET','/ShowSystemStats',call_show_system_stats());
    1921$klein->respond('POST','/notify',call_bd());
    2022
  • lliurex-analytics-server/trunk/fuentes/lliurex-analytics-server/usr/sbin/analyticsd

    r5932 r6767  
    1 #!/usr/bin/python
     1#!/usr/bin/python3
    22
    33import time
     
    1010import signal
    1111import os
    12 import Queue
     12import queue
    1313import hashlib
    1414import gc
     
    2222import logging.handlers
    2323from logging import config
     24from functools import reduce
     25import traceback
    2426
    2527##### START EDITABLE VARS #####
    2628
    2729DEBUG=False
     30MIN_LOG_LEVEL=logging.INFO
    2831DAEMON=True
    2932FILE='/usr/lib/analytics-server/analytics/config.php'
    30 LIMIT=5.0
     33LIMIT=70.0       # PERCENTAGE LOAD LIMIT
    3134
    3235##### END EDITABLE VARS #####
    3336
    34 DEBUG_PRINT_ALIVE_COUNTER=10
     37DEBUG_PRINT_ALIVE_COUNTER=60
    3538THREADED=True
    3639
    3740if DEBUG:
    38     loglevel=logging.DEBUG
     41    if MIN_LOG_LEVEL:
     42        loglevel=MIN_LOG_LEVEL
     43    else:
     44        loglevel=logging.DEBUG
    3945else:
    4046    loglevel=logging.INFO
     
    7177    }
    7278
     79def to_str(x):
     80    if isinstance(x,str):
     81        return to_utf(x).decode('unicode_escape')
     82    else:
     83        return x
     84
     85def to_utf(x):
     86    if isinstance(x,str):
     87        return x.encode('utf-8')
     88    else:
     89        return x
    7390
    7491def printea(msg="",level='critical'):
     
    90107                DEBUG_PRINT_ALIVE_COUNTER=DEBUG_PRINT_ALIVE_COUNTER-1
    91108            else:
    92                 DEBUG_PRINT_ALIVE_COUNTER=10
     109                DEBUG_PRINT_ALIVE_COUNTER=60
    93110                printea('on {} analyticsd({}) is alive, all good :-)'.format(t,who),'info')
    94111
     
    105122IP=None
    106123
    107 
    108 EMPTY_PAUSED_SLEEP=10
     124EMPTY_PAUSED_SLEEP=1
    109125CHECK_LOAD_TIME=5
    110126MAX_RETRIES=5
     
    150166    def __init__(self,mon,t='main'):
    151167        self.t=t
    152         self.reconnect=1
     168        self.reconnect=0
    153169        self.empty = False
    154170        self.conn=None
    155171        self.mon=mon
    156         self.q=Queue.Queue()
     172        self.q=queue.Queue()
    157173        self.processed=0
     174        self.need_wait = False
     175        self.need_clean = False
    158176        printea('Database worker {} initialized'.format(t),'info')
    159177
     
    217235            self.cur = self.conn.cursor()
    218236            self.cur.execute("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")
     237            variables=self.check_server_variables()
     238            if variables:
     239                self.mon.server_variables=variables
    219240            printea("Connected succesfully {}".format(self.t),'info')
    220241
    221         except mdb.Error, e:
     242        except mdb.Error as e:
    222243            printea("Error {}: {}".format(e.args[0],e.args[1]))
    223244            raise Exception(e)
     245
     246    def check_server_variables(self):
     247        if self.t != 'main':
     248            return None
     249        else:
     250            printea('Getting server variables','info')
     251            result = {}
     252            self.cur.execute("show global variables")
     253            printea('Setting {} vars'.format(self.cur.rowcount),'debug')
     254            if self.cur.rowcount > 0:
     255                for i in range(self.cur.rowcount):
     256                    var_name, var_value = self.cur.fetchone()
     257                    result.setdefault(var_name,var_value)
     258            return result
     259
     260    def get_config(self):
     261        values={}
     262        self.cur.execute('select name,value from Config')
     263        for val in self.cur.fetchall():
     264            values.setdefault(val[0],val[1])
     265        return values
     266
     267    def put_config(self,values):
     268        vals=[]
     269        for x in values.keys():
     270            vals.append("('{}','{}')".format(x,values[x]))
     271        try:
     272            self.cur.execute("insert into Config(`name`, `value`) values {} on duplicate key update name=VALUES(name), value=VALUES(value);".format(','.join(vals)))
     273            self.conn.commit()
     274        except Exception as e:
     275            print(e)
     276
     277    def check_temporary_tables_size(self,table_name):
     278        if self.t != 'load':
     279            return None
     280        else:
     281            size = 0
     282            rows = 0
     283            self.cur.execute('select round(((data_length + index_length - data_free) / 1024 / 1024),2) `size`,table_rows from information_schema.TABLES where table_schema = "analytics" and table_name = "{}";'.format(table_name))
     284
     285            res=self.cur.fetchone()
     286            size = float(res[0])
     287            rows = int(res[1])
     288            return (int(size),rows)
    224289
    225290    def close_db(self):
     
    252317
    253318    def gen_uuid(self,*args,**kwargs):
    254         return int(hashlib.sha1('-'.join([str(x) for x in args])).hexdigest()[0:16],16)
     319        try:
     320            string=to_utf(u'-'.join([str(x) for x in args]))
     321            h=hashlib.sha1(string)
     322            return int(h.hexdigest()[0:16],16)
     323        except Exception as e:
     324            print(traceback.format_exc())
    255325
    256326    @timed
     
    258328    def get_client(self,*args,**kwargs):
    259329        try:
    260             query="SELECT id,date,user,version,sabor from tmp_clients where status=1 LIMIT {}".format(self.mon.select_window)
     330            query="SELECT id,date,user,version,sabor from tmp_clients where status=1 LIMIT {}".format(int(self.mon.select_window))
    261331            self.execute(query=query)
    262332            ret =[]
     
    357427    def reset_autoinc(self):
    358428        try:
    359             query = "SELECT AUTO_INCREMENT FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '{}' AND TABLE_NAME = 'tmp_clients'".format(DBNAME)
     429            query = "SELECT AUTO_INCREMENT FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '{}' AND TABLE_NAME = 'tmp_packages'".format(DBNAME)
    360430            self.execute(query=query)
    361431            ainc = self.cur.fetchone()[0]
     
    379449    @timed
    380450    def process_main_thread(self,*args,**kwargs):
     451        if self.need_wait:
     452            time.sleep(EMPTY_PAUSED_SLEEP)
    381453        clis=self.get_client(mon=self.mon)
    382454        if clis == True: #No clients found (empty)
     
    400472                lapps_tmp['clients'].extend(lapps[fla]['clients'])
    401473                self.mon.db['main'].q.put(lapps_tmp,True)
    402         if DEBUG:
     474        #if DEBUG:
    403475            self.processed+=len(clis)
    404476        return True
     
    422494                self.q.put(lapps,True) # USELESS
    423495                return False    # USELESS
    424         if DEBUG:
     496        #if DEBUG:
    425497            self.processed+=len(lapps['clients'])
    426498        return True
     
    431503        printea("Running thread {}".format(self.t),'debug')
    432504        if self.t == 'main' and not self.mon.terminate:
     505           
    433506            ret=self.process_main_thread(*args,**kwargs)
    434507            if ret == False: #No more clients available
     
    445518                return ret
    446519        else:
     520            del self.q
     521            self.q = queue.Queue()
    447522            self.empty = True
    448523        return True
     
    471546                        self.mon.commited=time.time()
    472547                        self.reconnect = 0
     548                        if self.need_clean:
     549                            gc.collect()
    473550                    else:
    474551                        self.conn.rollback()
     
    480557                        printea("Can't rollback last actions",'info')
    481558                        pass
    482                     if e[0] != 2006:
    483                         printea("Exception processing worker({}): {}".format(self.t,e))
    484                     if e[0] == 2006: # SERVER GONE AWAY
    485                         printea("Worker ({}) detected server gone away !!!: {}".format(self.t,e))
     559                    #if e[0] != 2006:
     560                    #    printea("Exception processing worker({}): {}".format(self.t,e))
     561                    #if e[0] == 2006: # SERVER GONE AWAY
     562                    #    printea("Worker ({}) detected server gone away !!!: {}".format(self.t,e))
    486563                    printea("Trying to recover connection ({})".format(self.t))
    487564                    if self.reconnect == 100:
     
    504581        self.MAX_QUEUE_UTILIZATION = 100
    505582        self.USE_MAX_QUEUES = False
    506         self.MAX_SELECT_WINDOW = (2 ** 12) +1
     583        self.MAX_SELECT_WINDOW = (2 ** 13) +1
     584        self.MIN_SELECT_WINDOW = 32
    507585        self.MEM_USED=0
    508586        self.MAX_MEM=512
     587        self.MIN_FREE_MEM_SERVER=100
    509588        self.USE_MAX_MEM=True
    510589        self.lock = Lock()
     
    512591        self.finished = False
    513592        self.paused = False
    514         self.select_window = 1
     593        self.select_window = self.MIN_SELECT_WINDOW
    515594        self.commited = time.time()
    516595        self.procesed = 0
    517596        self.procesed_per_sec = [0]*10
     597        self.load = False
     598        self.server_variables = None  # initialized by main worker
     599        self.temporary_tables_size = { 'clients' : 0.0, 'packages':0.0 ,'sum': 0.0 }
     600        self.temporary_tables_rows = { 'clients': 0, 'packages' : 0 , 'sum': 0 }
     601        self.db_tables_size = { 'clients' : 0.0, 'packages':0.0 ,'sum': 0.0 }
     602        self.db_tables_rows = { 'clients': 0, 'packages' : 0 , 'sum': 0 }
     603
     604        self.server_mem = None
     605        self.loadlist = [ 0.0 ] * 100
    518606        signal.signal(signal.SIGQUIT,self.term)
    519607        signal.signal(signal.SIGTERM,self.term)
     
    529617            #    printea('Error initializing database connections: {}'.format(str(e)))
    530618            #    sys.exit(1)
     619        self.cfg= None
    531620        printea("Monitor initialized with {} threads".format(len(THREADS)),'info')
    532621
    533622    def schedule(self,*args,**kwargs):
    534623        if kwargs['event']=='NO_MORE_CLIENTS':
    535             if self.select_window > 1:
     624            if self.select_window > self.MIN_SELECT_WINDOW:
    536625                self.select_window/=2
     626                self.select_window=int(self.select_window)
    537627        if kwargs['event']=='HAVE_CLIENTS':
    538628            if kwargs['nclients'] == self.select_window:
    539                 if self.USE_MAX_QUEUES  and self.sum_q_sizes() > self.MAX_QUEUE_UTILIZATION:
    540                     if self.select_window > 1:
     629                if self.USE_MAX_QUEUES and self.sum_q_sizes() > self.MAX_QUEUE_UTILIZATION:
     630                    if self.select_window > self.MIN_SELECT_WINDOW:
    541631                        self.select_window/=2
     632                        self.select_window=int(self.select_window)
    542633                if self.USE_MAX_MEM and self.MEM_USED > self.MAX_MEM:
    543                     if self.select_window > 1:
     634                    if self.select_window > self.MIN_SELECT_WINDOW:
    544635                        self.select_window/=2
     636                        self.select_window=int(self.select_window)
    545637                else:
    546638                    if self.select_window*2 < self.MAX_SELECT_WINDOW:
    547639                        self.select_window*=2
     640                        self.select_window=int(self.select_window)
    548641            elif kwargs['nclients']<self.select_window/2:
    549642                self.select_window/=2
     643                self.select_window=int(self.select_window)
     644
     645        if kwargs['event']=='CHECK_SANITY':
     646            #nprocs=multiprocessing.cpu_count()
     647            #limit=nprocs*LIMIT
     648
     649            self.load=self.get_cpu_load()
     650            if not self.terminate and self.load > LIMIT:
     651                self.paused = True
     652            else:
     653                self.paused = False
     654
     655            self.MEM_USED=self.get_mem_usage()
     656            self.server_mem=self.get_server_free_mem()
     657
     658            max_heap=None
     659            if self.server_variables and 'max_heap_table_size' in self.server_variables:
     660                max_heap=int(self.server_variables['max_heap_table_size'])/(2**20)
     661            self.temporary_tables_size['sum'] =self.temporary_tables_size['clients']+self.temporary_tables_size['packages']
     662            self.temporary_tables_rows['sum'] =self.temporary_tables_rows['clients']+self.temporary_tables_rows['packages']
     663            self.db_tables_size['sum'] =self.db_tables_size['clients']+self.db_tables_size['packages']
     664            self.db_tables_rows['sum'] =self.db_tables_rows['clients']+self.db_tables_rows['packages']
     665            if max_heap and self.temporary_tables_size['sum']:
     666                if self.temporary_tables_size['sum'] > max_heap * 0.4:
     667                    if self.select_window*2 < self.MAX_SELECT_WINDOW:
     668                        self.select_window *= 2
     669                        self.select_window=int(self.select_window)
     670                    if self.paused:
     671                        #printea('Hitting max temporary table size unpausing','critical')
     672                        self.paused = False
     673            if self.server_mem and self.server_mem < self.MIN_FREE_MEM_SERVER:
     674                #printea('Hitting max memory from server collecting and reducing window','critical')
     675                if self.select_window > self.MIN_SELECT_WINDOW:
     676                    self.select_window/=2
     677                    self.select_window=int(self.select_window)
     678                self.db['main'].need_wait=True
     679                self.USE_MAX_QUEUES=True
     680                for x in THREADS:
     681                    self.db[x].need_clean=True
     682                gc.collect()
     683            else:
     684                self.db['main'].need_wait=False
     685                self.USE_MAX_QUEUES=False
     686                for x in THREADS:
     687                    self.db[x].need_clean=True
    550688
    551689    def get_config(self):
    552690        pass
     691
     692    def get_cpu_load(self):
     693        self.loadlist.append(psutil.cpu_percent())
     694        self.loadlist=self.loadlist[1:]
     695        avg=0.0
     696        for x in self.loadlist:
     697            avg+=x
     698        return round(avg/100.0,2)
    553699
    554700    def put_config(self,key='',value=''):
     
    572718    def get_mem_usage(self):
    573719        process = psutil.Process(os.getpid())
    574         mem = process.get_memory_info()[0] / float(2 ** 20)
     720        mem = process.memory_info()[0] / float(2 ** 20)
    575721        return mem
     722
     723    def get_server_free_mem(self):
     724        mem = psutil.virtual_memory()
     725        return mem.free / (2 ** 20)
    576726
    577727    def print_stats(self):
    578728        global CHECK_LOAD_TIME
    579         if DEBUG:
     729#        if DEBUG:
     730        if True:
    580731            out="Processed: "
    581732            out2=''
     
    583734            for x in THREADS:
    584735                out2+='{}={} '.format(x,self.db[x].processed)
     736                self.cfg.store('processed '+x,self.db[x].processed)
    585737                if THREADED:
    586738                    if x != 'main':
     
    589741                    total += self.db[x].processed
    590742            out += "TOTAL={} {}".format(total,out2)
    591             self.procesed_per_sec.append(int((total-self.procesed)/CHECK_LOAD_TIME))
     743            self.cfg.store('processed total',total)
     744            proc_per_sec=int((total-self.procesed)/CHECK_LOAD_TIME)
     745            self.procesed_per_sec.append(proc_per_sec)
    592746            self.procesed_per_sec=self.procesed_per_sec[-10:]
    593747            f=lambda x,y:x+y
    594748            suma_proc=reduce(f,self.procesed_per_sec)
     749            self.cfg.store('processing at',int(suma_proc/10))
    595750            self.procesed=total
    596751            total = 0
     
    600755                out2=''
    601756                for x in sizes:
     757                    self.cfg.store('queue '+x,sizes[x])
    602758                    out2+='{}={} '.format(x,sizes[x])
    603759                    total += sizes[x]
     760                self.cfg.store('queue totals',total)
    604761                out+="TOTAL={} {}".format(total,out2)
    605             if THREADED:
    606                 printea("{} {}SelectSize={} ProcessingAt={} Mem={}\n".format(time.strftime("%Y-%m-%d %H:%M:%S",time.gmtime()),out,self.select_window,int(suma_proc/10),int(self.MEM_USED)),'debug')
    607                 #sys.stdout.write("{}{} {}SelectSize={} ProcessingAt={} Mem={}\n".format('\r'*100,time.strftime("%Y-%m-%d %H:%M:%S",time.gmtime()),out,self.select_window,int(suma_proc/10),int(self.MEM_USED)))
     762            self.cfg.store('select window',self.select_window)
     763            self.cfg.store('mem used',self.MEM_USED)
     764            self.cfg.store('load',self.load)
     765            if (self.paused):
     766                self.cfg.store('paused',1)
    608767            else:
    609                 printea("{} {}SelectSize={} ProcessingAt={} Mem={}\n".format(time.strftime("%Y-%m-%d %H:%M:%S",time.gmtime()),out,self.select_window,int(suma_proc/10),int(self.MEM_USED)),'debug')
    610                 #sys.stdout.write("{}{} {}SelectSize={} ProcessingAt={} Mem={}\n".format('\r'*100,time.strftime("%Y-%m-%d %H:%M:%S",time.gmtime()),out,self.select_window,int(suma_proc/10),int(self.MEM_USED)))
     768                self.cfg.store('paused',0)
     769            self.cfg.store('temp_clients_size',int(self.temporary_tables_size['clients']))
     770            self.cfg.store('temp_packages_size',int(self.temporary_tables_size['packages']))
     771            self.cfg.store('db_clients_size',int(self.db_tables_size['clients']))
     772            self.cfg.store('db_packages_size',int(self.db_tables_size['packages']))
     773            if DEBUG:
     774                if THREADED:
     775                    printea("{} {}SelectSize={} ProcessingAt={} Mem={} Load={} Paused={} Tsize={} Trows={}".format(time.strftime("%Y-%m-%d %H:%M:%S",time.gmtime()),out,self.select_window,int(suma_proc/10),int(self.MEM_USED),self.load,self.paused,self.temporary_tables_size['sum'],self.temporary_tables_rows['sum']),'info')
     776                    #sys.stdout.write("{}{} {}SelectSize={} ProcessingAt={} Mem={}\n".format('\r'*100,time.strftime("%Y-%m-%d %H:%M:%S",time.gmtime()),out,self.select_window,int(suma_proc/10),int(self.MEM_USED)))
     777                else:
     778                    printea("{} {}SelectSize={} ProcessingAt={} Mem={} Load={} Paused={} Tsize={} Trows={}".format(time.strftime("%Y-%m-%d %H:%M:%S",time.gmtime()),out,self.select_window,int(suma_proc/10),int(self.MEM_USED),self.load,self.paused,self.temporary_tables_size['sum'],self.temporary_tables_rows['sum']),'info')
     779                    #sys.stdout.write("{}{} {}SelectSize={} ProcessingAt={} Mem={}\n".format('\r'*100,time.strftime("%Y-%m-%d %H:%M:%S",time.gmtime()),out,self.select_window,int(suma_proc/10),int(self.MEM_USED)))
    611780
    612781    def get_q_sizes(self):
     
    629798
    630799    def get_load(self):
    631         nprocs=multiprocessing.cpu_count()
    632         limit=nprocs*LIMIT
    633         while not (self.terminate and not self.paused and self.finished):
    634             self.print_stats()
    635             self.load=os.getloadavg()[0]
    636             if not self.terminate and self.load > limit:
    637                 self.paused = True
    638             else:
    639                 self.paused = False
    640             if self.all_queues_empty():
    641                 gc.collect()
    642             self.MEM_USED=self.get_mem_usage()
    643             time.sleep(CHECK_LOAD_TIME)
     800        # runs on separate thread
     801        db = DB(self,'load')
     802        db.init_db()
     803        self.cfg = Config(db)
     804        ctime=0
     805        while not (self.terminate and self.finished): #and not self.paused
     806            self.cfg.store('keepalive',int(time.time()))
     807            time.sleep(0.5)
     808            ctime+=0.5
     809            self.schedule(event='CHECK_SANITY')
     810
     811            if ctime >CHECK_LOAD_TIME:
     812                self.cfg.write()
     813                ctime=0.0
     814                self.temporary_tables_size['clients'],self.temporary_tables_rows['clients']=db.check_temporary_tables_size('tmp_clients')
     815                self.temporary_tables_size['packages'],self.temporary_tables_rows['packages']=db.check_temporary_tables_size('tmp_packages')
     816                self.db_tables_size['clients'],self.db_tables_rows['clients']=db.check_temporary_tables_size('Client_Versions')
     817                self.db_tables_size['packages'],self.db_tables_rows['packages']=db.check_temporary_tables_size('RecvPackages')
     818                self.print_stats()
     819                #self.load=os.getloadavg()[0]
     820                if self.all_queues_empty():
     821                    gc.collect()
     822            #end if
     823        #end while
     824        db.close_db()
    644825
    645826    def start(self):
     
    652833        self.finished = True
    653834        self.print_stats()
     835
     836
     837class Config():
     838    def __init__(self,connection):
     839        self._db = connection
     840        self.read()
     841
     842    def store(self,var,value):
     843        var=var.replace(' ','_')
     844        if isinstance(value,str):
     845            if value.isnumeric():
     846                setattr(self,var,int(value))
     847            else:
     848                setattr(self,var,str(value))
     849        else:
     850            setattr(self,var,int(value))
     851
     852    def write(self):
     853        if self._db:
     854            values={}
     855            for x in self.get_internal_vars():
     856                values.setdefault(str(x),str(getattr(self,x)))
     857            self._db.put_config(values)
     858
     859    def read(self):
     860        if self._db:
     861            config=self._db.get_config()
     862            for key in config.keys():
     863                if config[key].isnumeric():
     864                    setattr(self,key,int(config[key]))
     865                else:
     866                    setattr(self,key,config[key])
     867        else:
     868            print('No config yet')
     869
     870    def get_internal_vars(self):
     871        return list(filter(lambda x : x[0] != '_',self.__dict__.keys()))
     872
     873    def print(self):
     874        for v in self.get_internal_vars():
     875            print('{} = {}'.format(v,getattr(self,v)))
    654876
    655877
     
    669891
    670892if __name__ == "__main__":
     893    size=len([ p.name() for p in psutil.process_iter() if p.name() == 'analyticsd' ])
     894    if size > 1:
     895        printea("Another daemon running... exitting now!")
     896        sys.exit(1)
    671897    if DAEMON:
    672         with daemon.DaemonContext(detach_process=True,working_directory='/tmp',umask=002,pidfile=lockfile.FileLock('/var/run/analyticsd'),files_preserve=[logger.handlers[0].socket.fileno()]):
     898        with daemon.DaemonContext(detach_process=True,working_directory='/tmp',umask=0o002,pidfile=lockfile.FileLock('/var/run/analyticsd'),files_preserve=[logger.handlers[0].socket.fileno()]):
    673899            main()
    674900    else:
Note: See TracChangeset for help on using the changeset viewer.