zendframework / zend-log

Log component from Zend Framework
BSD 3-Clause "New" or "Revised" License
62 stars 51 forks source link

Q: How to decorate with PsrLoggerAdapter via configuration #54

Closed basz closed 8 years ago

basz commented 8 years ago

Is it possible to use the LoggerAbstractServcieFactory configuration such that Loggers are decorated with PsrLoggerAdapter?

I don't think they can be currently...

basz commented 8 years ago

current solution

return [
    'log' => [
        'StreamLogger' => [
            'writers' => [
                [
                    'name'     => 'stream',
                    'priority' => Psr\Log\LogLevel::DEBUG,
                    'options'  => [
                        'stream'    => 'php://output',
                    ],
                ],
            ],
        ],
    ],

    'dependencies' => [
        'factories' => [
            'PsrStreamLogger' => function($container) {
                return new \Zend\Log\PsrLoggerAdapter($container->get('StreamLogger'));
            }
        ],
    ],
];
weierophinney commented 8 years ago

No. Currently, the LoggerAbstractServiceFactory always returns a Zend\Log\Logger instance.

Another approach to what you want to do is to use a delegator factory:

use Interop\Container\ContainerInterface;
use Zend\Log\PsrLoggerAdapter;
use Zend\ServiceManager\Factory\DelegatorFactoryInterface;

class PsrLoggerDelegator implements DelegatorFactoryInterface
{
    public function __invoke(ContainerInterface $container, $requestedName, callable $callback, array $options = null)
    {
        return new PsrLoggerAdapter($container->get('StreamLogger'));
    }
}

which you would then wire using:

'dependencies' => [
    'delegators' => [
        'StreamLogger' => [
            PsrLoggerDelegator::class,
        ],
    ]
],

This approach allows you to continue using the log name you've configured, and just ensures that it is decorated as a PSR-3-compliant logger. :smile:

weierophinney commented 8 years ago

Also: we won't be adding the ability to specify the class to use within the abstract service factory at this point, as it adds maintenance overhead, documentation and learning overhead, etc. You can achieve it easily with delegator factories, allowing a clean separation of concerns.

basz commented 8 years ago

that's a great solution! not sure what you mean with your second comment. thanks!

weierophinney commented 8 years ago

not sure what you mean with your second comment

Just that we won't be adding any new features to the abstract service factory (e.g., "logger_class" => ...) based on this issue report. :smile:

basz commented 8 years ago

looking at this again, wouldn't your solution cause an infinite loop?

sm->get(StreamLogger) enters Decorator which also does sm->get(StreamLogger)
basz commented 8 years ago

yes, got it, this works;

public function __invoke(ContainerInterface $container, $requestedName, callable $callback, array $options = null)
    {
        return new PsrLoggerAdapter($callback());
    }