diff --git a/public_html/deployment/classes/logger.class.php b/public_html/deployment/classes/logger.class.php index a25fcc959bdfc1ea6681c56a093d02edc1583c57..557cb7f5b3f4398d92c53d80cd6d6c95b8ea6a1f 100644 --- a/public_html/deployment/classes/logger.class.php +++ b/public_html/deployment/classes/logger.class.php @@ -27,15 +27,17 @@ * 2022-10-16 mark longest action with an icon * 2022-12-15 make it compatible to PHP 8.2; add doc + comments * 2023-05-15 fix _getBar() - division by zero + * 2024-07-12 php8 only: use variable types; update phpdocs * ---------------------------------------------------------------------- */ -class logger { +class logger +{ /** * @var {array} array of added messages */ protected $aMessages = []; - + /** * @var {bool} flag: show debug infos? default: false */ @@ -51,21 +53,22 @@ class logger { */ protected $sCssPrefix = ''; + protected $sSourceUrl = 'https://github.com/axelhahn/ahlogger'; + // ---------------------------------------------------------------------- // CONSTRUCTOR // ---------------------------------------------------------------------- /** - * constuctor + * Constuctor * @param string $sInitMessage init message - * @return boolean */ - public function __construct($sInitMessage = "Logger was initialized.") { - $this->_iMemStart=memory_get_usage(); + public function __construct(string $sInitMessage = "Logger was initialized.") + { + $this->_iMemStart = memory_get_usage(); $this->enableDebug(true); $this->add($sInitMessage); - $this->sCssPrefix='debug-'.md5(microtime(true)); - return true; + $this->sCssPrefix = 'debug-' . md5(microtime(true)); } // ---------------------------------------------------------------------- @@ -73,15 +76,16 @@ class logger { // ---------------------------------------------------------------------- /** - * add a logging message - * @param type $sMessage - * @param type $sLevel + * Add a logging message + * @param string $sMessage + * @param string $sLevel * @return boolean */ - public function add($sMessage, $sLevel = "info") { - if (!$this->bShowDebug){ + public function add(string $sMessage, string $sLevel = "info"): bool + { + if (!$this->bShowDebug) { return false; - } + } $this->aMessages[] = array( 'time' => microtime(true), 'message' => $sMessage, @@ -93,31 +97,34 @@ class logger { } /** - * enable / disable debugging - * @param type $bEnable - * @return type + * Enable / disable debugging + * @param bool $bEnable + * @return bool */ - public function enableDebug($bEnable=true){ - return $this->bShowDebug=!!$bEnable; + public function enableDebug(bool $bEnable = true): bool + { + return $this->bShowDebug = !!$bEnable; } /** - * enable client debugging by a given array of allowed ip addresses + * Enable client debugging by a given array of allowed ip addresses * @param array $aIpArray list of ip addresses in a flat array * @return boolean */ - public function enableDebugByIp($aIpArray){ + public function enableDebugByIp(array $aIpArray): bool + { $this->enableDebug(false); - if (!$_SERVER || !is_array($_SERVER) || !array_key_exists("REMOTE_ADDR", $_SERVER)){ + if (!$_SERVER || !is_array($_SERVER) || !array_key_exists("REMOTE_ADDR", $_SERVER)) { return false; } - if (array_search($_SERVER['REMOTE_ADDR'], $aIpArray)!==false){ + if (array_search($_SERVER['REMOTE_ADDR'], $aIpArray) !== false) { $this->enableDebug(true); } + return true; } /** - * helper function: prepare array of added massages before output + * Helper function: prepare array of added massages before output * - detect warnings and errors * - detect needed time for each action * - detect longest action @@ -126,14 +133,15 @@ class logger { * * @return array */ - protected function _prepareRendering(){ - $iMem=memory_get_usage(); + protected function _prepareRendering(): array + { + $iMem = memory_get_usage(); $this->add('<hr>'); $this->add('Memory on start: ' . number_format($this->_iMemStart, 0, '.', ',') . " bytes"); - $this->add('Memory on end: ' . number_format($iMem, 0, '.', ',') . " bytes"); - $this->add('Memory peak: ' . number_format(memory_get_peak_usage(), 0, '.', ',') . " bytes"); + $this->add('Memory on end: ' . number_format($iMem, 0, '.', ',') . " bytes"); + $this->add('Memory peak: ' . number_format(memory_get_peak_usage(), 0, '.', ',') . " bytes"); - $aReturn=[ + $aReturn = [ 'totaltime' => false, 'level' => false, 'warnings' => '', @@ -154,74 +162,77 @@ class logger { foreach ($this->aMessages as $aLogentry) { $iCounter++; - if($aLogentry["level"]=="warning"){ - $bHasWarning=true; + if ($aLogentry["level"] == "warning") { + $bHasWarning = true; } - if($aLogentry["level"]=="error"){ - $bHasError=true; + if ($aLogentry["level"] == "error") { + $bHasError = true; } - $sTrId = $this->sCssPrefix.'debugTableRow' . $iCounter; + $sTrId = $this->sCssPrefix . 'debugTableRow' . $iCounter; $iDelta = $aLogentry["time"] - $iLasttime; if ($iDelta > $iMaxtime) { $iMaxtime = $iDelta; $sMaxRowId = $sTrId; } - $iMaxmem=max($aLogentry["memory"], $iMaxmem); + $iMaxmem = max($aLogentry["memory"], $iMaxmem); if (($iDelta > 1) || $aLogentry["level"] == "warning") { - $aReturn['warnings'].='<a href="#' . $sTrId . '" title="' . sprintf("%01.4f", $iDelta) . ' s">' . $iCounter . '</a> '; + $aReturn['warnings'] .= '<a href="#' . $sTrId . '" title="' . sprintf("%01.4f", $iDelta) . ' s">' . $iCounter . '</a> '; } if ($aLogentry["level"] == "error") { - $aReturn['errors'].='<a href="#' . $sTrId . '" title="' . sprintf("%01.4f", $iDelta) . ' s">' . $iCounter . '</a> '; + $aReturn['errors'] .= '<a href="#' . $sTrId . '" title="' . sprintf("%01.4f", $iDelta) . ' s">' . $iCounter . '</a> '; } - $aReturn['entries'][]=[ - 'time'=>$aLogentry["time"], - 'level'=>$aLogentry["level"], - 'message'=>$aLogentry["message"], - 'memory'=>sprintf("%01.2f", $aLogentry["memory"]/1024/1024), // MB + $aReturn['entries'][] = [ + 'time' => $aLogentry["time"], + 'level' => $aLogentry["level"], + 'message' => $aLogentry["message"], + 'memory' => sprintf("%01.2f", $aLogentry["memory"] / 1024 / 1024), // MB - 'trid'=>$sTrId, - 'trclass'=>$aLogentry["level"], - 'counter'=>$iCounter, - 'timer'=>sprintf("%01.3f", $aLogentry["time"] - $sStarttime), - 'delta'=>sprintf("%01.0f", $iDelta*1000), + 'trid' => $sTrId, + 'trclass' => $aLogentry["level"], + 'counter' => $iCounter, + 'timer' => sprintf("%01.3f", $aLogentry["time"] - $sStarttime), + 'delta' => sprintf("%01.0f", $iDelta * 1000), ]; $iLasttime = $aLogentry["time"]; } - $aReturn['level']=($bHasWarning + $aReturn['level'] = ($bHasWarning ? ($bHasError ? 'error' : 'warning') : '' ); - $aReturn['maxrowid']=$sMaxRowId; - $aReturn['maxtime']=sprintf("%01.3f", $iMaxtime); - $aReturn['maxmem']=sprintf("%01.2f", $iMaxmem/1024/1024); - $aReturn['totaltime']=sprintf("%01.3f", $aLogentry['time']-$aReturn['entries'][0]['time']); + $aReturn['maxrowid'] = $sMaxRowId; + $aReturn['maxtime'] = sprintf("%01.3f", $iMaxtime); + $aReturn['maxmem'] = sprintf("%01.2f", $iMaxmem / 1024 / 1024); + $aReturn['totaltime'] = sprintf("%01.3f", $aLogentry['time'] - $aReturn['entries'][0]['time']); return $aReturn; } /** - * get html code for a progressbar with divs - * @param {int|float} $iVal value between 0..max value - * @param {int|float} $iMax max value - * @return {string} + * Get html code for a progressbar with divs + * @param int|float $iVal value between 0..max value + * @param int|float $iMax max value + * @return string */ - protected function _getBar($iVal, $iMax){ - return $iMax>0 - ? '<div class="bar"><div class="progress" style="width: '.($iVal/$iMax*100).'%;"> </div></div>' + protected function _getBar(int|float $iVal, int|float $iMax): string + { + return $iMax > 0 + ? '<div class="bar"><div class="progress" style="width: ' . ($iVal / $iMax * 100) . '%;"> </div></div>' : '' - ; + ; } /** - * render output of all logging messages + * Render output of all logging messages + * @return string */ - public function render() { - if (!$this->bShowDebug){ + public function render(): string + { + if (!$this->bShowDebug) { return false; } - $aData=$this->_prepareRendering(); + $aData = $this->_prepareRendering(); /* Array @@ -252,57 +263,58 @@ class logger { ) */ - $sOut=''; + $sOut = ''; // echo '<pre>'; print_r($aData); die(); - foreach ($aData['entries'] as $aLogentry){ - $sOut.='<tr class="'.$this->sCssPrefix.'-level-' . $aLogentry["level"] . ''.($aLogentry["trid"]==$aData["maxrowid"] ? ' '.$this->sCssPrefix.'-maxrow' : '').'" ' - .'id="' . $aLogentry["trid"] . '">' . - '<td>' . $aLogentry["counter"] . '</td>' . - '<td>' . $aLogentry["level"] . '</td>' . - '<td>' . $aLogentry["timer"] . '</td>' . - '<td>' . $this->_getBar($aLogentry["delta"], $aData["maxtime"]*1000). $aLogentry["delta"] .' ms'.($aLogentry["delta"]==$aData['maxtime']*1000 ? ' ⏱️' : '').'</td>' . - '<td>' . $this->_getBar($aLogentry["memory"], $aData["maxmem"]) . $aLogentry["memory"] .' MB'. '</td>' . - '<td>' . $aLogentry["message"] . '</td>' . - '</tr>'; + foreach ($aData['entries'] as $aLogentry) { + $sOut .= '<tr class="' . $this->sCssPrefix . '-level-' . $aLogentry["level"] . '' . ($aLogentry["trid"] == $aData["maxrowid"] ? ' ' . $this->sCssPrefix . '-maxrow' : '') . '" ' + . 'id="' . $aLogentry["trid"] . '">' . + '<td align="right">' . $aLogentry["counter"] . '</td>' . + '<td>' . $aLogentry["level"] . '</td>' . + '<td align="right">' . $aLogentry["timer"] . '</td>' . + '<td align="right">' . $this->_getBar($aLogentry["delta"], $aData["maxtime"] * 1000) . ($aLogentry["delta"] == $aData['maxtime'] * 1000 ? '⏱️ ' : '') . $aLogentry["delta"] . ' ms</td>' . + '<td align="right">' . $this->_getBar($aLogentry["memory"], $aData["maxmem"]) . $aLogentry["memory"] . ' MB' . '</td>' . + '<td>' . $aLogentry["message"] . '</td>' . + '</tr>'; } - if ($sOut){ + if ($sOut) { $sOut = ' <style> - .'.$this->sCssPrefix.'-info {position: fixed; top: 6em; right: 1em; background: rgba(200,228,255, 0.8); border: 1px solid; z-index: 99999;} - .'.$this->sCssPrefix.'-info .head {background: rgba(0,0,0,0.4); color: #fff;padding: 0em 0.5em 0.2em; } - .'.$this->sCssPrefix.'-info .content {padding: 0.5em; } - .'.$this->sCssPrefix.'-info .content .total {font-size: 160%; color: rgba(0,0,0,0.5); margin: 0.3em 0; display: inline-block;} + .' . $this->sCssPrefix . '-info {position: fixed; top: 6em; right: 1em; background: rgba(230,240,255, 0.8); border: 2px solid rgba(0,0,0,0.2); border-radius: 0.3em; z-index: 99999;} + .' . $this->sCssPrefix . '-info .loggerhead {background: rgba(0,0,0,0.4); color: #fff;padding: 0em 0.5em 0.2em; border-radius: 0.3em 0.3em 0 0; } + .' . $this->sCssPrefix . '-info .loggercontent {padding: 0.5em; } + .' . $this->sCssPrefix . '-info .loggercontent .total {font-size: 160%; color: rgba(0,0,0,0.5); margin: 0.3em 0; display: inline-block;} - .'.$this->sCssPrefix.'-messages {margin: 5em 2em 2em;} - .'.$this->sCssPrefix.'-messages .bar {background: rgba(0,0,0,0.03); height: 1.4em; position: absolute; width: 6em; border-right: 1px solid rgba(0,0,0,0.2);} - .'.$this->sCssPrefix.'-messages .progress {background: rgba(100,140,180,0.2); height: 1.4em; padding: 0;} - .'.$this->sCssPrefix.'-messages table{background: #fff; color: #222;table-layout:fixed; } - .'.$this->sCssPrefix.'-messages table th{background: none;} - .'.$this->sCssPrefix.'-messages table th.barcol{min-width: 7em; position: relative;} - .'.$this->sCssPrefix.'-messages table td{padding: 3px; vertical-align: top;} - .'.$this->sCssPrefix.'-messages table th:hover{background:#aaa !important;} + .' . $this->sCssPrefix . '-messages {margin: 5em 2em 2em;} + .' . $this->sCssPrefix . '-messages>h3 {font-size: 150%; margin: 0 0 0.5em 0;} + .' . $this->sCssPrefix . '-messages .bar {background: rgba(0,0,0,0.03); height: 1.4em; position: absolute; width: 6em; border-right: 1px solid rgba(0,0,0,0.2);} + .' . $this->sCssPrefix . '-messages .progress {background: rgba(100,140,180,0.2); height: 1.4em; padding: 0; float: left;} + .' . $this->sCssPrefix . '-messages table{background: #fff; color: #222;table-layout:fixed; border: 2px solid rgba(0,0,0,0.2); border-radius: 0.5em;} + .' . $this->sCssPrefix . '-messages table th{background: none; color: #222; border-bottom: 2px solid rgba(0,0,0,0.4);} + .' . $this->sCssPrefix . '-messages table th.barcol{min-width: 7em; position: relative;} + .' . $this->sCssPrefix . '-messages table td{padding: 3px; vertical-align: top;} + .' . $this->sCssPrefix . '-messages table th:hover{background:#aaa !important;} - .'.$this->sCssPrefix.'-level-info{background: #e0e8f8; color:#124} - .'.$this->sCssPrefix.'-level-warning{background: #fcf8e3; color: #980;} - .'.$this->sCssPrefix.'-level-error{background: #fce0e0; color: #944;} - .'.$this->sCssPrefix.'-maxrow{color:#f33; font-weight: bold;} + .' . $this->sCssPrefix . '-level-info{background: #f0f4f4; color:#124} + .' . $this->sCssPrefix . '-level-warning{background: #fcf8e3; color: #980;} + .' . $this->sCssPrefix . '-level-error{background: #fce0e0; color: #944;} + .' . $this->sCssPrefix . '-maxrow{color:#f33; font-weight: bold;} </style> - <div class="'.$this->sCssPrefix.' '.$this->sCssPrefix.'-info '.$this->sCssPrefix.'-level-'.$aData['level'].'"> - <div class="head">ahLogger</div> - <div class="content"> + <div class="' . $this->sCssPrefix . ' ' . $this->sCssPrefix . '-info ' . $this->sCssPrefix . '-level-' . $aData['level'] . '" onclick="location.href=\'#' . $this->sCssPrefix . '-messages\';"> + <div class="loggerhead">ahLogger</div> + <div class="loggercontent"> <span class="total">⏱️ ' . $aData['totaltime'] . ' s</span><br> - 🪲 <a href="#'.$this->sCssPrefix.'-messages">Debug infos</a> | 🔺 <a href="#">top</a><br> - <span>longest action: ⏱️ <a href="#' . $aData['maxrowid'] . '">' . ($aData['maxtime']*1000) . ' ms</a></span> - ' . ($aData['errors'] ? '<br><span>‼️ Errors: '.$aData['errors'] . '</span>' : '').' - ' . ($aData['warnings'] ? '<br><span>⚠️ Warnings: '.$aData['warnings'] . '</span>' : '').' + 🪲 <a href="#' . $this->sCssPrefix . '-messages">Debug infos</a> | 🔺 <a href="#">top</a><br> + <span>longest action: ⏱️ <a href="#' . $aData['maxrowid'] . '">' . ($aData['maxtime'] * 1000) . ' ms</a></span> + ' . ($aData['errors'] ? '<br><span>‼️ Errors: ' . $aData['errors'] . '</span>' : '') . ' + ' . ($aData['warnings'] ? '<br><span>⚠️ Warnings: ' . $aData['warnings'] . '</span>' : '') . ' </div> </div> - <div id="'.$this->sCssPrefix.'-messages" class="'.$this->sCssPrefix.' '.$this->sCssPrefix.'-messages"> - DEBUG :: LOG MESSAGES<br>' - . ($aData['errors'] ? '<span>Errors: '.$aData['errors'] . '</span><br>' : '') - . ($aData['warnings'] ? '<span>Warnings: '.$aData['warnings'] . '</span><br>' : '') - .'<br> + <div id="' . $this->sCssPrefix . '-messages" class="' . $this->sCssPrefix . ' ' . $this->sCssPrefix . '-messages"> + <h3>ahLogger 🪳 Debug messages</h3>' + . ($aData['errors'] ? '<span>Errors: ' . $aData['errors'] . '</span><br>' : '') + . ($aData['warnings'] ? '<span>Warnings: ' . $aData['warnings'] . '</span><br>' : '') + . '<br> <table > <thead> <tr> @@ -313,32 +325,36 @@ class logger { <th class="barcol">memory</th> <th>message</th> </tr></thead><tbody> - ' . $sOut . '</tbody></table>' + ' . $sOut + . '</tbody></table>' + . '🌐 <a href="'.$this->sSourceUrl.'" target="_blank">'.$this->sSourceUrl.'</a>' ; - } + } return $sOut; } - /** - * render output of all logging messages for cli output + + /** + * Render output of all logging messages for cli output * @return string */ - public function renderCli(){ - if (!$this->bShowDebug){ + public function renderCli(): string + { + if (!$this->bShowDebug) { return false; } - $aData=$this->_prepareRendering(); + $aData = $this->_prepareRendering(); - $sOut=''; - foreach ($aData['entries'] as $aLogentry){ - $sOut.=$aLogentry["timer"].' | ' - .$aLogentry["delta"].' ms | ' - .$aLogentry["level"].' | ' - .(sprintf("%01.3f", $aLogentry["memory"]/1024/1024)).' MB | ' - .$aLogentry["message"].' ' - . "\n" - ; + $sOut = ''; + foreach ($aData['entries'] as $aLogentry) { + $sOut .= $aLogentry["timer"] . ' | ' + . $aLogentry["delta"] . ' ms | ' + . $aLogentry["level"] . ' | ' + . (sprintf("%01.3f", $aLogentry["memory"] / 1024 / 1024)) . ' MB | ' + . $aLogentry["message"] . ' ' + . "\n" + ; } - $sOut.="\nTotal time: ".$aData['totaltime'] . "\n"; + $sOut .= "\nTotal time: " . $aData['totaltime'] . "\n"; return $sOut; } }