diff --git a/config/install/monitoring.sensor_config.user_sessions_logouts.yml b/config/install/monitoring.sensor_config.user_sessions_logouts.yml
index 7141ca3..75d4a86 100644
--- a/config/install/monitoring.sensor_config.user_sessions_logouts.yml
+++ b/config/install/monitoring.sensor_config.user_sessions_logouts.yml
@@ -2,7 +2,7 @@ id: user_session_logouts
 label: 'User session logouts'
 description: 'User session logouts by Watchdog'
 category: 'User activity'
-plugin_id: database_aggregator
+plugin_id: watchdog_aggregator
 value_type: 'number'
 value_label: 'Logouts'
 status: TRUE
diff --git a/config/install/monitoring.sensor_config.user_successful_logins.yml b/config/install/monitoring.sensor_config.user_successful_logins.yml
index 7fa49b3..dccaaea 100644
--- a/config/install/monitoring.sensor_config.user_successful_logins.yml
+++ b/config/install/monitoring.sensor_config.user_successful_logins.yml
@@ -2,7 +2,7 @@ id: user_successful_logins
 label: 'Successful user logins'
 description: 'Successful user logins by Watchdog'
 category: 'User activity'
-plugin_id: database_aggregator
+plugin_id: watchdog_aggregator
 value_type : 'number'
 value_label: 'Login attempts'
 status: TRUE
diff --git a/config/optional/monitoring.sensor_config.dblog_event_severity_alert.yml b/config/optional/monitoring.sensor_config.dblog_event_severity_alert.yml
index b859479..08238e5 100644
--- a/config/optional/monitoring.sensor_config.dblog_event_severity_alert.yml
+++ b/config/optional/monitoring.sensor_config.dblog_event_severity_alert.yml
@@ -7,7 +7,7 @@ id: dblog_event_severity_alert
 label: 'Severity Alert'
 description: 'Watchdog entries of severity Alert'
 category: Watchdog
-plugin_id: database_aggregator
+plugin_id: watchdog_aggregator
 result_class: null
 value_label: Events
 value_type: number
diff --git a/config/optional/monitoring.sensor_config.dblog_event_severity_critical.yml b/config/optional/monitoring.sensor_config.dblog_event_severity_critical.yml
index e8e7c12..c094ce5 100644
--- a/config/optional/monitoring.sensor_config.dblog_event_severity_critical.yml
+++ b/config/optional/monitoring.sensor_config.dblog_event_severity_critical.yml
@@ -7,7 +7,7 @@ id: dblog_event_severity_critical
 label: 'Severity Critical'
 description: 'Watchdog entries of severity Critical'
 category: Watchdog
-plugin_id: database_aggregator
+plugin_id: watchdog_aggregator
 result_class: null
 value_label: Events
 value_type: number
diff --git a/config/optional/monitoring.sensor_config.dblog_event_severity_debug.yml b/config/optional/monitoring.sensor_config.dblog_event_severity_debug.yml
index ddd18a6..d567a5e 100644
--- a/config/optional/monitoring.sensor_config.dblog_event_severity_debug.yml
+++ b/config/optional/monitoring.sensor_config.dblog_event_severity_debug.yml
@@ -7,7 +7,7 @@ id: dblog_event_severity_debug
 label: 'Severity Debug'
 description: 'Watchdog entries of severity Debug'
 category: Watchdog
-plugin_id: database_aggregator
+plugin_id: watchdog_aggregator
 result_class: null
 value_label: Events
 value_type: number
diff --git a/config/optional/monitoring.sensor_config.dblog_event_severity_emergency.yml b/config/optional/monitoring.sensor_config.dblog_event_severity_emergency.yml
index 54e3229..bb1820b 100644
--- a/config/optional/monitoring.sensor_config.dblog_event_severity_emergency.yml
+++ b/config/optional/monitoring.sensor_config.dblog_event_severity_emergency.yml
@@ -7,7 +7,7 @@ id: dblog_event_severity_emergency
 label: 'Severity Emergency'
 description: 'Watchdog entries of severity Emergency'
 category: Watchdog
