diff --git a/core/core.services.yml b/core/core.services.yml
index 402d6ee..a734c52 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -126,6 +126,14 @@ services:
     tags:
       - { name: needs_destruction }
     arguments: ['@database']
+  logger.factory:
+    class: Drupal\Core\Logger\LoggerChannelFactory
+    calls:
+      - [setContainer, ['@service_container']]
+  logger.channel.default:
+    class: Drupal\Core\Logger\LoggerChannel
+    tags:
+      - { name: logger_channel }
   settings:
     class: Drupal\Component\Utility\Settings
     factory_class: Drupal\Component\Utility\Settings
@@ -220,7 +228,7 @@ services:
     arguments: ['@service_container']
   controller_resolver:
     class: Drupal\Core\Controller\ControllerResolver
-    arguments: ['@service_container']
+    arguments: ['@service_container', '@logger.channel.default']
   title_resolver:
     class: Drupal\Core\Controller\TitleResolver
     arguments: ['@controller_resolver', '@string_translation']
@@ -280,7 +288,7 @@ services:
       - [setFinalMatcher, ['@router.matcher.final_matcher']]
   url_generator:
     class: Drupal\Core\Routing\UrlGenerator
-    arguments: ['@router.route_provider', '@path_processor_manager', '@route_processor_manager', '@config.factory', '@settings']
+    arguments: ['@router.route_provider', '@path_processor_manager', '@route_processor_manager', '@config.factory', '@settings', '@logger.channel.default']
     calls:
       - [setRequest, ['@?request']]
       - [setContext, ['@?router.request_context']]
@@ -538,7 +546,7 @@ services:
     class: Symfony\Component\HttpKernel\EventListener\ExceptionListener
     tags:
       - { name: event_subscriber }
-    arguments: [['@exception_controller', execute]]
+    arguments: [['@exception_controller', execute], '@logger.channel.default']
   route_processor_manager:
     class: Drupal\Core\RouteProcessor\RouteProcessorManager
   path_processor_manager:
diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index be8c695..770e7f3 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -1362,54 +1362,11 @@ function watchdog_exception($type, Exception $exception, $message = NULL, $varia
  * @see hook_watchdog()
  */
 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) ? $user->id() : 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' => '',
