-
Hahn Axel (hahn) authoredHahn Axel (hahn) authored
cronlog.class.php 10.07 KiB
<?php
/**
* central cronlog viewer
*
* cronlog contains non visual methods
* @see cronlog-renderer.class.php
*
* @author hahn
*/
class cronlog {
protected $_sDataDir = "__APPDIR__/data";
protected $_iTtlCache = 60; // in sec
/**
* when show an error for expired jobs (latency to execute job and sync logs)
* @var integer
*/
protected $_iExpiredJobsFailAfter = 60*30; // in sec
protected $_aSkipJoblogs = array();
protected $_aServers = array();
protected $_sActiveServer = false;
protected $_sFileFilter_serverjoblog = '*joblog*.done';
protected $_sFileFilter_serverlog = '*.log';
// ----------------------------------------------------------------------
// MAIN
// ----------------------------------------------------------------------
/**
* init
* @return boolean
*/
public function __construct() {
// read config
if (file_exists(__DIR__.'/../config/inc_cronlog.php')){
$aCfgTemp=include(__DIR__.'/../config/inc_cronlog.php');
$this->_sDataDir = isset($aCfgTemp['sDatadir']) ? $aCfgTemp['sDatadir'] : $this->_sDataDir;
$this->_iTtlCache = isset($aCfgTemp['iTtlCache']) ? (int)$aCfgTemp['iTtlCache'] : $this->_iTtlCache;
$this->_iExpiredJobsFailAfter = isset($aCfgTemp['iExpiredJobsFailAfter']) ? (int)$aCfgTemp['iExpiredJobsFailAfter'] : $this->_iExpiredJobsFailAfter;
$this->_aSkipJoblogs = isset($aCfgTemp['aHidelogs']) && is_array($aCfgTemp['aHidelogs']) ? $aCfgTemp['aHidelogs'] : $this->_aSkipJoblogs;
}
$this->_sDataDir = str_replace("__APPDIR__", dirname(dirname(__FILE__)), $this->_sDataDir);
$this->_sDataDir = str_replace('\\', '/', $this->_sDataDir);
$this->getServers();
return true;
}
// ----------------------------------------------------------------------
// private
// ----------------------------------------------------------------------
/**
* chaching: get the full path of directory for caching
* @return type
*/
protected function _getCacheDir(){
return $this->_sDataDir.'/__cache';
}
/**
* caching: get full path of a caching item
* @param type $sTaskId
* @return type
*/
protected function _getCacheFile($sTaskId){
return $this->_getCacheDir().'/'.$sTaskId;
}
/**
* read logs: get full path to a servers cronjob logdata
* @return type
*/
protected function _getServerlogDir(){
return $this->_sDataDir.'/'.$this->_sActiveServer;
}
/**
* caching: get cached data if they exist and aren't expired
* @param string $sTaskId
* @return boolean|array
*/
protected function _getCacheData($sTaskId){
// DISABLE CACHE return false;
$sFile=$this->_getCacheFile($sTaskId);
if(file_exists($sFile)){
if (filemtime($sFile)>(date('U')-$this->_iTtlCache)){
// echo "USE cache $sFile<br>";
return unserialize(file_get_contents($sFile));
} else {
// echo "DELETE cache $sFile<br>";
unlink($sFile);
}
}
return false;
}
/**
* read logs: parse a single line in the joblog and return has with all key value items
* @param string $sLine single line in the log
* @return array
*/
protected function _parseJoblogLine($sLine){
$aReturn=array();
// echo "DEBUG $sLine<br>";
// job=dok-kvm-instances:host=kalium:start=1538358001:end=1538358001:exectime=0:ttl=60:rc=0
$sLine=str_replace("\n", '', $sLine);
$sLine=str_replace(':', '", "', $sLine);
$sLine=str_replace('=', '": "', $sLine);
$sLine='{"'.$sLine.'"}';
// echo "DEBUG $sLine<br><br>";
$aReturn=json_decode($sLine, 1);
if(!is_array($aReturn)){
echo "not a JSON string<br>";
echo "DEBUG $sLine<br><br>";
die();
}
return $aReturn;
}
/**
* read logs: parse the whole cronwrapper logfile and return a hash
* @param string $sFile filename with full path
*/
protected function _parseLogfile($sFile) {
$aReturn=array(
'SCRIPTNAME'=>false,
'SCRIPTTTL'=>false,
'SCRIPTSTARTTIME'=>false,
'SCRIPTLABEL'=>false,
'SCRIPTENDTIME'=>false,
'SCRIPTEXECTIME'=>false,
'SCRIPTRC'=>false,
// 'SCRIPTOUT'=>array(),
);
$fileHandle = fopen($sFile, "r");
while (($line = fgets($fileHandle)) !== false) {
// get key ... the part before "="
$sKey=trim(preg_replace('/=.*/', '', $line));
if($sKey && isset($aReturn[$sKey])){
// add value ... the part behind "="
$aReturn[$sKey]=preg_replace('/^([A-Z]*\=)/', '', $line);
}
}
fclose($fileHandle);
// fetch unit timestamp from date values (they are like "2018-09-30 03:40:05, 1538278805")
$aReturn['SCRIPTSTARTTIME']=(int)preg_replace('/.*,\ /', '', $aReturn['SCRIPTSTARTTIME']);
$aReturn['SCRIPTENDTIME']=(int)preg_replace('/.*,\ /', '', $aReturn['SCRIPTSTARTTIME']);
// remove " s" from exec time value
$aReturn['SCRIPTEXECTIME']=preg_replace('/\ s$/', '', $aReturn['SCRIPTEXECTIME']);
return $aReturn;
}
/**
* caching: write new data; it returns the success of write operation as bool
* @param string $sTaskId
* @param [any] $data data to store; can be any serializable value
* @return boolean
*/
protected function _writeCacheData($sTaskId, $data){
$sFile=$this->_getCacheFile($sTaskId);
// echo "WRITE cache $sFile<br>";
return file_put_contents($sFile, serialize($data));
}
// ----------------------------------------------------------------------
// public getter
// ----------------------------------------------------------------------
/**
* get currently selected server
* @return string
*/
public function getServer(){
return $this->_sActiveServer;
}
/**
* get array with existing servers in data dir
* @return array
*/
public function getServers(){
if(is_array($this->_aServers) && count($this->_aServers)){
return $this->_aServers;
}
$this->_aServers=array();
// echo "DEBUG DATADIR: " . $this->_sDataDir."<br>";
if (!is_dir($this->_sDataDir)){
echo "WARNING: no data. Check sDatadir in the config and set it to an existing directory.<br>";
die();
}
if ($handle = opendir($this->_sDataDir)) {
while (false !== ($entry = readdir($handle))) {
if ($entry != "." && $entry != ".." && $entry != "__cache" && is_dir($this->_sDataDir.'/'.$entry)) {
// echo "DEBUG $entry<br>\n";
$this->_aServers[$entry]=array();
}
}
closedir($handle);
}
ksort($this->_aServers);
return $this->_aServers;
}
/**
* get logs from jobfilea of the current or given server
* @param boolean $bUseSkip hide jobs if their label matches the skip list; default: true
* @return array
*/
public function getServerJobHistory($bUseSkip=true){
$aReturn=array();
$sTaskId=__FUNCTION__.'-'.$this->_sActiveServer;
$aData=$this->_getCacheData($sTaskId);
if($aData){
return $aData;
}
$aData=array();
foreach(glob($this->_getServerlogDir().'/'.$this->_sFileFilter_serverjoblog) as $sMyJobfile){
// echo "DEBUG: $sMyJobfile<br>";
$fileHandle = fopen($sMyJobfile, "r");
while (($line = fgets($fileHandle)) !== false) {
// send the current file part to the browser
$aData=$this->_parseJoblogLine($line);
if($bUseSkip && array_search($aData['job'], $this->_aSkipJoblogs)===false){
$aReturn[$aData['start']]=$aData;
}
}
fclose($fileHandle);
}
krsort($aReturn);
$this->_writeCacheData($sTaskId, $aReturn);
return $aReturn;
}
/**
* get logs from jobfilea of the current or given server
* @return array
*/
public function getServersLastLog(){
$aReturn=array();
$aData=array();
foreach(glob($this->_getServerlogDir().'/'.$this->_sFileFilter_serverlog) as $sMyJobfile){
// echo "DEBUG: log file $sMyJobfile<br>";
$aData=$this->_parseLogfile($sMyJobfile);
$aData['server']=$this->_sActiveServer;
$aData['logfile']= $this->_sActiveServer.'/'.basename($sMyJobfile);
$aReturn[$aData['SCRIPTSTARTTIME'].$sMyJobfile]=$aData;
}
rsort($aReturn);
return $aReturn;
}
// ----------------------------------------------------------------------
// public setter
// ----------------------------------------------------------------------
/**
* set which server is selected
* The given server must exist as directory (that contains its logs)
* @param string $sServer server name
* @return string
*/
public function setServer($sServer){
$this->_sActiveServer=false;
if($sServer==='ALL'){
return false;
}
if($sServer && !array_key_exists($sServer, $this->_aServers)){
echo "WARNING: server [$sServer] does not exist<br>";
return false;
}
$this->_sActiveServer=$sServer;
return $this->_sActiveServer;
}
}