-plugin_id: database_aggregator
+plugin_id: watchdog_aggregator
 result_class: null
 value_label: Events
 value_type: number
diff --git a/config/optional/monitoring.sensor_config.dblog_event_severity_error.yml b/config/optional/monitoring.sensor_config.dblog_event_severity_error.yml
index 7a034b7..731e15d 100644
--- a/config/optional/monitoring.sensor_config.dblog_event_severity_error.yml
+++ b/config/optional/monitoring.sensor_config.dblog_event_severity_error.yml
@@ -7,7 +7,7 @@ id: dblog_event_severity_error
 label: 'Severity Error'
 description: 'Watchdog entries of severity Error'
 category: Watchdog
-plugin_id: database_aggregator
+plugin_id: watchdog_aggregator
 result_class: null
 value_label: Events
 value_type: number
diff --git a/config/optional/monitoring.sensor_config.dblog_event_severity_info.yml b/config/optional/monitoring.sensor_config.dblog_event_severity_info.yml
index eb134c3..5e50f45 100644
--- a/config/optional/monitoring.sensor_config.dblog_event_severity_info.yml
+++ b/config/optional/monitoring.sensor_config.dblog_event_severity_info.yml
@@ -7,7 +7,7 @@ id: dblog_event_severity_info
 label: 'Severity Info'
 description: 'Watchdog entries of severity Info'
 category: Watchdog
-plugin_id: database_aggregator
+plugin_id: watchdog_aggregator
 result_class: null
 value_label: Events
 value_type: number
diff --git a/config/optional/monitoring.sensor_config.dblog_event_severity_notice.yml b/config/optional/monitoring.sensor_config.dblog_event_severity_notice.yml
index c62e079..6d99f1e 100644
--- a/config/optional/monitoring.sensor_config.dblog_event_severity_notice.yml
+++ b/config/optional/monitoring.sensor_config.dblog_event_severity_notice.yml
@@ -7,7 +7,7 @@ id: dblog_event_severity_notice
 label: 'Severity Notice'
 description: 'Watchdog entries of severity Notice'
 category: Watchdog
-plugin_id: database_aggregator
+plugin_id: watchdog_aggregator
 result_class: null
 value_label: Events
 value_type: number
diff --git a/config/optional/monitoring.sensor_config.dblog_event_severity_warning.yml b/config/optional/monitoring.sensor_config.dblog_event_severity_warning.yml
index 21b35df..6f090c5 100644
--- a/config/optional/monitoring.sensor_config.dblog_event_severity_warning.yml
+++ b/config/optional/monitoring.sensor_config.dblog_event_severity_warning.yml
@@ -7,7 +7,7 @@ id: dblog_event_severity_warning
 label: 'Severity Warning'
 description: 'Watchdog entries of severity Warning'
 category: Watchdog
-plugin_id: database_aggregator
+plugin_id: watchdog_aggregator
 result_class: null
 value_label: Events
 value_type: number
diff --git a/config/schema/monitoring.schema.yml b/config/schema/monitoring.schema.yml
index 35942aa..8f49d6d 100644
--- a/config/schema/monitoring.schema.yml
+++ b/config/schema/monitoring.schema.yml
@@ -193,6 +193,10 @@ monitoring.settings.search_api_unindexed:
       type: string
       label: 'Index ID'
 
+monitoring.settings.watchdog_aggregator:
+  type: monitoring.settings.database_aggregator
+  label: 'Watchdog sensor settings'
+
 monitoring.settings.dblog_404:
   type: monitoring.settings.database_aggregator
   label: '404 settings'
diff --git a/src/Plugin/monitoring/SensorPlugin/DatabaseAggregatorSensorPlugin.php b/src/Plugin/monitoring/SensorPlugin/DatabaseAggregatorSensorPlugin.php
index a8ed1c5..eef80c9 100644
--- a/src/Plugin/monitoring/SensorPlugin/DatabaseAggregatorSensorPlugin.php
+++ b/src/Plugin/monitoring/SensorPlugin/DatabaseAggregatorSensorPlugin.php
@@ -160,6 +160,17 @@ class DatabaseAggregatorSensorPlugin extends DatabaseAggregatorSensorPluginBase
       '#title' => t('RESULT'),
     );
 
