Symfony 3.4 logger service

A.Seddighi picture A.Seddighi · Dec 10, 2017 · Viewed 17k times · Source

When I called logger service get this information message in log file it's worked but write this message in the log file:

php.INFO: User Deprecated: The "logger" service is private, getting it from the container is deprecated since Symfony 3.2 and will fail in 4.0. You should either make the service public, or stop using the container directly and use dependency injection instead. {"exception":"[object] (ErrorException(code: 0): User Deprecated: The \"logger\" service is private, getting it from the container is deprecated since Symfony 3.2 and will fail in 4.0. You should either make the service public, or stop using the container directly and use dependency injection instead. at /home/****/###/PROJECT/vendor/symfony/symfony/src/Symfony/Component/DependencyInjection/Container.php:275)"} []

My symfony version: 3.4.1

Answer

Will B. picture Will B. · Jan 19, 2018

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.yml

services:
    # 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.yml

services:

    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.yml

services:

    #...
    
    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.php
namespace 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.php
namespace 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.php
namespace 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);
    }
}