Symfony 3.4 logger service

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


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);
    }
}