+    $this->verboseResultUnaggregated($output);
+    return $output;
+  }
+
+  /**
+   * Adds unaggregated verbose output to the render array $output.
+   *
+   * @param array &$output
+   *   Render array where the result will be added.
+   */
+  public function verboseResultUnaggregated(array &$output) {
     // Fetch the last 10 matching entries, unaggregated.
     $query_result = $this->getQuery()
       ->range(0, 10)
@@ -177,8 +188,11 @@ class DatabaseAggregatorSensorPlugin extends DatabaseAggregatorSensorPluginBase
         'class' => 'entity',
       );
     }
+
     if (count($rows) > 0) {
-      $header = array_keys($rows[0]['data']);
+      // Provide consistent keys for header and data rows for easy altering.
+      $keys = array_keys($rows[0]['data']);
+      $header = array_combine($keys, $keys);
       $output['result'] = array(
         '#type' => 'table',
         '#header' => $header,
@@ -191,7 +205,6 @@ class DatabaseAggregatorSensorPlugin extends DatabaseAggregatorSensorPluginBase
         '#markup' => t('No results were found in the table.'),
       ];
     }
-    return $output;
   }
 
   /**
diff --git a/src/Plugin/monitoring/SensorPlugin/WatchdogAggregatorSensorPlugin.php b/src/Plugin/monitoring/SensorPlugin/WatchdogAggregatorSensorPlugin.php
new file mode 100644
index 0000000..03bf1f9
--- /dev/null
+++ b/src/Plugin/monitoring/SensorPlugin/WatchdogAggregatorSensorPlugin.php
@@ -0,0 +1,60 @@
+<?php
+/**
+ * @file
+ * Contains \Drupal\monitoring\Plugin\monitoring\SensorPlugin\WatchdogAggregatorSensorPlugin.
+ */
+
+namespace Drupal\monitoring\Plugin\monitoring\SensorPlugin;
+
+use Drupal\Core\Database\DatabaseExceptionWrapper;
+use Drupal\Core\Database\Query\SelectInterface;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\monitoring\Result\SensorResultInterface;
+use Drupal\monitoring\SensorPlugin\ExtendedInfoSensorPluginInterface;
+use Drupal\monitoring\SensorPlugin\DatabaseAggregatorSensorPluginBase;
+use Drupal\Core\Entity\DependencyTrait;
+use Drupal\Component\Utility\SafeMarkup;
+
+/**
+ * Watchdog aggregator which handles replacement of variables in the message.
+ *
+ * @SensorPlugin(
+ *   id = "watchdog_aggregator",
+ *   label = @Translation("Simple Watchdog Aggregator"),
+ *   description = @Translation("Simple aggregator able to query the watchdog table."),
+ *   addable = TRUE
+ * )
+ *
+ */
+class WatchdogAggregatorSensorPlugin extends DatabaseAggregatorSensorPlugin implements ExtendedInfoSensorPluginInterface {
+  /**
+   * {@inheritdoc}
+   */
+  public function verboseResultUnaggregated(array &$output) {
+    parent::verboseResultUnaggregated($output);
+    if (isset($output['result']['#rows'])) {
+      if (array_key_exists('message', $output['result']['#header']) && array_key_exists('variables', $output['result']['#header'])) {
+        unset($output['result']['#header']['variables']);
+      }
+      foreach ($output['result']['#rows'] as $delta => $row) {
+        if (array_key_exists('message', $row['data']) && array_key_exists('variables', $row['data'])) {
+          $output['result']['#rows'][$delta]['data']['message'] = SafeMarkup::format($row['data']['message'], unserialize($row['data']['variables']));
+          unset($output['result']['#rows'][$delta]['data']['variables']);
+        };
+      };
+    }
+  }
+
+  /**
+   * Adds UI for variables table and conditions.
+   */
+  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
+    $form = parent::buildConfigurationForm($form, $form_state);
+    $form['#title'] = t('Watchdog Sensor plugin settings');
+    // The following fields should not be edited, so we disable them.
+    $form['table']['#disabled'] = TRUE;
+    $form['aggregation']['time_interval_field']['#disabled'] = TRUE;
+    return $form;
+  }
+
+}
diff --git a/src/Tests/MonitoringCoreWebTest.php b/src/Tests/MonitoringCoreWebTest.php
index 562db7f..b498516 100644
--- a/src/Tests/MonitoringCoreWebTest.php
+++ b/src/Tests/MonitoringCoreWebTest.php
@@ -26,6 +26,43 @@ class MonitoringCoreWebTest extends MonitoringTestBase {
     $this->doTestDatabaseAggregatorSensorPluginActiveSessions();
     $this->doTestTwigDebugSensor();
     $this->doTestUserIntegritySensorPlugin();
+    $this->doTestWatchdogAggregatorSensorPlugin();
+  }
+
+  /**
+   * Tests successful user logins through watchdog sensor.
+   *
+   * @see DatabaseAggregatorSensorPlugin
+   */
+  protected function doTestWatchdogAggregatorSensorPlugin() {
+    // Create and login user with permission to edit sensors and view reports.
+    $test_user = $this->drupalCreateUser([
+      'administer site configuration',
+      'administer monitoring',
+      'monitoring reports',
+      'access site reports',
+      'monitoring verbose',
+    ]);
+    $this->drupalLogin($test_user);
+    // Test output and default message replacement.
+    $this->drupalGet('admin/reports/monitoring/sensors/user_successful_logins');
+    $xpath = $this->xpath('//fieldset[@id="edit-verbose"]/div[@class="fieldset-wrapper"]/table/tbody/tr[@class="entity odd"]');
+    $wid = (string) $xpath[0]->td[0];
+    $message = (string) $xpath[0]->td[1];
+    $this->assertTrue($wid == 6, 'Found WID in verbose output (WID == 6)');
+    $this->assertTrue($message == 'Session opened for .', 'Found replaced message in output.');
+    $this->assertText('Session opened for ' . $test_user->label());
+    // Remove variables from the fields and assert message has no replacements.
+    $this->drupalPostForm('admin/config/system/monitoring/sensors/user_successful_logins', ['keys' => 'wid' . PHP_EOL . 'message'], t('Save'));
+    $this->drupalGet('admin/reports/monitoring/sensors/user_successful_logins');
+    $xpath = $this->xpath('//fieldset[@id="edit-verbose"]/div[@class="fieldset-wrapper"]/table/tbody/tr[@class="entity odd"]');
+    $wid = (string) $xpath[0]->td[0];
+    $message = (string) $xpath[0]->td[1];
+    $this->assertTrue($wid == 6, 'Found WID in verbose output (WID == 6)');
+    $this->assertTrue($message == 'Session opened for %name.', 'Found unreplaced message in output.');
+    // Test wrong configuration (messages field does not exist).
+    $this->drupalPostForm('admin/config/system/monitoring/sensors/user_successful_logins', ['keys' => 'wid' . PHP_EOL . 'messages'], t('Save'));
+    $this->assertText('Verbose output configuration is invalid, keys were not saved.');
   }
 
   /**
@@ -63,7 +100,7 @@ class MonitoringCoreWebTest extends MonitoringTestBase {
     $this->assertTrue(count($results) == 3, '3 fields have been found in the verbose result.');
     // The username should be replaced in the message.
     $this->drupalGet('/admin/reports/monitoring/sensors/dblog_event_severity_notice');
-    $this->assertText('Session opened for %name');
+    $this->assertText('Session opened for ' . $test_user->label());
     // 'No results' text is displayed when the query has 0 results.
     $this->drupalGet('/admin/reports/monitoring/sensors/dblog_event_severity_warning');
     $this->assertText('No results were found in the table.');
