Skip to content
Snippets Groups Projects

OP#7365 PHP-8.1 - Upgrade - cronlog Viewer (monitors.ascii)https://projects.iml.unibe.ch/work_packages/7365

Merged Hahn Axel (hahn) requested to merge freshup-php into master
1 file
+ 6
6
Compare changes
  • Side-by-side
  • Inline
+ 433
383
@@ -32,49 +32,67 @@ require_once 'cronlog.class.php';
*
* @license GNU GPL 3.0
* @author Axel Hahn <axel.hahn@iml.unibe.ch>
*
* 2024-10-01 <axel.hahn@unibe.ch> added type declarations; update php docs
*/
class cronlogrenderer extends cronlog{
class cronlogrenderer extends cronlog
{
/**
* minimal length for execution time of a job to be rendered in the timeline; value is in seconds
* @var integer
*/
protected $_iMinTime4Timeline = 60;
protected int $_iMinTime4Timeline = 60;
/**
* Max count of entries in history table to prevent freezing of the screen
* when displaying a lot of entries, eg all logs of 100+ servers
* @var int
*/
protected int $_iHistoryLimit = 1000;
/**
* show date of last data and last access; used in rendering methods to display it on top
* Show date of last data and last access; used in rendering methods to display it on top
* @param integer $iLast unix timestamp of last log entry
* @return string
*/
protected function _renderAccessAndAge($iLast){
protected function _renderAccessAndAge(int $iLast): string
{
if (!$iLast) {
return '';
}
$iAge = round((date('U') - $iLast) / 60);
$sAge = ($iAge > 60*24 ? '<span class="message-error">'.$iAge.'</span>' : $iAge);
return '<div class="accessandage">'
. sprintf($this->t("request-time"), date("Y-m-d H:i:s")) . '<br>'
. sprintf($this->t("last-entry"), $iAge)
. sprintf($this->t("last-entry"), $sAge)
.($iAge > 60*24
? " <a href=\"?deleteserverlogs=$this->_sActiveServer\" class=\"btn btn-danger\">Delete server</a>"
: ''
)
. '</div>'
;
}
/**
* get onclick value to filter a datatable
* Get onclick value to filter a datatable
* @param string $sDatatable id of table
* @param string $sFiltertext text to filter
* @return string
*
*/
protected function _filterDatatable($sDatatable, $sFiltertext){
protected function _filterDatatable($sDatatable, $sFiltertext)
{
return '$(\'#' . $sDatatable . '\').dataTable().fnFilter(\'' . $sFiltertext . '\'); return false;';
}
/**
* helper function to be used in methods that render datatable tables
* get javascript code to be added in init options and set language specifi texts
* Helper function to be used in methods that render datatable tables
* Get javascript code to be added in init options and set language specifi texts
* @return string
*/
protected function _getDatatableLanguage(){
protected function _getDatatableLanguage(): string
{
return $this->t("dt-USE")
? ', "oLanguage":{
"sProcessing":"' . $this->t("dt-sProcessing") . '",
@@ -97,12 +115,13 @@ class cronlogrenderer extends cronlog{
;
}
/**
* get html code for a table with events of executed cronjobs
* Get html code for a table with events of executed cronjobs
*
* @param array $aData result of $this->getServerLogs()
* @return string
*/
public function renderCronlogs($aData=false){
public function renderCronlogs(array $aData = []): string
{
$sTaskId = __FUNCTION__ . '-' . $this->_sActiveServer;
$sHtml = $this->_getCacheData($sTaskId);
if ($sHtml) {
@@ -110,7 +129,7 @@ class cronlogrenderer extends cronlog{
}
$sHtml = '';
if(!$aData){
if (!count($aData)) {
$aData = array_merge($this->getRunningJobs(), $this->getServersLastLog());
}
$sTblHead = '';
@@ -120,7 +139,7 @@ class cronlogrenderer extends cronlog{
// Array ( [SCRIPTNAME] => apt-get update [SCRIPTTTL] => 1440 [SCRIPTSTARTTIME] => 2016-06-21 06:00:02, 1466481602 [SCRIPTLABEL] => apt-get [SCRIPTENDTIME] => 2016-06-21 06:00:49, 1466481649 [SCRIPTEXECTIME] => 47 s [SCRIPTRC] => 0 )
foreach ($aData as $sDtakey => $aEntry) {
if (!$sTblHead) {
foreach(array(
foreach ([
$this->t("col-starting-time"),
$this->t("col-label"),
$this->t("col-server"),
@@ -129,15 +148,15 @@ class cronlogrenderer extends cronlog{
$this->t("col-rc"),
$this->t("col-expired"),
$this->t("col-status"),
) as $sKey){
$sTblHead.='<th>'.$sKey.'</th>';
] as $sKey) {
$sTblHead .= "<th>$sKey</th>";
}
}
// $sViewerUrl='viewer.php?host='.$aEntry['host'].'&job='.$aEntry['job'];
// $sClass='message-'.($aEntry['SCRIPTRC']?'error':'ok');
$iLast=max(array($iLast, date("U", $aEntry['SCRIPTSTARTTIME'])));
$iLast = max([$iLast, date("U", $aEntry['SCRIPTSTARTTIME'])]);
$aErrors=array();
$aErrors = [];
$iTtlUsed = max($aEntry['SCRIPTTTL'], $this->_iMinTtl);
$iNextRun = $aEntry['SCRIPTSTARTTIME'] + ((int) $aEntry['SCRIPTTTL'] * 60);
$iNextRunWarn = $aEntry['SCRIPTSTARTTIME'] + ((int) $iTtlUsed * 60);
@@ -224,7 +243,7 @@ class cronlogrenderer extends cronlog{
// . '<td>'.$aEntry['SCRIPTNAME'].'</td>'
. '<td>' . $aEntry['SCRIPTLABEL'] . '</td>'
. '<td>' . $aEntry['server'] . '</td>'
. '<td'
. '<td align="right"'
. ((int) $aEntry['SCRIPTEXECTIME'] > $this->_iMinTime4Timeline ? ' class="message-warning"' : '')
. '>'
. '<span style="display: none">' . str_pad((int) $aEntry['SCRIPTEXECTIME'], 6, '0', STR_PAD_LEFT) . '</span>'
@@ -232,14 +251,14 @@ class cronlogrenderer extends cronlog{
. $iExectime . 's'
. ($iExectime > 100 ? ' (' . round($iExectime / 60) . 'min)' : '')
. '</td>'
. '<td'
. '<td align="right"'
. ($aEntry['SCRIPTTTL'] < $this->_iMinTtl ? ' class="message-warning" title="(using minimal TTL = ' . $this->_iMinTtl . ' min)"' : '')
. '>'
. '<span style="display: none">' . str_pad((int) $aEntry['SCRIPTTTL'], 6, '0', STR_PAD_LEFT) . '</span>'
. $aEntry['SCRIPTTTL']
. $sTtlHr
. '</td>'
. '<td class="'.($aEntry['SCRIPTRC'] ? ($aEntry['SCRIPTRC']>0 ? 'message-error' : 'message-ok') : '' ).'">'
. '<td align="right" class="' . ($aEntry['SCRIPTRC'] ? ($aEntry['SCRIPTRC'] > 0 ? 'message-error' : 'message-ok') : '') . '">'
. ($aEntry['SCRIPTRC'] ? $aEntry['SCRIPTRC'] : '⏳')
. '</td>'
. '<td class="' . ($iNextRunWarn < date("U")
@@ -298,13 +317,14 @@ class cronlogrenderer extends cronlog{
}
/**
* get html code for a table with events of executed cronjobs for ALL servers
* Get html code for a table with events of executed cronjobs for ALL servers
*
* @param array $aData result of $this->getServerLogs()
* @return string
*/
public function renderCronlogsOfAllServers(){
$aData=array();
public function renderCronlogsOfAllServers(): string
{
$aData = [];
foreach (array_keys($this->getServers()) as $sServer) {
$this->setServer($sServer);
$aData = array_merge($aData, $this->getRunningJobs(), $this->getServersLastLog());
@@ -314,17 +334,19 @@ class cronlogrenderer extends cronlog{
}
/**
* get html code for a switcher of multiple instances
* Get html code for a switcher of multiple instances.
* It returns an empty string if there is no / only one instance
*
* @param array $aData result of $oCL->getServerLogs()
* @return string
*/
public function renderInstances(){
public function renderInstances(): string
{
if (count($this->_aInstances) < 2) {
return false;
return '';
}
$sReturn = '';
$sServer=isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : false;
$sServer = isset($_SERVER['SERVER_NAME']) ?? false;
$sReturn .= '<li class="nav-item"><a class="nav-link nav-link" data-widget="pushmenu" href="#" role="button"><i class="fas fa-bars"></i></a></li>'
. '<li class="nav-item d-none d-sm-inline-block"><a href="#" class="nav-link">' . $this->t('instances') . ':</a></li>';
@@ -337,12 +359,13 @@ class cronlogrenderer extends cronlog{
return $sReturn;
}
/**
* get html code for a table with history of executed cronjobs
* Get html code for a table with history of executed cronjobs
*
* @param array $aData result of $oCL->getServerLogs()
* @return string
*/
public function renderJoblist($aData=false){
public function renderHistoryTable(array $aData = []): string
{
$sTaskId = __FUNCTION__ . '-' . $this->_sActiveServer;
$sHtml = $this->_getCacheData($sTaskId);
if ($sHtml) {
@@ -354,14 +377,28 @@ class cronlogrenderer extends cronlog{
$aData = $this->getServerJobHistory();
}
// sort by starting time - especially before cutting the list
$aTmp=[];
foreach($aData as $sKey => $aEntry) {
$aTmp[$aEntry['start'].'__'.$aEntry['host'].'__'.$aEntry['job']]=$aEntry;
}
krsort($aTmp);
$aData = array_values($aTmp);
// render table
$sTblHead = '';
$iOK = 0;
$iErrors = 0;
$iLast = false;
$iCounter = 0;
// job=dok-kvm-instances:host=kalium:start=1538358001:end=1538358001:exectime=0:ttl=60:rc=0
foreach ($aData as $aEntry) {
$iCounter++;
if($iCounter>$this->_iHistoryLimit) {
break;
}
if (!$sTblHead) {
foreach(array(
foreach ([
$this->t("col-starting-time"),
$this->t("col-label"),
$this->t("col-server"),
@@ -369,12 +406,11 @@ class cronlogrenderer extends cronlog{
$this->t("col-ttl"),
$this->t("col-rc"),
$this->t("col-status"),
) as $sKey){
] as $sKey) {
$sTblHead .= '<th>' . $sKey . '</th>';
}
}
$iLast=max(array($iLast, date("U", $aEntry['start'])));
$sClass='message-'.($aEntry['rc']?'error':'ok');
$iLast = max([$iLast, date("U", $aEntry['start'])]);
if ($aEntry['rc']) {
$iErrors++;
@@ -387,14 +423,14 @@ class cronlogrenderer extends cronlog{
// . '<td>'.date("Y-m-d H:i:s", $aEntry['end']).'</td>'
. '<td>' . $aEntry['job'] . '</td>'
. '<td>' . $aEntry['host'] . '</td>'
. '<td'
. '<td align="right"'
. ($aEntry['exectime'] > $this->_iMinTime4Timeline ? ' class="message-warning"' : '')
. '>'
. $aEntry['exectime'] . 's'
. ($aEntry['exectime'] > 100 ? ' (' . round($aEntry['exectime'] / 60) . 'min)' : '')
. '</td>'
. '<td>'.$aEntry['ttl'].'</td>'
. '<td class="'
. '<td align="right">' . $aEntry['ttl'] . '</td>'
. '<td align="right" class="'
. ($aEntry['rc'] > 0 ? 'message-error' : 'message-ok')
. '">' . $aEntry['rc'] . '</td>'
. '<td>' . ($aEntry['rc'] ? $this->t('status-error') : $this->t('status-ok')) . '</td>'
@@ -448,16 +484,18 @@ class cronlogrenderer extends cronlog{
/**
* get html code for a joblist of the selected server
* it uses the filter for hidden joblog entries (aHidelogs in config)
*
* @return string
*/
public function renderJoblistOfAllServers(){
$aData=array();
public function renderHistoryOfAllServers(): string
{
$aData = [];
foreach (array_keys($this->getServers()) as $sServer) {
$this->setServer($sServer);
$aData = array_merge($aData, $this->getServerJobHistory());
}
$this->setServer('ALL');
return $this->renderJoblist($aData);
return $this->renderHistoryTable($aData);
}
/**
@@ -470,7 +508,8 @@ class cronlogrenderer extends cronlog{
* @param array $aData result of $oCL->getServerLogs()
* @return string
*/
public function renderJobGraph($aData=false){
public function renderJobGraph(array $aData = []): string
{
$sTaskId = __FUNCTION__ . '-' . $this->_sActiveServer;
$sHtml = $this->_getCacheData($sTaskId);
if ($sHtml) {
@@ -482,19 +521,19 @@ class cronlogrenderer extends cronlog{
$iGraphCounter = 0;
}
$iGraphCounter++;
if(!$aData){
if (!count($aData)) {
$aData = $this->getServerJobHistory(false);
}
$sDivId = 'vis-timeline-' . $iGraphCounter;
$aDataset=array();
$aDataset = [];
$iLast = false;
$iEntry = 0;
foreach ($aData as $aEntry) {
if ($aEntry['exectime'] > $this->_iMinTime4Timeline) {
$iEntry++;
$iLast=max(array($iLast, date("U", $aEntry['start'])));
$aDataset[]=array(
$iLast = max([$iLast, date("U", $aEntry['start'])]);
$aDataset[] = [
'id' => $iEntry,
/*
'start'=>(int)date("U", $aEntry['start']),
@@ -520,7 +559,7 @@ class cronlogrenderer extends cronlog{
. '<br>'
. 'rc = ' . $aEntry['rc'] . '<br>'
,
);
];
// if($iEntry>=265){break;}
}
}
@@ -558,6 +597,9 @@ class cronlogrenderer extends cronlog{
// Create a Timeline
var timeline = new vis.Timeline(container, items, options);
// set focus to newest jobs
// timeline.moveTo("'.date("Y-m-d H:i:s", time()-60*60*24*4).'");
// fix: some timelines do not properly work ... but I make them visible
$(\'#' . $sDivId . ' .vis-timeline\').css(\'visibility\', \'visible\');
</script>
@@ -577,8 +619,13 @@ class cronlogrenderer extends cronlog{
;
}
public function renderJobGraphOfAllServers(){
$aData=array();
/**
* Get html code for the job graph of all servers
* @return string
*/
public function renderJobGraphOfAllServers(): string
{
$aData = [];
foreach (array_keys($this->getServers()) as $sServer) {
$this->setServer($sServer);
$aData = array_merge($aData, $this->getServerJobHistory());
@@ -588,10 +635,12 @@ class cronlogrenderer extends cronlog{
}
/**
* used in config/page-replacements.php
* generate an array of javascript lang texts
* used in config/page-replacements.php
* @return string
*/
public function renderJSLang(){
public function renderJSLang(): string
{
$aReturn = [];
foreach ($this->_aLang as $sKey => $sText) {
@@ -606,12 +655,13 @@ class cronlogrenderer extends cronlog{
}
/**
* show a single log file
* Get html code to show a single log file with syntax highligt an marking the reeturn code
*
* @param string $sLogfile logfile; [server]/[filename.log]
* @return string
*/
public function renderLogfile($sLogfile){
public function renderLogfile(string $sLogfile): string
{
$sHtml = ''
. '<button style="position: fixed;" onclick="closeOverlay();" class="btn btn-default"><i class="fas fa-chevron-left"></i> ' . $this->t('back') . '</button><br><br>'
. '<h3>' . $this->t('logfile') . ' ' . basename($sLogfile) . '</h3>'
@@ -628,7 +678,6 @@ class cronlogrenderer extends cronlog{
return $sHtml . sprintf($this->t('error-logfile-not-found'), $sMyFile);
}
if ($fileHandle = fopen($sMyFile, "r")) {
$sHtml .= '<div style="float: left;"><pre>';
while (($line = fgets($fileHandle)) !== false) {
@@ -665,14 +714,15 @@ class cronlogrenderer extends cronlog{
}
/**
* get html code for a select box with all servers
* Get html code for a select box with all servers
* @return string
*/
public function renderServerlist($sSelectedItem=false){
public function renderServerlist(string $sSelectedItem = ''): string
{
$sHtml = '';
$iMaxItemsToShow = 30;
$sHtml .= '<option value="ALL"'
.($sSelectedItem===false || $sSelectedItem==='ALL' ? ' selected="selected"' : '')
. ($sSelectedItem === '' || $sSelectedItem === 'ALL' ? ' selected="selected"' : '')
. '>[' . $this->t('ALL') . ' (' . count($this->getServers()) . ')]</option>';
foreach ($this->getServers() as $sServer => $aData) {
$sHtml .= '<option value="' . $sServer . '"'
@@ -689,7 +739,7 @@ class cronlogrenderer extends cronlog{
><button onclick="$(\'#serverfiltertext\').val(\'\'); filterServers();">X</button><br><br>'
*/
. '<select'
. ' size="'.( min(array(count($this->getServers())+1 , $iMaxItemsToShow)) ).'"'
. ' size="' . (min([count($this->getServers()) + 1, $iMaxItemsToShow])) . '"'
// . ' size="1"'
. ' onchange="setServer(this.value); return false;"'
. '>' . $sHtml . '</select>'
Loading