Symfony 3.4 logger service Symfony 3.4 logger service symfony symfony

Symfony 3.4 logger service


As stated in Symfony 3.4, the logger service provided by the MonologBundle and all other services, are set to private by default. [sic]

To workaround the issue, the recommended method is to use Dependency Injection.http://symfony.com/doc/3.4/logging.html

namespace AppBundle\Controller;use Psr\Log\LoggerInterface;use Symfony\Bundle\FrameworkBundle\Controller\Controller;class DefaultController extends Controller{     public function indexAction(LoggerInterface $logger)     {        $logger->info('Your Message');     }}

Source code Reference: https://github.com/symfony/monolog-bundle/blob/v3.1.0/Resources/config/monolog.xml#L17

For service definitions Dependency Injection is available when autowire is enabled. [sic]

#app/config/services.ymlservices:    # default configuration for services in *this* file    _defaults:        # automatically injects dependencies in your services        autowire: true        # automatically registers your services as commands, event subscribers, etc.        autoconfigure: true        # this means you cannot fetch services directly from the container via $container->get()        # if you need to do this, you can override this setting on individual services        public: false    # makes classes in src/AppBundle available to be used as services    # this creates a service per class whose id is the fully-qualified class name    AppBundle\:        resource: '../../src/AppBundle/*'        # you can exclude directories or files        # but if a service is unused, it's removed anyway        exclude: '../../src/AppBundle/{Entity,Repository,Tests}'    #enables dependency injection in controller actions    AppBundle\Controller\:        resource: '../../src/AppBundle/Controller'        public: true        tags: ['controller.service_arguments']   #all of your custom services should be below this line   #which will override the above configurations    #optionally declare an individual service as public    #AppBundle\Service\MyService:     #    public: true    #alternatively declare the namespace explicitly as public    #AppBundle\Service\:    #    resource: '../../src/AppBundle/Service/*'    #    public: true

Then to Inject the Dependency into the service, you add the type hint for the argument to the constructor.

namespace AppBundle\Service;use Psr\Log\LoggerInterface;class MyService{    private $logger;        public function __construct(LoggerInterface $logger)    {         $this->logger = $logger;    }   }

if autowire is disabled, you can manually define your services to inject the logger alias.

#app/config/services.ymlservices:    AppBundle\Service\MyService:        arguments: ['@logger']        public: true

Alternatively, to force the logger alias to be publicly accessible from the container, you can re-declare the service alias in your application services config.

#app/config/services.ymlservices:    #...        logger:        alias: 'monolog.logger'        public: true

Instead of overriding the value in the configuration, you can also set logger as a public service in a compiler pass. https://symfony.com/doc/4.4/service_container/compiler_passes.html

Symfony Flex

// src/Kernel.phpnamespace App;use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;use Symfony\Component\DependencyInjection\ContainerBuilder;use Symfony\Component\HttpKernel\Kernel as BaseKernel;class Kernel extends BaseKernel implements CompilerPassInterface{    use MicroKernelTrait;     public function process(ContainerBuilder $container)     {        // in this method you can manipulate the service container:        // for example, changing some container service:        $container->getDefinition('logger')->setPublic(true);    }}

Symfony Bundle

// src/AppBundle/AppBundle.phpnamespace AppBundle;use Symfony\Component\HttpKernel\Bundle\Bundle;use Symfony\Component\DependencyInjection\ContainerBuilder;use AppBundle\DependencyInjection\Compiler\CustomPass;class AppBundle extends Bundle{    public function build(ContainerBuilder $container)    {        parent::build($container);        $container->addCompilerPass(new CustomPass());    }}
// src/AppBundle/DependencyInjection/Compiler/CustomPass.phpnamespace AppBundle\DependencyInjection\Compiler;use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;use Symfony\Component\DependencyInjection\ContainerBuilder;class CustomPass implements CompilerPassInterface{    public function process(ContainerBuilder $container)    {        $container->getDefinition('logger')->setPublic(true);    }}


$this->container->get('logger') fails because logger is now (as of 3.2) marked as a private service, all services are private by default, that means that these services can not be returned from the container, and must instead be dependency injected (The class constructor must take the logger as a parameter and become a property of the class to be accessible), or marked as public in the service configuration, and since the logger is a symfony component, the service configuration is within the symfony project, you'd have to copy the logger configuration from symfony to your project service configuration and add public: true, to access the logger instance from the container.