From b844251ab46c3c3394a19c57af669dc30861fa89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Milan=20P=C3=A1la?= Date: Thu, 21 Feb 2019 16:12:19 +0100 Subject: [PATCH] Monolog 2 a Tracy 2.6+ --- .travis.yml | 20 +++++++ README.md | 41 ++++++++++--- composer.json | 12 +++- src/ChannelLogger.php | 85 +++++++++++++++++++++++++++ src/ChannelLoggerFactory.php | 27 +++++++++ src/DI/Extension.php | 39 ++++++------- src/DI/PresenterBridge.php | 56 ------------------ src/Handlers/BlueScreenHandler.php | 54 +++++++++++++++++ src/Handlers/DayFileHandler.php | 87 ++++++++++++++++++++++------ src/Handlers/FlashMessageHandler.php | 68 ---------------------- 10 files changed, 314 insertions(+), 175 deletions(-) create mode 100644 .travis.yml create mode 100644 src/ChannelLogger.php create mode 100644 src/ChannelLoggerFactory.php delete mode 100644 src/DI/PresenterBridge.php create mode 100644 src/Handlers/BlueScreenHandler.php delete mode 100644 src/Handlers/FlashMessageHandler.php diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..6693b92 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,20 @@ +language: php +php: + - 7.1 + - 7.2 + - 7.3 + +script: + - composer validate + - vendor/bin/phpcs src/ --standard=vendor/pd/coding-standard/src/PeckaCodingStandard/ruleset.xml + - vendor/bin/phpcs src/ --standard=vendor/pd/coding-standard/src/PeckaCodingStandardStrict/ruleset.xml + - vendor/bin/phpstan analyse src/ --level 2 --no-progress + +before_script: + - composer install --no-interaction --prefer-dist + +sudo: false + +cache: + directories: + - $HOME/.composer/cache diff --git a/README.md b/README.md index 7e6f7fc..40d1434 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,9 @@ # MonologModule - Vytváří `DayFileHandler`, který loguje výstup Monologu do struktury `log/kanál/YYYY-MM/YYYY-MM-DD.log` - - Umožňuje zobrazit v presenteru všechen výstup Monologu prostřednictvím FlashMessage. Vhodné např. pro administraci, kdy se zobrazí všechen výstup ze synchroních operací prováděných při požadavku obsluhy (e-maily, výstupy importů/exportů, atd.) + - Vytváří `BlueScreenHandler`, který ukládá výjimky z Tracy do `log/exception/YYYY-MM/` + - Napojuje logování z Tracy do Monologu + ## Instalace @@ -15,17 +17,38 @@ $ composer require pd/monolog-module # common.neon extensions: - pd.monolog: Pd\MonologModule\DI\Extension + pd.monolog: \Pd\MonologModule\DI\Extension -monolog: +pd.monolog: name: projekt - handlers: - - Pd\MonologModule\Handlers\DayFileHandler("projekt", %logDir%) -pd.monolog: - # Povolené typy prosenterů pro zobrazení výstupu Monologu jako FlashMessage - allowedTypes: - - Pd\AdminModule\BasePresenter +services: + myService: + arguments: + logger: @\Pd\MonologModule\ChannelLoggerFactory::create('myChannel') + + - + factory: \Monolog\Processor\WebProcessor + + - + factory: \Pd\MonologModule\Handlers\DayFileHandler + arguments: + appName: myProjectName + logDir: %logDir% + + - + factory: \Pd\MonologModule\Handlers\BlueScreenHandler + arguments: + logDir: %logDir% + + + pd.monolog.logger: + setup: + - pushProcessor(@\Monolog\Processor\WebProcessor) + - pushHandler(@\Pd\MonologModule\Handlers\DayFileHandler) + - pushHandler(@\Pd\CoreModule\LogModule\Handlers\NewRelicHandler) + - pushHandler(@\Pd\MonologModule\Handlers\BlueScreenHandler) + ``` diff --git a/composer.json b/composer.json index ba48eb7..e6e9e2a 100644 --- a/composer.json +++ b/composer.json @@ -1,10 +1,18 @@ { "name": "pd/monolog-module", + "description": "Integrace Monologu do projektů PeckaDesign", "license": "MIT", "require": { - "kdyby/monolog": "1.3.*", + "monolog/monolog": "2.0.*@beta", "nette/di": "2.4.*", - "nette/application": "2.4.*" + "nette/application": "2.4.*", + "nette/security": "2.4.*", + "tracy/tracy": "^2.6.0", + "kdyby/clock": "1.0.*" + }, + "require-dev": { + "pd/coding-standard": "1.17.*", + "phpstan/phpstan-strict-rules": "0.11.*" }, "autoload": { "psr-4": { diff --git a/src/ChannelLogger.php b/src/ChannelLogger.php new file mode 100644 index 0000000..8c19707 --- /dev/null +++ b/src/ChannelLogger.php @@ -0,0 +1,85 @@ +logger = $logger; + $this->channel = $channel; + } + + + private function getContext(array $context): array + { + return ['channel' => $this->channel] + $context; + } + + + public function emergency($message, array $context = []) + { + $this->logger->emergency($message, $this->getContext($context)); + } + + + public function alert($message, array $context = []) + { + $this->logger->alert($message, $this->getContext($context)); + } + + + public function critical($message, array $context = []) + { + $this->logger->critical($message, $this->getContext($context)); + } + + + public function error($message, array $context = []) + { + $this->logger->error($message, $this->getContext($context)); + } + + + public function warning($message, array $context = []) + { + $this->logger->warning($message, $this->getContext($context)); + } + + + public function notice($message, array $context = []) + { + $this->logger->notice($message, $this->getContext($context)); + } + + + public function info($message, array $context = []) + { + $this->logger->info($message, $this->getContext($context)); + } + + + public function debug($message, array $context = []) + { + $this->logger->debug($message, $this->getContext($context)); + } + + + public function log($level, $message, array $context = []) + { + $this->logger->log($message, $this->getContext($context)); + } + +} diff --git a/src/ChannelLoggerFactory.php b/src/ChannelLoggerFactory.php new file mode 100644 index 0000000..dd4beaf --- /dev/null +++ b/src/ChannelLoggerFactory.php @@ -0,0 +1,27 @@ +logger = $logger; + } + + + public function create(string $channel): \Psr\Log\LoggerInterface + { + $logger = new ChannelLogger($this->logger, $channel); + + return $logger; + } + +} diff --git a/src/DI/Extension.php b/src/DI/Extension.php index 19e163d..63f872f 100644 --- a/src/DI/Extension.php +++ b/src/DI/Extension.php @@ -1,45 +1,42 @@ - [ - ], + 'name' => '', ]; - public function beforeCompile() + public function loadConfiguration() { + parent::loadConfiguration(); + $containerBuilder = $this->getContainerBuilder(); $config = $this->validateConfig($this->defaults); - $presenterBridge = $containerBuilder - ->addDefinition($this->prefix('presenterBridge')) - ->setClass(PresenterBridge::class, [$config['allowedTypes']]) + $containerBuilder + ->addDefinition($this->prefix('channelLoggerFactory')) + ->setFactory(\Pd\MonologModule\ChannelLoggerFactory::class) ; - $application = $containerBuilder->getDefinition($containerBuilder->getByType(Nette\Application\Application::class)); - $application->addSetup('?->onPresenter[] = ?', ['@self', [$presenterBridge, 'onPresenter']]); + $containerBuilder + ->addDefinition($this->prefix('logger')) + ->setType(\Monolog\Logger::class) + ->setFactory(\Monolog\Logger::class, ['name' => $config['name']]) + ; } - public function setCompiler(Nette\DI\Compiler $compiler, $name) + public function afterCompile(\Nette\PhpGenerator\ClassType $class) { - $parent = parent::setCompiler($compiler, $name); - - $monologExtension = new Kdyby\Monolog\DI\MonologExtension(); - $compiler->addExtension('monolog', $monologExtension); + $initialize = $class->getMethod('initialize'); - return $parent; + $initialize->addBody('$tracyLogger = new \Tracy\Bridges\Psr\PsrToTracyLoggerAdapter($this->getByType(\Psr\Log\LoggerInterface::class));'); + $initialize->addBody('\Tracy\Debugger::setLogger($tracyLogger);'); } } diff --git a/src/DI/PresenterBridge.php b/src/DI/PresenterBridge.php deleted file mode 100644 index 9092f05..0000000 --- a/src/DI/PresenterBridge.php +++ /dev/null @@ -1,56 +0,0 @@ -allowedTypes = $allowedTypes; - $this->logger = $logger; - $this->user = $user; - } - - - public function onPresenter(Nette\Application\Application $application, Nette\Application\IPresenter $presenter) - { - $success = FALSE; - foreach ($this->allowedTypes as $allowedType) { - $success = $presenter instanceof $allowedType; - } - - if ( ! $success) { - return; - } - - $handler = new Pd\MonologModule\Handlers\FlashMessageHandler($presenter, $this->user); - $this->logger->pushHandler($handler); - } - -} diff --git a/src/Handlers/BlueScreenHandler.php b/src/Handlers/BlueScreenHandler.php new file mode 100644 index 0000000..9f3387f --- /dev/null +++ b/src/Handlers/BlueScreenHandler.php @@ -0,0 +1,54 @@ +blueScreenRenderer = new \Tracy\BlueScreen(); + $this->logDirectory = $logDir; + } + + + private function getLogDirectory(\DateTimeInterface $dateTime) + { + $pathParts = [ + $this->logDirectory, + 'exception', + $dateTime->format('Y-m'), + ]; + + return \implode('/', $pathParts); + } + + + protected function write(array $record): void + { + if ( ! isset($record['context']['exception'])) { + return; + } + + $extensionLogger = new \Tracy\Logger($this->getLogDirectory($record['datetime'])); + + $exception = $record['context']['exception']; + $exceptionFile = $extensionLogger->getExceptionFile($exception); + + $this->blueScreenRenderer->renderToFile($exception, $exceptionFile); + } + +} diff --git a/src/Handlers/DayFileHandler.php b/src/Handlers/DayFileHandler.php index c0ef3d5..f93aa66 100644 --- a/src/Handlers/DayFileHandler.php +++ b/src/Handlers/DayFileHandler.php @@ -1,50 +1,99 @@ -dateTime = $dateTimeProvider->getDateTime(); $this->logDir = $logDir; + $this->appName = $appName; + $this->expandNewlines = $expandNewlines; + + $this->defaultFormatter = new \Monolog\Formatter\LineFormatter('[%datetime%] %message% %context% %extra%'); + $this->priorityFormatter = new \Monolog\Formatter\LineFormatter('[%datetime%] %level_name%: %message% %context% %extra%'); + } + + + public function handle(array $record): bool + { + if ($record['channel'] === $this->appName) { + $this->setFormatter($this->defaultFormatter); + $record['filename'] = \strtolower($record['level_name']); + } else { + $this->setFormatter($this->priorityFormatter); + $record['filename'] = $record['channel']; + } + + return parent::handle($record); + } + + + private function getFileName(\DateTimeInterface $dateTime, string $fileName) + { + $pathParts = [ + $fileName, + $dateTime->format('Y-m'), + $dateTime->format('Y-m-d') . '-' . $fileName, + ]; + + return '/' . \implode('/', $pathParts) . '.log'; } - protected function write(array $record) + protected function write(array $record): void { - $record['filename'] = $record['filename'] . '/' . $this->dateTime->format('Y-m') . '/' . $this->dateTime->format('Y-m-d') . '-' . $record['filename']; + $filePath = $this->logDir . $this->getFileName($record['datetime'], $record['filename']); + $logDirectory = \dirname($filePath); + \Nette\Utils\FileSystem::createDir($logDirectory); - $logDirectory = dirname($this->logDir . '/' . strtolower($record['filename'])); - Nette\Utils\FileSystem::createDir($logDirectory); + if ($this->expandNewlines) { + $entry = ''; + foreach (\preg_split('{[\r\n]+}', (string) $record['message']) as $line) { + $entry .= \trim($this->getFormatter()->format(['message' => $line] + $record)) . \PHP_EOL; + } + } else { + $entry = \preg_replace('#\s*\r?\n\s*#', ' ', \trim($record['formatted'])) . \PHP_EOL; + } - parent::write($record); + if ( ! @\file_put_contents($filePath, $entry, \FILE_APPEND | \LOCK_EX)) { + throw new \RuntimeException(\sprintf('Unable to write to log file %s. Is directory writable?', $filePath)); + } } } diff --git a/src/Handlers/FlashMessageHandler.php b/src/Handlers/FlashMessageHandler.php deleted file mode 100644 index a3ae9ab..0000000 --- a/src/Handlers/FlashMessageHandler.php +++ /dev/null @@ -1,68 +0,0 @@ -control = $control; - $this->formater = new Monolog\Formatter\LineFormatter('%datetime%: %message%'); - $this->setFormatter($this->formater); - $this->level = Monolog\Logger::DEBUG; - $this->user = $user; - } - - - public function isHandling(array $record) - { - $return = parent::isHandling($record); - - if ( - $return - && - $record['level'] === Monolog\Logger::DEBUG - && - ! $this->user->isInRole(Pd\User\Acl::ROLE_DEVELOPER) - ) { - $return = FALSE; - } - - return $return; - } - - - protected function write(array $record) - { - if ($record['level'] > Monolog\Logger::NOTICE) { - $level = Pd\Controls\FlashMessageControl::STATUS_ERROR; - } else { - $level = Pd\Controls\FlashMessageControl::STATUS_INFO; - } - - $this->control->flashMessage($record['formatted'], $level); - } -}