Problem/Motivation

I started dipping my toes into autowiring yesterday and one of the first things I butted up against was how to autowire loggers.

If a module needs to log something, most of the time it will do something like this:

services:
  logger.channel.my_module:
    parent: logger.channel_base
    arguments: ['my_module']

  my_module.service:
    class: Drupal\my_module\Foo
    arguments: ['@logger.channel.my_module']

I discovered in my own discussions internally that we can use calls in the service to avoid having to pass the logger into the constructor by using LoggerAwareTrait

  my_module.service:
    class: Drupal\my_module\Foo
    calls:
      - [setLogger, ['@logger.channel.my_module']]

That works well, but what if we automated it?

We could detect services implementing LoggerAwareInterface and autoconfigure a logger for the module and automate the calls part of the service.

Proposed resolution

Add a compiler pass that finds services implementing LoggerAwareInterface and autoconfigure a logger for them using setLogger with a logger service that matches the service's module name.

Remaining tasks

Agree
Code
Test

User interface changes

API changes

Data model changes

Release notes snippet

Issue fork drupal-3395032

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

acbramley created an issue. See original summary.

acbramley’s picture

Issue summary: View changes
dpi’s picture

The main technical challenge would be having different logger instances (channels) autowired per module.

dpi’s picture

kim.pepper made their first commit to this issue’s fork.

kim.pepper’s picture

Had a quick look at this, and it doesn't look like we know which module the services.yml is being loaded from. By the time we get to CoreServiceProvider we have a fully merged container definition.

This would make it hard to auto configure file.services.yml with a logger service id logger.channel.file for example.

One option is to loop through the service definitions and try to guess a prefix?

kim.pepper’s picture

I was looking at \Drupal\Core\CoreServiceProvider::register() and adding something like:

$container->registerForAutoconfiguration(LoggerAwareInterface::class)
    ->addMethodCall('setLogger', [new Reference('logger.channel.default')]);
longwave’s picture

YamlFileLoader::parseDefinitions() appears to add a _provider tag to each service with the name of the module.

See also #3295542-10: Use logger channel services consistently, instead of the factory object where I suggested a similar idea.

kim.pepper’s picture

Nice!

kim.pepper’s picture

Assigned: Unassigned » kim.pepper

Having a look at this.

kim.pepper’s picture

Status: Active » Needs review

Tried an approach of first adding a logger_aware tag to any service with a class implementing \Psr\Log\LoggerAwareInterface by using +

$container->registerForAutoconfiguration(LoggerAwareInterface::class)
      ->addTag('logger_aware');

Then a \Drupal\Core\DependencyInjection\Compiler\LoggerAwarePass that looks for those tagged services.

Not finding my test service at the moment, so I thought I'd push up what I have to see if others have ideas?

kim.pepper’s picture

Needed to add:

services:
  _defaults:
    autoconfigure: true

to logger_aware_test.services.yml.

kim.pepper’s picture

Added a change record.

acbramley’s picture

Manually tested with services I was playing with before creating this issue and (after applying the other patch to allow autoconfigure) it's working really well. Nice one!

acbramley’s picture

Issue summary: View changes
joachim’s picture

The CR doesn't mention the 'logger_aware' tag, but the code looks like it's still using it.

longwave’s picture

Status: Needs review » Needs work

Overall I like this approach; previously I considered automatically creating lots of loggers but that just bloats the container - allowing this to be opt-in simply by implementing an interface is really clean.

I don't think there are any big issues but just to make sure we considered it: are there BC concerns here where services might have previously implemented LoggerAwareInterface and now we have added behaviour to that? Should we also check that the setLogger() method call isn't already present, just in case?

acbramley’s picture

Agreed we should probably he checking for existing calls, is it also possible existing class members called $logger could be overwritten? I suppose the interface/trait covers us there.

We should also add a before and after to the CR showing how you no longer need to inject the logger.

kim.pepper’s picture

Should we also check that the setLogger() method call isn't already present, just in case?

Sorry, not sure I follow... We are only checking services that implement LoggerAwareInterface. The setLogger() method will always be there if they implement LoggerAwareInterface.

kim.pepper’s picture

Status: Needs work » Needs review

Updated CR

kim.pepper’s picture

Ah I think I follow now.

Should we also check that the setLogger() method call isn't already present, just in case?

Sorry, not sure I follow... We are only checking services that implement LoggerAwareInterface. The setLogger() method will always be there if they implement LoggerAwareInterface.

We just need to check if the definition already has a setLogger method call defined.

longwave’s picture

I wonder if we should also detect LoggerInterface being used in service constructor arguments (as opposed to a setter method) and automatically create and inject a logger, if that argument is not yet wired - then we don't even need LoggerAwareInterface. Or should that be a followup?

longwave’s picture

Thinking again we should only do #23 if autowire: true is set which probably means we have to wait for #3295751: Autowire core services that do not require explicit configuration

longwave’s picture

Status: Needs review » Reviewed & tested by the community

This looks good to me as a self contained issue. I don't think we need to explicitly test that exception, nothing else to do here so this is RTBC.

larowlan’s picture

Status: Reviewed & tested by the community » Needs work

One minor issue with PHPCS

kim.pepper’s picture

Status: Needs work » Reviewed & tested by the community

Tests green ✅

  • larowlan committed 931ad45c on 10.2.x
    Issue #3395032 by kim.pepper, acbramley, longwave: Add autoconfigure for...

  • larowlan committed 3d917f37 on 11.x
    Issue #3395032 by kim.pepper, acbramley, longwave: Add autoconfigure for...
larowlan’s picture

Version: 11.x-dev » 10.2.x-dev
Status: Reviewed & tested by the community » Fixed

Committed to 11.x and backported to 10.2.x

Published CR

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.