/** * Append a message onto the end of a given log file. * * @param string $filebase The log type base to write to, (used to create ${filebase}.log). * @param string $message The message to append. * @param null|string $code Code or error type to prefix the log with. * * @throws \Exception */ function append_to($filebase, $message, $code = null){ if(class_exists('Core\\Utilities\\Logger\\LogFile')){ $log = new LogFile($filebase); $log->write($message, $code); } else{ error_log($message); } }
/** * Remove the test log file left on the filesystem. * * @depends testArchive */ public function testDelete(\Core\Utilities\Logger\LogFile $log){ // Delete will throw exceptions if there were any problems. $log->delete(); }
private static function _Rotate(){ $dir = new DirectoryLocal('logs/'); $entries = $dir->ls('log'); foreach($entries as $file){ /** @var \Core\Filestore\Backends\FileLocal $file */ $log = new LogFile($file->getBasename(true)); try{ $log->archive(); echo 'Archived ' . $file->getBasename(true) . ' log.' . NL; } catch(\Exception $e){ echo $e->getMessage(); return false; } } if(\ConfigHandler::Get('/core/logs/rotate/keep')){ $entries = $dir->ls(); $types = []; foreach($entries as $file){ /** @var \Core\Filestore\Backends\FileLocal $file */ $base = $file->getBasename(); // I want only the filename before the first '.'. $base = substr($base, 0, strpos($base, '.')); if(!isset($types[$base])){ $types[$base] = []; } $types[$base][ $file->getMTime() ] = $file; } foreach($types as $base => $files){ // This will sort the files newest-to-oldest. krsort($files); $limit = \ConfigHandler::Get('/core/logs/rotate/keep'); $x = 0; $deleted = 0; foreach($files as $file){ /** @var \Core\Filestore\Backends\FileLocal $file */ ++$x; if($x > $limit){ if($file->exists()){ $file->delete(); ++$deleted; } } } if($deleted > 0){ echo 'Purged ' . $deleted . ' old ' . $base . ' log file(s).' . NL; } } } return true; }
/** * Handle an error and report it to the Core system log. * * @param $errno * @param $errstr * @param $errfile * @param $errline * @param null $errcontext */ function error_handler($errno, $errstr, $errfile, $errline, $errcontext = null){ $type = null; $fatal = false; $code = null; $class = ''; // The exception to this is when error_reporting is explictly set to 0. // This happens when a function is called with the "@" error suppressor. // In this event, I still want to log the error, but simply do not display it on the screen. // Damn f*****g "@" operator..... $suppressed = (error_reporting() === 0); switch($errno){ case E_ERROR: case E_USER_ERROR: $fatal = true; $type = 'error'; $class = 'error'; $code = 'PHP Error'; break; case E_WARNING: case E_USER_WARNING: $type = 'error'; $class = 'warning'; $code = 'PHP Warning'; break; case E_NOTICE: case E_USER_NOTICE: $type = 'info'; $class = 'info'; $code = 'PHP Notice'; break; case E_DEPRECATED: case E_USER_DEPRECATED: $type = 'info'; $class = 'deprecated'; $code = 'PHP Deprecated Notice'; break; case E_STRICT: $type = 'info'; $class = 'warning'; $code = 'PHP Strict Warning'; $suppressed = true; break; default: $type = 'info'; $class = 'unknown'; $code = 'Unknown PHP Error [' . $errno . ']'; break; } if($suppressed){ // Ignore suppressed errors when on production. // This is required because PHP < 7.0 has some functions that can only be called with the '@' operator. // Such as LDAP binding or many things in Smarty. if(!DEVELOPMENT_MODE){ return; } $code .= ' @SUPPRESSED'; } // All errors/warnings/notices get logged! if($errfile && strpos($errfile, ROOT_PDIR) === 0){ $details = '[src: ' . '/' . substr($errfile, strlen(ROOT_PDIR)) . ':' . $errline . '] '; } elseif($errfile){ $details = '[src: ' . $errfile . ':' . $errline . '] '; } else{ $details = ''; } try{ if(!\Core::GetComponent()){ // SQUAK! Core isn't even loaded yet! return; } // Allow external systems to hook into this event. \HookHandler::DispatchHook('/core/error_handler', $code, $errstr); $log = \SystemLogModel::Factory(); $log->setFromArray([ 'type' => $type, 'code' => $code, 'message' => $details . $errstr ]); $log->save(); } catch(\Exception $e){ // meh, try a traditional log. try{ if(class_exists('Core\\Utilities\\Logger\\LogFile')){ $log = new LogFile($type); $log->write($details . $errstr, $code); } else{ error_log($details . $errstr); } } catch(\Exception $e){ // Really meh now! } } // Display all errors when in development mode. if(DEVELOPMENT_MODE && !$suppressed){ // The correct way to handle output is via EXEC_MODE. // HOWEVER, since the unit tests emulate a WEB mode so that the scripts behave as they would in the web browser, // this is not a reliable test here. if(isset($_SERVER['TERM']) || isset($_SERVER['SHELL'])){ print_error_as_text($class, $code, $errstr); } elseif(EXEC_MODE == 'WEB'){ print_error_as_html($class, $code, $errstr); } else{ print_error_as_text($class, $code, $errstr); } } // If it's a fatal error and it's not in development mode, simply display a friendly error page instead. if($fatal){ if(EXEC_MODE == 'WEB'){ require(ROOT_PDIR . 'core/templates/halt_pages/fatal_error.inc.html'); } exit(); } }