-      'referer'     => '',
-      'ip'          => '',
-      // Request time isn't accurate for long processes, use time() instead.
-      'timestamp'   => time(),
-    );
-
-    try {
-      $request = \Drupal::request();
-      $log_entry['request_uri'] = $request->getUri();
-      $log_entry['referer'] = $request->headers->get('Referer', '');
-      $log_entry['ip'] = $request->getClientIP();
-    }
-    catch (DependencyInjectionRuntimeException $e) {
-      // We are not in a request context.
-    }
-
-    // Call the logging hooks to log/process the message
-    foreach (\Drupal::moduleHandler()->getImplementations('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;
+  $variables = $variables ?: array();
+  if ($link) {
+    $variables['link'] = $link;
   }
+  \Drupal::service('logger.factory')->getLogger($type)->log($severity, $message, $variables);
 }
 
 /**
diff --git a/core/lib/Drupal/Core/Controller/ControllerResolver.php b/core/lib/Drupal/Core/Controller/ControllerResolver.php
index 7928c36..2ce142b 100644
--- a/core/lib/Drupal/Core/Controller/ControllerResolver.php
+++ b/core/lib/Drupal/Core/Controller/ControllerResolver.php
@@ -7,9 +7,9 @@
 
 namespace Drupal\Core\Controller;
 
+use Psr\Log\LoggerInterface;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpKernel\Controller\ControllerResolver as BaseControllerResolver;
-use Symfony\Component\HttpKernel\Log\LoggerInterface;
 use Symfony\Component\DependencyInjection\ContainerAwareInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -49,7 +49,7 @@ class ControllerResolver extends BaseControllerResolver implements ControllerRes
    *
    * @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/CoreServiceProvider.php b/core/lib/Drupal/Core/CoreServiceProvider.php
index d99ae28..1d6cf42 100644
--- a/core/lib/Drupal/Core/CoreServiceProvider.php
+++ b/core/lib/Drupal/Core/CoreServiceProvider.php
@@ -13,6 +13,7 @@
 use Drupal\Core\DependencyInjection\Compiler\ModifyServiceDefinitionsPass;
 use Drupal\Core\DependencyInjection\Compiler\RegisterKernelListenersPass;
 use Drupal\Core\DependencyInjection\Compiler\RegisterAccessChecksPass;
+use Drupal\Core\DependencyInjection\Compiler\RegisterLoggersPass;
 use Drupal\Core\DependencyInjection\Compiler\RegisterPathProcessorsPass;
 use Drupal\Core\DependencyInjection\Compiler\RegisterRouteProcessorsPass;
 use Drupal\Core\DependencyInjection\Compiler\RegisterRouteFiltersPass;
@@ -69,6 +70,8 @@ public function register(ContainerBuilder $container) {
     $container->addCompilerPass(new ListCacheBinsPass());
     // Add the compiler pass for appending string translators.
     $container->addCompilerPass(new RegisterStringTranslatorsPass());
+    // Add a compiler pass for registering logging services.
+    $container->addCompilerPass(new RegisterLoggersPass());
     // Add the compiler pass that will process the tagged breadcrumb builder
     // services.
     $container->addCompilerPass(new RegisterBreadcrumbBuilderPass());
diff --git a/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterLoggersPass.php b/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterLoggersPass.php
new file mode 100644
index 0000000..3b6a82c
--- /dev/null
+++ b/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterLoggersPass.php
@@ -0,0 +1,36 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\DependencyInjection\Compiler\RegisterLoggersPass.
+ */
+
+namespace Drupal\Core\DependencyInjection\Compiler;
+
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
+use Symfony\Component\DependencyInjection\Reference;
+
+class RegisterLoggersPass implements CompilerPassInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function process(ContainerBuilder $container) {
+    $definitions = array();
+    foreach ($container->findTaggedServiceIds('logger_channel') as $id => $attributes) {
+      $definition = $container->getDefinition($id);
+      $definitions[] = $definition;
+    }
+    // Loop through all available logger services (eg dblog, syslog) and add
+    // the available logging channels
+    foreach ($container->findTaggedServiceIds('logger') as $id => $attributes) {
+      $priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0;
+      foreach ($definitions as $definition) {
+        $definition->addMethodCall('addLogger', array(new Reference($id), $priority));
+      }
+    }
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Logger/LoggerBase.php b/core/lib/Drupal/Core/Logger/LoggerBase.php
new file mode 100644
index 0000000..e099640
--- /dev/null
+++ b/core/lib/Drupal/Core/Logger/LoggerBase.php
@@ -0,0 +1,60 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Logger\LoggerBase.
+ */
+
+namespace Drupal\Core\Logger;
+
+use Psr\Log\AbstractLogger;
+
+/**
+ * Defines a base PSR3 compatible logger class.
+ */
+abstract class LoggerBase extends AbstractLogger {
+
+  /**
+   * Parses and transforms message and its placeholders to a common format.
+   *
+   * For a value to be considered as a placeholder should be in the following
+   * formats:
+   *   - PSR3 format:
+   *     @see https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md#12-message
+   *   - Drupal specific string placeholder format:
+   *     @see \Drupal\Component\Utility\String::format()
+   *
+   * Values in PSR3 format will be transformed to String::format() format.
+   *
+   * @param string $message
+   *   The message that contains the placeholders.
+   * @param array $context
+   *   An array that may or may not contain placeholder variables.
+   */
+  protected function parseMessagePlaceholders(&$message, array &$context) {
+    $variables = array();
+    $has_ps3 = FALSE;
+    if (($start = strpos($message, '{')) !== FALSE && strpos($message, '}') > $start) {
+      $has_ps3 = TRUE;
+      // Replace PSR3 style messages containing placeholders.
+      $message = preg_replace('/\{(.*)\}/U', '@$1', $message);
+    }
+    foreach ($context as $key => $variable) {
+      // PSR3 style placeholders.
+      if ($has_ps3) {
+        // Keys are not prefixed with anything according to PSR3 specs.
+        // If the message is "User {username} created" the variable key will be
+        // just "username".
+        if (strpos($message, '@' . $key) !== FALSE) {
+          $key = '@' . $key;
+        }
+      }
+      if (!empty($key) && ($key[0] === '@' || $key[0] === '%' || $key[0] === '!')) {
+        // The key is now in \Drupal\Component\Utility\String::format() style.
+        $variables[$key] = $variable;
+      }
+    }
+    $context['variables'] = $variables;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Logger/LoggerChannel.php b/core/lib/Drupal/Core/Logger/LoggerChannel.php
new file mode 100644
index 0000000..0e32da6
--- /dev/null
+++ b/core/lib/Drupal/Core/Logger/LoggerChannel.php
@@ -0,0 +1,177 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Logger\LoggerChannel.
+ */
+
+namespace Drupal\Core\Logger;
+
+use Drupal\Core\Session\AccountInterface;
+use Psr\Log\AbstractLogger;
+use Psr\Log\LoggerInterface;
+use Psr\Log\LogLevel;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Defines a logger channel that most implementations will use.
+ */
+class LoggerChannel extends AbstractLogger {
+
+  /**
+   * The name of the channel of this logger instance.
+   */
+  protected $channel;
+
+  /**
+   * 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;
+
+  /**
+   * The current user object.
+   *
+   * @var \Drupal\Core\Session\AccountInterface
+   */
+  protected $currentUser;
+
+  /**
+   * Constructs a LoggerChannel object
+   *
+   * @param string $channel
+   *   The channel name for this instance.
+   */
+  public function __construct($channel = 'system') {
+    $this->channel = $channel;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function log($level, $message, array $context = array()) {
+    // Merge in defaults.
+    $context += array(
+      'channel' => $this->channel,
+      'link' => '',
+      'user' => NULL,
+      'uid' => 0,
+      'request_uri' => '',
+      'referer' => '',
+      'ip' => '',
+      'timestamp' => time(),
+    );
+    if ($this->currentUser) {
+      $context['user'] = $this->currentUser;
+      $context['uid'] = $this->currentUser->id();
+    }
+    // Some context values are only available when in a request context.
+    if ($this->request) {
+      $context['request_uri'] = $this->request->getUri();
+      $context['referer'] = $this->request->headers->get('Referer', '');
+      $context['ip'] = $this->request->getClientIP();
+    }
+
+    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 = NULL) {
+    $this->request = $request;
+  }
+
+  /**
+   * Sets the current user.
+   *
+   * @param \Drupal\Core\Session\AccountInterface $current_user
+   *   The current user object.
+   */
+  public function setCurrentUser(AccountInterface $current_user = NULL) {
+    $this->currentUser = $current_user;
+  }
+
+  /**
+   * 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.
+   *
+   * This only exists for BC.
+   * @todo Remove once watchdog() is removed.
+   *
+   * @param string $level
+   *   A PSR-3 logging level string.
+   *
+   * @return int
+   *   The corresponding Watchdog constant.
+   */
+  protected function mapLevel($level) {
+    if (empty($this->levelTranslation)) {
+      $this->levelTranslation = array(
+        LogLevel::EMERGENCY => WATCHDOG_EMERGENCY,
+        LogLevel::ALERT => WATCHDOG_ALERT,
+        LogLevel::CRITICAL => WATCHDOG_CRITICAL,
+        LogLevel::ERROR => WATCHDOG_ERROR,
+        LogLevel::WARNING => WATCHDOG_WARNING,
+        LogLevel::NOTICE => WATCHDOG_NOTICE,
+        LogLevel::INFO => WATCHDOG_INFO,
+        LogLevel::DEBUG => WATCHDOG_DEBUG,
+      );
+    }
+
+    return $this->levelTranslation[$level];
+  }
+
+  /**
+   * Sorts loggers according to priority.
+   *
+   * @return array
+   *   An array of sorted loggers by 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/lib/Drupal/Core/Logger/LoggerChannelFactory.php b/core/lib/Drupal/Core/Logger/LoggerChannelFactory.php
new file mode 100644
index 0000000..917aad7
--- /dev/null
+++ b/core/lib/Drupal/Core/Logger/LoggerChannelFactory.php
@@ -0,0 +1,47 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Logger\LoggerChannelFactory.
+ */
+
+namespace Drupal\Core\Logger;
+
+use Symfony\Component\DependencyInjection\ContainerAware;
+use Symfony\Component\DependencyInjection\Exception\RuntimeException;
+
+/**
+ * Defines a factory for logging channels.
+ */
+class LoggerChannelFactory extends ContainerAware {
+
+  /**
+   * Retrieves the registered logger for the requested channel.
+   *
+   * If the channel does not exist, the default "system" channel is being used.
+   *
+   * @return \Psr\Log\LoggerInterface
+   *   The registered logger for this channel.
+   */
+  public function getLogger($channel) {
+    $channel_service = 'logger.channel.' . str_replace(' ', '_', $channel);
+    if ($this->container->has($channel_service)) {
+      $logger = $this->container->get($channel_service);
+    }
+    else {
+      $logger = $this->container->get('logger.channel.default');
+    }
+
+    // If the request is available, set it with the current user to the logger.
+    try {
+      $logger->setRequest($this->container->get('request'));
+      $logger->setCurrentUser($this->container->get('current_user'));
+    }
+    catch (RuntimeException $e) {
+      // We are not in a request context.
+    }
+
+    return $logger;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Routing/UrlGenerator.php b/core/lib/Drupal/Core/Routing/UrlGenerator.php
index 1bb4b53..25ab91e 100644
--- a/core/lib/Drupal/Core/Routing/UrlGenerator.php
+++ b/core/lib/Drupal/Core/Routing/UrlGenerator.php
@@ -7,8 +7,8 @@
 
 namespace Drupal\Core\Routing;
 
+use Psr\Log\LoggerInterface;
 use Symfony\Component\HttpFoundation\Request;
-use Symfony\Component\HttpKernel\Log\LoggerInterface;
 
 use Symfony\Component\Routing\Route as SymfonyRoute;
 use Symfony\Component\Routing\Exception\RouteNotFoundException;
@@ -82,7 +82,7 @@ class UrlGenerator extends ProviderBasedGenerator implements UrlGeneratorInterfa
    *   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, OutboundPathProcessorInterface $path_processor, OutboundRouteProcessorInterface $route_processor, ConfigFactory $config, Settings $settings, LoggerInterface $logger = NULL) {
diff --git a/core/modules/action/action.services.yml b/core/modules/action/action.services.yml
new file mode 100644
index 0000000..709f763
--- /dev/null
+++ b/core/modules/action/action.services.yml
@@ -0,0 +1,6 @@
+services:
+  logger.channel.action:
+    class: Drupal\Core\Logger\LoggerChannel
+    arguments: ['action']
+    tags:
+      - { name: logger_channel }
diff --git a/core/modules/aggregator/aggregator.services.yml b/core/modules/aggregator/aggregator.services.yml
index c00b2ac..2ba3fdf 100644
--- a/core/modules/aggregator/aggregator.services.yml
+++ b/core/modules/aggregator/aggregator.services.yml
@@ -16,3 +16,8 @@ services:
   aggregator.category.storage:
     class: Drupal\aggregator\CategoryStorageController
     arguments: ['@database']
+  logger.channel.aggregator:
+    class: Drupal\Core\Logger\LoggerChannel
+    arguments: ['aggregator']
+    tags:
+      - { name: logger_channel }
diff --git a/core/modules/block/custom_block/custom_block.services.yml b/core/modules/block/custom_block/custom_block.services.yml
new file mode 100644
index 0000000..faa8500
--- /dev/null
+++ b/core/modules/block/custom_block/custom_block.services.yml
@@ -0,0 +1,6 @@
+services:
+  logger.channel.custom_block:
+    class: Drupal\Core\Logger\LoggerChannel
+    arguments: ['custom block']
+    tags:
+      - { name: logger_channel }
diff --git a/core/modules/contact/contact.services.yml b/core/modules/contact/contact.services.yml
index acb2866..0776ae9 100644
--- a/core/modules/contact/contact.services.yml
+++ b/core/modules/contact/contact.services.yml
@@ -4,3 +4,8 @@ services:
     tags:
       - { name: access_check, applies_to: _access_contact_personal_tab }
     arguments: ['@config.factory', '@user.data']
+  logger.channel.contact:
+    class: Drupal\Core\Logger\LoggerChannel
+    arguments: ['contact']
+    tags:
+      - { name: logger_channel }
diff --git a/core/modules/content_translation/content_translation.services.yml b/core/modules/content_translation/content_translation.services.yml
index da2acb2..e2ff53d 100644
--- a/core/modules/content_translation/content_translation.services.yml
+++ b/core/modules/content_translation/content_translation.services.yml
@@ -24,3 +24,9 @@ services:
   content_translation.manager:
     class: Drupal\content_translation\ContentTranslationManager
     arguments: ['@entity.manager']
+
+  logger.channel.content_translation:
+    class: Drupal\Core\Logger\LoggerChannel
+    arguments: ['content translation']
+    tags:
+      - { name: logger_channel }
diff --git a/core/modules/dblog/dblog.module b/core/modules/dblog/dblog.module
index 4060d63..3aab1cc 100644
--- a/core/modules/dblog/dblog.module
+++ b/core/modules/dblog/dblog.module
@@ -163,31 +163,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..c07cb32
--- /dev/null
+++ b/core/modules/dblog/dblog.services.yml
@@ -0,0 +1,6 @@
+services:
+  logger.dblog:
+    class: Drupal\dblog\Logger\DbLog
+    arguments: ['@database']
+    tags:
+      - { name: logger }
diff --git a/core/modules/dblog/lib/Drupal/dblog/Logger/DbLog.php b/core/modules/dblog/lib/Drupal/dblog/Logger/DbLog.php
new file mode 100644
index 0000000..36b553e
--- /dev/null
+++ b/core/modules/dblog/lib/Drupal/dblog/Logger/DbLog.php
@@ -0,0 +1,63 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\dblog\Logger\DbLog.
+ */
+
+namespace Drupal\dblog\Logger;
+
+use Drupal\Core\Database\Connection;
+use Drupal\Core\Logger\LoggerBase;
+
+/**
+ * Logs events in the watchdog database table.
+ */
+class DbLog extends LoggerBase {
+
+  /**
+   * The database connection object.
+   *
+   * @var \Drupal\Core\Database\Connection
+   */
+  protected $database;
+
+  /**
+   * Constructs a DbLog 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['backtrace']);
+
+    // Convert PSR3-style messages to format_string() style, so they can be
+    // translated too in runtime.
+    $this->parseMessagePlaceholders($message, $context);
+
+    $this->database
+      ->insert('watchdog')
+      ->fields(array(
+        'uid' => $context['uid'],
+        'type' => substr($context['channel'], 0, 64),
+        'message' => $message,
+        'variables' => serialize($context['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 24add00..dd4a575 100644
--- a/core/modules/dblog/lib/Drupal/dblog/Tests/DbLogTest.php
+++ b/core/modules/dblog/lib/Drupal/dblog/Tests/DbLogTest.php
@@ -129,7 +129,7 @@ private function generateLogEntries($count, $type = 'custom', $severity = WATCHD
 
     // Prepare the fields to be logged
     $log = array(
-      'type'        => $type,
+      'channel'     => $type,
       'message'     => 'Log entry added to test the dblog row limit.',
       'variables'   => array(),
       'severity'    => $severity,
@@ -144,7 +144,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('logger.dblog')->log($severity, $log['message'], $log);
     }
   }
 
@@ -412,7 +412,7 @@ protected function testDBLogAddAndClear() {
     // Get a count of how many watchdog entries already exist.
     $count = db_query('SELECT COUNT(*) FROM {watchdog}')->fetchField();
     $log = array(
-      'type'        => 'custom',
+      'channel'     => 'system',
       'message'     => 'Log entry added to test the doClearTest clear down.',
       'variables'   => array(),
       'severity'    => WATCHDOG_NOTICE,
@@ -425,7 +425,7 @@ protected function testDBLogAddAndClear() {
       'timestamp'   => REQUEST_TIME,
     );
     // Add a watchdog entry.
-    dblog_watchdog($log);
+    $this->container->get('logger.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.
@@ -530,7 +530,7 @@ protected function getLogEntries() {
       foreach ($table->tbody->tr as $row) {
         $entries[] = array(
           'severity' => $this->getSeverityConstant($row['class']),
-          'type' => $this->asText($row->td[1]),
+          'channel' => $this->asText($row->td[1]),
           'message' => $this->asText($row->td[3]),
           'user' => $this->asText($row->td[4]),
         );
@@ -553,7 +553,7 @@ protected function getTypeCount(array $types) {
     $count = array_fill(0, count($types), 0);
     foreach ($entries as $entry) {
       foreach ($types as $key => $type) {
-        if ($entry['type'] == $type['type'] && $entry['severity'] == $type['severity']) {
+        if ($entry['channel'] == $type['type'] && $entry['severity'] == $type['severity']) {
           $count[$key]++;
           break;
         }
diff --git a/core/modules/filter/filter.services.yml b/core/modules/filter/filter.services.yml
index c355c0c..7d3d157 100644
--- a/core/modules/filter/filter.services.yml
+++ b/core/modules/filter/filter.services.yml
@@ -13,3 +13,8 @@ services:
   plugin.manager.filter:
     class: Drupal\filter\FilterPluginManager
     parent: default_plugin_manager
+  logger.channel.filter:
+    class: Drupal\Core\Logger\LoggerChannel
+    arguments: ['filter']
+    tags:
+      - { name: logger_channel }
diff --git a/core/modules/filter/lib/Drupal/filter/Tests/FilterSettingsTest.php b/core/modules/filter/lib/Drupal/filter/Tests/FilterSettingsTest.php
index a11db5d..f37d48b 100644
--- a/core/modules/filter/lib/Drupal/filter/Tests/FilterSettingsTest.php
+++ b/core/modules/filter/lib/Drupal/filter/Tests/FilterSettingsTest.php
@@ -34,13 +34,11 @@ public static function getInfo() {
    */
   function testFilterDefaults() {
     $filter_info = $this->container->get('plugin.manager.filter')->getDefinitions();
-    $filters = array_fill_keys(array_keys($filter_info), array());
 
     // Create text format using filter default settings.
     $filter_defaults_format = entity_create('filter_format', array(
       'format' => 'filter_defaults',
       'name' => 'Filter defaults',
-      'filters' => $filters,
     ));
     $filter_defaults_format->save();
 
diff --git a/core/modules/forum/forum.services.yml b/core/modules/forum/forum.services.yml
index f27ffc0..1b8f516 100644
--- a/core/modules/forum/forum.services.yml
+++ b/core/modules/forum/forum.services.yml
@@ -7,3 +7,8 @@ services:
     arguments: ['@entity.manager', '@config.factory', '@forum_manager']
     tags:
       - { name: breadcrumb_builder, priority: 1001 }
+  logger.channel.forum:
+    class: Drupal\Core\Logger\LoggerChannel
+    arguments: ['forum']
+    tags:
+      - { name: logger_channel }
diff --git a/core/modules/language/language.services.yml b/core/modules/language/language.services.yml
index 422644a..fb68808 100644
--- a/core/modules/language/language.services.yml
+++ b/core/modules/language/language.services.yml
@@ -11,3 +11,8 @@ services:
     class: Drupal\language\EventSubscriber\ConfigSubscriber
     tags:
       - { name: event_subscriber }
+  logger.channel.language:
+    class: Drupal\Core\Logger\LoggerChannel
+    arguments: ['language']
+    tags:
+      - { name: logger_channel }
diff --git a/core/modules/locale/locale.services.yml b/core/modules/locale/locale.services.yml
index b5f4cf4..cb074bf 100644
--- a/core/modules/locale/locale.services.yml
+++ b/core/modules/locale/locale.services.yml
@@ -16,3 +16,8 @@ services:
     tags:
       - { name: string_translator }
       - { name: needs_destruction }
+  logger.channel.locale:
+    class: Drupal\Core\Logger\LoggerChannel
+    arguments: ['locale']
+    tags:
+      - { name: logger_channel }
diff --git a/core/modules/menu/menu.services.yml b/core/modules/menu/menu.services.yml
new file mode 100644
index 0000000..32a2a76
--- /dev/null
+++ b/core/modules/menu/menu.services.yml
@@ -0,0 +1,6 @@
+services:
+  logger.channel.menu:
+    class: Drupal\Core\Logger\LoggerChannel
+    arguments: ['menu']
+    tags:
+      - { name: logger_channel }
diff --git a/core/modules/node/node.services.yml b/core/modules/node/node.services.yml
index 7329685..07f2076 100644
--- a/core/modules/node/node.services.yml
+++ b/core/modules/node/node.services.yml
@@ -12,3 +12,13 @@ services:
     arguments: ['@entity.manager']
     tags:
       - { name: access_check, applies_to: _node_add_access }
+  logger.channel.content:
+    class: Drupal\Core\Logger\LoggerChannel
+    arguments: ['content']
+    tags:
+      - { name: logger_channel }
+  logger.channel.node:
+    class: Drupal\Core\Logger\LoggerChannel
+    arguments: ['node']
+    tags:
+      - { name: logger_channel }
diff --git a/core/modules/rest/lib/Drupal/rest/Tests/DBLogTest.php b/core/modules/rest/lib/Drupal/rest/Tests/DBLogTest.php
index f3e0eda..62852fb 100644
--- a/core/modules/rest/lib/Drupal/rest/Tests/DBLogTest.php
+++ b/core/modules/rest/lib/Drupal/rest/Tests/DBLogTest.php
@@ -40,9 +40,9 @@ public function setUp() {
    */
   public function testWatchdog() {
     // Write a log message to the DB.
-    watchdog('rest_test', 'Test message');
+    watchdog('rest', 'Test message');
     // Get the ID of the written message.
-    $id = db_query_range("SELECT wid FROM {watchdog} WHERE type = :type ORDER BY wid DESC", 0, 1, array(':type' => 'rest_test'))
+    $id = db_query_range("SELECT wid FROM {watchdog} WHERE type = :type ORDER BY wid DESC", 0, 1, array(':type' => 'rest'))
       ->fetchField();
 
     // Create a user account that has the required permissions to read
@@ -55,7 +55,7 @@ public function testWatchdog() {
     $this->assertHeader('content-type', $this->defaultMimeType);
     $log = drupal_json_decode($response);
     $this->assertEqual($log['wid'], $id, 'Log ID is correct.');
-    $this->assertEqual($log['type'], 'rest_test', 'Type of log message is correct.');
+    $this->assertEqual($log['type'], 'rest', 'Type of log message is correct.');
     $this->assertEqual($log['message'], 'Test message', 'Log message text is correct.');
 
     // Request an unknown log entry.
diff --git a/core/modules/rest/rest.services.yml b/core/modules/rest/rest.services.yml
index 7c63426..c829bf7 100644
--- a/core/modules/rest/rest.services.yml
+++ b/core/modules/rest/rest.services.yml
@@ -22,3 +22,8 @@ services:
   rest.link_manager.relation:
     class: Drupal\rest\LinkManager\RelationLinkManager
     arguments: ['@cache.cache']
+  logger.channel.rest:
+    class: Drupal\Core\Logger\LoggerChannel
+    arguments: ['rest']
+    tags:
+      - { name: logger_channel }
diff --git a/core/modules/search/search.services.yml b/core/modules/search/search.services.yml
index a92d161..4b5e59e 100644
--- a/core/modules/search/search.services.yml
+++ b/core/modules/search/search.services.yml
@@ -6,3 +6,8 @@ services:
   search.search_page_repository:
     class: Drupal\search\SearchPageRepository
     arguments: ['@config.factory', '@entity.manager']
+  logger.channel.search:
+    class: Drupal\Core\Logger\LoggerChannel
+    arguments: ['search']
+    tags:
+      - { name: logger_channel }
diff --git a/core/modules/syslog/lib/Drupal/syslog/Logger/SysLog.php b/core/modules/syslog/lib/Drupal/syslog/Logger/SysLog.php
new file mode 100644
index 0000000..2c19f0a
--- /dev/null
+++ b/core/modules/syslog/lib/Drupal/syslog/Logger/SysLog.php
@@ -0,0 +1,64 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\syslog\Logger\SysLog.
+ */
+
+namespace Drupal\syslog\Logger;
+
+use Drupal\Core\Config\ConfigFactory;
+use Drupal\Core\Logger\LoggerBase;
+
+/**
+ * Redirects logging messages to syslog.
+ */
+class SysLog extends LoggerBase {
+
+  /**
+   * A configuration object containin syslog settings.
+   *
+   * @var \Drupal\Core\Config\Config
+   */
+  protected $config;
+
+  /**
+   * Constructs a SysLog 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;
+
+    // Populate the $context['variables'] with the message placeholders.
+    $this->parseMessagePlaceholders($message, $context);
+
+    $entry = strtr($this->config->get('format'), array(
+      '!base_url' => $base_url,
+      '!timestamp' => $context['timestamp'],
+      '!type' => $context['channel'],
+      '!ip' => $context['ip'],
+      '!request_uri' => $context['request_uri'],
+      '!referer' => $context['referer'],
+      '!uid' => $context['uid'],
+      '!link' => strip_tags($context['link']),
+      '!message' => strip_tags(empty($context['variables']) ? $message : strtr($message, $context['variables'])),
+    ));
+
+    syslog($level, $entry);
+  }
+
+}
diff --git a/core/modules/syslog/syslog.module b/core/modules/syslog/syslog.module
index 287cfaf..24e7299 100644
--- a/core/modules/syslog/syslog.module
+++ b/core/modules/syslog/syslog.module
@@ -87,36 +87,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 = \Drupal::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..98f6041
--- /dev/null
+++ b/core/modules/syslog/syslog.services.yml
@@ -0,0 +1,6 @@
+services:
+  logger.syslog:
+    class: Drupal\syslog\Logger\SysLog
+    arguments: ['@config.factory']
+    tags:
+      - { name: 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 4d36338..62776ca 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityApiInfoTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityApiInfoTest.php
@@ -48,9 +48,9 @@ function testEntityInfoChanges() {
   /**
    * Tests entity info cache after enabling a module with a dependency on an entity providing module.
    *
-   * @see entity_cache_test_watchdog()
+   * @see entity_cache_test_modules_enabled()
    */
-  function testEntityInfoCacheWatchdog() {
+  function testEntityInfoCacheModulesEnabled() {
     \Drupal::moduleHandler()->install(array('entity_cache_test'));
     $info = \Drupal::state()->get('entity_cache_test');
     $this->assertEqual($info->getLabel(), 'Entity Cache Test', 'Entity info label is correct.');
diff --git a/core/modules/system/system.api.php b/core/modules/system/system.api.php
index 6c83611..bbfa9eb 100644
--- a/core/modules/system/system.api.php
+++ b/core/modules/system/system.api.php
@@ -1491,94 +1491,6 @@ function hook_template_preprocess_default_variables_alter(&$variables) {
 }
 
 /**
- * Log an event message.
- *
- * This hook allows modules to route log events to custom destinations, such as
- * SMS, Email, pager, syslog, ...etc.
- *
- * @param array $log_entry
- *   An associative array containing the following keys:
- *   - type: The type of message for this entry.
- *   - user: The user object for the user who was logged in when the event
- *     happened.
- *   - uid: The user ID for the user who was logged in when the event happened.
- *   - request_uri: The request URI for the page the event happened in.
- *   - referer: The page that referred the user to the page where the event
- *     occurred.
- *   - ip: The IP address where the request for the page came from.
- *   - timestamp: The UNIX timestamp of the date/time the event occurred.
- *   - severity: The severity of the message; one of the following values as
- *     defined in @link http://www.faqs.org/rfcs/rfc3164.html RFC 3164: @endlink
- *     - WATCHDOG_EMERGENCY: Emergency, system is unusable.
- *     - WATCHDOG_ALERT: Alert, action must be taken immediately.
- *     - WATCHDOG_CRITICAL: Critical conditions.
- *     - WATCHDOG_ERROR: Error conditions.
- *     - WATCHDOG_WARNING: Warning conditions.
- *     - WATCHDOG_NOTICE: Normal but significant conditions.
- *     - WATCHDOG_INFO: Informational messages.
- *     - WATCHDOG_DEBUG: Debug-level messages.
- *   - link: An optional link provided by the module that called the watchdog()
- *     function.
- *   - message: The text of the message to be logged. Variables in the message
- *     are indicated by using placeholder strings alongside the variables
- *     argument to declare the value of the placeholders. See t() for
- *     documentation on how the message and variable parameters interact.
- *   - variables: An array of variables to be inserted into the message on
- *     display. Will be NULL or missing if a message is already translated or if
- *     the message is not possible to translate.
- */
-function hook_watchdog(array $log_entry) {
-  global $base_url;
-  $language_interface = language(\Drupal\Core\Language\Language::TYPE_INTERFACE);
-
-  $severity_list = array(
-    WATCHDOG_EMERGENCY     => t('Emergency'),
-    WATCHDOG_ALERT     => t('Alert'),
-    WATCHDOG_CRITICAL     => t('Critical'),
-    WATCHDOG_ERROR       => t('Error'),
-    WATCHDOG_WARNING   => t('Warning'),
-    WATCHDOG_NOTICE    => t('Notice'),
-    WATCHDOG_INFO      => t('Info'),
-    WATCHDOG_DEBUG     => t('Debug'),
-  );
-
-  $to = 'someone@example.com';
-  $params = array();
-  $params['subject'] = t('[@site_name] @severity_desc: Alert from your web site', array(
-    '@site_name' => \Drupal::config('system.site')->get('name'),
-    '@severity_desc' => $severity_list[$log_entry['severity']],
-  ));
-
-  $params['message']  = "\nSite:         @base_url";
-  $params['message'] .= "\nSeverity:     (@severity) @severity_desc";
-  $params['message'] .= "\nTimestamp:    @timestamp";
-  $params['message'] .= "\nType:         @type";
-  $params['message'] .= "\nIP Address:   @ip";
-  $params['message'] .= "\nRequest URI:  @request_uri";
-  $params['message'] .= "\nReferrer URI: @referer_uri";
-  $params['message'] .= "\nUser:         (@uid) @name";
-  $params['message'] .= "\nLink:         @link";
-  $params['message'] .= "\nMessage:      \n\n@message";
-
-  $params['message'] = t($params['message'], array(
-    '@base_url'      => $base_url,
-    '@severity'      => $log_entry['severity'],
-    '@severity_desc' => $severity_list[$log_entry['severity']],
-    '@timestamp'     => format_date($log_entry['timestamp']),
-    '@type'          => $log_entry['type'],
-    '@ip'            => $log_entry['ip'],
-    '@request_uri'   => $log_entry['request_uri'],
-    '@referer_uri'   => $log_entry['referer'],
-    '@uid'           => $log_entry['uid'],
-    '@name'          => $log_entry['user']->name,
-    '@link'          => strip_tags($log_entry['link']),
-    '@message'       => strip_tags($log_entry['message']),
-  ));
-
-  drupal_mail('emaillog', 'entry', $to, $language_interface->id, $params);
-}
-
-/**
  * Prepare a message based on parameters; called from drupal_mail().
  *
  * Note that hook_mail(), unlike hook_mail_alter(), is only called on the
diff --git a/core/modules/system/system.services.yml b/core/modules/system/system.services.yml
index 179bb27..fe5bafb 100644
--- a/core/modules/system/system.services.yml
+++ b/core/modules/system/system.services.yml
@@ -24,3 +24,68 @@ services:
     class: Drupal\system\SystemConfigSubscriber
     tags:
       - { name: event_subscriber }
+  logger.channel.access_denied:
+    class: Drupal\Core\Logger\LoggerChannel
+    arguments: ['access denied']
+    tags:
+      - { name: logger_channel }
+  logger.channel.ajax:
+    class: Drupal\Core\Logger\LoggerChannel
+    arguments: ['ajax']
+    tags:
+      - { name: logger_channel }
+  logger.channel.cron:
+    class: Drupal\Core\Logger\LoggerChannel
+    arguments: ['cron']
+    tags:
+      - { name: logger_channel }
+  logger.channel.debug:
+    class: Drupal\Core\Logger\LoggerChannel
+    arguments: ['debug']
+    tags:
+      - { name: logger_channel }
+  logger.channel.file:
+    class: Drupal\Core\Logger\LoggerChannel
+    arguments: ['file']
+    tags:
+      - { name: logger_channel }
+  logger.channel.file_system:
+    class: Drupal\Core\Logger\LoggerChannel
+    arguments: ['file system']
+    tags:
+      - { name: logger_channel }
+  logger.channel.form:
+    class: Drupal\Core\Logger\LoggerChannel
+    arguments: ['form']
+    tags:
+      - { name: logger_channel }
+  logger.channel.image:
+    class: Drupal\Core\Logger\LoggerChannel
+    arguments: ['image']
+    tags:
+      - { name: logger_channel }
+  logger.channel.mail:
+    class: Drupal\Core\Logger\LoggerChannel
+    arguments: ['mail']
+    tags:
+      - { name: logger_channel }
+  logger.channel.theme:
+    class: Drupal\Core\Logger\LoggerChannel
+    arguments: ['theme']
+    tags:
+      - { name: logger_channel }
+  logger.channel.page_not_found:
+    class: Drupal\Core\Logger\LoggerChannel
+    arguments: ['page not found']
+    tags:
+      - { name: logger_channel }
+  logger.channel.php:
+    class: Drupal\Core\Logger\LoggerChannel
+    arguments: ['php']
+    tags:
+      - { name: logger_channel }
+  logger.channel.security:
+    class: Drupal\Core\Logger\LoggerChannel
+    arguments: ['security']
+    tags:
+      - { name: logger_channel }
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 9b28815..9a0676d 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_installed().
  *
  * This hook is called during \Drupal\Core\Extension\ModuleHandler::install()
  * and since this hook implementation is invoked, we have to expect that this
@@ -14,13 +14,11 @@
  * expect to be able to 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 = \Drupal::entityManager()->getDefinition('entity_cache_test');
-    // Store the information in a system variable to analyze it later in the
-    // test case.
-    \Drupal::state()->set('entity_cache_test', $info);
-  }
+function entity_cache_test_modules_installed($modules_enabled) {
+  $info = entity_get_info('entity_cache_test');
+  // Store the information in a system variable to analyze it later in the
+  // test case.
+  \Drupal::state()->set('entity_cache_test', $info);
 }
diff --git a/core/modules/taxonomy/taxonomy.services.yml b/core/modules/taxonomy/taxonomy.services.yml
index 686f6ea..e4be14e 100644
--- a/core/modules/taxonomy/taxonomy.services.yml
+++ b/core/modules/taxonomy/taxonomy.services.yml
@@ -3,3 +3,8 @@ services:
     class: Drupal\taxonomy\TermBreadcrumbBuilder
     tags:
       - { name: breadcrumb_builder, priority: 1002 }
+  logger.channel.taxonomy:
+    class: Drupal\Core\Logger\LoggerChannel
+    arguments: ['taxonomy']
+    tags:
+      - { name: logger_channel }
diff --git a/core/modules/tracker/tracker.services.yml b/core/modules/tracker/tracker.services.yml
index 11e29e7..1279cd6 100644
--- a/core/modules/tracker/tracker.services.yml
+++ b/core/modules/tracker/tracker.services.yml
@@ -3,3 +3,8 @@ services:
     class: Drupal\tracker\Access\ViewOwnTrackerAccessCheck
     tags:
       - { name: access_check, applies_to: _access_tracker_own_information }
+  logger.channel.tracker:
+    class: Drupal\Core\Logger\LoggerChannel
+    arguments: ['tracker']
+    tags:
+      - { name: logger_channel }
diff --git a/core/modules/user/user.services.yml b/core/modules/user/user.services.yml
index 23d8706..a91c700 100644
--- a/core/modules/user/user.services.yml
+++ b/core/modules/user/user.services.yml
@@ -33,3 +33,8 @@ services:
   user.permissions_hash:
     class: Drupal\user\PermissionsHash
     arguments: ['@private_key', '@cache.cache']
+  logger.channel.user:
+    class: Drupal\Core\Logger\LoggerChannel
+    arguments: ['user']
+    tags:
+      - { name: logger_channel }
diff --git a/core/modules/views/views.services.yml b/core/modules/views/views.services.yml
index 30aa96a..b8c9d48 100644
--- a/core/modules/views/views.services.yml
+++ b/core/modules/views/views.services.yml
@@ -93,3 +93,8 @@ services:
       - { name: 'access_check' }
   views.exposed_form_cache:
     class: Drupal\views\ExposedFormCache
+  logger.channel.views:
+    class: Drupal\Core\Logger\LoggerChannel
+    arguments: ['views']
+    tags:
+      - { name: logger_channel }
diff --git a/core/tests/Drupal/Tests/Core/Logger/LoggerBaseTest.php b/core/tests/Drupal/Tests/Core/Logger/LoggerBaseTest.php
new file mode 100644
index 0000000..0f93256
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/Logger/LoggerBaseTest.php
@@ -0,0 +1,91 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Core\Logger\LoggerBaseTest
+ */
+
+namespace Drupal\Tests\Core\Logger;
+
+use Drupal\Core\Logger\LoggerBase;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * Tests the base logger object.
+ *
+ * @group Logger
+ */
+class LoggerBaseTest extends UnitTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Logger base',
+      'description' => 'Unit tests for the logger base.',
+      'group' => 'Logger',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    $this->logger = $this->getMockForAbstractClass('Drupal\Core\Logger\LoggerBase');
+  }
+
+  /**
+   * Test for LoggerBase::parseMessagePlaceholders()
+   *
+   * @param array $value
+   *   An array containing:
+   *    - message: A string that contains a message with placeholders.
+   *    - context: An array with placeholder values.
+   * @param array $expected
+   *   An array with the expected values after the test has run.
+   *    - message: The expected parsed message.
+   *    - context: The expected values of the placeholders.
+   *
+   * @dataProvider providerTestParseMessagePlaceholders
+   */
+  public function testParseMessagePlaceholders(array $value, array $expected) {
+    $class = new \ReflectionClass('Drupal\Core\Logger\LoggerBase');
+    $method = $class->getMethod('parseMessagePlaceholders');
+    $method->setAccessible(TRUE);
+    $method->invokeArgs($this->logger, array(&$value['message'], &$value['context']));
+    $this->assertEquals($expected['message'], $value['message']);
+    $this->assertEquals($expected['context'], $value['context']['variables']);
+  }
+
+  /**
+   * Data provider for testParseMessagePlaceholders().
+   */
+  public function providerTestParseMessagePlaceholders() {
+    return array(
+      // PSR3 only message.
+      array(
+        array('message' => 'User {username} created', 'context' => array('username' => 'Dries')),
+        array('message' => 'User @username created', 'context' => array('@username' => 'Dries')),
+      ),
+      // PSR3 style mixed in a format_string style message.
+      array(
+        array('message' => 'User {username} created @time', 'context' => array('username' => 'Dries', '@time' => 'now')),
+        array('message' => 'User @username created @time', 'context' => array('@username' => 'Dries', '@time' => 'now')),
+      ),
+      // format_string style message only.
+      array(
+        array('message' => 'User @username created', 'context' => array('@username' => 'Dries')),
+        array('message' => 'User @username created', 'context' => array('@username' => 'Dries')),
+      ),
+      // Messsage without placeholders but wildcard characters.
+      array(
+        array('message' => 'User W-\\};~{&! created @', 'context' => array('' => '')),
+        array('message' => 'User W-\\};~{&! created @', 'context' => array()),
+      ),
+      // Messsage with double PSR3 style messages.
+      array(
+        array('message' => 'Test {with} two {encapsuled} strings', 'context' => array('with' => 'together', 'encapsuled' => 'awesome')),
+        array('message' => 'Test @with two @encapsuled strings', 'context' => array('@with' => 'together', '@encapsuled' => 'awesome')),
+      ),
+    );
+  }
+
+}
