Marius Cramer
2015-08-06 37b29231e47a0c4458dc1c15d98588f16f07e1e2
commit | author | age
5de2af 1 <?php
M 2
3 /*
4 Copyright (c) 2013, Marius Cramer, pixcept KG
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without modification,
8 are permitted provided that the following conditions are met:
9
10     * Redistributions of source code must retain the above copyright notice,
11       this list of conditions and the following disclaimer.
12     * Redistributions in binary form must reproduce the above copyright notice,
13       this list of conditions and the following disclaimer in the documentation
14       and/or other materials provided with the distribution.
15     * Neither the name of ISPConfig nor the names of its contributors
16       may be used to endorse or promote products derived from this software without
17       specific prior written permission.
18
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
23 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
26 OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 class cronjob_logfiles extends cronjob {
32
b1a6a5 33     // job schedule
MC 34     protected $_schedule = '0 0 * * *';
5de2af 35
b1a6a5 36     /* this function is optional if it contains no custom code */
MC 37     public function onPrepare() {
38         global $app;
5de2af 39
b1a6a5 40         parent::onPrepare();
MC 41     }
5de2af 42
b1a6a5 43     /* this function is optional if it contains no custom code */
MC 44     public function onBeforeRun() {
45         global $app;
5de2af 46
b1a6a5 47         return parent::onBeforeRun();
MC 48     }
5de2af 49
b1a6a5 50     public function onRunJob() {
MC 51         global $app, $conf;
5de2af 52
b1a6a5 53         //######################################################################################################
MC 54         // Make the web logfiles directories world readable to enable ftp access
55         //######################################################################################################
5de2af 56
b1a6a5 57         if(is_dir('/var/log/ispconfig/httpd')) exec('chmod +r /var/log/ispconfig/httpd/*');
5de2af 58
b1a6a5 59         //######################################################################################################
MC 60         // Manage and compress web logfiles and create traffic statistics
61         //######################################################################################################
5de2af 62
a6e3ae 63         $sql = "SELECT domain_id, domain, type, document_root, web_folder, parent_domain_id FROM web_domain WHERE (type = 'vhost' or type = 'vhostsubdomain' or type = 'vhostalias') AND server_id = ?";
MC 64         $records = $app->db->queryAllRecords($sql, $conf['server_id']);
b1a6a5 65         foreach($records as $rec) {
5de2af 66
b1a6a5 67             //* create traffic statistics based on yesterdays access log file
MC 68             $yesterday = date('Ymd', time() - 86400);
5de2af 69
b1a6a5 70             $log_folder = 'log';
511ba5 71             if($rec['type'] == 'vhostsubdomain' || $rec['type'] == 'vhostalias') {
cc7a82 72                 $tmp = $app->db->queryOneRecord('SELECT `domain` FROM web_domain WHERE domain_id = ?', $rec['parent_domain_id']);
b1a6a5 73                 $subdomain_host = preg_replace('/^(.*)\.' . preg_quote($tmp['domain'], '/') . '$/', '$1', $rec['domain']);
MC 74                 if($subdomain_host == '') $subdomain_host = 'web'.$rec['domain_id'];
75                 $log_folder .= '/' . $subdomain_host;
76                 unset($tmp);
77             }
5de2af 78
b1a6a5 79             $logfile = $rec['document_root'].'/' . $log_folder . '/'.$yesterday.'-access.log';
MC 80             $total_bytes = 0;
5de2af 81
b1a6a5 82             $handle = @fopen($logfile, "r");
MC 83             if ($handle) {
84                 while (($line = fgets($handle, 4096)) !== false) {
85                     if (preg_match('/^\S+ \S+ \S+ \[.*?\] "\S+.*?" \d+ (\d+) ".*?" ".*?"/', $line, $m)) {
86                         $total_bytes += intval($m[1]);
87                     }
88                 }
5de2af 89
b1a6a5 90                 //* Insert / update traffic in master database
MC 91                 $traffic_date = date('Y-m-d', time() - 86400);
cc7a82 92                 $tmp = $app->dbmaster->queryOneRecord("select hostname from web_traffic where hostname=? and traffic_date=?", $rec['domain'], $traffic_date);
b1a6a5 93                 if(is_array($tmp) && count($tmp) > 0) {
cc7a82 94                     $sql = "UPDATE web_traffic SET traffic_bytes=traffic_bytes + ? WHERE hostname = ? AND traffic_date = ?";
MC 95                     $app->dbmaster->query($sql, $total_bytes, $rec['domain'], $traffic_date);
b1a6a5 96                 } else {
cc7a82 97                     $sql = "INSERT INTO web_traffic (hostname, traffic_date, traffic_bytes) VALUES (?, ?, ?)";
MC 98                     $app->dbmaster->query($sql, $rec['domain'], $traffic_date, $total_bytes);
b1a6a5 99                 }
5de2af 100
b1a6a5 101                 fclose($handle);
MC 102             }
5de2af 103
b1a6a5 104             $yesterday2 = date('Ymd', time() - 86400*2);
MC 105             $logfile = escapeshellcmd($rec['document_root'].'/' . $log_folder . '/'.$yesterday2.'-access.log');
5de2af 106
b1a6a5 107             //* Compress logfile
MC 108             if(@is_file($logfile)) {
109                 // Compress yesterdays logfile
110                 exec("gzip -c $logfile > $logfile.gz");
111                 unlink($logfile);
112             }
da0a81 113             
MC 114             $cron_logfiles = array('cron.log', 'cron_error.log', 'cron_wget.log');
115             foreach($cron_logfiles as $cron_logfile) {
116                 $cron_logfile = escapeshellcmd($rec['document_root'].'/' . $log_folder . '/' . $cron_logfile);
117                 
118                 // rename older files (move up by one)
119                 $num = 7;
120                 while($num >= 1 && is_file($cron_logfile . '.' . $num . '.gz')) {
121                     rename($cron_logfile . '.' . $num . '.gz', $cron_logfile . '.' . ($num + 1) . '.gz');
122                     $num--;
123                 }
124                 
125                 // compress current logfile
b41dfd 126                 if(is_file($cron_logfile)) {
da0a81 127                     exec("gzip -c $cron_logfile > $cron_logfile.1.gz");
MC 128                     exec("cat /dev/null > $cron_logfile");
129                 }
130                 // remove older logs
131                 $num = 7;
132                 while(is_file($cron_logfile . '.' . $num . '.gz')) {
133                     @unlink($cron_logfile . '.' . $num . '.gz');
134                     $num++;
135                 }
136             }
5de2af 137
b1a6a5 138             // rotate and compress the error.log when it exceeds a size of 10 MB
MC 139             $logfile = escapeshellcmd($rec['document_root'].'/' . $log_folder . '/error.log');
140             if(is_file($logfile) && filesize($logfile) > 10000000) {
141                 exec("gzip -c $logfile > $logfile.1.gz");
142                 exec("cat /dev/null > $logfile");
143             }
5de2af 144
b1a6a5 145             // delete logfiles after 30 days
MC 146             $month_ago = date('Ymd', time() - 86400 * 30);
147             $logfile = escapeshellcmd($rec['document_root'].'/' . $log_folder . '/'.$month_ago.'-access.log.gz');
148             if(@is_file($logfile)) {
149                 unlink($logfile);
150             }
5de2af 151
b1a6a5 152             //* Delete older Log files, in case that we missed them before due to serverdowntimes.
MC 153             $datepart = date('Ym', time() - 86400 * 31 * 2);
5de2af 154
b1a6a5 155             $logfile = escapeshellcmd($rec['document_root']).'/' . $log_folder . '/'.$datepart.'*-access.log.gz';
MC 156             exec('rm -f '.$logfile);
5de2af 157
b1a6a5 158             $logfile = escapeshellcmd($rec['document_root']).'/' . $log_folder . '/'.$datepart.'*-access.log';
MC 159             exec('rm -f '.$logfile);
160         }
5de2af 161
b1a6a5 162         //* Delete old logfiles in /var/log/ispconfig/httpd/ that were created by vlogger for the hostname of the server
MC 163         exec('hostname -f', $tmp_hostname);
164         if($tmp_hostname[0] != '' && is_dir('/var/log/ispconfig/httpd/'.$tmp_hostname[0])) {
165             exec('cd /var/log/ispconfig/httpd/'.$tmp_hostname[0]."; find . -mtime +30 -name '*.log' | xargs rm > /dev/null 2> /dev/null");
166         }
167         unset($tmp_hostname);
5de2af 168
b1a6a5 169         //######################################################################################################
MC 170         // Rotate the ispconfig.log file
171         //######################################################################################################
5de2af 172
b1a6a5 173         // rotate the ispconfig.log when it exceeds a size of 10 MB
MC 174         $logfile = $conf['ispconfig_log_dir'].'/ispconfig.log';
175         if(is_file($logfile) && filesize($logfile) > 10000000) {
176             exec("gzip -c $logfile > $logfile.1.gz");
177             exec("cat /dev/null > $logfile");
178         }
179
180         // rotate the cron.log when it exceeds a size of 10 MB
181         $logfile = $conf['ispconfig_log_dir'].'/cron.log';
182         if(is_file($logfile) && filesize($logfile) > 10000000) {
183             exec("gzip -c $logfile > $logfile.1.gz");
184             exec("cat /dev/null > $logfile");
185         }
186
187         // rotate the auth.log when it exceeds a size of 10 MB
188         $logfile = $conf['ispconfig_log_dir'].'/auth.log';
189         if(is_file($logfile) && filesize($logfile) > 10000000) {
190             exec("gzip -c $logfile > $logfile.1.gz");
191             exec("cat /dev/null > $logfile");
192         }
193
194         //######################################################################################################
195         // Cleanup website tmp directories
196         //######################################################################################################
197
cc7a82 198         $sql = "SELECT domain_id, domain, document_root, system_user FROM web_domain WHERE server_id = ?";
MC 199         $records = $app->db->queryAllRecords($sql, $conf['server_id']);
b1a6a5 200         $app->uses('system');
MC 201         if(is_array($records)) {
202             foreach($records as $rec){
203                 $tmp_path = realpath(escapeshellcmd($rec['document_root'].'/tmp'));
204                 if($tmp_path != '' && strlen($tmp_path) > 10 && is_dir($tmp_path) && $app->system->is_user($rec['system_user'])){
205                     exec('cd '.$tmp_path."; find . -mtime +1 -name 'sess_*' | grep -v -w .no_delete | xargs rm > /dev/null 2> /dev/null");
206                 }
207             }
208         }
209
210         //######################################################################################################
211         // Cleanup logs in master database (only the "master-server")
212         //######################################################################################################
213
214         if ($app->dbmaster == $app->db) {
215             /** 7 days */
216
217
218             $tstamp = time() - (60*60*24*7);
219
220             /*
5de2af 221              *  Keep 7 days in sys_log
M 222              * (we can delete the old items, because if they are OK, they don't interrest anymore
223              * if they are NOT ok, the server will try to process them in 1 minute and so the
224              * error appears again after 1 minute. So it is no problem to delete the old one!
225              */
cc7a82 226             $sql = "DELETE FROM sys_log WHERE tstamp < ? AND server_id != 0";
MC 227             $app->dbmaster->query($sql, $tstamp);
5de2af 228
b1a6a5 229             /*
5de2af 230              * Delete all remote-actions "done" and older than 7 days
M 231              * ATTENTION: We have the same problem as described in cleaning the datalog. We must not
232              * delete the last entry
233              */
b1a6a5 234             $sql = "SELECT max(action_id) FROM sys_remoteaction";
MC 235             $res = $app->dbmaster->queryOneRecord($sql);
236             $maxId = $res['max(action_id)'];
cc7a82 237             $sql =  "DELETE FROM sys_remoteaction WHERE tstamp < ? AND action_state = 'ok' AND action_id < ?";
MC 238             $app->dbmaster->query($sql, $tstamp, $maxId);
5de2af 239
b1a6a5 240             /*
5de2af 241              * The sys_datalog is more difficult.
M 242              * 1) We have to keet ALL entries with
243              *    server_id=0, because they depend on ALL servers (even if they are not
244              *    actually in the system (and will be insered in 3 days or so).
245              * 2) We have to keey ALL entries which are not actually precessed by the
246              *    server never mind how old they are!
247              * 3) We have to keep the entry with the highest autoinc-id, because mysql calculates the
248              *    autoinc-id as "new value = max(row) +1" and does not store this in a separate table.
249              *    This means, if we delete to entry with the highest autoinc-value then this value is
250              *    reused as autoinc and so there are more than one entries with the same value (over
251              *    for example 4 Weeks). This is confusing for our system.
252              *    ATTENTION 2) and 3) is in some case NOT the same! so we have to check both!
253              */
254
b1a6a5 255             /* First we need all servers and the last sys_datalog-id they processed */
MC 256             $sql = "SELECT server_id, updated FROM server ORDER BY server_id";
257             $records = $app->dbmaster->queryAllRecords($sql);
5de2af 258
b1a6a5 259             /* Then we need the highest value ever */
MC 260             $sql = "SELECT max(datalog_id) FROM sys_datalog";
261             $res = $app->dbmaster->queryOneRecord($sql);
262             $maxId = $res['max(datalog_id)'];
5de2af 263
b1a6a5 264             /* Then delete server by server */
MC 265             foreach($records as $server) {
266                 $tmp_server_id = intval($server['server_id']);
267                 if($tmp_server_id > 0) {
cc7a82 268                     $sql =  "DELETE FROM sys_datalog WHERE tstamp < ? AND server_id = ? AND datalog_id < ? AND datalog_id < ?";
MC 269                     //  echo $sql . "\n";
270                     $app->dbmaster->query($sql, $tstamp, $server['server_id'], $server['updated'], $maxId);
b1a6a5 271                 }
MC 272             }
273         }
274
275
276         parent::onRunJob();
277     }
278
279     /* this function is optional if it contains no custom code */
280     public function onAfterRun() {
281         global $app;
282
283         parent::onAfterRun();
284     }
5de2af 285
M 286 }
287
288 ?>