collect unhandled exceptions, errors from Smarty and PHP

This commit is contained in:
Daniel Seifert 2022-08-14 01:08:02 +02:00
parent a87bc1d9bd
commit c892b3bd03
Signed by: DanielS
GPG Key ID: 6A513E13AEE66170
6 changed files with 197 additions and 4 deletions

View File

@ -22,6 +22,7 @@ use D3\DebugBar\Application\Models\Collectors\SmartyCollector;
use D3\DebugBar\Application\Models\TimeDataCollectorHandler;
use DebugBar\Bridge\DoctrineCollector;
use DebugBar\Bridge\MonologCollector;
use DebugBar\DataCollector\ExceptionsCollector;
use DebugBar\DataCollector\MemoryCollector;
use DebugBar\DataCollector\MessagesCollector;
use DebugBar\DataCollector\PhpInfoCollector;
@ -163,6 +164,7 @@ class DebugBarComponent extends BaseController
$debugbar->addCollector(new RequestDataCollector());
$debugbar->addCollector(new TimeDataCollector());
$debugbar->addCollector(new MemoryCollector());
$debugbar->addCollector(new ExceptionsCollector());
// add custom collectors
$debugbar->addCollector($this->getOxidShopCollector());

View File

@ -0,0 +1,98 @@
<?php
/**
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* https://www.d3data.de
*
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
* @author D3 Data Development - Daniel Seifert <info@shopmodule.com>
* @link https://www.oxidmodule.com
*/
declare(strict_types=1);
namespace D3\DebugBar\Core;
use D3\DebugBar\Application\Component\DebugBarComponent;
use DebugBar\DataCollector\ExceptionsCollector;
use DebugBar\DebugBarException;
use OxidEsales\Eshop\Application\Controller\FrontendController;
use OxidEsales\Eshop\Core\Exception\DatabaseException;
use OxidEsales\Eshop\Core\Exception\ExceptionHandler;
use OxidEsales\Eshop\Core\Registry;
use OxidEsales\EshopCommunity\Internal\Framework\Logger\LoggerServiceFactory;
use OxidEsales\EshopCommunity\Internal\Transition\Utility\Context;
use Throwable;
class DebugBarExceptionHandler
{
/**
* Handler for uncaught exceptions.
*
* @param Throwable $exception exception object
* @throws DebugBarException
*/
public function handleUncaughtException(Throwable $exception)
{
//dumpvar(__METHOD__.__LINE__);
try {
$debugMode = (bool) \OxidEsales\Eshop\Core\Registry::get(\OxidEsales\Eshop\Core\ConfigFile::class)->getVar('iDebug');
$defaultExceptionHandler = new ExceptionHandler($debugMode);
$defaultExceptionHandler->writeExceptionToLog($exception);
} catch (Throwable $loggerException) {
/**
* Its not possible to get the logger from the DI container.
* Try again to log original exception (without DI container) in order to show the root cause of a problem.
*/
try {
$loggerServiceFactory = new LoggerServiceFactory(new Context(Registry::getConfig()));
$logger = $loggerServiceFactory->getLogger();
$logger->error($exception->getTraceAsString());
} catch (Throwable $throwableWithoutPossibilityToWriteToLogFile) {
// It is not possible to log because e.g. the log file is not writable.
}
}
global $debugBarSet;
if ($debugBarSet !== 1) {
/** @var FrontendController $activeView */
$activeView = Registry::getConfig()->getTopActiveView();
/** @var DebugBarComponent|null $debugBarComponent */
$debugBarComponent = $activeView->getComponent(DebugBarComponent::class) ?: oxNew(DebugBarComponent::class);
/** @var ExceptionsCollector $excCollector */
$excCollector = $debugBarComponent->getDebugBar()->getCollector('exceptions');
$excCollector->addThrowable($exception);
echo <<<HTML
<!DOCTYPE html>
<html>
<head>
HTML;
echo $debugBarComponent->getRenderer()->renderHead();
$debugBarComponent->addTimelineMessures();
echo <<<HTML
</head>
<body>
HTML;
$debugBarSet = 1;
echo $debugBarComponent->getRenderer()->render();
echo <<<HTML
</body>
</html>
HTML;
}
}
/**
* @param DatabaseException $exception
* @return void
* @throws DebugBarException
*/
public function handleDatabaseException(DatabaseException $exception)
{
$this->handleUncaughtException($exception);
}
}

