Skip to content
Permalink
Browse files

MonologExtension adapted to Nette3

  • Loading branch information...
solcik authored and f3l1x committed May 30, 2019
1 parent b2461ce commit 53e99b7bb7ddf3a533ab571f5d306baf35e44542
@@ -18,8 +18,8 @@
"require": {
"php": ">=7.1.0",
"monolog/monolog": "^1.23.0",
"nette/di": "~2.4.12",
"nette/utils": "~2.5.2"
"nette/di": "~3.0.0",
"nette/utils": "~3.0.0"
},
"require-dev": {
"ninjify/qa": "^0.9.0",
@@ -6,5 +6,4 @@ includes:

parameters:
ignoreErrors:
- '#^Call to deprecated method formatPhp\(\) of class Nette\\DI\\ContainerBuilder\.$#'
- '#^Method Contributte\\Monolog\\Tracy\\LazyTracyLogger\:\:log\(\) has parameter (\$priority|\$value) with no typehint specified\.$#'
@@ -9,10 +9,11 @@
use Contributte\Monolog\Tracy\LazyTracyLogger;
use Monolog\Handler\PsrHandler;
use Monolog\Logger;
use Nette\DI\Compiler;
use Nette\DI\CompilerExtension;
use Nette\DI\Statement;
use Nette\DI\Definitions\Statement;
use Nette\PhpGenerator\ClassType;
use Nette\Schema\Expect;
use Nette\Schema\Schema;
use Nette\Utils\Strings;
use Tracy\Bridges\Psr\PsrToTracyLoggerAdapter;
use Tracy\Bridges\Psr\TracyToPsrLoggerAdapter;
@@ -21,30 +22,29 @@
class MonologExtension extends CompilerExtension
{
/** @var mixed[] */
private $defaults = [
'channel' => [],
'hook' => [
'fromTracy' => true, // log through Tracy
'toTracy' => true, // log through Monolog
],
'holder' => [
'enabled' => false,
],
'manager' => [
'enabled' => false,
],
];
/** @var mixed [] */
private $channelDefaults = [
'handlers' => [],
'processors' => [],
];
public function getConfigSchema(): Schema
{
return Expect::structure([
'channel' => Expect::arrayOf(Expect::structure([
'handlers' => Expect::array()->required()->min(1),
'processors' => Expect::array()->default([]),
])->castTo('array'))->required()->min(1),
'hook' => Expect::structure([
'fromTracy' => Expect::bool()->default(true),
'toTracy' => Expect::bool()->default(true),
])->castTo('array'),
'holder' => Expect::structure([
'enabled' => Expect::bool()->default(false),
])->castTo('array'),
'manager' => Expect::structure([
'enabled' => Expect::bool()->default(false),
])->castTo('array'),
])->castTo('array');
}
public function loadConfiguration(): void
{
$config = $this->validateConfig($this->defaults);
$config = (array) $this->getConfig();
$builder = $this->getContainerBuilder();
if (!isset($config['channel']['default'])) {
@@ -61,16 +61,11 @@ public function loadConfiguration(): void
$tracyHandler = null;
if (class_exists(Debugger::class) && $config['hook']['toTracy'] && $builder->hasDefinition('tracy.logger')) {
$tracyAdapter = new Statement(TracyToPsrLoggerAdapter::class);
$tracyAdapter->arguments = ['@tracy.logger'];
$tracyHandler = new Statement(PsrHandler::class);
$tracyHandler->arguments = [$tracyAdapter];
$tracyAdapter = new Statement(TracyToPsrLoggerAdapter::class, ['@tracy.logger']);
$tracyHandler = new Statement(PsrHandler::class, [$tracyAdapter]);
}
foreach ($config['channel'] as $name => $channel) {
$channel = $this->validateConfig($this->channelDefaults, $channel, $this->prefix('channel.' . $name));
if (!is_string($name)) {
throw new InvalidArgumentException(sprintf('%s.channel.%s name must be a string', $this->name, (string) $name));
}
@@ -79,10 +74,6 @@ public function loadConfiguration(): void
$channel['handlers']['tracy'] = $tracyHandler;
}
if (!isset($channel['handlers']) || $channel['handlers'] === []) {
throw new InvalidStateException(sprintf('%s.channel.%s.handlers must contain at least one handler', $this->name, $name));
}
// Register handlers same way as services (setup, arguments, type etc.)
foreach ($channel['handlers'] as $handlerKey => $handlerValue) {
// Don't register handler as service, it's already registered service
@@ -91,35 +82,29 @@ public function loadConfiguration(): void
}
$handlerName = $this->prefix('logger.' . $name . '.handler.' . $handlerKey);
$handler = $builder->addDefinition($handlerName)
->setAutowired(false);
Compiler::loadDefinition($handler, $handlerValue);
$this->compiler->loadDefinitionsFromConfig([$handlerName => $handlerValue]);
$builder->getDefinition($handlerName)->setAutowired(false);
$channel['handlers'][$handlerKey] = '@' . $handlerName;
}
// Register processors same way as services (setup, arguments, type etc.)
if (isset($channel['processors'])) {
foreach ($channel['processors'] as $processorKey => $processorValue) {
// Don't register processor as service, it's already registered service
if (is_string($processorValue) && Strings::startsWith($processorValue, '@')) {
continue;
}
$processorName = $this->prefix('logger.' . $name . '.processor.' . $processorKey);
$processor = $builder->addDefinition($processorName)
->setAutowired(false);
Compiler::loadDefinition($processor, $processorValue);
$channel['processors'][$processorKey] = '@' . $processorName;
foreach ($channel['processors'] as $processorKey => $processorValue) {
// Don't register processor as service, it's already registered service
if (is_string($processorValue) && Strings::startsWith($processorValue, '@')) {
continue;
}
$processorName = $this->prefix('logger.' . $name . '.processor.' . $processorKey);
$this->compiler->loadDefinitionsFromConfig([$processorName => $processorValue]);
$builder->getDefinition($processorName)->setAutowired(false);
$channel['processors'][$processorKey] = '@' . $processorName;
}
$logger = $builder->addDefinition($this->prefix('logger.' . $name))
->setFactory(Logger::class, [
$name,
$channel['handlers'],
$channel['processors'] ?? [],
$channel['processors'],
]);
// Only default logger is autowired
@@ -144,12 +129,12 @@ public function loadConfiguration(): void
public function afterCompile(ClassType $class): void
{
$builder = $this->getContainerBuilder();
$config = $this->validateConfig($this->defaults);
$config = (array) $this->getConfig();
$initialize = $class->getMethod('initialize');
if (class_exists(Debugger::class) && $config['hook']['fromTracy'] && $builder->hasDefinition('tracy.logger')) {
$initialize->addBody('$this->getService("tracy.logger");'); // Create original Tracy\Logger service to prevent psrToTracyLazyAdapter contain itself - workaround for Tracy\ILogger service created statically
$initialize->addBody($builder->formatPhp(Debugger::class . '::setLogger(?);', [$this->prefix('@psrToTracyLazyAdapter')]));
$initialize->addBody(Debugger::class . '::setLogger($this->getService(?));', [$this->prefix('psrToTracyLazyAdapter')]);
}
if ($config['holder']['enabled']) {
@@ -3,14 +3,14 @@
namespace Tests\Contributte\Monolog\Unit\DI;
use Contributte\Monolog\DI\MonologExtension;
use Contributte\Monolog\Exception\Logic\InvalidStateException;
use Contributte\Monolog\LoggerHolder;
use Contributte\Monolog\LoggerManager;
use Contributte\Monolog\Tracy\LazyTracyLogger;
use Monolog\Logger;
use Nette\DI\Compiler;
use Nette\DI\Container;
use Nette\DI\ContainerLoader;
use Nette\DI\InvalidConfigurationException;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
use Tracy\Bridges\Nette\TracyExtension;
@@ -19,9 +19,11 @@
class MonologExtensionTest extends TestCase
{
private const FIXTURES_DIR = __DIR__ . '/../../fixtures';
public function testRegistration(): void
{
$container = $this->createContainer(__DIR__ . '/config.neon');
$container = $this->createContainer(self::FIXTURES_DIR . '/config.neon');
// Needed for LoggerHolder and creation of original Tracy\Logger
$container->initialize();
@@ -54,16 +56,40 @@ public function testRegistration(): void
public function testRegistrationNoDefault(): void
{
$this->expectException(InvalidStateException::class);
$this->expectExceptionMessage('monolog.channel.default is required.');
$this->expectException(InvalidConfigurationException::class);
$this->expectExceptionMessage('The mandatory option \'monolog › channel\' is missing.');
$container = $this->createContainer(self::FIXTURES_DIR . '/config_00.neon');
}
public function testRegistrationEmptyChannels(): void
{
$this->expectException(InvalidConfigurationException::class);
$this->expectExceptionMessage('The option \'monolog › channel\' expects to be array in range 1.., array given.');
$container = $this->createContainer(self::FIXTURES_DIR . '/config_01.neon');
}
public function testRegistrationEmptyChannel(): void
{
$this->expectException(InvalidConfigurationException::class);
$this->expectExceptionMessage('The mandatory option \'monolog › channel › default › handlers\' is missing.');
$container = $this->createContainer(self::FIXTURES_DIR . '/config_02.neon');
}
public function testRegistrationEmptyHandlers(): void
{
$this->expectException(InvalidConfigurationException::class);
$this->expectExceptionMessage('The option \'monolog › channel › default › handlers\' expects to be array in range 1.., array given.');
$container = $this->createContainer(__DIR__ . '/empty.neon');
$container = $this->createContainer(self::FIXTURES_DIR . '/config_03.neon');
}
private function createContainer(string $configFile): Container
{
$loader = new ContainerLoader(__DIR__ . '/../../../temp/tests/' . getmypid(), true);
$class = $loader->load(function (Compiler $compiler) use ($configFile): void {
$class = $loader->load(static function (Compiler $compiler) use ($configFile): void {
$compiler->loadConfig($configFile);
$compiler->addExtension('tracy', new TracyExtension());
$compiler->addExtension('monolog', new MonologExtension());
No changes.
@@ -3,6 +3,8 @@ monolog:
default:
handlers:
- Monolog\Handler\NullHandler
processors:
- Monolog\Processor\MemoryPeakUsageProcessor
foo:
handlers:
- Monolog\Handler\NullHandler
@@ -0,0 +1 @@
monolog:
@@ -0,0 +1,2 @@
monolog:
channel:
@@ -0,0 +1,3 @@
monolog:
channel:
default:
@@ -0,0 +1,4 @@
monolog:
channel:
default:
handlers:

0 comments on commit 53e99b7

Please sign in to comment.
You can’t perform that action at this time.