diff --git a/src/DI/MonologExtension.php b/src/DI/MonologExtension.php index 4b5f9b0..cca05a8 100644 --- a/src/DI/MonologExtension.php +++ b/src/DI/MonologExtension.php @@ -16,6 +16,7 @@ use Mallgroup\Monolog\Processor\TracyUrlProcessor; use Mallgroup\Monolog\Tracy\BlueScreenRenderer; use Mallgroup\Monolog\Tracy\MonologAdapter; +use Monolog\ErrorHandler; use Nette\Configurator; use Nette\DI\Compiler; use Nette\DI\CompilerExtension; @@ -38,6 +39,11 @@ */ class MonologExtension extends CompilerExtension { + private const + EXCEPTION_HANDLER = 'exception', + ERROR_HANDLER = 'error', + FATAL_HANDLER = 'fatal'; + /** @var PriorityDefinition[] */ private array $handlers = []; @@ -71,6 +77,13 @@ public function getConfigSchema(): Schema ]), 'registerFallback' => Expect::bool(false)->deprecated(), 'accessPriority' => Expect::string(ILogger::INFO), + 'errorHandler' => Expect::structure([ + 'handlers' => Expect::arrayOf( + Expect::anyOf(self::ERROR_HANDLER, self::EXCEPTION_HANDLER, self::FATAL_HANDLER) + ), + 'reportedOnly' => Expect::bool(true), + 'errorTypes' => Expect::int(-1), + ])->required(false), ]); } @@ -198,6 +211,29 @@ public function beforeCompile(): void /** @var ServiceDefinition $service */ $service->addSetup('setLogger', ['@' . $this->prefix('logger')]); } + + if ($this->config->errorHandler) { + $errorHandlerDefinition = $builder + ->addDefinition(($this->prefix('errorHandler'))) + ->setFactory(ErrorHandler::class, ['logger' => '@' . $this->prefix('logger')]) + ->setAutowired(false); + + if(in_array(self::ERROR_HANDLER, $this->config->errorHandler->handlers, true)){ + $errorHandlerDefinition->addSetup( + 'registerErrorHandler', + [ + 'errorTypes' => $this->config->errorHandler->errorTypes, + 'handleOnlyReportedErrors' => $this->config->errorHandler->reportedOnly + ] + ); + } + if(in_array(self::EXCEPTION_HANDLER, $this->config->errorHandler->handlers, true)){ + $errorHandlerDefinition->addSetup('registerExceptionHandler'); + } + if(in_array(self::FATAL_HANDLER, $this->config->errorHandler->handlers, true)){ + $errorHandlerDefinition->addSetup('registerFatalHandler'); + } + } } public function afterCompile(ClassType $class): void @@ -218,6 +254,11 @@ public function afterCompile(ClassType $class): void $initialize->addBody('?::$logDirectory = ?;', [new PhpLiteral(Debugger::class), $this->config->logDir]); } + + if(!empty($this->config->errorHandler->handlers)){ + $initialize->addBody('$this->getService(?);', [$this->prefix('errorHandler')]); + } + $initialize->addBody("// monolog\n($closure)();"); } diff --git a/tests/Monolog/ExtensionTest.phpt b/tests/Monolog/ExtensionTest.phpt index 30aea67..812534b 100644 --- a/tests/Monolog/ExtensionTest.phpt +++ b/tests/Monolog/ExtensionTest.phpt @@ -24,6 +24,7 @@ use Monolog\Processor\WebProcessor; use Nette\Configurator; use Tester\Assert; use Tracy\Debugger; +use Tracy\ILogger; require_once __DIR__ . '/../bootstrap.php'; @@ -56,9 +57,7 @@ class ExtensionTest extends \Tester\TestCase public function testFunctional(): void { - foreach (array_merge(glob(TEMP_DIR . '/*.log'), glob(TEMP_DIR . '/*.html')) as $logFile) { - unlink($logFile); - } + $this->cleanUpTemp(); Debugger::$logDirectory = TEMP_DIR; @@ -257,6 +256,53 @@ class ExtensionTest extends \Tester\TestCase Assert::type(FallbackNetteHandler::class, array_shift($handlers)); }, E_USER_DEPRECATED); } + + public function testErrorHandler(): void + { + Assert::error(function() { + $this->cleanUpTemp(); + $this->createContainer('errorHandler'); + + Debugger::log('tracy message 1'); + trigger_error('Custom user Notice', E_USER_NOTICE); + @trigger_error('Custom user Notice suppressed', E_USER_NOTICE); + trigger_error('Custom user Deprecated', E_USER_DEPRECATED); + @trigger_error('Custom user Deprecated suppressed', E_USER_DEPRECATED); + + trigger_error('Custom user Warning', E_USER_WARNING); + @trigger_error('Custom user Warning suppressed', E_USER_WARNING); + + Debugger::log('tracy warning message', ILogger::WARNING); + + Assert::match( + '[%a%] tracy message 1 {"at":"%a%"} []' . "\n" , + file_get_contents(TEMP_DIR . '/log/info.log') + ); + + Assert::match( + '[%a%] E_USER_NOTICE: Custom user Notice {%a%} []'. "\n". + '[%a%] E_USER_NOTICE: Custom user Notice suppressed {%a%} []'. "\n". + '[%a%] E_USER_DEPRECATED: Custom user Deprecated {%a%} []'. "\n". + '[%a%] E_USER_DEPRECATED: Custom user Deprecated suppressed {%a%} []'. "\n", + file_get_contents(TEMP_DIR . '/log/notice.log') + ); + + Assert::match( + '[%a%] E_USER_WARNING: Custom user Warning {%a%} []'. "\n". + '[%a%] E_USER_WARNING: Custom user Warning suppressed {%a%} []'. "\n". + '[%a%] tracy warning message {%a%} []'. "\n", + file_get_contents(TEMP_DIR . '/log/warning.log') + ); + }, [E_USER_NOTICE, E_USER_DEPRECATED, E_USER_WARNING]); + + } + + private function cleanUpTemp(): void + { + foreach (array_merge(glob(TEMP_DIR . '/*.log'), glob(TEMP_DIR . '/*.html')) as $logFile) { + unlink($logFile); + } + } } (new ExtensionTest())->run(); diff --git a/tests/Monolog/config/errorHandler.neon b/tests/Monolog/config/errorHandler.neon new file mode 100644 index 0000000..d60e1d1 --- /dev/null +++ b/tests/Monolog/config/errorHandler.neon @@ -0,0 +1,6 @@ +monolog: + logDir: %tempDir%/log + errorHandler: + handlers: ['exception', 'error', 'fatal'] + reportedOnly: false + errorTypes: -1 \ No newline at end of file