5

I wanted to override the logger.filelog service from filelog module to make use of my own parser.

An error occurred through drush cim and drush cr when the new custom module that overrides the service is enabled.

The website encountered an unexpected error. Please try again later.
Symfony\Component\DependencyInjection\Exception\LogicException: Service 'logger.filelog' for consumer 'logger.factory' does not implement Psr\Log\LoggerInterface. in Drupal\Core\DependencyInjection\Compiler\TaggedHandlersPass->processServiceCollectorPass() (line 182 of /app/docroot/core/lib/Drupal/Core/DependencyInjection/Compiler/TaggedHandlersPass.php).

My custom modules structure looks like this

custom_module
  - src
    - Logger
      - TestFilelog.php
    CustomModuleServiceProvider.php
  custom_module.info.yml
  custom_module.module

Currently the service provider class has implemented ServiceModifierInterface and altered the original logger.filelog service by setting its class to Drupal\custom_module\Logger\TestFilelog.

/**
 * Class to override contrib module logger.filelog service.
 */
class CustomModuleServiceProvider implements ServiceModifierInterface {

  /**
   * {@inheritdoc}
   */
  public function alter(ContainerBuilder $container) {
    if ($container->has('logger.filelog')) {
      $definition = $container->getDefinition('logger.filelog');
      $definition->setClass('Drupal\custom_module\Logger\TestFilelog');
    }
  }

}

TestFilelog.php

namespace Drupal\custom_module\Logger;

use Drupal\filelog\Logger\FileLog;

/**
 * File-based logger.
 */
class TestFileLog extends FileLog {

  /**
   * Renders a message to a string.
   *
   * @param mixed $level
   *   Severity level of the log message.
   * @param string $message
   *   Content of the log message.
   * @param array $context
   *   Context of the log message.
   *
   * @return string
   *   The formatted message.
   */
  protected function render($level, $message, array $context = []): string {

    $plainString = parent::render($level, $message, $context);

    $custom_channel = [
      'filter_custom_channel'
    ];

    if (in_array($context['channel'], $custom_channel)) {
      $plainString = $this->parseStrMasking($plainString);
    }
    return $plainString;
  }

  /**
   * Mask personal details from strings to logs.
   *
   * @param string $pureString
   *   The string to be parsed.
   *
   * @return string
   *   The string that has been masked.
   */
  protected function parseStrMasking(string $pureString) {
    // Default to return finalString.
    $finalString = $pureString;
    
    // Custom parsing goes here.
    
    return $finalString;
  }

}

I see that Drupal\filelog\Logger\FileLog; has use RfcLoggerTrait; which does implement the Psr\Log\LoggerInterface, what am I missing here??

4
  • Your code works fine for me - have you tried restarting Apache/PHP-FPM?
    – Clive
    Commented Dec 21, 2021 at 20:22
  • 4
    You do have a small discrepancy though - you're mixing the casing of TestFileLog (it's Testfilelog in the filename and service alter). Might make a difference if you're on a case-sensitive file system
    – Clive
    Commented Dec 21, 2021 at 20:58
  • OMG @Clive you are absolutely right! Kudos for you mate! Commented Dec 22, 2021 at 2:55
  • FYI, while struggling last night, I'd discovered another way to override the contrib module's service through custom_module.services.yml. It works, so I made use of it instead. Thanks for your effort on testing and reading through, thanks! Commented Dec 22, 2021 at 3:00

1 Answer 1

2

As pointed out by @Clive in the comment above, I had a discrepancy in the casing of TestFilelog and TestFileLog. Thanks again!

This should make a difference on why the implementation of interface wasn't read by Drupal on service handling.

On the other hand, I discovered another approach to override filelog module's service, which I took instead.

  1. I deleted the CustomModuleServiceProvider.php file
  2. Created custom_module.services.yml
  3. service machine name should be the same as the overridden service. (e.g. logger.filelog)
    Check docroot/modules/contrib/filelog/filelog.services.yml

Content of custom_module.services.yml

services:
  logger.filelog:
    class: Drupal\custom_module\Logger\TestFileLog
    arguments:
      - '@config.factory'
      - '@state'
      - '@token'
      - '@datetime.time'
      - '@logger.log_message_parser'
      - '@filelog.file_manager'
    tags:
      - { name: logger }

Ref:

  1. How to decorate Services - Symfony
  2. Altering existing services - Drupal
  3. Overriding services in Drupal - PreviousNext
4
  • 3
    Redefining the service like that would be my last choice. Better choices are the way you did it in the original question, or by decoration. The reason is that defining your own logger.filelog in the services.yml file does nothing to indicate that this is an overridden service - the intention of the programmer is obscured (was it just a mistake that a previously-named service was used?). Also, what happens if the Filelog module is loaded after your module - which service actually gets defined, yours or the Filelog service? And what happens if another module overrides logger.filelog?
    – anonymous
    Commented Dec 22, 2021 at 5:23
  • Oh dear! Your concern do have a point, maybe I should refine it back to the original format and check that it works. On the other hand, is there other resources that I may reference in decoration of service? I only read that decoration extends the original service, but while implementing it, I don't actually know how I should override the original service with a decorate service. Cheers! Commented Dec 23, 2021 at 6:41
  • 1
    This is a pretty good article which should help: phase2technology.com/blog/…
    – anonymous
    Commented Dec 23, 2021 at 10:40
  • Thanks for the info, this article has been really helpful as it written every detail of their consideration and thinking process. Commented Dec 26, 2021 at 4:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.