diff --git a/core/core.services.yml b/core/core.services.yml
index 42b5614..91d3231 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -96,6 +96,9 @@ services:
     factory_class: Drupal\Core\Database\Database
     factory_method: getConnection
     arguments: [default]
+  watchdog:
+    class: Drupal\Core\WatchdogLogger
+    arguments: ['@request']
   keyvalue:
     class: Drupal\Core\KeyValueStore\KeyValueFactory
     arguments: ['@service_container']
@@ -161,7 +164,7 @@ services:
     arguments: ['@service_container']
   controller_resolver:
     class: Drupal\Core\Controller\ControllerResolver
-    arguments: ['@service_container']
+    arguments: ['@service_container', '@watchdog']
   http_kernel:
     class: Drupal\Core\HttpKernel
     arguments: ['@event_dispatcher', '@service_container', '@controller_resolver']
@@ -200,7 +203,7 @@ services:
       - [setFinalMatcher, ['@router.matcher.final_matcher']]
   router.generator:
     class: Drupal\Core\Routing\UrlGenerator
-    arguments: ['@router.route_provider', '@path.alias_manager.cached']
+    arguments: ['@router.route_provider', '@path.alias_manager.cached', '@watchdog']
   router.dynamic:
     class: Symfony\Cmf\Component\Routing\DynamicRouter
     arguments: ['@router.request_context', '@router.matcher', '@router.generator']
@@ -415,3 +418,8 @@ services:
   token:
     class: Drupal\Core\Utility\Token
     arguments: ['@module_handler']
