2

Is there a way to perform additional actions every time watchdog logs something? For example, I wanted to record, parse, and compile logs with additional information elsewhere, but still have watchdog perform its default function.

Is there any hook I could use?

3 Answers 3

5

In Drupal 7, you would use hook_watchdog() to achieve the task, which is exactly the hook implemented by dblog.module, the module that shows in admin/reports/dblog the messages added with watchdog().

In Drupal 8, you need to implement a service that is invoked everytime a message is logged, for example with the following code.

mylog.services.yml

services:

  logger.mylog:
    class: Drupal\mylog\Logger\MyLog
    tags:
      - { name: logger }

src/Logger/mylog.php

namespace Drupal\mylog\Logger;

use Drupal\Core\Logger\RfcLoggerTrait;
use Psr\Log\LoggerInterface;

class MyLog implements LoggerInterface {
  use RfcLoggerTrait;

  /**
   * {@inheritdoc}
   */
  public function log($level, $message, array $context = array()) {
    // Log the message, for example writing it in a file.
  }

}

The key is how the service is tagged. Without tags: [{ name: logger }], the service would not be used to log the message.

The example code is taken from hook_watchdog() and watchdog() removed. For an example of code implemented from Drupal core, see SysLog.php, which logs the messages in the Syslog server.

class SysLog implements LoggerInterface {
  use RfcLoggerTrait;

  /**
   * A configuration object containing syslog settings.
   *
   * @var \Drupal\Core\Config\Config
   */
  protected $config;

  /**
   * The message's placeholders parser.
   *
   * @var \Drupal\Core\Logger\LogMessageParserInterface
   */
  protected $parser;

  /**
   * Stores whether there is a system logger connection opened or not.
   *
   * @var bool
   */
  protected $connectionOpened = FALSE;

  /**
   * Constructs a SysLog object.
   *
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   The configuration factory object.
   * @param \Drupal\Core\Logger\LogMessageParserInterface $parser
   *   The parser to use when extracting message variables.
   */
  public function __construct(ConfigFactoryInterface $config_factory, LogMessageParserInterface $parser) {
    $this->config = $config_factory
      ->get('syslog.settings');
    $this->parser = $parser;
  }

  /**
   * Opens a connection to the system logger.
   */
  protected function openConnection() {
    if (!$this->connectionOpened) {
      $facility = $this->config
        ->get('facility');
      $this->connectionOpened = openlog($this->config
        ->get('identity'), LOG_NDELAY, $facility);
    }
  }

  /**
   * {@inheritdoc}
   */
  public function log($level, $message, array $context = []) {
    global $base_url;

    // Ensure we have a connection available.
    $this
      ->openConnection();

    // Populate the message placeholders and then replace them in the message.
    $message_placeholders = $this->parser
      ->parseMessagePlaceholders($message, $context);
    $message = empty($message_placeholders) ? $message : strtr($message, $message_placeholders);
    $entry = strtr($this->config
      ->get('format'), [
      '!base_url' => $base_url,
      '!timestamp' => $context['timestamp'],
      '!type' => $context['channel'],
      '!ip' => $context['ip'],
      '!request_uri' => $context['request_uri'],
      '!referer' => $context['referer'],
      '!severity' => $level,
      '!uid' => $context['uid'],
      '!link' => strip_tags($context['link']),
      '!message' => strip_tags($message),
    ]);
    $this
      ->syslogWrapper($level, $entry);
  }

  /**
   * A syslog wrapper to make syslog functionality testable.
   *
   * @param int $level
   *   The syslog priority.
   * @param string $entry
   *   The message to send to syslog function.
   */
  protected function syslogWrapper($level, $entry) {
    syslog($level, $entry);
  }

}

Notice that in Drupal 8, as in Drupal 7, it is possible to have different loggers active at the same time, so the log messages can be recorded in different ways at the same time.

0

Drupal 8 uses PSR3 compatible logging API. In order to implement additional logger behavior you can create and register a custom logger service.

https://www.drupal.org/docs/8/api/logging-api/overview

You can create a logger service with the drush generate logger command.

Note that at this moment there is no an easy way to alter logged messages in Drupal 8. https://drupal.stackexchange.com/a/222123/433

0

In Drupal 8 :

// Logs a notice
\Drupal::logger('my_module')->notice($message);
// Logs an error
\Drupal::logger('my_module')->error($message);

In Drupal 7 :

// Logs a notice
watchdog('my_module', $message, array());
// Logs an error
watchdog('my_module', $message, array(), WATCHDOG_ERROR);

Your Answer

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

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