diff --git a/core/log.class.inc.php b/core/log.class.inc.php index 98852acfd..0e4962c43 100644 --- a/core/log.class.inc.php +++ b/core/log.class.inc.php @@ -691,11 +691,26 @@ abstract class LogAPI static::$m_oMockMetaModelConfig = $oMetaModelConfig; } - public static function Exception(string $sMessage, throwable $previous, string $sChannel = null, array $aContext = []): void + public static function Exception(string $sMessage, throwable $oException, string $sChannel = null, array $aContext = []): void { - $aContext['Error Message'] = $previous->getMessage(); - $aContext['Stack Trace'] = $previous->getTraceAsString(); - static::Error($sMessage, $sChannel, $aContext); + $aErrorLogs = []; + $aErrorLogs[] = static::PrepareErrorLog($sMessage, $oException, $aContext); + $oException = $oException->getPrevious(); + while ($oException !== null) { + $aErrorLogs[] = static::PrepareErrorLog($oException->getMessage(), $oException, $aContext, true); + $oException = $oException->getPrevious(); + } + $aErrorLogs = array_reverse($aErrorLogs); + foreach ($aErrorLogs as $aErrorLog) { + static::Error($aErrorLog['message'], $sChannel, $aErrorLog['context']); + } + } + + private static function PrepareErrorLog(string $sMessage, throwable $oException, array $aContext, bool $isPrevious = false): array + { + $aContext['Error Message'] = $oException->getMessage(); + $aContext['Stack Trace'] = $oException->getTraceAsString(); + return ['message' => ($isPrevious ? "Previous " : '')."Exception: $sMessage", 'context' => $aContext]; } public static function Error($sMessage, $sChannel = null, $aContext = []) diff --git a/pages/UI.php b/pages/UI.php index ce93b0614..02f02738e 100644 --- a/pages/UI.php +++ b/pages/UI.php @@ -1375,7 +1375,7 @@ try { $oErrorPage->add("

".Dict::S('UI:FatalErrorMessage')."

\n"); } $sErrorDetails = ($e instanceof CoreException) ? $e->getHtmlDesc() : $e->getMessage(); - $oErrorPage->error(Dict::Format('UI:Error_Details', utils::EscapeHtml($sErrorDetails))); + $oErrorPage->error(Dict::Format('UI:Error_Details', utils::EscapeHtml($sErrorDetails)), $e); $oErrorPage->output(); $sErrorStackTrace = ($e instanceof CoreException) ? $e->getFullStackTraceAsString() : $e->getTraceAsString(); @@ -1394,7 +1394,7 @@ try { $oLog->Set('data', $aData); $oLog->DBInsertNoReload(); } catch (Exception $e) { - IssueLog::Error("Failed to log issue into the DB"); + IssueLog::Exception("Failed to log issue into the DB", $e); } } } diff --git a/sources/Application/TwigBase/Controller/Controller.php b/sources/Application/TwigBase/Controller/Controller.php index 0b86aa718..d6dcde90e 100644 --- a/sources/Application/TwigBase/Controller/Controller.php +++ b/sources/Application/TwigBase/Controller/Controller.php @@ -272,7 +272,7 @@ abstract class Controller extends AbstractController $oP->add(get_class($e).' : '.utils::EscapeHtml($e->GetMessage())); $oP->output(); - IssueLog::Error($e->getMessage()); + IssueLog::Exception('HandleOperation failed for '.json_encode($this->m_sOperation), $e); } } diff --git a/sources/Application/WebPage/ErrorPage.php b/sources/Application/WebPage/ErrorPage.php index e499c2c4a..b7af8a46d 100644 --- a/sources/Application/WebPage/ErrorPage.php +++ b/sources/Application/WebPage/ErrorPage.php @@ -51,7 +51,7 @@ class ErrorPage extends NiceWebPage $this->log_warning($sText); } - public function error($sText) + public function error($sText, \Throwable $oException = null) { $this->add("
$sText
"); if (utils::IsEasterEggAllowed()) { @@ -59,6 +59,10 @@ class ErrorPage extends NiceWebPage $this->add(''); $this->add('
'.nl2br(Dict::S('UI:ErrorPage:KittyDisclaimer')).'
'); } + if (!is_null($oException)) { + $this->log_exception($sText, $oException); + return; + } $this->log_error($sText); } @@ -78,6 +82,10 @@ class ErrorPage extends NiceWebPage return parent::output(); } + public static function log_exception($sText, \Throwable $oException) + { + IssueLog::Exception($sText, $oException); + } public static function log_error($sText) { diff --git a/sources/Forms/Block/Base/FormBlock.php b/sources/Forms/Block/Base/FormBlock.php index e6e84fdc3..4bf80a794 100644 --- a/sources/Forms/Block/Base/FormBlock.php +++ b/sources/Forms/Block/Base/FormBlock.php @@ -43,6 +43,8 @@ class FormBlock extends AbstractTypeFormBlock try { // Build the form $this->BuildForm(); + } catch (FormsException $e) { + throw $e; } catch (Exception $e) { throw new FormBlockException('Unable to construct form', 0, $e); } diff --git a/sources/Forms/IO/Converter/OqlToClassConverter.php b/sources/Forms/IO/Converter/OqlToClassConverter.php index 66e36d71b..46baec02a 100644 --- a/sources/Forms/IO/Converter/OqlToClassConverter.php +++ b/sources/Forms/IO/Converter/OqlToClassConverter.php @@ -11,6 +11,7 @@ use Combodo\iTop\Service\DependencyInjection\DIException; use Combodo\iTop\Service\DependencyInjection\DIService; use Combodo\iTop\Forms\IO\Format\ClassIOFormat; use Combodo\iTop\Forms\IO\FormBlockIOException; +use Exception; /** * OQL expression to class converter. @@ -28,7 +29,11 @@ class OqlToClassConverter extends AbstractConverter } $oModelReflection = DIService::GetInstance()->GetService('ModelReflection'); - $oQuery = $oModelReflection->GetQuery($oData); + try { + $oQuery = $oModelReflection->GetQuery($oData); + } catch (Exception $e) { + throw new FormBlockIOException($e->getMessage(), $e->getCode(), $e); + } return new ClassIOFormat($oQuery->GetClass()); } }