+  watchdog_request_subscriber:
+    class: Drupal\Core\EventSubscriber\WatchdogRequestSubscriber
+    tags:
+      - { name: event_subscriber }
+    arguments: ['@watchdog']
diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index 7dc75f5..06164ae 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -1398,7 +1398,7 @@ function drupal_serve_page_from_cache(stdClass $cache) {
  * Defines the critical hooks that force modules to always be loaded.
  */
 function bootstrap_hooks() {
-  return array('watchdog');
+  return array();
 }
 
 /**
@@ -1651,47 +1651,15 @@ function watchdog_exception($type, Exception $exception, $message = NULL, $varia
  *   A link to associate with the message.
  *
  * @see watchdog_severity_levels()
- * @see hook_watchdog()
+ * @see \Drupal\Core\WatchdogLogger::log()
  */
 function watchdog($type, $message, array $variables = NULL, $severity = WATCHDOG_NOTICE, $link = NULL) {
-  global $user, $base_root;
-
-  static $in_error_state = FALSE;
-
-  // It is possible that the error handling will itself trigger an error. In that case, we could
-  // end up in an infinite loop. To avoid that, we implement a simple static semaphore.
-  if (!$in_error_state && function_exists('module_implements')) {
-    $in_error_state = TRUE;
-
-    // The user object may not exist in all conditions, so 0 is substituted if needed.
-    $user_uid = isset($user->uid) ? $user->uid : 0;
-
-    // Prepare the fields to be logged
-    $log_entry = array(
-      'type'        => $type,
-      'message'     => $message,
-      'variables'   => $variables,
-      'severity'    => $severity,
-      'link'        => $link,
-      'user'        => $user,
-      'uid'         => $user_uid,
-      'request_uri' => $base_root . request_uri(),
-      'referer'     => isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '',
-      'ip'          => Drupal::request()->getClientIP(),
-      // Request time isn't accurate for long processes, use time() instead.
-      'timestamp'   => time(),
-    );
-
-    // Call the logging hooks to log/process the message
-    foreach (module_implements('watchdog') as $module) {
-      $function = $module . '_watchdog';
-      $function($log_entry);
-    }
-
-    // It is critical that the semaphore is only cleared here, in the parent
-    // watchdog() call (not outside the loop), to prevent recursive execution.
-    $in_error_state = FALSE;
-  }
+  $context = array(
+    'type' => $type,
+    'message_variables' => $variables,
+    'link' => $link,
+  );
+  Drupal::service('watchdog')->log($severity, $message, $context);
 }
 
 /**
diff --git a/core/lib/Drupal/Core/Controller/ControllerResolver.php b/core/lib/Drupal/Core/Controller/ControllerResolver.php
index bded7a6..5fda8ce 100644
--- a/core/lib/Drupal/Core/Controller/ControllerResolver.php
+++ b/core/lib/Drupal/Core/Controller/ControllerResolver.php
@@ -7,8 +7,8 @@
 
 namespace Drupal\Core\Controller;
 
+use Psr\Log\LoggerInterface;
 use Symfony\Component\HttpKernel\Controller\ControllerResolver as BaseControllerResolver;
-use Symfony\Component\HttpKernel\Log\LoggerInterface;
 use Symfony\Component\DependencyInjection\ContainerAwareInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -41,7 +41,7 @@ class ControllerResolver extends BaseControllerResolver {
    *
    * @param Symfony\Component\DependencyInjection\ContainerInterface $container
    *   A ContainerInterface instance.
-   * @param Symfony\Component\HttpKernel\Log\LoggerInterface $logger
+   * @param \Psr\Log\LoggerInterface $logger
    *   (optional) A LoggerInterface instance.
    */
   public function __construct(ContainerInterface $container, LoggerInterface $logger = NULL) {
diff --git a/core/lib/Drupal/Core/CoreBundle.php b/core/lib/Drupal/Core/CoreBundle.php
index 2d85f6a..1387159 100644
--- a/core/lib/Drupal/Core/CoreBundle.php
+++ b/core/lib/Drupal/Core/CoreBundle.php
@@ -16,6 +16,7 @@
 use Drupal\Core\DependencyInjection\Compiler\RegisterRouteEnhancersPass;
 use Drupal\Core\DependencyInjection\Compiler\RegisterParamConvertersPass;
 use Drupal\Core\DependencyInjection\Compiler\RegisterServicesForDestructionPass;
+use Drupal\Core\DependencyInjection\Compiler\RegisterWatchdogLoggersPass;
 use Symfony\Component\DependencyInjection\ContainerBuilder;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\DependencyInjection\Reference;
@@ -60,6 +61,8 @@ public function build(ContainerBuilder $container) {
     // Add the compiler pass that will process the tagged services.
     $container->addCompilerPass(new RegisterPathProcessorsPass());
     $container->addCompilerPass(new ListCacheBinsPass());
+    // Add a compiler pass for registering logging services.
+    $container->addCompilerPass(new RegisterWatchdogLoggersPass());
   }
 
   /**
diff --git a/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterWatchdogLoggersPass.php b/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterWatchdogLoggersPass.php
new file mode 100644
index 0000000..7bdb97e
--- /dev/null
+++ b/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterWatchdogLoggersPass.php
@@ -0,0 +1,32 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\DependencyInjection\Compiler\RegisterWatchdogLoggersPass.
+ */
+
+namespace Drupal\Core\DependencyInjection\Compiler;
+
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
+use Symfony\Component\DependencyInjection\Reference;
+
+class RegisterWatchdogLoggersPass implements CompilerPassInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function process(ContainerBuilder $container) {
+    if (!$container->hasDefinition('watchdog')) {
+      return;
+    }
+
+    $definition = $container->getDefinition('watchdog');
+
+    foreach ($container->findTaggedServiceIds('watchdog_logger') as $id => $attributes) {
+      $priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0;
+      $definition->addMethodCall('addLogger', array(new Reference($id), $priority));
+    }
+  }
+
+}
diff --git a/core/lib/Drupal/Core/EventSubscriber/WatchdogRequestSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/WatchdogRequestSubscriber.php
new file mode 100644
index 0000000..66ebbcb
--- /dev/null
+++ b/core/lib/Drupal/Core/EventSubscriber/WatchdogRequestSubscriber.php
@@ -0,0 +1,62 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\EventSubscriber\WatchdogRequestSubscriber.
+ */
+
+namespace Drupal\Core\EventSubscriber;
+
+use Drupal\Core\WatchdogLogger;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+use Symfony\Component\HttpKernel\KernelEvents;
+use Symfony\Component\HttpKernel\Event\GetResponseEvent;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+
+/**
+ * Sets the $request property on the watchdog logger.
+ */
+class WatchdogRequestSubscriber implements EventSubscriberInterface {
+
+  /**
+   * The watchdog logger service.
+   *
+   * @var \Drupal\Core\WatchdogLogger
+   */
+  protected $watchdogLogger;
+
+  /**
+   * Constructs a WatchdogRequestSubscriber object.
+   *
+   * @param \Drupal\Core\WatchdogLogger $watchdog_logger
+   *   The watchdog logger service.
+   */
+  public function __construct(WatchdogLogger $watchdog_logger) {
+    $this->watchdogLogger = $watchdog_logger;
+  }
+
+  /**
+   * Sets the request on the watchdog logger.
+   *
+   * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event
+   *   The Event to process.
+   */
+  public function setWatchdogLoggerRequest(GetResponseEvent $event) {
+    if ($event->getRequestType() == HttpKernelInterface::MASTER_REQUEST) {
+      $this->watchdogLogger->setRequest($event->getRequest());
+    }
+  }
+
+  /**
+   * Registers the methods in this class that should be listeners.
+   *
+   * @return array
+   *   An array of event listener definitions.
+   */
+  static function getSubscribedEvents() {
+    $events[KernelEvents::REQUEST][] = array('setWatchdogLoggerRequest', 350);
+
+    return $events;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Routing/UrlGenerator.php b/core/lib/Drupal/Core/Routing/UrlGenerator.php
index 75779a2..f82c1ac 100644
--- a/core/lib/Drupal/Core/Routing/UrlGenerator.php
+++ b/core/lib/Drupal/Core/Routing/UrlGenerator.php
@@ -7,8 +7,7 @@
 
 namespace Drupal\Core\Routing;
 
-use Symfony\Component\HttpKernel\Log\LoggerInterface;
-
+use Psr\Log\LoggerInterface;
 use Symfony\Cmf\Component\Routing\ProviderBasedGenerator;
 use Symfony\Cmf\Component\Routing\RouteProviderInterface;
 
@@ -33,7 +32,7 @@ class UrlGenerator extends ProviderBasedGenerator {
    *   The route provider to be searched for routes.
    * @param \Drupal\Core\Path\AliasManagerInterface $alias_manager
    *   The alias manager responsible for path aliasing.
-   * @param \Symfony\Component\HttpKernel\Log\LoggerInterface $logger
+   * @param \Psr\Log\LoggerInterface $logger
    *   An optional logger for recording errors.
    */
   public function __construct(RouteProviderInterface $provider, AliasManagerInterface $alias_manager, LoggerInterface $logger = NULL) {
diff --git a/core/lib/Drupal/Core/WatchdogLogger.php b/core/lib/Drupal/Core/WatchdogLogger.php
new file mode 100644
index 0000000..a344fe3
--- /dev/null
+++ b/core/lib/Drupal/Core/WatchdogLogger.php
@@ -0,0 +1,142 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\WatchdogLogger.
+ */
+
+namespace Drupal\Core;
+
+use Psr\Log\AbstractLogger;
+use Psr\Log\LoggerInterface;
+use Psr\Log\LogLevel;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Watchdog-backed implementation of the PSR-3 Logger interface.
+ */
+class WatchdogLogger extends AbstractLogger {
+
+  /**
+   * Map of PSR Log constants to Watchdog log constants.
+   *
+   * @var array
+   */
+  protected $levelTranslation;
+
+  /**
+   * Array of \Psr\Log\LoggerInterface objects.
+   *
+   * @var array
+   */
+  protected $loggers = array();
+
+  /**
+   * The request object.
+   *
+   * @var \Symfony\Component\HttpFoundation\Request
+   */
+  protected $request;
+
+  /**
+   * Constructs a WatchdogLogger object.
+   *
+   * This is needed to retrieve request when kernel is being rebuilt or we have
+   * no listeners, like installation or update process.
+   *
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The current request object.
+   */
+  public function __construct(Request $request) {
+    $this->request = $request;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function log($level, $message, array $context = array()) {
+    global $user;
+    $context += array(
+      'type' => 'system',
+      'message_variables' => array(),
+      'link' => '',
+      'user' => $user,
+      'uid' => isset($user->uid) ? $user->uid : 0,
+      'request_uri' => $this->request->server->get('REQUEST_URI', ''),
+      'referer' => $this->request->server->get('HTTP_REFERER', ''),
+      'ip' => $this->request->getClientIP(),
+      'timestamp' => time(),
+    );
+    if (is_string($level)) {
+      // Convert to integer equivalent for BC and PHP syslog() compatibility.
+      $level = $this->mapLevel($level);
+    }
+    // Call all available loggers.
+    foreach ($this->sortLoggers() as $logger) {
+      $logger->log($level, $message, $context);
+    }
+  }
+
+  /**
+   * Sets the request.
+   *
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The current request object.
+   */
+  public function setRequest(Request $request) {
+    $this->request = $request;
+  }
+
+  /**
+   * Adds a logger.
+   *
+   * @param \Psr\Log\LoggerInterface $logger
+   *   The PSR-3 logger to add.
+   * @param int $priority
+   *   The priority of the logger being added.
+   */
+  public function addLogger(LoggerInterface $logger, $priority = 0) {
+    $this->loggers[$priority][] = $logger;
+  }
+
+  /**
+   * Converts a PSR Log level to a Watchdog log level.
+   *
+   * @param string $level
+   *   A PSR-3 logging level string.
+   *
+   * @return int
+   *   The corresponding Watchdog constant.
+   */
+  protected function mapLevel($level) {
+    if (empty($this->levelTranslation)) {
+      // Use PHP constants to keep this unit-testable.
+      $this->levelTranslation = array(
+        LogLevel::EMERGENCY => LOG_EMERG,
+        LogLevel::ALERT => LOG_ALERT,
+        LogLevel::CRITICAL => LOG_CRIT,
+        LogLevel::ERROR => LOG_ERR,
+        LogLevel::WARNING => LOG_WARNING,
+        LogLevel::NOTICE => LOG_NOTICE,
+        LogLevel::INFO => LOG_INFO,
+        LogLevel::DEBUG => LOG_DEBUG,
+      );
+    }
+
+    return $this->levelTranslation[$level];
+  }
+
+  /**
+   * Sorts loggers according to priority.
+   */
+  protected function sortLoggers() {
+    $sorted = array();
+    krsort($this->loggers);
+
+    foreach ($this->loggers as $loggers) {
+      $sorted = array_merge($sorted, $loggers);
+    }
+    return $sorted;
+  }
+
+}
diff --git a/core/modules/action/tests/action_loop_test/action_loop_test.module b/core/modules/action/tests/action_loop_test/action_loop_test.module
index 36f6d9b..5cb5fc8 100644
--- a/core/modules/action/tests/action_loop_test/action_loop_test.module
+++ b/core/modules/action/tests/action_loop_test/action_loop_test.module
@@ -1,22 +1,23 @@
 <?php
 
 /**
- * Implements hook_watchdog().
+ * Implements hook_permission().
  */
-function action_loop_test_watchdog(array $log_entry) {
+function action_loop_test_permission() {
   // If the triggering actions are not explicitly enabled, abort.
   if (empty($_GET['trigger_action_on_watchdog'])) {
-    return;
+    return array();
   }
   // We can pass in any applicable information in $context. There isn't much in
   // this case, but we'll pass in the hook name as the bare minimum.
   $context = array(
-    'hook' => 'watchdog',
+    'hook' => 'permission',
   );
   // Fire the actions on the associated object ($log_entry) and the context
   // variable.
   $aids = (array) $_GET['trigger_action_on_watchdog'];
-  actions_do($aids, $log_entry, $context);
+  actions_do($aids, array(), $context);
+  return array();
 }
 
 /**
@@ -24,7 +25,8 @@ function action_loop_test_watchdog(array $log_entry) {
  */
 function action_loop_test_init() {
   if (!empty($_GET['trigger_action_on_watchdog'])) {
-    watchdog_skip_semaphore('action_loop_test', 'Triggering action loop');
+    watchdog('action_loop_test', 'Triggering action loop');
+    module_invoke_all('permission');
   }
 }
 
@@ -48,33 +50,6 @@ function action_loop_test_action_info() {
 function action_loop_test_log() {
   $count = &drupal_static(__FUNCTION__, 0);
   $count++;
-  watchdog_skip_semaphore('action_loop_test', "Test log #$count");
-}
-
-/**
- * Replacement of the watchdog() function that eliminates the use of semaphores
- * so that we can test the abortion of an action loop.
- */
-function watchdog_skip_semaphore($type, $message, $variables = array(), $severity = WATCHDOG_NOTICE, $link = NULL) {
-  global $user, $base_root;
-
-  // Prepare the fields to be logged
-  $log_entry = array(
-    'type'        => $type,
-    'message'     => $message,
-    'variables'   => $variables,
-    'severity'    => $severity,
-    'link'        => $link,
-    'user'        => $user,
-    'uid'         => isset($user->uid) ? $user->uid : 0,
-    'request_uri' => $base_root . request_uri(),
-    'referer'     => $_SERVER['HTTP_REFERER'],
-    'ip'          => Drupal::request()->getClientIP(),
-    'timestamp'   => REQUEST_TIME,
-  );
-
-  // Call the logging hooks to log/process the message
-  foreach (module_implements('watchdog') as $module) {
-    module_invoke($module, 'watchdog', $log_entry);
-  }
+  watchdog('action_loop_test', "Test log #$count");
+  module_invoke_all('permission');
 }
diff --git a/core/modules/dblog/dblog.module b/core/modules/dblog/dblog.module
index d28f3b7..520faeb 100644
--- a/core/modules/dblog/dblog.module
+++ b/core/modules/dblog/dblog.module
@@ -140,31 +140,6 @@ function _dblog_get_message_types() {
 }
 
 /**
- * Implements hook_watchdog().
- *
- * Note: Some values may be truncated to meet database column size restrictions.
- */
-function dblog_watchdog(array $log_entry) {
-  // Remove any backtraces since they may contain an unserializable variable.
-  unset($log_entry['variables']['backtrace']);
-
-  Database::getConnection('default', 'default')->insert('watchdog')
-    ->fields(array(
-      'uid' => $log_entry['uid'],
-      'type' => substr($log_entry['type'], 0, 64),
-      'message' => $log_entry['message'],
-      'variables' => serialize($log_entry['variables']),
-      'severity' => $log_entry['severity'],
-      'link' => substr($log_entry['link'], 0, 255),
-      'location' => $log_entry['request_uri'],
-      'referer' => $log_entry['referer'],
-      'hostname' => substr($log_entry['ip'], 0, 128),
-      'timestamp' => $log_entry['timestamp'],
-    ))
-    ->execute();
-}
-
-/**
  * Implements hook_form_FORM_ID_alter() for system_logging_settings().
  */
 function dblog_form_system_logging_settings_alter(&$form, $form_state) {
diff --git a/core/modules/dblog/dblog.services.yml b/core/modules/dblog/dblog.services.yml
new file mode 100644
index 0000000..320386f
--- /dev/null
+++ b/core/modules/dblog/dblog.services.yml
@@ -0,0 +1,6 @@
+services:
+  watchdog.dblog:
+    class: Drupal\dblog\DbLogWatchdog
+    arguments: ['@database']
+    tags:
+      - { name: watchdog_logger }
diff --git a/core/modules/dblog/lib/Drupal/dblog/DbLogWatchdog.php b/core/modules/dblog/lib/Drupal/dblog/DbLogWatchdog.php
new file mode 100644
index 0000000..35e4b7e
--- /dev/null
+++ b/core/modules/dblog/lib/Drupal/dblog/DbLogWatchdog.php
@@ -0,0 +1,59 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\dblog\DbLogWatchdog.
+ */
+
+namespace Drupal\dblog;
+
+use Drupal\Core\Database\Connection;
+use Psr\Log\AbstractLogger;
+
+/**
+ * Logs events in the watchdog database table.
+ */
+class DbLogWatchdog extends AbstractLogger {
+
+  /**
+   * The database connection object.
+   *
+   * @var \Drupal\Core\Database\Connection
+   */
+  protected $database;
+
+  /**
+   * Constructs a DbLogWatchdog object.
+   *
+   * @param \Drupal\Core\Database\Connection $database
+   *   The database connection object.
+   */
+  public function __construct(Connection $database) {
+    $this->database = $database;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function log($level, $message, array $context = array()) {
+    // Remove any backtraces since they may contain an unserializable variable.
+    unset($context['message_variables']['backtrace']);
+
+    $this->database
+      ->insert('watchdog')
+      ->fields(array(
+        'uid' => $context['uid'],
+        'type' => substr($context['type'], 0, 64),
+        'message' => $message,
+        'variables' => serialize($context['message_variables']),
+        'severity' => $level,
+        'link' => substr($context['link'], 0, 255),
+        'location' => $context['request_uri'],
+        'referer' => $context['referer'],
+        'hostname' => substr($context['ip'], 0, 128),
+        'timestamp' => $context['timestamp'],
+      ))
+      ->execute();
+  }
+
+}
diff --git a/core/modules/dblog/lib/Drupal/dblog/Tests/DBLogTest.php b/core/modules/dblog/lib/Drupal/dblog/Tests/DBLogTest.php
index 9fcc1ee..a3b9fb0 100644
--- a/core/modules/dblog/lib/Drupal/dblog/Tests/DBLogTest.php
+++ b/core/modules/dblog/lib/Drupal/dblog/Tests/DBLogTest.php
@@ -130,7 +130,7 @@ private function generateLogEntries($count, $type = 'custom', $severity = WATCHD
     $log = array(
       'type'        => $type,
       'message'     => 'Log entry added to test the dblog row limit.',
-      'variables'   => array(),
+      'message_variables' => array(),
       'severity'    => $severity,
       'link'        => NULL,
       'user'        => $this->big_user,
@@ -143,7 +143,7 @@ private function generateLogEntries($count, $type = 'custom', $severity = WATCHD
     $message = 'Log entry added to test the dblog row limit. Entry #';
     for ($i = 0; $i < $count; $i++) {
       $log['message'] = $message . $i;
-      dblog_watchdog($log);
+      $this->container->get('watchdog.dblog')->log($severity, $log['message'], $log);
     }
   }
 
@@ -417,7 +417,7 @@ protected function testDBLogAddAndClear() {
     $log = array(
       'type'        => 'custom',
       'message'     => 'Log entry added to test the doClearTest clear down.',
-      'variables'   => array(),
+      'message_variables' => array(),
       'severity'    => WATCHDOG_NOTICE,
       'link'        => NULL,
       'user'        => $this->big_user,
@@ -428,7 +428,7 @@ protected function testDBLogAddAndClear() {
       'timestamp'   => REQUEST_TIME,
     );
     // Add a watchdog entry.
-    dblog_watchdog($log);
+    $this->container->get('watchdog.dblog')->log($log['severity'], $log['message'], $log);
     // Make sure the table count has actually been incremented.
     $this->assertEqual($count + 1, db_query('SELECT COUNT(*) FROM {watchdog}')->fetchField(), format_string('dblog_watchdog() added an entry to the dblog :count', array(':count' => $count)));
     // Login the admin user.
diff --git a/core/modules/syslog/lib/Drupal/syslog/SysLogWatchdog.php b/core/modules/syslog/lib/Drupal/syslog/SysLogWatchdog.php
new file mode 100644
index 0000000..3d97d36
--- /dev/null
+++ b/core/modules/syslog/lib/Drupal/syslog/SysLogWatchdog.php
@@ -0,0 +1,61 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\syslog\SysLogWatchdog.
+ */
+
+namespace Drupal\syslog;
+
+use Drupal\Core\Config\ConfigFactory;
+use Psr\Log\AbstractLogger;
+
+/**
+ * Redirects logging messages to syslog.
+ */
+class SysLogWatchdog extends AbstractLogger {
+
+  /**
+   * A configuration object containin syslog settings.
+   *
+   * @var \Drupal\Core\Config\Config
+   */
+  protected $config;
+
+  /**
+   * Constructs a SysLogWatchdog object.
+   *
+   * @param \Drupal\Core\Config\ConfigFactory $config_factory
+   *   The configuration factory object.
+   */
+  public function __construct(ConfigFactory $config_factory) {
+    $this->config = $config_factory->get('syslog.settings');
+    $facility = $this->config->get('facility');
+    if ($facility === '') {
+      $facility = defined('LOG_LOCAL0') ? LOG_LOCAL0 : LOG_USER;
+    }
+    openlog($this->config->get('identity'), LOG_NDELAY, $facility);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function log($level, $message, array $context = array()) {
+    global $base_url;
+
+    $entry = strtr($this->config->get('format'), array(
+      '!base_url' => $base_url,
+      '!timestamp' => $context['timestamp'],
+      '!type' => $context['type'],
+      '!ip' => $context['ip'],
+      '!request_uri' => $context['request_uri'],
+      '!referer' => $context['referer'],
+      '!uid' => $context['uid'],
+      '!link' => strip_tags($context['link']),
+      '!message' => strip_tags(!isset($context['message_variables']) ? $message : strtr($message, $context['message_variables'])),
+    ));
+
+    syslog($level, $entry);
+  }
+
+}
diff --git a/core/modules/syslog/syslog.module b/core/modules/syslog/syslog.module
index 8af77c1..3d152fe 100644
--- a/core/modules/syslog/syslog.module
+++ b/core/modules/syslog/syslog.module
@@ -103,36 +103,3 @@ function syslog_facility_list() {
     LOG_LOCAL7 => 'LOG_LOCAL7',
   );
 }
-
-/**
- * Implements hook_watchdog().
- */
-function syslog_watchdog(array $log_entry) {
-  global $base_url;
-
-  $log_init = &drupal_static(__FUNCTION__, FALSE);
-  $config = config('syslog.settings');
-
-  if (!$log_init) {
-    $log_init = TRUE;
-    $facility = $config->get('facility');
-    if ($facility === '') {
-      $facility = defined('LOG_LOCAL0') ? LOG_LOCAL0 : LOG_USER;
-    }
-    openlog($config->get('identity'), LOG_NDELAY, $facility);
-  }
-
-  $message = strtr($config->get('format'), array(
-    '!base_url'    => $base_url,
-    '!timestamp'   => $log_entry['timestamp'],
-    '!type'        => $log_entry['type'],
-    '!ip'          => $log_entry['ip'],
-    '!request_uri' => $log_entry['request_uri'],
-    '!referer'     => $log_entry['referer'],
-    '!uid'         => $log_entry['uid'],
-    '!link'        => strip_tags($log_entry['link']),
-    '!message'     => strip_tags(!isset($log_entry['variables']) ? $log_entry['message'] : strtr($log_entry['message'], $log_entry['variables'])),
-  ));
-
-  syslog($log_entry['severity'], $message);
-}
diff --git a/core/modules/syslog/syslog.services.yml b/core/modules/syslog/syslog.services.yml
new file mode 100644
index 0000000..c4aa866
--- /dev/null
+++ b/core/modules/syslog/syslog.services.yml
@@ -0,0 +1,6 @@
+services:
+  watchdog.syslog:
+    class: Drupal\syslog\SysLogWatchdog
+    arguments: ['@config.factory']
+    tags:
+      - { name: watchdog_logger }
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityApiInfoTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityApiInfoTest.php
index cb0ea4d..9b62817 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityApiInfoTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityApiInfoTest.php
@@ -50,7 +50,7 @@ function testEntityInfoChanges() {
    *
    * @see entity_cache_test_watchdog()
    */
-  function testEntityInfoCacheWatchdog() {
+  function testEntityInfoCacheModulesEnabled() {
     module_enable(array('entity_cache_test'));
     $info = state()->get('entity_cache_test');
     $this->assertEqual($info['label'], 'Entity Cache Test', 'Entity info label is correct.');
diff --git a/core/modules/system/tests/modules/entity_cache_test/entity_cache_test.module b/core/modules/system/tests/modules/entity_cache_test/entity_cache_test.module
index 6f23ebb..ff34ed7 100644
--- a/core/modules/system/tests/modules/entity_cache_test/entity_cache_test.module
+++ b/core/modules/system/tests/modules/entity_cache_test/entity_cache_test.module
@@ -6,7 +6,7 @@
  */
 
 /**
- * Implements hook_watchdog().
+ * Implements hook_modules_enabled().
  *
  * This hook is called during module_enable() and since this hook
  * implementation is invoked, we have to expect that this module and dependent
@@ -14,13 +14,11 @@
  * retrieve the entity information that has been registered by the required
  * dependency module.
  *
- * @see EnableDisableTestCase::testEntityCache()
+ * @see EntityApiInfoTest::testEntityInfoCacheModulesEnabled()
  */
-function entity_cache_test_watchdog($log_entry) {
-  if ($log_entry['type'] == 'system' && $log_entry['message'] == '%module module installed.') {
-    $info = entity_get_info('entity_cache_test');
-    // Store the information in a system variable to analyze it later in the
-    // test case.
-    state()->set('entity_cache_test', $info);
-  }
+function entity_cache_test_modules_enabled($modules_enabled) {
+  $info = entity_get_info('entity_cache_test');
+  // Store the information in a system variable to analyze it later in the
+  // test case.
+  state()->set('entity_cache_test', $info);
 }
