In Drupal 8 watchdog has been refactored to an OO, PSR-3 compatible framework.
In the paragraphs below, a "channel" refers to what used to be the $type
argument to watchdog()
. For logging you would have done with simple watchdog()
statements in Drupal 7, look at the example for injecting a specific channel.
The switch to PSR-3 logging has resulted in the following API changes:
-
hook_watchdog()
is gone. For a module to implement a logger, it has to register a service tagged as logger in the module's services.yml file. eg:services: logger.mylog: class: Drupal\mylog\Logger\MyLog tags: - { name: logger }
This class must implement \Psr\Log\LoggerInterface. like this:
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()) { // Do stuff } }
watchdog($type, $message, $variables, $severity, $link)
has been removed in favor of\Drupal::logger($type)->log($severity, $message, $variables)
D7
// Logs a notice watchdog('my_module', $message, array()); // Logs an error watchdog('my_module', $message, array(), WATCHDOG_ERROR);
D8 - procedural
// Logs a notice \Drupal::logger('my_module')->notice($message); // Logs an error \Drupal::logger('my_module')->error($message);
D8 - injecting the whole factory
services: myservice_that_needs_to_log_to_multiple_channels: class: Drupal\mymodule\MyService arguments: ['@logger.factory']
use Drupal\Core\Logger\LoggerChannelFactoryInterface; class MyService { /** * The logger factory. * * @var \Drupal\Core\Logger\LoggerChannelFactoryInterface */ protected $loggerFactory; /** * Constructs a MyService object. * * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $loggerFactory * The logger factory. */ public function __construct(LoggerChannelFactoryInterface $loggerFactory) { $this->loggerFactory = $loggerFactory; } public function doStuff() { // Logs a notice to "my_module" channel. $this->loggerFactory->get('my_module')->notice($message); // Logs an error to "my_other_module" channel. $this->loggerFactory->get('my_other_module')->error($message); } }
D8 - injecting a specific channel
Drupal core registers only one channel incore.services.yml
for "system" channel.
There might be cases where you don't want to inject the whole factory to your class, but just a specific channel.
In that case you can easily register this channel with something like this:services: logger.channel.mymodule: parent: logger.channel_base arguments: ['mymodule']
And then inject
logger.channel.mymodule
to your services.services: myservice_that_needs_specific_channel: class: Drupal\mymodule\MyService arguments: ['@logger.channel.mymodule']
class MyService { public function __construct($logger) { $this->logger = $logger; } public function doStuff() { // Logs a notice. $this->logger->notice($message); // Logs an error. $this->logger->error($message); } }
- WATCHDOG_* constants and
watchdog_severity_levels()
are removed
D7$severity = WATCHDOG_EMERGENCY; $severity = WATCHDOG_ALERT; $severity = WATCHDOG_CRITICAL; $severity = WATCHDOG_ERROR; $severity = WATCHDOG_WARNING; $severity = WATCHDOG_NOTICE; $severity = WATCHDOG_INFO; $severity = WATCHDOG_DEBUG; $levels = watchdog_severity_levels();
D8
use Drupal\Core\Logger\RfcLogLevel; $severity = RfcLogLevel::EMERGENCY; $severity = RfcLogLevel::ALERT; $severity = RfcLogLevel::CRITICAL; $severity = RfcLogLevel::ERROR; $severity = RfcLogLevel::WARNING; $severity = RfcLogLevel::NOTICE; $severity = RfcLogLevel::INFO; $severity = RfcLogLevel::DEBUG; $levels = RfcLogLevel::getLevels();