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.