diff --git a/modules/search_api_db/src/Plugin/search_api/backend/Database.php b/modules/search_api_db/src/Plugin/search_api/backend/Database.php
index b5ee3511..abe099e8 100644
--- a/modules/search_api_db/src/Plugin/search_api/backend/Database.php
+++ b/modules/search_api_db/src/Plugin/search_api/backend/Database.php
@@ -32,7 +32,6 @@
 use Drupal\search_api_autocomplete\Suggestion;
 use Drupal\search_api_db\DatabaseCompatibility\DatabaseCompatibilityHandlerInterface;
 use Drupal\search_api_db\DatabaseCompatibility\GenericDatabase;
-use Psr\Log\LoggerInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -119,13 +118,6 @@ class Database extends BackendPluginBase implements PluginFormInterface {
   protected $dataTypePluginManager;
 
   /**
-   * The logger to use for logging messages.
-   *
-   * @var \Psr\Log\LoggerInterface|null
-   */
-  protected $logger;
-
-  /**
    * The key-value store to use.
    *
    * @var \Drupal\Core\KeyValueStore\KeyValueStoreInterface
@@ -187,37 +179,20 @@ public static function create(ContainerInterface $container, array $configuratio
     /** @var static $backend */
     $backend = parent::create($container, $configuration, $plugin_id, $plugin_definition);
 
-    /** @var \Drupal\Core\Extension\ModuleHandlerInterface $module_handler */
-    $module_handler = $container->get('module_handler');
-    $backend->setModuleHandler($module_handler);
-
-    /** @var \Drupal\Core\Config\ConfigFactoryInterface $config_factory */
-    $config_factory = $container->get('config.factory');
-    $backend->setConfigFactory($config_factory);
-
-    /** @var \Drupal\search_api\DataType\DataTypePluginManager $data_type_plugin_manager */
-    $data_type_plugin_manager = $container->get('plugin.manager.search_api.data_type');
-    $backend->setDataTypePluginManager($data_type_plugin_manager);
-
-    /** @var \Psr\Log\LoggerInterface $logger */
-    $logger = $container->get('logger.channel.search_api_db');
-    $backend->setLogger($logger);
-
-    /** @var \Drupal\Core\KeyValueStore\KeyValueFactoryInterface $keyvalue_factory */
-    $keyvalue_factory = $container->get('keyvalue');
-    $backend->setKeyValueStore($keyvalue_factory->get(self::INDEXES_KEY_VALUE_STORE_ID));
+    $backend->setModuleHandler($container->get('module_handler'));
+    $backend->setConfigFactory($container->get('config.factory'));
+    $backend->setDataTypePluginManager($container->get('plugin.manager.search_api.data_type'));
+    $backend->setLogger($container->get('logger.channel.search_api_db'));
+    $backend->setKeyValueStore($container->get('keyvalue')->get(self::INDEXES_KEY_VALUE_STORE_ID));
 
     // For a new backend plugin, the database might not be set yet. In that case
     // we of course also don't need a DBMS compatibility handler.
     if ($backend->getDatabase()) {
-      /** @var \Drupal\search_api_db\DatabaseCompatibility\DatabaseCompatibilityHandlerInterface $dbms_compatibility_handler */
       $dbms_compatibility_handler = $container->get('search_api_db.database_compatibility');
       // Make sure that we actually provide a handler for the right database,
       // otherwise fall back to the generic handler.
       if ($dbms_compatibility_handler->getDatabase() != $backend->getDatabase()) {
-        /** @var \Drupal\Component\Transliteration\TransliterationInterface $transliterator */
-        $transliterator = $container->get('transliteration');
-        $dbms_compatibility_handler = new GenericDatabase($backend->getDatabase(), $transliterator);
+        $dbms_compatibility_handler = new GenericDatabase($backend->getDatabase(), $container->get('transliteration'));
       }
       $backend->setDbmsCompatibilityHandler($dbms_compatibility_handler);
     }
@@ -305,29 +280,6 @@ public function setDataTypePluginManager(DataTypePluginManager $data_type_plugin
   }
 
   /**
-   * Retrieves the logger to use.
-   *
-   * @return \Psr\Log\LoggerInterface
-   *   The logger to use.
-   */
-  public function getLogger() {
-    return $this->logger ?: \Drupal::service('logger.channel.search_api_db');
-  }
-
-  /**
-   * Sets the logger to use.
-   *
-   * @param \Psr\Log\LoggerInterface $logger
-   *   The logger to use.
-   *
-   * @return $this
-   */
-  public function setLogger(LoggerInterface $logger) {
-    $this->logger = $logger;
-    return $this;
-  }
-
-  /**
    * Retrieves the key-value store to use.
    *
    * @return \Drupal\Core\KeyValueStore\KeyValueStoreInterface
@@ -802,7 +754,7 @@ protected function createFieldTable(FieldInterface $field = NULL, $db, $type = '
     catch (\PDOException $e) {
       $variables['%column'] = $column;
       $variables['%table'] = $db['table'];
-      watchdog_exception('search_api_db', $e, '%type while trying to add a database index for column %column to table %table: @message in %function (line %line of %file).', $variables, RfcLogLevel::WARNING);
+      $this->logException($e, '%type while trying to add a database index for column %column to table %table: @message in %function (line %line of %file).', $variables, RfcLogLevel::WARNING);
     }
 
     if ($new_table) {
@@ -2447,7 +2399,7 @@ protected function getTemporaryResultsTable(SelectInterface $db_query) {
       $result = $this->database->queryTemporary((string) $db_query, $args);
     }
     catch (\PDOException $e) {
-      watchdog_exception('search_api', $e, '%type while trying to create a temporary table: @message in %function (line %line of %file).');
+      $this->logException($e, '%type while trying to create a temporary table: @message in %function (line %line of %file).');
       return FALSE;
     }
     return $result;
diff --git a/src/Backend/BackendPluginBase.php b/src/Backend/BackendPluginBase.php
index 8674d8ac..48211244 100644
--- a/src/Backend/BackendPluginBase.php
+++ b/src/Backend/BackendPluginBase.php
@@ -4,6 +4,7 @@
 
 use Drupal\search_api\Entity\Server;
 use Drupal\search_api\Item\ItemInterface;
+use Drupal\search_api\LoggerTrait;
 use Drupal\search_api\Query\QueryInterface;
 use Drupal\search_api\SearchApiException;
 use Drupal\search_api\IndexInterface;
@@ -40,6 +41,8 @@
  */
 abstract class BackendPluginBase extends ConfigurablePluginBase implements BackendInterface {
 
+  use LoggerTrait;
+
   /**
    * The server this backend is configured for.
    *
@@ -137,7 +140,7 @@ public function preDelete() {
       $vars = array(
         '%server' => $this->getServer()->label(),
       );
-      watchdog_exception('search_api', $e, '%type while deleting items from server %server: @message in %function (line %line of %file).', $vars);
+      $this->logException($e, '%type while deleting items from server %server: @message in %function (line %line of %file).', $vars);
       drupal_set_message($this->t('Deleting some of the items on the server failed. Check the logs for details. The server was still removed.'), 'error');
     }
   }
diff --git a/src/Entity/Index.php b/src/Entity/Index.php
index af8fd620..744bcf95 100644
--- a/src/Entity/Index.php
+++ b/src/Entity/Index.php
@@ -11,6 +11,7 @@
 use Drupal\search_api\Datasource\DatasourceInterface;
 use Drupal\search_api\IndexInterface;
 use Drupal\search_api\Item\FieldInterface;
+use Drupal\search_api\LoggerTrait;
 use Drupal\search_api\Processor\ProcessorInterface;
 use Drupal\search_api\Query\QueryInterface;
 use Drupal\search_api\Query\ResultSetInterface;
@@ -87,6 +88,8 @@
  */
 class Index extends ConfigEntityBase implements IndexInterface {
 
+  use LoggerTrait;
+
   /**
    * The ID of the index.
    *
@@ -866,7 +869,7 @@ public function loadItemsMultiple(array $item_ids) {
         }
       }
       catch (SearchApiException $e) {
-        watchdog_exception('search_api', $e);
+        $this->logException($e);
         // If the complete datasource could not be loaded, don't report all its
         // individual requested items as missing.
         unset($items_by_datasource[$datasource_id]);
@@ -881,8 +884,7 @@ public function loadItemsMultiple(array $item_ids) {
       $missing_ids = array_reduce(array_map('array_values', $items_by_datasource), 'array_merge', array());
       $args['%index'] = $this->label();
       $args['@items'] = '"' . implode('", "', $missing_ids) . '"';
-      \Drupal::service('logger.channel.search_api')
-        ->warning('Could not load the following items on index %index: @items.', $args);
+      $this->getLogger()->warning('Could not load the following items on index %index: @items.', $args);
       // Also remove those items from tracking so we don't keep trying to load
       // them.
       foreach ($items_by_datasource as $datasource_id => $raw_ids) {
@@ -908,7 +910,7 @@ public function indexItems($limit = '-1', $datasource_id = NULL) {
         }
         catch (SearchApiException $e) {
           $variables['%index'] = $this->label();
-          watchdog_exception('search_api', $e, '%type while trying to index items on index %index: @message in %function (line %line of %file)', $variables);
+          $this->logException($e, '%type while trying to index items on index %index: @message in %function (line %line of %file)', $variables);
         }
       }
     }
@@ -1051,7 +1053,7 @@ protected function trackItemsInsertedOrUpdated($datasource_id, array $ids, $trac
           }
         }
         catch (SearchApiException $e) {
-          watchdog_exception('search_api', $e);
+          $this->logException($e);
         }
       }
     }
@@ -1301,7 +1303,7 @@ public function postSave(EntityStorageInterface $storage, $update = TRUE) {
       Cache::invalidateTags($this->getCacheTags());
     }
     catch (SearchApiException $e) {
-      watchdog_exception('search_api', $e);
+      $this->logException($e);
     }
 
     // Reset the field instances so saved renames won't be reported anymore.
diff --git a/src/Entity/Server.php b/src/Entity/Server.php
index 723f5e19..a147415e 100644
--- a/src/Entity/Server.php
+++ b/src/Entity/Server.php
@@ -5,6 +5,7 @@
 use Drupal\Core\Config\Entity\ConfigEntityBase;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\search_api\IndexInterface;
+use Drupal\search_api\LoggerTrait;
 use Drupal\search_api\Query\QueryInterface;
 use Drupal\search_api\SearchApiException;
 use Drupal\search_api\ServerInterface;
@@ -58,6 +59,8 @@
  */
 class Server extends ConfigEntityBase implements ServerInterface {
 
+  use LoggerTrait;
+
   /**
    * The ID of the server.
    *
@@ -258,7 +261,7 @@ public function addIndex(IndexInterface $index) {
         '%server' => $this->label(),
         '%index' => $index->label(),
       );
-      watchdog_exception('search_api', $e, '%type while adding index %index to server %server: @message in %function (line %line of %file).', $vars);
+      $this->logException($e, '%type while adding index %index to server %server: @message in %function (line %line of %file).', $vars);
     }
 
     $task_manager = \Drupal::getContainer()
@@ -282,7 +285,7 @@ public function updateIndex(IndexInterface $index) {
         '%server' => $this->label(),
         '%index' => $index->label(),
       );
-      watchdog_exception('search_api', $e, '%type while updating the fields of index %index on server %server: @message in %function (line %line of %file).', $vars);
+      $this->logException($e, '%type while updating the fields of index %index on server %server: @message in %function (line %line of %file).', $vars);
     }
 
     $task_manager = \Drupal::getContainer()
@@ -310,7 +313,7 @@ public function removeIndex($index) {
         '%server' => $this->label(),
         '%index' => is_object($index) ? $index->label() : $index,
       );
-      watchdog_exception('search_api', $e, '%type while removing index %index from server %server: @message in %function (line %line of %file).', $vars);
+      $this->logException($e, '%type while removing index %index from server %server: @message in %function (line %line of %file).', $vars);
     }
 
     $task_manager = \Drupal::getContainer()
@@ -343,7 +346,7 @@ public function deleteItems(IndexInterface $index, array $item_ids) {
       $vars = array(
         '%index' => $index->label(),
       );
-      \Drupal::service('logger.channel.search_api')->warning('Trying to delete items from index %index which is marked as read-only.', $vars);
+      $this->getLogger()->warning('Trying to delete items from index %index which is marked as read-only.', $vars);
       return;
     }
 
@@ -358,7 +361,7 @@ public function deleteItems(IndexInterface $index, array $item_ids) {
       $vars = array(
         '%server' => $this->label(),
       );
-      watchdog_exception('search_api', $e, '%type while deleting items from server %server: @message in %function (line %line of %file).', $vars);
+      $this->logException($e, '%type while deleting items from server %server: @message in %function (line %line of %file).', $vars);
     }
 
     $task_manager = \Drupal::getContainer()
@@ -374,7 +377,7 @@ public function deleteAllIndexItems(IndexInterface $index, $datasource_id = NULL
       $vars = array(
         '%index' => $index->label(),
       );
-      \Drupal::service('logger.channel.search_api')->warning('Trying to delete items from index %index which is marked as read-only.', $vars);
+      $this->getLogger()->warning('Trying to delete items from index %index which is marked as read-only.', $vars);
       return;
     }
 
@@ -401,7 +404,7 @@ public function deleteAllIndexItems(IndexInterface $index, $datasource_id = NULL
         '%server' => $this->label(),
         '%index' => $index->label(),
       );
-      watchdog_exception('search_api', $e, '%type while deleting items of index %index from server %server: @message in %function (line %line of %file).', $vars);
+      $this->logException($e, '%type while deleting items of index %index from server %server: @message in %function (line %line of %file).', $vars);
     }
 
     $task_manager = \Drupal::getContainer()
@@ -424,7 +427,7 @@ public function deleteAllItems() {
         $args = array(
           '%index' => $index->label(),
         );
-        watchdog_exception('search_api', $e, '%type while deleting all items from index %index: @message in %function (line %line of %file).', $args);
+        $this->logException($e, '%type while deleting all items from index %index: @message in %function (line %line of %file).', $args);
         $failed[] = $index->label();
       }
     }
diff --git a/src/Form/IndexClearConfirmForm.php b/src/Form/IndexClearConfirmForm.php
index 34aecde8..d0dd68c5 100644
--- a/src/Form/IndexClearConfirmForm.php
+++ b/src/Form/IndexClearConfirmForm.php
@@ -5,6 +5,7 @@
 use Drupal\Core\Entity\EntityConfirmFormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
+use Drupal\search_api\LoggerTrait;
 use Drupal\search_api\SearchApiException;
 
 /**
@@ -12,6 +13,8 @@
  */
 class IndexClearConfirmForm extends EntityConfirmFormBase {
 
+  use LoggerTrait;
+
   /**
    * {@inheritdoc}
    */
@@ -45,7 +48,7 @@ public function submitForm(array &$form, FormStateInterface $form_state) {
     }
     catch (SearchApiException $e) {
       drupal_set_message($this->t('Failed to clear the search index %name.', array('%name' => $entity->label())), 'error');
-      watchdog_exception('search_api', $e, '%type while trying to clear the index %name: @message in %function (line %line of %file)', array('%name' => $entity->label()));
+      $this->logException($e, '%type while trying to clear the index %name: @message in %function (line %line of %file)', array('%name' => $entity->label()));
     }
 
     $form_state->setRedirect('entity.search_api_index.canonical', array('search_api_index' => $entity->id()));
diff --git a/src/Form/IndexForm.php b/src/Form/IndexForm.php
index 2c8e89ad..405d86b6 100644
--- a/src/Form/IndexForm.php
+++ b/src/Form/IndexForm.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Form\SubformState;
 use Drupal\search_api\Datasource\DatasourcePluginManager;
 use Drupal\search_api\IndexInterface;
+use Drupal\search_api\LoggerTrait;
 use Drupal\search_api\SearchApiException;
 use Drupal\search_api\Tracker\TrackerPluginManager;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -19,6 +20,8 @@
  */
 class IndexForm extends EntityForm {
 
+  use LoggerTrait;
+
   /**
    * The entity type manager.
    *
@@ -618,9 +621,9 @@ public function save(array $form, FormStateInterface $form_state) {
           $form_state->setRedirect('entity.search_api_index.canonical', array('search_api_index' => $index->id()));
         }
       }
-      catch (SearchApiException $ex) {
+      catch (SearchApiException $e) {
         $form_state->setRebuild();
-        watchdog_exception('search_api', $ex);
+        $this->logException($e);
         drupal_set_message($this->t('The index could not be saved.'), 'error');
       }
     }
diff --git a/src/Form/IndexProcessorsForm.php b/src/Form/IndexProcessorsForm.php
index 6f650cca..a1114f25 100644
--- a/src/Form/IndexProcessorsForm.php
+++ b/src/Form/IndexProcessorsForm.php
@@ -8,6 +8,7 @@
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\PluginFormInterface;
 use Drupal\Core\Form\SubformState;
+use Drupal\search_api\LoggerTrait;
 use Drupal\search_api\Processor\ProcessorInterface;
 use Drupal\search_api\Processor\ProcessorPluginManager;
 use Psr\Log\LoggerInterface;
@@ -18,6 +19,8 @@
  */
 class IndexProcessorsForm extends EntityForm {
 
+  use LoggerTrait;
+
   /**
    * The index being configured.
    *
@@ -26,13 +29,6 @@ class IndexProcessorsForm extends EntityForm {
   protected $entity;
 
   /**
-   * The entity type manager.
-   *
-   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
-   */
-  protected $entityTypeManager;
-
-  /**
    * The datasource manager.
    *
    * @var \Drupal\search_api\Processor\ProcessorPluginManager
@@ -40,13 +36,6 @@ class IndexProcessorsForm extends EntityForm {
   protected $processorPluginManager;
 
   /**
-   * The logger to use.
-   *
-   * @var \Psr\Log\LoggerInterface
-   */
-  protected $logger;
-
-  /**
    * Constructs an IndexProcessorsForm object.
    *
    * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
@@ -357,7 +346,7 @@ protected function getAllProcessors() {
         }
       }
       else {
-        $this->logger->warning('Processor %id specifies a non-existing class %class.', array(
+        $this->getLogger()->warning('Processor %id specifies a non-existing class %class.', array(
           '%id' => $name,
           '%class' => $processor_definition['class']
         ));
diff --git a/src/Form/IndexReindexConfirmForm.php b/src/Form/IndexReindexConfirmForm.php
index 354a7712..ffad95a5 100644
--- a/src/Form/IndexReindexConfirmForm.php
+++ b/src/Form/IndexReindexConfirmForm.php
@@ -5,6 +5,7 @@
 use Drupal\Core\Entity\EntityConfirmFormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
+use Drupal\search_api\LoggerTrait;
 use Drupal\search_api\SearchApiException;
 
 /**
@@ -12,6 +13,8 @@
  */
 class IndexReindexConfirmForm extends EntityConfirmFormBase {
 
+  use LoggerTrait;
+
   /**
    * {@inheritdoc}
    */
@@ -46,7 +49,7 @@ public function submitForm(array &$form, FormStateInterface $form_state) {
     }
     catch (SearchApiException $e) {
       drupal_set_message($this->t('Failed to reindex items for the search index %name.', array('%name' => $entity->label())), 'error');
-      watchdog_exception('search_api', $e, '%type while trying to reindex items on index %name: @message in %function (line %line of %file)', array('%name' => $entity->label()));
+      $this->logException($e, '%type while trying to reindex items on index %name: @message in %function (line %line of %file)', array('%name' => $entity->label()));
     }
 
     $form_state->setRedirect('entity.search_api_index.canonical', array('search_api_index' => $entity->id()));
diff --git a/src/Form/ServerClearConfirmForm.php b/src/Form/ServerClearConfirmForm.php
index 23faefd7..556d07ab 100644
--- a/src/Form/ServerClearConfirmForm.php
+++ b/src/Form/ServerClearConfirmForm.php
@@ -5,6 +5,7 @@
 use Drupal\Core\Entity\EntityConfirmFormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
+use Drupal\search_api\LoggerTrait;
 use Drupal\search_api\SearchApiException;
 
 /**
@@ -12,6 +13,8 @@
  */
 class ServerClearConfirmForm extends EntityConfirmFormBase {
 
+  use LoggerTrait;
+
   /**
    * {@inheritdoc}
    */
@@ -61,7 +64,7 @@ public function submitForm(array &$form, FormStateInterface $form_state) {
         $args = array(
           '%index' => $index->label(),
         );
-        watchdog_exception('search_api', $e, '%type while clearing index %index: @message in %function (line %line of %file).', $args);
+        $this->logException($e, '%type while clearing index %index: @message in %function (line %line of %file).', $args);
         $failed_reindexing[] = $index->label();
       }
     }
diff --git a/src/Form/ServerForm.php b/src/Form/ServerForm.php
index 6616950e..daa25417 100644
--- a/src/Form/ServerForm.php
+++ b/src/Form/ServerForm.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Form\SubformState;
 use Drupal\Core\Url;
 use Drupal\search_api\Backend\BackendPluginManager;
+use Drupal\search_api\LoggerTrait;
 use Drupal\search_api\SearchApiException;
 use Drupal\search_api\ServerInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -19,6 +20,8 @@
  */
 class ServerForm extends EntityForm {
 
+  use LoggerTrait;
+
   /**
    * The server storage controller.
    *
@@ -309,7 +312,7 @@ public function save(array $form, FormStateInterface $form_state) {
       }
       catch (SearchApiException $e) {
         $form_state->setRebuild();
-        watchdog_exception('search_api', $e);
+        $this->logException($e);
         drupal_set_message($this->t('The server could not be saved.'), 'error');
       }
     }
diff --git a/src/IndexBatchHelper.php b/src/IndexBatchHelper.php
index 610a9ee6..9b0c6af9 100644
--- a/src/IndexBatchHelper.php
+++ b/src/IndexBatchHelper.php
@@ -169,10 +169,10 @@ public static function process(IndexInterface $index, $batch_size, $limit, &$con
         $context['finished'] = ($context['sandbox']['progress'] / $context['sandbox']['original_item_count']);
       }
     }
-    catch (\Exception $ex) {
+    catch (\Exception $e) {
       // Log exception to watchdog and abort the batch job.
-      watchdog_exception('search_api', $ex);
-      $context['message'] = static::t('An error occurred during indexing: @message', array('@message' => $ex->getMessage()));
+      watchdog_exception('search_api', $e);
+      $context['message'] = static::t('An error occurred during indexing: @message', array('@message' => $e->getMessage()));
       $context['finished'] = 1;
       $context['results']['not indexed'] += ($context['sandbox']['limit'] - $context['sandbox']['progress']);
     }
diff --git a/src/Item/Field.php b/src/Item/Field.php
index f7ee8bcc..d9b466d9 100644
--- a/src/Item/Field.php
+++ b/src/Item/Field.php
@@ -5,6 +5,7 @@
 use Drupal\search_api\DataType\DataTypePluginManager;
 use Drupal\search_api\Entity\Index;
 use Drupal\search_api\IndexInterface;
+use Drupal\search_api\LoggerTrait;
 use Drupal\search_api\Processor\ConfigurablePropertyInterface;
 use Drupal\search_api\SearchApiException;
 use Drupal\search_api\Utility\Utility;
@@ -14,6 +15,8 @@
  */
 class Field implements \IteratorAggregate, FieldInterface {
 
+  use LoggerTrait;
+
   /**
    * The index this field is attached to.
    *
@@ -365,7 +368,7 @@ public function getDescription() {
         $this->description = $this->description ?: FALSE;
       }
       catch (SearchApiException $e) {
-        watchdog_exception('search_api', $e);
+        $this->logException($e);
       }
     }
     return $this->description ?: NULL;
@@ -392,7 +395,7 @@ public function getPrefixedLabel() {
           $this->labelPrefix = $this->getDatasource()->label();
         }
         catch (SearchApiException $e) {
-          watchdog_exception('search_api', $e);
+          $this->logException($e);
         }
         $this->labelPrefix .= ' » ';
       }
@@ -511,7 +514,7 @@ public function getOriginalType() {
         $this->originalType = $this->getDataDefinition()->getDataType();
       }
       catch (SearchApiException $e) {
-        watchdog_exception('search_api', $e);
+        $this->logException($e);
       }
     }
     return $this->originalType;
diff --git a/src/Item/Item.php b/src/Item/Item.php
index 71d70e83..0280dde5 100644
--- a/src/Item/Item.php
+++ b/src/Item/Item.php
@@ -5,6 +5,7 @@
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\TypedData\ComplexDataInterface;
 use Drupal\search_api\Datasource\DatasourceInterface;
+use Drupal\search_api\LoggerTrait;
 use Drupal\search_api\Processor\ProcessorInterface;
 use Drupal\search_api\Processor\ProcessorPropertyInterface;
 use Drupal\search_api\SearchApiException;
@@ -16,6 +17,8 @@
  */
 class Item implements \IteratorAggregate, ItemInterface {
 
+  use LoggerTrait;
+
   /**
    * The search index with which this item is associated.
    *
@@ -250,7 +253,7 @@ public function getFields($extract = TRUE) {
         catch (SearchApiException $e) {
           // If we couldn't load the object, just log an error and fail
           // silently to set the values.
-          watchdog_exception('search_api', $e);
+          $this->logException($e);
         }
       }
       $this->fieldsExtracted = TRUE;
diff --git a/src/LoggerTrait.php b/src/LoggerTrait.php
new file mode 100644
index 00000000..28169fde
--- /dev/null
+++ b/src/LoggerTrait.php
@@ -0,0 +1,80 @@
+<?php
+
+namespace Drupal\search_api;
+
+use Drupal\Core\Logger\LoggerChannelInterface;
+use Drupal\Core\Utility\Error;
+use Drupal\Core\Logger\RfcLogLevel;
+
+/**
+ * Provides helper methods for logging with dependency injection.
+ */
+trait LoggerTrait {
+
+  /**
+   * The logging channel to use.
+   *
+   * @var \Drupal\Core\Logger\LoggerChannelInterface|null
+   */
+  protected $logger;
+
+  /**
+   * Retrieves the logger.
+   *
+   * @return \Drupal\Core\Logger\LoggerChannelInterface
+   *   The logger.
+   */
+  public function getLogger() {
+    return $this->logger ?: \Drupal::service('logger.channel.search_api');
+  }
+
+  /**
+   * Sets the logger.
+   *
+   * @param \Drupal\Core\Logger\LoggerChannelInterface $logger
+   *   The new logger.
+   *
+   * @return $this
+   */
+  public function setLogger(LoggerChannelInterface $logger) {
+    $this->logger = $logger;
+    return $this;
+  }
+
+  /**
+   * Logs an exception.
+   *
+   * @param \Exception $exception
+   *   The exception that is going to be logged.
+   * @param string|null $message
+   *   (optional) The message to display in the log, which can use variables
+   *   retrieved from the exception (like "%type" or "@message"). Or NULL to use
+   *   the default message.
+   * @param array $variables
+   *   (optional) Array of variables to replace in the message when it is
+   *   displayed, or NULL if the message should not be translated. The normal
+   *   patterns for translation variables can be used.
+   * @param int $severity
+   *   (optional) The severity of the message, as per RFC 3164.
+   * @param string|null $link
+   *   (optional) A link to associate with the message, if any.
+   *
+   * @see watchdog_exception()
+   * @see \Drupal\Core\Utility\Error::decodeException()
+   */
+  protected function logException(\Exception $exception, $message = NULL, $variables = array(), $severity = RfcLogLevel::ERROR, $link = NULL) {
+    // Use a default value if $message is not set.
+    if (empty($message)) {
+      $message = '%type: @message in %function (line %line of %file).';
+    }
+
+    if ($link) {
+      $variables['link'] = $link;
+    }
+
+    $variables += Error::decodeException($exception);
+
+    $this->getLogger()->log($severity, $message, $variables);
+  }
+
+}
diff --git a/src/Plugin/search_api/processor/ContentAccess.php b/src/Plugin/search_api/processor/ContentAccess.php
index 6397329a..8c68d529 100644
--- a/src/Plugin/search_api/processor/ContentAccess.php
+++ b/src/Plugin/search_api/processor/ContentAccess.php
@@ -4,18 +4,18 @@
 
 use Drupal\comment\CommentInterface;
 use Drupal\Core\Database\Connection;
-use Psr\Log\LoggerInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Session\AnonymousUserSession;
 use Drupal\Core\TypedData\ComplexDataInterface;
 use Drupal\node\NodeInterface;
 use Drupal\search_api\Datasource\DatasourceInterface;
-use Drupal\search_api\Item\ItemInterface;
-use Drupal\search_api\Processor\ProcessorProperty;
-use Drupal\search_api\SearchApiException;
 use Drupal\search_api\IndexInterface;
+use Drupal\search_api\Item\ItemInterface;
+use Drupal\search_api\LoggerTrait;
 use Drupal\search_api\Processor\ProcessorPluginBase;
+use Drupal\search_api\Processor\ProcessorProperty;
 use Drupal\search_api\Query\QueryInterface;
+use Drupal\search_api\SearchApiException;
 use Drupal\user\Entity\User;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -35,6 +35,8 @@
  */
 class ContentAccess extends ProcessorPluginBase {
 
+  use LoggerTrait;
+
   /**
    * The database connection.
    *
@@ -43,13 +45,6 @@ class ContentAccess extends ProcessorPluginBase {
   protected $database;
 
   /**
-   * The logger to use for logging messages.
-   *
-   * @var \Psr\Log\LoggerInterface|null
-   */
-  protected $logger;
-
-  /**
    * {@inheritdoc}
    */
   public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
@@ -86,26 +81,6 @@ public function setDatabase(Connection $database) {
   }
 
   /**
-   * Retrieves the logger to use.
-   *
-   * @return \Psr\Log\LoggerInterface
-   *   The logger to use.
-   */
-  public function getLogger() {
-    return $this->logger ?: \Drupal::service('logger.channel.search_api');
-  }
-
-  /**
-   * Sets the logger to use.
-   *
-   * @param \Psr\Log\LoggerInterface $logger
-   *   The logger to use.
-   */
-  public function setLogger(LoggerInterface $logger) {
-    $this->logger = $logger;
-  }
-
-  /**
    * {@inheritdoc}
    */
   public static function supportsIndex(IndexInterface $index) {
@@ -238,7 +213,7 @@ public function preprocessSearchQuery(QueryInterface $query) {
           $this->addNodeAccess($query, $account);
         }
         catch (SearchApiException $e) {
-          watchdog_exception('search_api', $e);
+          $this->logException($e);
         }
       }
       else {
diff --git a/src/Plugin/search_api/processor/RenderedItem.php b/src/Plugin/search_api/processor/RenderedItem.php
index be0541f5..1dd7e83e 100644
--- a/src/Plugin/search_api/processor/RenderedItem.php
+++ b/src/Plugin/search_api/processor/RenderedItem.php
@@ -11,9 +11,9 @@
 use Drupal\Core\Theme\ThemeManagerInterface;
 use Drupal\search_api\Datasource\DatasourceInterface;
 use Drupal\search_api\Item\ItemInterface;
+use Drupal\search_api\LoggerTrait;
 use Drupal\search_api\Plugin\search_api\processor\Property\RenderedItemProperty;
 use Drupal\search_api\Processor\ProcessorPluginBase;
-use Psr\Log\LoggerInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -33,6 +33,8 @@
  */
 class RenderedItem extends ProcessorPluginBase {
 
+  use LoggerTrait;
+
   /**
    * The current_user service used by this plugin.
    *
@@ -48,13 +50,6 @@ class RenderedItem extends ProcessorPluginBase {
   protected $renderer;
 
   /**
-   * The logger to use for log messages.
-   *
-   * @var \Psr\Log\LoggerInterface|null
-   */
-  protected $logger;
-
-  /**
    * Theme manager service.
    *
    * @var \Drupal\Core\Theme\ThemeManagerInterface
@@ -139,29 +134,6 @@ public function setRenderer(RendererInterface $renderer) {
   }
 
   /**
-   * Retrieves the logger to use for log messages.
-   *
-   * @return \Psr\Log\LoggerInterface
-   *   The logger to use.
-   */
-  public function getLogger() {
-    return $this->logger ?: \Drupal::service('logger.channel.search_api');
-  }
-
-  /**
-   * Sets the logger to use for log messages.
-   *
-   * @param \Psr\Log\LoggerInterface $logger
-   *   The new logger.
-   *
-   * @return $this
-   */
-  public function setLogger(LoggerInterface $logger) {
-    $this->logger = $logger;
-    return $this;
-  }
-
-  /**
    * Retrieves the theme manager.
    *
    * @return \Drupal\Core\Theme\ThemeManagerInterface $theme_manager
diff --git a/src/Plugin/search_api/tracker/Basic.php b/src/Plugin/search_api/tracker/Basic.php
index 2c962fe6..8928280f 100644
--- a/src/Plugin/search_api/tracker/Basic.php
+++ b/src/Plugin/search_api/tracker/Basic.php
@@ -3,6 +3,7 @@
 namespace Drupal\search_api\Plugin\search_api\tracker;
 
 use Drupal\Core\Database\Connection;
+use Drupal\search_api\LoggerTrait;
 use Drupal\search_api\Tracker\TrackerPluginBase;
 use Drupal\search_api\Utility\Utility;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -10,7 +11,7 @@
 /**
  * Provides a tracker implementation which uses a FIFO-like processing order.
  *
- * @SearchApiTracker(
+ *  @SearchApiTracker(
  *   id = "default",
  *   label = @Translation("Default"),
  *   description = @Translation("Index tracker which uses first in/first out for processing pending items.")
@@ -18,6 +19,8 @@
  */
 class Basic extends TrackerPluginBase {
 
+  use LoggerTrait;
+
   /**
    * Status value that represents items which are indexed in their latest form.
    */
@@ -179,7 +182,7 @@ public function trackItemsInserted(array $ids) {
       }
     }
     catch (\Exception $e) {
-      watchdog_exception('search_api', $e);
+      $this->logException($e);
       $transaction->rollBack();
     }
   }
@@ -203,7 +206,7 @@ public function trackItemsUpdated(array $ids = NULL) {
       }
     }
     catch (\Exception $e) {
-      watchdog_exception('search_api', $e);
+      $this->logException($e);
       $transaction->rollBack();
     }
   }
@@ -222,7 +225,7 @@ public function trackAllItemsUpdated($datasource_id = NULL) {
       $update->execute();
     }
     catch (\Exception $e) {
-      watchdog_exception('search_api', $e);
+      $this->logException($e);
       $transaction->rollBack();
     }
   }
@@ -244,7 +247,7 @@ public function trackItemsIndexed(array $ids) {
       }
     }
     catch (\Exception $e) {
-      watchdog_exception('search_api', $e);
+      $this->logException($e);
       $transaction->rollBack();
     }
   }
@@ -267,7 +270,7 @@ public function trackItemsDeleted(array $ids = NULL) {
       }
     }
     catch (\Exception $e) {
-      watchdog_exception('search_api', $e);
+      $this->logException($e);
       $transaction->rollBack();
     }
   }
@@ -285,7 +288,7 @@ public function trackAllItemsDeleted($datasource_id = NULL) {
       $delete->execute();
     }
     catch (\Exception $e) {
-      watchdog_exception('search_api', $e);
+      $this->logException($e);
       $transaction->rollBack();
     }
   }
diff --git a/src/Plugin/views/argument/SearchApiMoreLikeThis.php b/src/Plugin/views/argument/SearchApiMoreLikeThis.php
index 9bffbc2e..66380fb6 100644
--- a/src/Plugin/views/argument/SearchApiMoreLikeThis.php
+++ b/src/Plugin/views/argument/SearchApiMoreLikeThis.php
@@ -5,6 +5,7 @@
 use Drupal\Core\Cache\UncacheableDependencyTrait;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\search_api\Entity\Index;
+use Drupal\search_api\LoggerTrait;
 use Drupal\search_api\SearchApiException;
 
 /**
@@ -16,6 +17,7 @@
  */
 class SearchApiMoreLikeThis extends SearchApiStandard {
 
+  use LoggerTrait;
   use UncacheableDependencyTrait;
 
   /**
@@ -70,7 +72,7 @@ public function query($group_by = FALSE) {
       $server = $this->query->getIndex()->getServerInstance();
       if (!$server->supportsFeature('search_api_mlt')) {
         $backend_id = $server->getBackendId();
-        \Drupal::service('logger.channel.search_api')->error('The search backend "@backend_id" does not offer "More like this" functionality.',
+        $this->getLogger()->error('The search backend "@backend_id" does not offer "More like this" functionality.',
           array('@backend_id' => $backend_id));
         $this->query->abort();
         return;
diff --git a/src/Plugin/views/field/SearchApiFieldTrait.php b/src/Plugin/views/field/SearchApiFieldTrait.php
index fe4f8596..823d6b59 100644
--- a/src/Plugin/views/field/SearchApiFieldTrait.php
+++ b/src/Plugin/views/field/SearchApiFieldTrait.php
@@ -9,7 +9,6 @@
 use Drupal\Core\TypedData\DataReferenceInterface;
 use Drupal\Core\TypedData\ListInterface;
 use Drupal\search_api\Plugin\views\SearchApiHandlerTrait;
-use Drupal\search_api\Processor\ProcessorInterface;
 use Drupal\search_api\Processor\ProcessorPropertyInterface;
 use Drupal\search_api\Utility\Utility;
 use Drupal\views\Plugin\views\field\MultiItemsFieldHandlerInterface;
diff --git a/src/Plugin/views/query/SearchApiQuery.php b/src/Plugin/views/query/SearchApiQuery.php
index 6137a6f9..bd0cd89c 100644
--- a/src/Plugin/views/query/SearchApiQuery.php
+++ b/src/Plugin/views/query/SearchApiQuery.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 use Drupal\search_api\Entity\Index;
+use Drupal\search_api\LoggerTrait;
 use Drupal\search_api\ParseMode\ParseModeInterface;
 use Drupal\search_api\Query\ConditionGroupInterface;
 use Drupal\search_api\Query\QueryInterface;
@@ -20,7 +21,6 @@
 use Drupal\views\Plugin\views\query\QueryPluginBase;
 use Drupal\views\ResultRow;
 use Drupal\views\ViewExecutable;
-use Psr\Log\LoggerInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -34,6 +34,7 @@
  */
 class SearchApiQuery extends QueryPluginBase {
 
+  use LoggerTrait;
   use UncacheableDependencyTrait;
 
   /**
@@ -113,13 +114,6 @@ class SearchApiQuery extends QueryPluginBase {
   protected $groupOperator = 'AND';
 
   /**
-   * The logger to use for log messages.
-   *
-   * @var \Psr\Log\LoggerInterface|null
-   */
-  protected $logger;
-
-  /**
    * {@inheritdoc}
    */
   public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
@@ -132,29 +126,6 @@ public static function create(ContainerInterface $container, array $configuratio
   }
 
   /**
-   * Retrieves the logger to use for log messages.
-   *
-   * @return \Psr\Log\LoggerInterface
-   *   The logger to use.
-   */
-  public function getLogger() {
-    return $this->logger ?: \Drupal::service('logger.channel.search_api');
-  }
-
-  /**
-   * Sets the logger to use for log messages.
-   *
-   * @param \Psr\Log\LoggerInterface $logger
-   *   The new logger.
-   *
-   * @return $this
-   */
-  public function setLogger(LoggerInterface $logger) {
-    $this->logger = $logger;
-    return $this;
-  }
-
-  /**
    * Loads the search index belonging to the given Views base table.
    *
    * @param string $table
diff --git a/src/Plugin/views/row/SearchApiRow.php b/src/Plugin/views/row/SearchApiRow.php
index 6b795c84..fcf90142 100644
--- a/src/Plugin/views/row/SearchApiRow.php
+++ b/src/Plugin/views/row/SearchApiRow.php
@@ -5,7 +5,7 @@
 use Drupal\Core\Cache\UncacheableDependencyTrait;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Form\FormStateInterface;
-use Psr\Log\LoggerInterface;
+use Drupal\search_api\LoggerTrait;
 use Drupal\Core\TypedData\ComplexDataInterface;
 use Drupal\search_api\Plugin\views\query\SearchApiQuery;
 use Drupal\search_api\SearchApiException;
@@ -27,6 +27,7 @@
  */
 class SearchApiRow extends RowPluginBase {
 
+  use LoggerTrait;
   use UncacheableDependencyTrait;
 
   /**
@@ -44,13 +45,6 @@ class SearchApiRow extends RowPluginBase {
   protected $entityTypeManager;
 
   /**
-   * The logger to use for logging messages.
-   *
-   * @var \Psr\Log\LoggerInterface|null
-   */
-  protected $logger;
-
-  /**
    * {@inheritdoc}
    */
   public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
@@ -87,26 +81,6 @@ public function setEntityTypeManager(EntityTypeManagerInterface $entity_type_man
   }
 
   /**
-   * Retrieves the logger to use.
-   *
-   * @return \Psr\Log\LoggerInterface
-   *   The logger to use.
-   */
-  public function getLogger() {
-    return $this->logger ?: \Drupal::service('logger.channel.search_api');
-  }
-
-  /**
-   * Sets the logger to use.
-   *
-   * @param \Psr\Log\LoggerInterface $logger
-   *   The logger to use.
-   */
-  public function setLogger(LoggerInterface $logger) {
-    $this->logger = $logger;
-  }
-
-  /**
    * {@inheritdoc}
    */
   public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) {
@@ -229,7 +203,7 @@ public function render($row) {
       return $this->index->getDatasource($datasource_id)->viewItem($row->_object, $view_mode);
     }
     catch (SearchApiException $e) {
-      watchdog_exception('search_api', $e);
+      $this->logException($e);
       return '';
     }
   }
diff --git a/src/Task/ServerTaskManager.php b/src/Task/ServerTaskManager.php
index 2f384898..2da7c47a 100644
--- a/src/Task/ServerTaskManager.php
+++ b/src/Task/ServerTaskManager.php
@@ -5,6 +5,7 @@
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Drupal\search_api\IndexInterface;
+use Drupal\search_api\LoggerTrait;
 use Drupal\search_api\SearchApiException;
 use Drupal\search_api\ServerInterface;
 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
@@ -14,6 +15,7 @@
  */
 class ServerTaskManager implements ServerTaskManagerInterface, EventSubscriberInterface {
 
+  use LoggerTrait;
   use StringTranslationTrait;
 
   /**
@@ -92,7 +94,7 @@ public function execute(ServerInterface $server = NULL) {
       return $this->taskManager->executeAllTasks($conditions, 100);
     }
     catch (SearchApiException $e) {
-      watchdog_exception('search_api', $e);
+      $this->logException($e);
       return FALSE;
     }
   }
