├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── composer.json ├── examples ├── container-interop-config.php └── generic-factory.php └── src ├── AbstractDiContainerLoggerFactory.php ├── Config ├── BaseConfig.php ├── ConfigAssertion.php ├── FormatterConfig.php ├── HandlerConfig.php ├── LoggerConfig.php ├── ParametrizedObjectConfig.php └── ProcessorConfig.php ├── DiContainerLoggerFactory.php ├── Exception ├── BadStaticDiContainerFactoryUsage.php ├── CannotResolveLoggerComponent.php ├── InvalidConfig.php └── MonologFactoryException.php ├── Helper ├── GenericObjectFactory.php └── ObjectFactory.php └── LoggerFactory.php /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | ## 3.1.0 - 2020-12-14 6 | ### Added 7 | - [9: Allow PHP 8 installations](https://github.com/nikolaposa/monolog-factory/pull/9) 8 | ### Changed 9 | - [8: Migration to GitHub Actions](https://github.com/nikolaposa/monolog-factory/pull/8) thanks to [Alejandro Celaya](https://github.com/acelaya) 10 | 11 | ### Added 12 | - Support for Monolog v2 13 | - Support for configuring Logger timezone 14 | 15 | ## 3.0.0 - 2019-11-30 16 | ### Added 17 | - Support for Monolog v2 18 | - Support for configuring Logger timezone 19 | 20 | ### Changed 21 | - PHP 7.2 is now the minimum required version 22 | - Monolog 2.0 is now the minimum required version 23 | - Use PSR-11 instead of ContainerInterop 24 | - Rename `LoggerFactory::createLogger()` to `LoggerFactory::create()` 25 | - Reformulate Options into Config 26 | - Rename `options` configuration key to `params` 27 | - Handler-level `processors` and `formatter` must be supplied as distinct configuration keys (out of `params`) 28 | 29 | ### Removed 30 | - `LoggerFactory::createHandler()` 31 | - `LoggerFactory::createProcessor()` 32 | - `LoggerFactory::createFormatter()` 33 | 34 | ## 2.0.2 - 2018-10-08 35 | ### Fixed 36 | - [4: Cannot define configuration for GroupHandler](https://github.com/nikolaposa/monolog-factory/issues/4) 37 | 38 | ## 2.0.1 - 2018-09-22 39 | ### Fixed 40 | - [3: Cannot define logger configuration for handlers that depend on interfaces or abstract classes in their constructors](https://github.com/nikolaposa/monolog-factory/issues/3) 41 | 42 | ## 2.0.0 - 2017-09-22 43 | ### Added 44 | - `AbstractDiContainerLoggerFactory` to allow for having a custom logger config resolution strategy. 45 | - Possibility for defining per-handler processors. 46 | 47 | ### Changed 48 | - Rename `ContainerInteropLoggerFactory` to `DiContainerLoggerFactory`. 49 | 50 | ## 1.0.0 - 2017-06-15 51 | ### Changed 52 | - Improved error handling in ContainerInteropLoggerFactory. 53 | 54 | ### Fixed 55 | - Proper ordering of handlers and processors. 56 | - `ContainerInteropLoggerFactory` resolves logger configuration from either `Config` and `config` container entries. 57 | 58 | ## 0.1.0 - 2017-06-11 59 | 60 | 61 | [Unreleased]: https://github.com/nikolaposa/monolog-factory/compare/3.0.0...HEAD 62 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are accepted via Pull Requests on [Github](https://github.com/nikolaposa/monolog-factory). 4 | 5 | ## Running tests 6 | 7 | ``` bash 8 | $ composer test 9 | ``` 10 | 11 | ## Fixing coding standards issues 12 | 13 | ``` bash 14 | $ composer cs-fix 15 | ``` 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 Nikola Posa 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Monolog Factory 2 | 3 | [![Build Status][ico-build]][link-build] 4 | [![Code Quality][ico-code-quality]][link-code-quality] 5 | [![Code Coverage][ico-code-coverage]][link-code-coverage] 6 | [![Latest Version][ico-version]][link-packagist] 7 | [![PDS Skeleton][ico-pds]][link-pds] 8 | 9 | [Monolog][link-monolog] Factory that allows configuration-based creation of Logger objects. 10 | 11 | In addition to the generic factory, this package features one to be used with [PSR-11][link-psr11] dependency injection containers. 12 | 13 | ## Installation 14 | 15 | The preferred method of installation is via [Composer](http://getcomposer.org/). Run the following command to install 16 | the latest version of a package and add it to your project's `composer.json`: 17 | 18 | ```bash 19 | composer require nikolaposa/monolog-factory 20 | ``` 21 | 22 | ## Usage 23 | 24 | **Generic factory** 25 | 26 | ``` php 27 | use Monolog\Formatter\HtmlFormatter; 28 | use Monolog\Handler\NativeMailerHandler; 29 | use Monolog\Logger; 30 | use Monolog\Processor\PsrLogMessageProcessor; 31 | use MonologFactory\LoggerFactory; 32 | 33 | $loggerFactory = new LoggerFactory(); 34 | 35 | $logger = $loggerFactory->create('my_logger', [ 36 | 'handlers' => [ 37 | [ 38 | 'name' => NativeMailerHandler::class, 39 | 'params' => [ 40 | 'to' => 'test@example.com', 41 | 'subject' => 'Test', 42 | 'from' => 'noreply@example.com', 43 | 'level' => Logger::ALERT, 44 | ], 45 | 'formatter' => [ 46 | 'name' => HtmlFormatter::class, 47 | ], 48 | ], 49 | ], 50 | 'processors' => [ 51 | [ 52 | 'name' => PsrLogMessageProcessor::class, 53 | ], 54 | ], 55 | ]); 56 | ``` 57 | 58 | **DI container factory configuration** 59 | 60 | ```php 61 | use Monolog\Formatter\HtmlFormatter; 62 | use Monolog\Handler\BufferHandler; 63 | use Monolog\Handler\NativeMailerHandler; 64 | use Monolog\Logger; 65 | use Monolog\Processor\PsrLogMessageProcessor; 66 | use MonologFactory\DiContainerLoggerFactory; 67 | 68 | return [ 69 | 'logger' => [ 70 | 'logger1' => [ 71 | 'name' => 'logger1', 72 | 'handlers' => [ 73 | [ 74 | 'name' => NativeMailerHandler::class, 75 | 'params' => [ 76 | 'to' => 'test@example.com', 77 | 'subject' => 'Test', 78 | 'from' => 'noreply@example.com', 79 | 'level' => Logger::ALERT, 80 | ], 81 | 'formatter' => [ 82 | 'name' => HtmlFormatter::class, 83 | ], 84 | ], 85 | ], 86 | 'processors' => [ 87 | [ 88 | 'name' => PsrLogMessageProcessor::class, 89 | ], 90 | ], 91 | ], 92 | 'logger2' => [ 93 | 'name' => 'logger2', 94 | 'handlers' => [ 95 | [ 96 | 'name' => BufferHandler::class, 97 | 'params' => [ 98 | 'handler' => [ 99 | '__class__' => NativeMailerHandler::class, 100 | 'to' => 'test@example.com', 101 | 'subject' => 'Test', 102 | 'from' => 'noreply@example.com', 103 | ], 104 | 'buffer_limit' => 5, 105 | ], 106 | 'processors' => [ 107 | [ 108 | 'name' => MemoryUsageProcessor::class, 109 | ], 110 | ], 111 | ], 112 | ], 113 | 'processors' => [ 114 | [ 115 | 'name' => PsrLogMessageProcessor::class, 116 | ], 117 | ], 118 | ], 119 | ], 120 | 'di' => [ 121 | 'factories' => [ 122 | 'Logger1' => new DiContainerLoggerFactory('logger1'), 123 | //... or more preferred/optimal way: 124 | 'Logger2' => [DiContainerLoggerFactory::class, 'logger2'], 125 | ], 126 | ], 127 | ]; 128 | ``` 129 | 130 | See [more examples][link-examples]. 131 | 132 | ## Credits 133 | 134 | - [Nikola Poša][link-author] 135 | - [All Contributors][link-contributors] 136 | 137 | ## License 138 | 139 | Released under MIT License - see the [License File](LICENSE) for details. 140 | 141 | 142 | [ico-version]: https://poser.pugx.org/nikolaposa/monolog-factory/v/stable 143 | [ico-build]: https://github.com/nikolaposa/monolog-factory/workflows/Build/badge.svg?branch=master 144 | [ico-code-coverage]: https://scrutinizer-ci.com/g/nikolaposa/monolog-factory/badges/coverage.png?b=master 145 | [ico-code-quality]: https://scrutinizer-ci.com/g/nikolaposa/monolog-factory/badges/quality-score.png?b=master 146 | [ico-pds]: https://img.shields.io/badge/pds-skeleton-blue.svg 147 | 148 | [link-monolog]: https://github.com/Seldaek/monolog 149 | [link-psr11]: https://www.php-fig.org/psr/psr-11/ 150 | [link-examples]: examples 151 | [link-packagist]: https://packagist.org/packages/nikolaposa/monolog-factory 152 | [link-build]: https://github.com/nikolaposa/monolog-factory/actions 153 | [link-code-coverage]: https://scrutinizer-ci.com/g/nikolaposa/monolog-factory/code-structure 154 | [link-code-quality]: https://scrutinizer-ci.com/g/nikolaposa/monolog-factory 155 | [link-pds]: https://github.com/php-pds/skeleton 156 | [link-author]: https://github.com/nikolaposa 157 | [link-contributors]: ../../contributors 158 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nikolaposa/monolog-factory", 3 | "description": "Configuration-based Monolog factory", 4 | "type": "library", 5 | "license": "MIT", 6 | "keywords": [ 7 | "monolog", 8 | "factory", 9 | "container", 10 | "psr11" 11 | ], 12 | "authors": [ 13 | { 14 | "name": "Nikola Poša", 15 | "email": "posa.nikola@gmail.com", 16 | "homepage": "https://www.nikolaposa.in.rs" 17 | } 18 | ], 19 | "config": { 20 | "sort-packages": true 21 | }, 22 | "require": { 23 | "php": "^7.2 || ^8.0", 24 | "beberlei/assert": "^3.2", 25 | "monolog/monolog": "^2.0", 26 | "nikolaposa/cascader": "^1.3", 27 | "psr/container": "^1.0 || ^2.0" 28 | }, 29 | "require-dev": { 30 | "friendsofphp/php-cs-fixer": "^2.7", 31 | "phpunit/phpunit": "^8.0 || ^9.4", 32 | "rollbar/rollbar": "^2.0" 33 | }, 34 | "autoload": { 35 | "psr-4": { 36 | "MonologFactory\\": "src/" 37 | } 38 | }, 39 | "autoload-dev": { 40 | "psr-4": { 41 | "MonologFactory\\Tests\\": "tests/" 42 | } 43 | }, 44 | "scripts": { 45 | "test": "phpunit --colors=always", 46 | "cs-fix": "php-cs-fixer fix --config=.php_cs --allow-risky=yes", 47 | "cs-check": "php-cs-fixer fix --config=.php_cs --allow-risky=yes -v --diff --dry-run" 48 | }, 49 | "extra": { 50 | "branch-alias": { 51 | "dev-master": "3.1.x-dev" 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /examples/container-interop-config.php: -------------------------------------------------------------------------------- 1 | [ 15 | 'logger1' => [ 16 | 'name' => 'logger1', 17 | 'handlers' => [ 18 | [ 19 | 'name' => NativeMailerHandler::class, 20 | 'params' => [ 21 | 'to' => 'test@example.com', 22 | 'subject' => 'Test', 23 | 'from' => 'noreply@example.com', 24 | 'level' => Logger::ALERT, 25 | 26 | ], 27 | 'formatter' => [ 28 | 'name' => HtmlFormatter::class, 29 | ], 30 | ], 31 | ], 32 | 'processors' => [ 33 | [ 34 | 'name' => PsrLogMessageProcessor::class, 35 | ], 36 | ], 37 | ], 38 | 'logger2' => [ 39 | 'name' => 'logger2', 40 | 'handlers' => [ 41 | 'DefaultLoggerHandler', //service name 42 | [ 43 | 'name' => NativeMailerHandler::class, 44 | 'params' => [ 45 | 'to' => 'test@example.com', 46 | 'subject' => 'Test', 47 | 'from' => 'noreply@example.com', 48 | 'level' => Logger::ALERT, 49 | ], 50 | 'formatter' => 'HtmlLoggerFormatter', //service name 51 | ], 52 | ], 53 | 'processors' => [ 54 | 'MemoryUsageProcessor', //service name 55 | ], 56 | ], 57 | ], 58 | 'di' => [ 59 | 'Logger1' => new DiContainerLoggerFactory('logger1'), 60 | 'Logger2' => [DiContainerLoggerFactory::class, 'logger2'], //static variance; recommended for having plain-array configurations 61 | 'DefaultLoggerHandler' => function () { 62 | return new NullHandler(); 63 | }, 64 | 'HtmlLoggerFormatter' => function () { 65 | return new HtmlFormatter(); 66 | }, 67 | 'MemoryUsageLoggerProcessor' => function () { 68 | return new MemoryUsageProcessor(); 69 | }, 70 | ], 71 | ]; 72 | -------------------------------------------------------------------------------- /examples/generic-factory.php: -------------------------------------------------------------------------------- 1 | create('logger1', [ 18 | 'handlers' => [ 19 | new NullHandler(), 20 | ], 21 | 'processors' => [ 22 | new PsrLogMessageProcessor(), 23 | ], 24 | ]); 25 | 26 | //plain-array handlers/processors configuration 27 | $logger2 = $loggerFactory->create('logger2', [ 28 | 'handlers' => [ 29 | [ 30 | 'name' => NativeMailerHandler::class, 31 | 'params' => [ 32 | 'to' => 'test@example.com', 33 | 'subject' => 'Test', 34 | 'from' => 'noreply@example.com', 35 | 'level' => Logger::ALERT, 36 | ], 37 | 'formatter' => [ 38 | 'name' => HtmlFormatter::class, 39 | ], 40 | ], 41 | ], 42 | 'processors' => [ 43 | [ 44 | 'name' => PsrLogMessageProcessor::class, 45 | ], 46 | ], 47 | ]); 48 | -------------------------------------------------------------------------------- /src/AbstractDiContainerLoggerFactory.php: -------------------------------------------------------------------------------- 1 | loggerName = $loggerName; 31 | } 32 | 33 | public function __invoke(ContainerInterface $container): Logger 34 | { 35 | $this->container = $container; 36 | 37 | $loggerConfig = array_merge([ 38 | LoggerConfig::NAME => $this->loggerName, 39 | LoggerConfig::HANDLERS => [], 40 | LoggerConfig::PROCESSORS => [], 41 | ], $this->getLoggerConfig($this->loggerName)); 42 | 43 | return $this->createLogger($loggerConfig); 44 | } 45 | 46 | public static function __callStatic(string $name, array $arguments): Logger 47 | { 48 | if (0 === count($arguments) || ! ($container = current($arguments)) instanceof ContainerInterface) { 49 | throw BadStaticDiContainerFactoryUsage::missingContainerArgument(static::class); 50 | } 51 | 52 | return (new static($name))->__invoke($container); 53 | } 54 | 55 | abstract protected function getLoggerConfig(string $loggerName): array; 56 | 57 | protected function createLogger(array $config): Logger 58 | { 59 | if (is_array($config[LoggerConfig::HANDLERS])) { 60 | $config[LoggerConfig::HANDLERS] = $this->prepareHandlers($config[LoggerConfig::HANDLERS]); 61 | } 62 | 63 | if (is_array($config[LoggerConfig::PROCESSORS])) { 64 | $config[LoggerConfig::PROCESSORS] = $this->prepareProcessors($config[LoggerConfig::PROCESSORS]); 65 | } 66 | 67 | return static::getLoggerFactory()->create($config[LoggerConfig::NAME], $config); 68 | } 69 | 70 | protected function getContainer(): ContainerInterface 71 | { 72 | return $this->container; 73 | } 74 | 75 | private function prepareHandlers(array $handlers): array 76 | { 77 | return array_map(function ($handler) { 78 | if (is_string($handler)) { 79 | $handler = $this->resolveHandler($handler); 80 | } elseif (is_array($handler) && isset($handler[HandlerConfig::FORMATTER]) && is_string($handler[HandlerConfig::FORMATTER])) { 81 | $handler[HandlerConfig::FORMATTER] = $this->resolveFormatter($handler[HandlerConfig::FORMATTER]); 82 | } 83 | 84 | return $handler; 85 | }, $handlers); 86 | } 87 | 88 | private function prepareProcessors(array $processors): array 89 | { 90 | return array_map(function ($processor) { 91 | if (is_string($processor)) { 92 | $processor = $this->resolveProcessor($processor); 93 | } 94 | 95 | return $processor; 96 | }, $processors); 97 | } 98 | 99 | private function resolveHandler(string $handlerName): HandlerInterface 100 | { 101 | return $this->resolveFromContainer($handlerName); 102 | } 103 | 104 | private function resolveFormatter(string $formatterName): FormatterInterface 105 | { 106 | return $this->resolveFromContainer($formatterName); 107 | } 108 | 109 | private function resolveProcessor(string $processorName): callable 110 | { 111 | return $this->resolveFromContainer($processorName); 112 | } 113 | 114 | private function resolveFromContainer(string $serviceOrFactory) 115 | { 116 | try { 117 | if ($this->container->has($serviceOrFactory)) { 118 | return $this->container->get($serviceOrFactory); 119 | } 120 | 121 | if (class_exists($serviceOrFactory)) { 122 | $factory = new $serviceOrFactory(); 123 | return $factory($this->container); 124 | } 125 | } catch (Throwable $ex) { 126 | throw CannotResolveLoggerComponent::resolutionFailed($serviceOrFactory, $ex); 127 | } 128 | 129 | throw CannotResolveLoggerComponent::unknownService($serviceOrFactory); 130 | } 131 | 132 | protected static function getLoggerFactory(): LoggerFactory 133 | { 134 | if (null === self::$loggerFactory) { 135 | self::$loggerFactory = new LoggerFactory(); 136 | } 137 | 138 | return self::$loggerFactory; 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/Config/BaseConfig.php: -------------------------------------------------------------------------------- 1 | processors = $processors; 28 | $this->formatter = $formatter; 29 | } 30 | 31 | public static function fromArray(array $config) 32 | { 33 | $config = self::filter($config); 34 | 35 | return new static( 36 | $config[self::NAME], 37 | $config[self::PARAMETERS], 38 | array_map(function ($processor) { 39 | return is_array($processor) ? ProcessorConfig::fromArray($processor) : $processor; 40 | }, $config[self::PROCESSORS]), 41 | is_array($config[self::FORMATTER]) 42 | ? FormatterConfig::fromArray($config[self::FORMATTER]) 43 | : $config[self::FORMATTER] 44 | ); 45 | } 46 | 47 | protected static function defaults(): array 48 | { 49 | return array_merge(parent::defaults(), [ 50 | self::PROCESSORS => [], 51 | self::FORMATTER => null, 52 | ]); 53 | } 54 | 55 | protected static function validate(array $config): void 56 | { 57 | parent::validate($config); 58 | ConfigAssertion::isArray($config[self::PROCESSORS], "'" . self::PROCESSORS . "' must be an array"); 59 | ConfigAssertion::allIsArrayOrCallable($config[self::PROCESSORS], "'" . self::PROCESSORS . "' must be an array of callables or configuration arrays"); 60 | ConfigAssertion::nullOrIsArrayOrInstanceOf($config[self::FORMATTER], FormatterInterface::class, "'" . self::FORMATTER . "' must be Formatter instance or configuration array"); 61 | } 62 | 63 | public function getProcessors(): array 64 | { 65 | return $this->processors; 66 | } 67 | 68 | public function getFormatter() 69 | { 70 | return $this->formatter; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/Config/LoggerConfig.php: -------------------------------------------------------------------------------- 1 | name = $name; 32 | $this->handlers = $handlers; 33 | $this->processors = $processors; 34 | $this->timezone = $timezone; 35 | } 36 | 37 | public static function fromArray(array $config) 38 | { 39 | $config = self::filter($config); 40 | 41 | return new static( 42 | $config[self::NAME], 43 | array_map(function ($handler) { 44 | return is_array($handler) ? HandlerConfig::fromArray($handler) : $handler; 45 | }, $config[self::HANDLERS]), 46 | array_map(function ($processor) { 47 | return is_array($processor) ? ProcessorConfig::fromArray($processor) : $processor; 48 | }, $config[self::PROCESSORS]), 49 | new DateTimeZone($config[self::TIMEZONE]) 50 | ); 51 | } 52 | 53 | protected static function defaults(): array 54 | { 55 | return [ 56 | self::NAME => '', 57 | self::HANDLERS => [], 58 | self::PROCESSORS => [], 59 | self::TIMEZONE => date_default_timezone_get(), 60 | ]; 61 | } 62 | 63 | protected static function validate(array $config): void 64 | { 65 | ConfigAssertion::notEmptyString($config[self::NAME], "'" . self::NAME . "' is required and cannot be empty"); 66 | ConfigAssertion::isArray($config[self::HANDLERS], "'" . self::HANDLERS . "' must be an array"); 67 | ConfigAssertion::allIsArrayOrInstanceOf($config[self::HANDLERS], HandlerInterface::class, "'" . self::HANDLERS . "' must be an array of Handler instances or configuration arrays"); 68 | ConfigAssertion::isArray($config[self::PROCESSORS], "'" . self::PROCESSORS . "' must be an array"); 69 | ConfigAssertion::allIsArrayOrCallable($config[self::PROCESSORS], "'" . self::PROCESSORS . "' must be an array of callables or configuration arrays"); 70 | ConfigAssertion::string($config[self::TIMEZONE], "'" . self::TIMEZONE . "' must be a string"); 71 | } 72 | 73 | public function getName(): string 74 | { 75 | return $this->name; 76 | } 77 | 78 | public function getHandlers(): array 79 | { 80 | return $this->handlers; 81 | } 82 | 83 | public function getProcessors(): array 84 | { 85 | return $this->processors; 86 | } 87 | 88 | public function getTimezone(): DateTimeZone 89 | { 90 | return $this->timezone; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/Config/ParametrizedObjectConfig.php: -------------------------------------------------------------------------------- 1 | name = $name; 21 | $this->parameters = $parameters; 22 | } 23 | 24 | public static function fromArray(array $config) 25 | { 26 | $config = self::filter($config); 27 | 28 | return new static($config[self::NAME], $config[self::PARAMETERS]); 29 | } 30 | 31 | protected static function defaults(): array 32 | { 33 | return [ 34 | self::NAME => '', 35 | self::PARAMETERS => [], 36 | ]; 37 | } 38 | 39 | protected static function validate(array $config): void 40 | { 41 | ConfigAssertion::notEmptyString($config[self::NAME], "'" . self::NAME . "' is required and cannot be empty"); 42 | ConfigAssertion::isArray($config[self::PARAMETERS], "'" . self::PARAMETERS . "' must be an array"); 43 | } 44 | 45 | public function getName(): string 46 | { 47 | return $this->name; 48 | } 49 | 50 | public function getParameters(): array 51 | { 52 | return $this->parameters; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Config/ProcessorConfig.php: -------------------------------------------------------------------------------- 1 | getContainer()->has($configServiceName)) { 17 | $config = $this->getContainer()->get($configServiceName); 18 | break; 19 | } 20 | } 21 | 22 | return $config[self::CONFIG_KEY][$loggerName] ?? []; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Exception/BadStaticDiContainerFactoryUsage.php: -------------------------------------------------------------------------------- 1 | cascader = $cascader; 17 | } 18 | 19 | public function create(string $className, array $parameters = []): object 20 | { 21 | return $this->cascader->create($className, $parameters); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Helper/ObjectFactory.php: -------------------------------------------------------------------------------- 1 | objectFactory = $objectFactory ?? new GenericObjectFactory(new Cascader()); 28 | } 29 | 30 | public function create(string $name, array $config = []): Logger 31 | { 32 | $config[LoggerConfig::NAME] = $name; 33 | $config = LoggerConfig::fromArray($config); 34 | 35 | return new Logger( 36 | $config->getName(), 37 | array_map([$this, 'createHandler'], $config->getHandlers()), 38 | array_map([$this, 'createProcessor'], $config->getProcessors()), 39 | $config->getTimezone() 40 | ); 41 | } 42 | 43 | /** 44 | * @param HandlerInterface|HandlerConfig $handler 45 | * @return HandlerInterface 46 | */ 47 | protected function createHandler($handler): HandlerInterface 48 | { 49 | if ($handler instanceof HandlerInterface) { 50 | return $handler; 51 | } 52 | 53 | $handlerConfig = $handler; 54 | 55 | $handler = $this->objectFactory->create($handlerConfig->getName(), $handlerConfig->getParameters()); 56 | 57 | if ($handler instanceof ProcessableHandlerInterface) { 58 | foreach (array_reverse($handlerConfig->getProcessors()) as $processorConfig) { 59 | $handler->pushProcessor($this->createProcessor($processorConfig)); 60 | } 61 | } 62 | 63 | if ($handler instanceof FormattableHandlerInterface && null !== ($formatterConfig = $handlerConfig->getFormatter())) { 64 | $handler->setFormatter($this->createFormatter($formatterConfig)); 65 | } 66 | 67 | /** @noinspection PhpIncompatibleReturnTypeInspection */ 68 | return $handler; 69 | } 70 | 71 | /** 72 | * @param callable|ProcessorConfig $processor 73 | * @return callable 74 | */ 75 | protected function createProcessor($processor): callable 76 | { 77 | if (is_callable($processor)) { 78 | return $processor; 79 | } 80 | 81 | /** @noinspection PhpIncompatibleReturnTypeInspection */ 82 | return $this->objectFactory->create($processor->getName(), $processor->getParameters()); 83 | } 84 | 85 | /** 86 | * @param FormatterInterface|FormatterConfig $formatter 87 | * @return FormatterInterface 88 | */ 89 | protected function createFormatter($formatter): FormatterInterface 90 | { 91 | if ($formatter instanceof FormatterInterface) { 92 | return $formatter; 93 | } 94 | 95 | /** @noinspection PhpIncompatibleReturnTypeInspection */ 96 | return $this->objectFactory->create($formatter->getName(), $formatter->getParameters()); 97 | } 98 | } 99 | --------------------------------------------------------------------------------