View File

@ -16,6 +16,11 @@ declare(strict_types=1);
namespace D3\DebugBar\Modules\Core {
use OxidEsales\Eshop\Core\ShopControl;
use OxidEsales\EshopCommunity\Core\Config;
class Config_DebugBar_parent extends Config
{
}
class ShopControl_DebugBar_parent extends ShopControl
{

View File

@ -0,0 +1,29 @@
<?php
/**
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* https://www.d3data.de
*
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
* @author D3 Data Development - Daniel Seifert <info@shopmodule.com>
* @link https://www.oxidmodule.com
*/
declare(strict_types=1);
namespace D3\DebugBar\Modules\Core;
use D3\DebugBar\Core\DebugBarExceptionHandler;
class Config_DebugBar extends Config_DebugBar_parent
{
/**
* @return DebugBarExceptionHandler
*/
protected function getExceptionHandler()
{
return new DebugBarExceptionHandler();
}
}

View File

@ -16,22 +16,78 @@ declare(strict_types=1);
namespace D3\DebugBar\Modules\Core;
use D3\DebugBar\Application\Component\DebugBarComponent;
use D3\DebugBar\Core\DebugBarExceptionHandler;
use DebugBar\DataCollector\ExceptionsCollector;
use ErrorException;
use OxidEsales\Eshop\Application\Controller\FrontendController;
use OxidEsales\Eshop\Core\Registry;
class ShopControl_DebugBar extends ShopControl_DebugBar_parent
{
/**
* @throws ErrorException
*/
public function __construct()
{
$this->_d3AddDebugBarComponent();
$this->d3DebugBarSetErrorHandler();;
$this->d3DebugBarSetExceptionHandler();
$this->d3AddDebugBarComponent();
parent::__construct();
}
/**
* @return void
* @throws ErrorException
*/
protected function _d3AddDebugBarComponent(): void
public function d3DebugBarSetErrorHandler()
{
set_error_handler(function ($severity, $message, $file, $line) {
if (!(error_reporting() & $severity)) {
// This error code is not included in error_reporting.
return;
}
$smartyTemplate = $this->getSmartyTemplateLocationFromError($message);
if (is_array($smartyTemplate)) {
[$file, $line] = $smartyTemplate;
}
throw new ErrorException($message, 0, $severity, $file, $line);
});
}
/**
* @return void
*/
protected function d3DebugBarSetExceptionHandler(): void
{
set_exception_handler([
new DebugBarExceptionHandler(),
'handleUncaughtException'
]);
}
/**
* @param $messsage
* @return array|null
*/
protected function getSmartyTemplateLocationFromError($messsage)
{
if (stristr($messsage, 'Smarty error: [in ')) {
$start = strpos($messsage, '[')+1;
$end = strpos($messsage, ']');
$parts = explode(' ', substr($messsage, $start, $end - $start));
return [Registry::getConfig()->getTemplateDir(isAdmin()).$parts[1], (int) $parts[3]];
}
return null;
}
/**
* @return void
*/
protected function d3AddDebugBarComponent(): void
{
$userComponentNames = Registry::getConfig()->getConfigParam('aUserComponentNames');
$d3CmpName = DebugBarComponent::class;
@ -49,8 +105,8 @@ class ShopControl_DebugBar extends ShopControl_DebugBar_parent
public function __destruct()
{
if (!isAdmin()) {
/** @var FrontendController $activeView */
global $debugBarSet;
if (!isAdmin() && $debugBarSet !== 1) {
$activeView = Registry::getConfig()->getTopActiveView();
/** @var DebugBarComponent|null $debugBarComponent */
$debugBarComponent = $activeView->getComponent(DebugBarComponent::class);

View File

@ -13,7 +13,9 @@
declare(strict_types=1);
use D3\DebugBar\Modules\Core\Config_DebugBar;
use D3\DebugBar\Modules\Core\ShopControl_DebugBar;
use OxidEsales\Eshop\Core\Config;
use OxidEsales\Eshop\Core\ShopControl;
$sMetadataVersion = '2.1';
@ -37,6 +39,7 @@ $aModule = [
'url' => 'https://www.oxidmodule.com/',
'controllers' => [],
'extend' => [
Config::class => Config_DebugBar::class,
ShopControl::class => ShopControl_DebugBar::class,
],
'events' => [],