.Blog

Logging in Drupal 8

Logging in Drupal 8

Many Drupal websites are not just simple websites but real applications, with many functionalities, integrations and logic. It’s often necessary to keep track of what is happening in the application to understand if something went wrong or even just to monitor the user activities.
It is well known that Drupal has limitations in the logging mechanism, which allows the developer to identify: the type message to save, the message itself, the attention level (from “debug” to “emergency”) and few more:

watchdog('content', '@type: added %title.', $watchdog_args, WATCHDOG_NOTICE, $node_link);

The system will add some metadata, and the information that will be saved in the database is:

The only thing we can do is to redirect the log to another destination. The core will suggest just Syslog. If you are using other frameworks, for example Symfony, you are probably used to a different grade of flexibility. There, the state of art is represented by the Monolog library written by the same developer who invented Composer. Monolog supports Channels of different logs, each of which are associated to some handler that can write a log message about the most diverse destination: from a simple database through Syslog, to the most evolutive solutions like posting a message on Slack or Logstash.

The interesting thing about those handler is that they write a line of just if the attention level is over a certain limit. We can send to Logstash every log, and to Slack (by email) just the most serious “Critical” mistakes. At the end of the list we have the “Formatters” to decide the shape of the log message, and the“Processor” to add metadata to it (for example the clients IP or the user data).

Nice, isn’t it?  But, can we actually have the same flexibility on Drupal?
Sure! "There is a module for that!”. The Monolog module was already available for Drupal 7, but now the integration is just perfect thanks to the new Drupal 8 architecture. Let’s explore how it works.

First of all we need to download and install the Monolog module and its dependence: Composer manager. If we do it with Drush at the end of the process we should have  the two modules installed, and the library downloaded in the vendor/monolog file.

The module is already set up with two channels : default and php. The default channel saves the log on Sysloh while the php channel saves the log on the error_log standard.

In Drupal 7 (and also in a preview of Drupal 8) it was possible to modify the handler set up directly on the CMS web interface. The current version doesn’t have a graphic interface: preferring a more efficient architecture with less dependences than an easier usability.

For example if we want to save all the log messages on a file inside a private filesystems on Drupal, what we have to do it’s creating a file named services.yml inside the sites/default folder of our website:

services:
  monolog.handler.file
:
    class
: Monolog\Handler\StreamHandler
    arguments
: ['private://monolog/debug.log', '200', false]

The content of this file is unified to the Service Container (Drupal component that collect all the available services so that each site can personalize the services to use and their topics. In this case we are redefining the “monolog.handler.file service -originally presents in monolog.services.yml- interpreting as topics the file in which to log, the minimum level of attention to insert in logs (200 corresponds to an INFO level) and bubbling : if this is the last handler of the chain or if the message need to continue to be processed by consecutive handler. In order for Drupal to be able to understand the content of this file it will be enough to empty the cache.

Let’s see how to extend the module to define new channels and Processor.

Adding a new channel is quite easy: we can use the key “parameters” of the services.yml file:

parameters:
  monolog.channel_handlers
:
    webprofiler
: ['file']
  monolog.processors
: ['message_placeholder', 'current_user', 'request_uri', 'ip', 'referer']

In this example we added a new channel so that we can separate and manage differently the generated lot from the Webprofiler module. In order to write log on this new channel you just need to use:

\Drupal::logger('webprofiler')->info('Info message');

In order to define a new Processor it is necessary to use one of the new concept of Drupal 8: services. Let’s suppose that we are planning to add the active theme to all the log messages, we have to start with the creation of the new module: monolog_theme_processor in which we will define a service (within the “monolog_theme_processor.services.yml” file):

services:
  monolog.processor.theme
:
    class
: Drupal\monolog_theme_processor\Logger\Processor\ThemeProcessor
    arguments
: ['@theme.manager']

The new service takes as new subject another service: the “theme.manager”. Let’s introduce now the code of the “ThemeProcessor” class:

<?php
namespace Drupal\monolog_theme_processor\Logger\Processor;

use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\Theme\ThemeManagerInterface;
use Drupal\monolog\Logger\Processor\ProcessorInterface;

ThemeProcessor {
  private $themeManager;

  public function __construct(ThemeManagerInterface $themeManager) {
    $this->themeManager = $themeManager;
  }

  public function __invoke(array $record) {
    $record['extra']['theme'] = $this->themeManager->getActiveTheme()->getName();
    return $record;
  }
}

The class receives in the builder  a request by the theme.manager service. During the saving of the messages log the processor will be evoked and it has the possibility to add elements to the array $record, in this case we use the manger of the theme to recover the name of the active theme. In order to activate this processor it will be enough to add the key “theme” (in a nutshell the id of the service without monolog.processor) to a defined channel in service yml::

parameters:
  monolog.channel_handlers
:
    default
: ['file']
  monolog.processors
: ['message_placeholder', 'current_user', 'request_uri', 'ip', 'referer', 'theme']

services
:
  monolog.handler.file
:
    class
: Monolog\Handler\StreamHandler
    arguments
: ['public://monolog/debug.log', '200', false]

The outcome is:

In the message together with other data we can see that the active theme was Bartik.

While I am writing, this article the module Monolog is not available yet in a stable version for Drupal 8 but it's working and usable also in the production environment.

With this type of integration Drupal 8 is looking more and more interesting for the enterprise sector where this type of functionality is essential.