diff --git a/.circleci/config.yml b/.circleci/config.yml
new file mode 100644
index 0000000..9ec4f99
--- /dev/null
+++ b/.circleci/config.yml
@@ -0,0 +1,187 @@
+# Default configuration file for Drupal modules.
+#
+# Use setup.sh to automate setting this up. Otherwise, to use this in a new
+# module:
+#   1. Copy config.yml to the module's .circleci directory.
+#   2. Change 'latest' in the image tag to the latest tag.
+#   3. Update the working_directory key.
+#   4. Connect CircleCI to the repository through the Circle UI.
+#   5. Set the COMPOSER_AUTH environment variable in Circle to grant access to
+#      any private repositories.
+#   6. Create a status badge embed code in Circle and add it to the README.md.
+#
+# Check https://circleci.com/docs/2.0/language-php/ for more details
+#
+
+defaults: &defaults
+  docker:
+    # specify the version you desire here (avoid latest except for testing)
+    - image: andrewberry/drupal_tests:0.1.0
+
+    # Use our fork until https://github.com/wernight/docker-phantomjs/pull/3 is
+    # merged.
+    # - image: wernight/phantomjs:2.1.1
+    - image: andrewberry/docker-phantomjs:v2.1.1-patch1
+      command: [phantomjs, --webdriver=8910]
+
+    - image: mariadb:10.3
+      environment:
+        MYSQL_ALLOW_EMPTY_PASSWORD: 1
+
+    # Specify service dependencies here if necessary
+    # CircleCI maintains a library of pre-built images
+    # documented at https://circleci.com/docs/2.0/circleci-images/
+    # - image: circleci/mysql:9.4
+
+  # 'checkout' supports a path key, but not on locals where you test with the
+  # circleci CLI tool.
+  # https://discuss.circleci.com/t/bug-circleci-build-command-ignores-checkout-path-config/13004
+  working_directory: /var/www/html/modules/audit_log
+
+# YAML does not support merging of lists. That means we can't have a default
+# 'steps' configuration, though we can have defaults for individual step
+# properties.
+
+# We use the composer.json as a way to determine if we can cache our build.
+restore_cache: &restore_cache
+  keys:
+  - v1-dependencies-{{ checksum "composer.json" }}
+  # fallback to using the latest cache if no exact match is found
+  - v1-dependencies-
+
+# If composer.json hasn't changed, restore the vendor directory. We don't
+# restore the lock file so we ensure we get updated dependencies.
+save_cache: &save_cache
+  paths:
+    - ./vendor
+  key: v1-dependencies-{{ checksum "composer.json" }}
+
+# Run Drupal unit and kernel tests as one job. This command invokes the test.sh
+# hook.
+unit_kernel_tests: &unit_kernel_tests
+  <<: *defaults
+  steps:
+    - checkout
+
+    - restore_cache: *restore_cache
+    - save_cache: *save_cache
+
+    - run:
+        working_directory: /var/www/html
+        command: |
+          ./test.sh $CIRCLE_PROJECT_REPONAME
+
+    - store_test_results:
+        path: /var/www/html/artifacts/phpunit
+    - store_artifacts:
+        path: /var/www/html/artifacts
+
+# Run Behat tests. This command invokes the test-js.sh hook.
+behat_tests: &behat_tests
+  <<: *defaults
+  steps:
+    - checkout
+
+    - restore_cache: *restore_cache
+    - save_cache: *save_cache
+
+    - run:
+        working_directory: /var/www/html
+        command: |
+          ./test-js.sh $CIRCLE_PROJECT_REPONAME
+
+    - store_test_results:
+        path: /var/www/html/artifacts/behat
+    - store_artifacts:
+        path: /var/www/html/artifacts
+
+# Run code quality tests. This invokes code-sniffer.sh.
+code_sniffer: &code_sniffer
+  <<: *defaults
+  steps:
+    - checkout
+
+    - restore_cache: *restore_cache
+    - save_cache: *save_cache
+
+    - run:
+        working_directory: /var/www/html
+        command: |
+          ./code-sniffer.sh $CIRCLE_PROJECT_REPONAME
+
+    - store_test_results:
+        path: /var/www/html/artifacts/phpcs
+    - store_artifacts:
+        path: /var/www/html/artifacts
+
+# Run code coverage tests. This invokes code-coverage-stats.sh.
+code_coverage: &code_coverage
+  <<: *defaults
+  steps:
+    - checkout
+
+    - restore_cache: *restore_cache
+    - save_cache: *save_cache
+
+    - run:
+        working_directory: /var/www/html
+        command: |
+          ./code-coverage-stats.sh $CIRCLE_PROJECT_REPONAME
+    - store_artifacts:
+        path: /var/www/html/artifacts
+
+# Deploy job
+deploy_job: &deploy_job
+  <<: *defaults
+  steps:
+    - checkout
+
+    - restore_cache: *restore_cache
+    - save_cache: *save_cache
+
+    - run:
+        name: Deploy to pantheon
+        command: |
+
+          git config --global user.email "circleci@circleci.com"
+          git config --global user.name "CircleCI"
+
+          git clone git@github.com:Mitsuroseba/pantheon-d8.git --branch=master pantheon
+          cd pantheon
+          composer update
+          git commit --allow-empty -am "Update audit_log package $CIRCLE_SHA1"
+          git push origin master
+
+# Declare all of the jobs we should run.
+version: 2
+jobs:
+  run-unit-kernel-tests:
+     <<: *unit_kernel_tests
+  run-behat-tests:
+     <<: *behat_tests
+  run-code-sniffer:
+     <<: *code_sniffer
+  run-code-coverage:
+     <<: *code_coverage
+  deploy-job:
+     <<: *deploy_job
+
+workflows:
+  version: 2
+
+  # Declare a workflow that runs all of our jobs in parallel.
+  test_and_lint:
+    jobs:
+      - run-unit-kernel-tests
+      - run-behat-tests
+      - run-code-sniffer
+      - run-code-coverage
+  build-deploy:
+    jobs:
+      - deploy-job:
+          filters:
+            branches:
+              only:
+                - 8.x-1.x
+                - 1.x
+                - 1.x-temp
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..8e166ed
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+tests/src/Behat/behat.local.yml
diff --git a/audit_log.install b/audit_log.install
deleted file mode 100644
index 164eacb..0000000
--- a/audit_log.install
+++ /dev/null
@@ -1,87 +0,0 @@
-<?php
-
-/**
- * @file
- * Install, update and uninstall functions for the audit_log module.
- */
-
-/**
- * Implements hook_schema().
- */
-function audit_log_schema() {
-  $schema['audit_log'] = [
-    'description' => 'Table that contains logs of all entity events.',
-    'fields' => [
-      'id' => [
-        'type' => 'serial',
-        'not null' => TRUE,
-        'description' => 'Unique event ID.',
-      ],
-      'entity_id' => [
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'default' => 0,
-        'description' => 'The entity id of the entity that was created, modified or deleted',
-      ],
-      'entity_type' => [
-        'type' => 'varchar_ascii',
-        'length' => 128,
-        'not null' => TRUE,
-        'default' => '',
-        'description' => 'The event type, usually insert, update or delete.',
-      ],
-      'user_id' => [
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'default' => 0,
-        'description' => 'The user id of the user who triggered the event.',
-      ],
-      'event' => [
-        'type' => 'varchar_ascii',
-        'length' => 64,
-        'not null' => TRUE,
-        'default' => '',
-        'description' => 'The event type, usually insert, update or delete.',
-      ],
-      'previous_state' => [
-        'type' => 'varchar_ascii',
-        'length' => 64,
-        'default' => '',
-        'description' => 'The previous state of the entity if available',
-      ],
-      'current_state' => [
-        'type' => 'varchar_ascii',
-        'length' => 64,
-        'default' => '',
-        'description' => 'The current state of the entity if available',
-      ],
-      'message' => [
-        'type' => 'text',
-        'not null' => TRUE,
-        'size' => 'big',
-        'description' => 'Text of log message to be passed into the t() function.',
-      ],
-      'variables' => [
-        'type' => 'blob',
-        'not null' => TRUE,
-        'size' => 'big',
-        'description' => 'Serialized array of variables that match the message string and that is passed into the t() function.',
-      ],
-      'timestamp' => [
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-        'description' => 'Unix timestamp of when event occurred.',
-      ],
-    ],
-    'primary key' => ['id'],
-    'indexes' => [
-      'user_id' => ['user_id'],
-      'entity_id' => ['entity_id'],
-    ],
-  ];
-
-  return $schema;
-}
diff --git a/audit_log.links.menu.yml b/audit_log.links.menu.yml
new file mode 100644
index 0000000..3aa5c91
--- /dev/null
+++ b/audit_log.links.menu.yml
@@ -0,0 +1,7 @@
+
+# Audit log menu items definition
+audit_log.admin.structure.settings:
+  title: Audit log settings
+  description: 'Configure Audit log entities'
+  route_name: audit_log.settings
+  parent: system.admin_structure
diff --git a/audit_log.links.task.yml b/audit_log.links.task.yml
new file mode 100644
index 0000000..cefe18b
--- /dev/null
+++ b/audit_log.links.task.yml
@@ -0,0 +1,21 @@
+# Audit log routing definition
+audit_log.settings_tab:
+  route_name: audit_log.settings
+  title: 'Settings'
+  base_route: audit_log.settings
+
+entity.audit_log.canonical:
+  route_name: entity.audit_log.canonical
+  base_route: entity.audit_log.canonical
+  title: 'View'
+
+entity.audit_log.edit_form:
+  route_name: entity.audit_log.edit_form
+  base_route: entity.audit_log.canonical
+  title: 'Edit'
+
+entity.audit_log.delete_form:
+  route_name:  entity.audit_log.delete_form
+  base_route:  entity.audit_log.canonical
+  title: Delete
+  weight: 10
diff --git a/audit_log.module b/audit_log.module
index 2f4c1c9..4242764 100644
--- a/audit_log.module
+++ b/audit_log.module
@@ -5,6 +5,7 @@
  * Contains hook implementations for the audit_log module.
  */
 
+use Drupal\audit_log\Entity\AuditLogInterface;
 use Drupal\Core\Entity\EntityInterface;
 
 /**
diff --git a/audit_log.page.inc b/audit_log.page.inc
new file mode 100644
index 0000000..2b580ee
--- /dev/null
+++ b/audit_log.page.inc
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * @file
+ * Contains audit_log.page.inc.
+ *
+ * Page callback for Audit log entities.
+ */
+
+use Drupal\Core\Render\Element;
+
+/**
+ * Prepares variables for Audit log templates.
+ *
+ * Default template: audit_log.html.twig.
+ *
+ * @param array $variables
+ *   An associative array containing:
+ *   - elements: An associative array containing the user information and any
+ *   - attributes: HTML attributes for the containing element.
+ */
+function template_preprocess_audit_log(array &$variables) {
+  // Fetch AuditLog Entity Object.
+  $audit_log = $variables['elements']['#audit_log'];
+
+  // Helpful $content variable for templates.
+  foreach (Element::children($variables['elements']) as $key) {
+    $variables['content'][$key] = $variables['elements'][$key];
+  }
+}
diff --git a/audit_log.permissions.yml b/audit_log.permissions.yml
new file mode 100644
index 0000000..42a993b
--- /dev/null
+++ b/audit_log.permissions.yml
@@ -0,0 +1,16 @@
+add audit log entities:
+  title: 'Create new Audit log entities'
+
+administer audit log entities:
+  title: 'Administer Audit log entities'
+  description: 'Allow to access the administration form to configure Audit log entities.'
+  restrict access: true
+
+delete audit log entities:
+  title: 'Delete Audit log entities'
+
+edit audit log entities:
+  title: 'Edit Audit log entities'
+
+view audit log entities:
+  title: 'View Audit log entities'
diff --git a/audit_log.services.yml b/audit_log.services.yml
index e536006..efc2d11 100644
--- a/audit_log.services.yml
+++ b/audit_log.services.yml
@@ -23,3 +23,8 @@ services:
     class: Drupal\audit_log\EventSubscriber\User
     tags:
       - { name: audit_log_event_subscriber }
+
+  audit_log.event_subscriber.taxonomy:
+    class: Drupal\audit_log\EventSubscriber\Taxonomy
+    tags:
+      - { name: audit_log_event_subscriber }
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..23270d0
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,31 @@
+{
+    "name": "mitsuroseba/audit_log",
+    "type": "drupal-module",
+    "authors": [
+        {
+            "name": "Yuriy Boychenko",
+            "email": "yuboychenko@gmail.com"
+        },
+        {
+            "name": "Valeriy Garzha",
+            "email": "valeriy.garzha@ffwagency.com"
+        }
+    ],
+    "require": {
+        "drupal/csv_serialization": "^1.0",
+        "drupal/views_data_export": "^1.0@alpha",
+        "drupal/better_exposed_filters": "^3.0@alpha",
+        "drupal/deploy": "^1.0@beta",
+        "drupal/relaxed": "^1.0@beta"
+    },
+    "require-dev": {
+        "cweagans/composer-patches": "^1.6",
+        "behat/mink-selenium2-driver": "^1.3",
+        "drupal/coder": "^8.2",
+        "drupal/drupal-extension": "master-dev",
+        "bex/behat-screenshot": "^1.2",
+        "phpmd/phpmd": "^2.6",
+        "phpmetrics/phpmetrics": "^2.3"
+    },
+    "minimum-stability": "dev"
+}
diff --git a/config/schema/audit_log.schema.yml b/config/schema/audit_log.schema.yml
new file mode 100644
index 0000000..41a1f3e
--- /dev/null
+++ b/config/schema/audit_log.schema.yml
@@ -0,0 +1,7 @@
+views.filter.audit_log_date:
+  type: views_filter
+  label: 'audit_log_date numeric'
+
+views.filter_value.audit_log_date:
+  type: views.filter_value.numeric
+  label: 'audit_log_date Numeric'
diff --git a/phpunit.core.xml.dist b/phpunit.core.xml.dist
new file mode 100644
index 0000000..8c8c319
--- /dev/null
+++ b/phpunit.core.xml.dist
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- This based on Drupal's core phpunit.xml.dist. -->
+<!-- TODO set checkForUnintentionallyCoveredCode="true" once https://www.drupal.org/node/2626832 is resolved. -->
+<!-- PHPUnit expects functional tests to be run with either a privileged user
+ or your current system user. See core/tests/README.md and
+ https://www.drupal.org/node/2116263 for details.
+-->
+<phpunit bootstrap="tests/bootstrap.php" colors="true"
+         beStrictAboutTestsThatDoNotTestAnything="true"
+         beStrictAboutOutputDuringTests="true"
+         beStrictAboutChangesToGlobalState="true"
+         checkForUnintentionallyCoveredCode="false">
+<!-- TODO set printerClass="\Drupal\Tests\Listeners\HtmlOutputPrinter" once
+ https://youtrack.jetbrains.com/issue/WI-24808 is resolved. Drupal provides a
+ result printer that links to the html output results for functional tests.
+ Unfortunately, this breaks the output of PHPStorm's PHPUnit runner. However, if
+ using the command line you can add
+ - -printerClass="\Drupal\Tests\Listeners\HtmlOutputPrinter" to use it (note
+ there should be no spaces between the hyphens).
+-->
+  <php>
+    <!-- Set error reporting to E_ALL. -->
+    <ini name="error_reporting" value="32767"/>
+    <!-- Do not limit the amount of memory tests take to run. -->
+    <ini name="memory_limit" value="-1"/>
+    <!-- Example SIMPLETEST_BASE_URL value: http://localhost -->
+    <env name="SIMPLETEST_BASE_URL" value=""/>
+    <!-- Example SIMPLETEST_DB value: mysql://username:password@localhost/databasename#table_prefix -->
+    <env name="SIMPLETEST_DB" value=""/>
+    <!-- Example BROWSERTEST_OUTPUT_DIRECTORY value: /path/to/webroot/sites/simpletest/browser_output -->
+    <env name="BROWSERTEST_OUTPUT_DIRECTORY" value=""/>
+  </php>
+  <testsuites>
+    <testsuite name="unit">
+      <file>./tests/TestSuites/UnitTestSuite.php</file>
+    </testsuite>
+    <testsuite name="kernel">
+      <file>./tests/TestSuites/KernelTestSuite.php</file>
+    </testsuite>
+    <testsuite name="functional">
+      <file>./tests/TestSuites/FunctionalTestSuite.php</file>
+    </testsuite>
+    <testsuite name="nonfunctional">
+      <file>./tests/TestSuites/UnitTestSuite.php</file>
+      <file>./tests/TestSuites/KernelTestSuite.php</file>
+    </testsuite>
+  </testsuites>
+  <listeners>
+    <listener class="\Drupal\Tests\Listeners\DrupalStandardsListener">
+    </listener>
+  </listeners>
+  <!-- Filter for coverage reports. -->
+  <filter>
+    <whitelist processUncoveredFilesFromWhitelist="true">
+      <directory>../modules/audit_log</directory>
+      <exclude>
+        <directory>../modules/audit_log/tests</directory>
+        <directory>../modules/audit_log/test_modules</directory>
+      </exclude>
+    </whitelist>
+  </filter>
+</phpunit>
diff --git a/src/AuditLogAccessControlHandler.php b/src/AuditLogAccessControlHandler.php
new file mode 100644
index 0000000..46bcd62
--- /dev/null
+++ b/src/AuditLogAccessControlHandler.php
@@ -0,0 +1,44 @@
+<?php
+
+namespace Drupal\audit_log;
+
+use Drupal\Core\Entity\EntityAccessControlHandler;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\Access\AccessResult;
+
+/**
+ * Access controller for the Audit log entity.
+ *
+ * @see \Drupal\audit_log\Entity\AuditLog.
+ */
+class AuditLogAccessControlHandler extends EntityAccessControlHandler {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
+    /** @var \Drupal\audit_log\Entity\AuditLogInterface $entity */
+    switch ($operation) {
+      case 'view':
+        return AccessResult::allowedIfHasPermission($account, 'view audit log entities');
+
+      case 'update':
+        return AccessResult::allowedIfHasPermission($account, 'edit audit log entities');
+
+      case 'delete':
+        return AccessResult::allowedIfHasPermission($account, 'delete audit log entities');
+    }
+
+    // Unknown operation, no opinion.
+    return AccessResult::neutral();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function checkCreateAccess(AccountInterface $account, array $context, $entity_bundle = NULL) {
+    return AccessResult::allowedIfHasPermission($account, 'add audit log entities');
+  }
+
+}
diff --git a/src/AuditLogEvent.php b/src/AuditLogEvent.php
index a4819dd..4b8a392 100644
--- a/src/AuditLogEvent.php
+++ b/src/AuditLogEvent.php
@@ -94,7 +94,7 @@ class AuditLogEvent implements AuditLogEventInterface {
   /**
    * {@inheritdoc}
    */
-  public function setMessagePlaceholders($variables) {
+  public function setMessagePlaceholders(array $variables) {
     $this->messagePlaceholders = $variables;
     return $this;
   }
diff --git a/src/AuditLogEventInterface.php b/src/AuditLogEventInterface.php
index d03cea1..7196566 100644
--- a/src/AuditLogEventInterface.php
+++ b/src/AuditLogEventInterface.php
@@ -54,7 +54,7 @@ interface AuditLogEventInterface {
    * @return AuditLogEventInterface
    *   The current instance of the event.
    */
-  public function setMessagePlaceholders($variables);
+  public function setMessagePlaceholders(array $variables);
 
   /**
    * Stores the type of event being reported.
@@ -161,6 +161,7 @@ interface AuditLogEventInterface {
    * The timestamp for when the event was initiated.
    *
    * @return int
+   *   Timestamp value.
    */
   public function getRequestTime();
 
diff --git a/src/AuditLogHtmlRouteProvider.php b/src/AuditLogHtmlRouteProvider.php
new file mode 100644
index 0000000..136579b
--- /dev/null
+++ b/src/AuditLogHtmlRouteProvider.php
@@ -0,0 +1,56 @@
+<?php
+
+namespace Drupal\audit_log;
+
+use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\Entity\Routing\AdminHtmlRouteProvider;
+use Symfony\Component\Routing\Route;
+
+/**
+ * Provides routes for Audit log entities.
+ *
+ * @see \Drupal\Core\Entity\Routing\AdminHtmlRouteProvider
+ * @see \Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider
+ */
+class AuditLogHtmlRouteProvider extends AdminHtmlRouteProvider {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getRoutes(EntityTypeInterface $entity_type) {
+    $collection = parent::getRoutes($entity_type);
+
+    $entity_type_id = $entity_type->id();
+
+    if ($settings_form_route = $this->getSettingsFormRoute($entity_type)) {
+      $collection->add("$entity_type_id.settings", $settings_form_route);
+    }
+
+    return $collection;
+  }
+
+  /**
+   * Gets the settings form route.
+   *
+   * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
+   *   The entity type.
+   *
+   * @return \Symfony\Component\Routing\Route|null
+   *   The generated route, if available.
+   */
+  protected function getSettingsFormRoute(EntityTypeInterface $entity_type) {
+    if (!$entity_type->getBundleEntityType()) {
+      $route = new Route("/admin/structure/{$entity_type->id()}/settings");
+      $route
+        ->setDefaults([
+          '_form' => 'Drupal\audit_log\Form\AuditLogSettingsForm',
+          '_title' => "{$entity_type->getLabel()} settings",
+        ])
+        ->setRequirement('_permission', $entity_type->getAdminPermission())
+        ->setOption('_admin_route', TRUE);
+
+      return $route;
+    }
+  }
+
+}
diff --git a/src/AuditLogLogger.php b/src/AuditLogLogger.php
index bb5292e..8ce7082 100644
--- a/src/AuditLogLogger.php
+++ b/src/AuditLogLogger.php
@@ -32,7 +32,7 @@ class AuditLogLogger {
     $event->setUser($account);
     $event->setEntity($entity);
     $event->setEventType($event_type);
-    $event->setRequestTime(REQUEST_TIME);
+    $event->setRequestTime(\Drupal::time()->getRequestTime());
 
     foreach ($this->sortEventSubscribers() as $event_subscriber) {
       if ($event_subscriber->reactTo($event)) {
@@ -60,6 +60,13 @@ class AuditLogLogger {
     $this->entityEventEventSubscribers[$priority][] = $event_subscriber;
   }
 
+  /**
+   * Get event subscribers.
+   */
+  public function getEventSubscribers() {
+    return $this->sortEventSubscribers();
+  }
+
   /**
    * Sorts the available event subscribers by priority.
    *
diff --git a/src/AuditLogStorage.php b/src/AuditLogStorage.php
index 922b24a..1186848 100644
--- a/src/AuditLogStorage.php
+++ b/src/AuditLogStorage.php
@@ -15,7 +15,7 @@ class AuditLogStorage {
    *
    * @var array
    */
-  protected $storage_backends;
+  protected $storageBackends;
 
   /**
    * Writes the audit event to each available logging destination.
@@ -43,7 +43,7 @@ class AuditLogStorage {
    *   before higher number storage backend s.
    */
   public function addStorageBackend(StorageBackendInterface $storage_backend, $priority = 0) {
-    $this->storage_backends[$priority][] = $storage_backend;
+    $this->storageBackends[$priority][] = $storage_backend;
   }
 
   /**
@@ -54,9 +54,9 @@ class AuditLogStorage {
    */
   protected function sortStorageBackends() {
     $sorted = [];
-    krsort($this->storage_backends);
+    krsort($this->storageBackends);
 
-    foreach ($this->storage_backends as $storage_backends) {
+    foreach ($this->storageBackends as $storage_backends) {
       $sorted = array_merge($sorted, $storage_backends);
     }
     return $sorted;
diff --git a/src/Entity/AuditLog.php b/src/Entity/AuditLog.php
new file mode 100644
index 0000000..f7f876e
--- /dev/null
+++ b/src/Entity/AuditLog.php
@@ -0,0 +1,194 @@
+<?php
+
+namespace Drupal\audit_log\Entity;
+
+use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\Core\Field\BaseFieldDefinition;
+use Drupal\Core\Entity\ContentEntityBase;
+use Drupal\Core\Entity\EntityChangedTrait;
+use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\user\UserInterface;
+
+/**
+ * Defines the Audit log entity.
+ *
+ * @ingroup audit_log
+ *
+ * @ContentEntityType(
+ *   id = "audit_log",
+ *   label = @Translation("Audit log"),
+ *   handlers = {
+ *     "view_builder" = "Drupal\Core\Entity\EntityViewBuilder",
+ *     "views_data" = "Drupal\audit_log\Entity\AuditLogViewsData",
+ *     "form" = {
+ *       "default" = "Drupal\audit_log\Form\AuditLogForm",
+ *     },
+ *     "access" = "Drupal\audit_log\AuditLogAccessControlHandler",
+ *     "route_provider" = {
+ *       "html" = "Drupal\audit_log\AuditLogHtmlRouteProvider",
+ *     },
+ *   },
+ *   base_table = "audit_log",
+ *   admin_permission = "administer audit log entities",
+ *   entity_keys = {
+ *     "id" = "id",
+ *     "label" = "name",
+ *     "uuid" = "uuid",
+ *     "uid" = "user_id",
+ *     "langcode" = "langcode",
+ *   }
+ * )
+ */
+class AuditLog extends ContentEntityBase implements AuditLogInterface {
+
+  use EntityChangedTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function preCreate(EntityStorageInterface $storage_controller, array &$values) {
+    parent::preCreate($storage_controller, $values);
+    $values += [
+      'user_id' => \Drupal::currentUser()->id(),
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function label() {
+    return $this->getMessage();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCreatedTime() {
+    return $this->get('created')->value;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setCreatedTime($timestamp) {
+    $this->set('created', $timestamp);
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getOwner() {
+    return $this->get('user_id')->entity;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getOwnerId() {
+    return $this->get('user_id')->target_id;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getType() {
+    return $this->get('entity_type')->value;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getEvent() {
+    return $this->get('event')->value;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getMessage() {
+    return $this->get('message')->value;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDate() {
+    return $this->get('created')->value;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setOwnerId($uid) {
+    $this->set('user_id', $uid);
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getWorkspace() {
+    // @TODO fix it.
+    return 'live';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setOwner(UserInterface $account) {
+    $this->set('user_id', $account->id());
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
+    $fields = parent::baseFieldDefinitions($entity_type);
+
+    $fields['user_id'] = BaseFieldDefinition::create('entity_reference')
+      ->setLabel(t('Authored by'))
+      ->setDescription(t('The user ID of author of the Audit log entity.'))
+      ->setSetting('target_type', 'user');
+
+    $fields['entity_id'] = BaseFieldDefinition::create('entity_reference')
+      ->setLabel(t('Target entity'))
+      ->setDescription(t('The entity id of the entity that was created, modified or deleted.'));
+
+    $fields['entity_type'] = BaseFieldDefinition::create('string')
+      ->setLabel(t('Target entity type'))
+      ->setDescription(t('The target entity type.'));
+
+    $fields['event'] = BaseFieldDefinition::create('string')
+      ->setLabel(t('Event'))
+      ->setDescription(t('The event type, usually insert, update or delete.'));
+
+    $fields['previous_state'] = BaseFieldDefinition::create('string')
+      ->setLabel(t('Previous state'))
+      ->setDescription(t('The previous state of the entity if available.'));
+
+    $fields['current_state'] = BaseFieldDefinition::create('string')
+      ->setLabel(t('Current state'))
+      ->setDescription(t('The current state of the entity if available.'));
+
+    $fields['message'] = BaseFieldDefinition::create('string_long')
+      ->setLabel(t('Text of log message'))
+      ->setDescription(t('Text of log message to be passed into the t() function.'));
+
+    $fields['variables'] = BaseFieldDefinition::create('map')
+      ->setLabel(t('Variables of log message'))
+      ->setDescription(t('Serialized array of variables that match the message string and that is passed into the t() function.'));
+
+    $fields['created'] = BaseFieldDefinition::create('created')
+      ->setLabel(t('Created'))
+      ->setDescription(t('The time that the entity was created.'));
+
+    $fields['changed'] = BaseFieldDefinition::create('changed')
+      ->setLabel(t('Changed'))
+      ->setDescription(t('The time that the entity was last edited.'));
+
+    return $fields;
+  }
+
+}
diff --git a/src/Entity/AuditLogInterface.php b/src/Entity/AuditLogInterface.php
new file mode 100644
index 0000000..bcd130a
--- /dev/null
+++ b/src/Entity/AuditLogInterface.php
@@ -0,0 +1,35 @@
+<?php
+
+namespace Drupal\audit_log\Entity;
+
+use Drupal\Core\Entity\ContentEntityInterface;
+use Drupal\Core\Entity\EntityChangedInterface;
+use Drupal\user\EntityOwnerInterface;
+
+/**
+ * Provides an interface for defining Audit log entities.
+ *
+ * @ingroup audit_log
+ */
+interface AuditLogInterface extends ContentEntityInterface, EntityChangedInterface, EntityOwnerInterface {
+
+  /**
+   * Gets the Audit log creation timestamp.
+   *
+   * @return int
+   *   Creation timestamp of the Audit log.
+   */
+  public function getCreatedTime();
+
+  /**
+   * Sets the Audit log creation timestamp.
+   *
+   * @param int $timestamp
+   *   The Audit log creation timestamp.
+   *
+   * @return \Drupal\audit_log\Entity\AuditLogInterface
+   *   The called Audit log entity.
+   */
+  public function setCreatedTime($timestamp);
+
+}
diff --git a/src/Entity/AuditLogViewsData.php b/src/Entity/AuditLogViewsData.php
new file mode 100644
index 0000000..d3cfa2c
--- /dev/null
+++ b/src/Entity/AuditLogViewsData.php
@@ -0,0 +1,72 @@
+<?php
+
+namespace Drupal\audit_log\Entity;
+
+use Drupal\views\EntityViewsData;
+
+/**
+ * Provides Views data for Audit log entities.
+ */
+class AuditLogViewsData extends EntityViewsData {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getViewsData() {
+    $data = parent::getViewsData();
+
+    $data['audit_log']['target_entity_view_link'] = [
+      'title' => $this->t('Target entity view link'),
+      'real field' => 'entity_id',
+      'field' => [
+        'id' => 'audit_log_target_view_link',
+      ],
+    ];
+
+    $data['audit_log']['event']['filter'] = [
+      'id' => 'in_operator',
+      'options callback' => 'Drupal\audit_log\Entity\AuditLogViewsData::getEventOptions',
+    ];
+
+    $data['audit_log']['entity_type']['filter'] = [
+      'id' => 'in_operator',
+      'options callback' => 'Drupal\audit_log\Entity\AuditLogViewsData::getEntityTypeOptions',
+    ];
+
+    $data['audit_log']['created']['filter']['id'] = 'audit_log_date';
+
+    return $data;
+  }
+
+  /**
+   * Get event options.
+   */
+  public static function getEventOptions() {
+    return [
+      'insert' => t('Insert'),
+      'update' => t('Update'),
+      'delete' => t('Delete'),
+    ];
+  }
+
+  /**
+   * Get entity type options.
+   */
+  public static function getEntityTypeOptions() {
+    $entity_manager = \Drupal::entityTypeManager();
+    $subscribers = \Drupal::service('audit_log.logger')->getEventSubscribers();
+    $return = [];
+
+    /* @var \Drupal\audit_log\EventSubscriber\EventSubscriberInterface[] $subscribers */
+    foreach ($subscribers as $subscriber) {
+      $entity_type = $subscriber->getEntityType();
+      if ($entity_manager->hasDefinition($entity_type)) {
+        $definition = $entity_manager->getDefinition($entity_type);
+        $return[$entity_type] = $definition->getLabel();
+      }
+    }
+
+    return $return;
+  }
+
+}
diff --git a/src/EventSubscriber/EventSubscriberInterface.php b/src/EventSubscriber/EventSubscriberInterface.php
index 085858b..5c9c615 100644
--- a/src/EventSubscriber/EventSubscriberInterface.php
+++ b/src/EventSubscriber/EventSubscriberInterface.php
@@ -22,4 +22,9 @@ interface EventSubscriberInterface {
    */
   public function reactTo(AuditLogEventInterface $event);
 
+  /**
+   * Return entity type machine name.
+   */
+  public function getEntityType();
+
 }
diff --git a/src/EventSubscriber/Node.php b/src/EventSubscriber/Node.php
index 3a8b99b..190d27f 100644
--- a/src/EventSubscriber/Node.php
+++ b/src/EventSubscriber/Node.php
@@ -3,6 +3,7 @@
 namespace Drupal\audit_log\EventSubscriber;
 
 use Drupal\audit_log\AuditLogEventInterface;
+use Drupal\Core\Render\Markup;
 
 /**
  * Processes node entity events.
@@ -16,7 +17,7 @@ class Node implements EventSubscriberInterface {
    */
   public function reactTo(AuditLogEventInterface $event) {
     $entity = $event->getEntity();
-    if ($entity->getEntityTypeId() != 'node') {
+    if ($entity->getEntityTypeId() != $this->getEntityType()) {
       return FALSE;
     }
     $event_type = $event->getEventType();
@@ -26,12 +27,13 @@ class Node implements EventSubscriberInterface {
     if (isset($entity->original)) {
       $previous_state = $entity->original->isPublished() ? 'published' : 'unpublished';
     }
-    $args = ['@title' => $entity->getTitle()];
+    $args = [
+      '@title' => Markup::create($entity->label()),
+    ];
 
     if ($event_type == 'insert') {
       $event
-        ->setMessage('@name was created.')
-        ->setMessagePlaceholders(['@name' => $entity->label()])
+        ->setMessage(t('@title was created.', $args))
         ->setPreviousState(NULL)
         ->setCurrentState($current_state);
       return TRUE;
@@ -39,8 +41,7 @@ class Node implements EventSubscriberInterface {
 
     if ($event_type == 'update') {
       $event
-        ->setMessage('@name was updated.')
-        ->setMessagePlaceholders(['@name' => $entity->label()])
+        ->setMessage(t('@title was updated.', $args))
         ->setPreviousState($previous_state)
         ->setCurrentState($current_state);
       return TRUE;
@@ -48,8 +49,7 @@ class Node implements EventSubscriberInterface {
 
     if ($event_type == 'delete') {
       $event
-        ->setMessage('@name was deleted.')
-        ->setMessagePlaceholders(['@name' => $entity->label()])
+        ->setMessage(t('@title was deleted.', $args))
         ->setPreviousState($previous_state)
         ->setCurrentState(NULL);
       return TRUE;
@@ -58,4 +58,11 @@ class Node implements EventSubscriberInterface {
     return FALSE;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getEntityType() {
+    return 'node';
+  }
+
 }
diff --git a/src/EventSubscriber/Taxonomy.php b/src/EventSubscriber/Taxonomy.php
new file mode 100644
index 0000000..f078d9a
--- /dev/null
+++ b/src/EventSubscriber/Taxonomy.php
@@ -0,0 +1,68 @@
+<?php
+
+namespace Drupal\audit_log\EventSubscriber;
+
+use Drupal\audit_log\AuditLogEventInterface;
+use Drupal\Core\Render\Markup;
+
+/**
+ * Processes taxonomy_term entity events.
+ *
+ * @package Drupal\audit_log\EventSubscriber
+ */
+class Taxonomy implements EventSubscriberInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function reactTo(AuditLogEventInterface $event) {
+    $entity = $event->getEntity();
+    if (!in_array($entity->getEntityTypeId(), [$this->getEntityType()])) {
+      return FALSE;
+    }
+
+    $event_type = $event->getEventType();
+
+    $current_state = $previous_state = 'active';
+
+    /** @var \Drupal\taxonomy\Entity\Term $entity */
+    $args = [
+      '@title' => Markup::create($entity->getName()),
+      '@voc' => Markup::create($entity->getVocabularyId()),
+    ];
+
+    if ($event_type == 'insert') {
+      $event
+        ->setMessage(t('@title term has been added to @voc vocabulary.', $args))
+        ->setPreviousState(NULL)
+        ->setCurrentState($current_state);
+      return TRUE;
+    }
+
+    if ($event_type == 'update') {
+      $event
+        ->setMessage(t('@title term has been update in @voc vocabulary.', $args))
+        ->setPreviousState($previous_state)
+        ->setCurrentState($current_state);
+      return TRUE;
+    }
+
+    if ($event_type == 'delete') {
+      $event
+        ->setMessage(t('@title term has been deleted from @voc vocabulary.', $args))
+        ->setPreviousState($previous_state)
+        ->setCurrentState(NULL);
+      return TRUE;
+    }
+
+    return FALSE;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getEntityType() {
+    return 'taxonomy_term';
+  }
+
+}
diff --git a/src/EventSubscriber/User.php b/src/EventSubscriber/User.php
index aad2e17..df0f498 100644
--- a/src/EventSubscriber/User.php
+++ b/src/EventSubscriber/User.php
@@ -3,6 +3,7 @@
 namespace Drupal\audit_log\EventSubscriber;
 
 use Drupal\audit_log\AuditLogEventInterface;
+use Drupal\Core\Render\Markup;
 use Drupal\user\UserInterface;
 
 /**
@@ -16,12 +17,13 @@ class User implements EventSubscriberInterface {
    * {@inheritdoc}
    */
   public function reactTo(AuditLogEventInterface $event) {
+    /** @var \Drupal\user\Entity\User $entity */
     $entity = $event->getEntity();
-    if ($entity->getEntityTypeId() != 'user') {
+    if ($entity->getEntityTypeId() != $this->getEntityType()) {
       return FALSE;
     }
     $event_type = $event->getEventType();
-    $args = ['@name' => $entity->label()];
+    $args = ['@name' => Markup::create($entity->label())];
     $current_state = $entity->status->value ? 'active' : 'blocked';
     $original_state = NULL;
     if (isset($entity->original) && $entity->original instanceof UserInterface) {
@@ -46,7 +48,7 @@ class User implements EventSubscriberInterface {
 
     if ($event_type == 'delete') {
       $event
-        ->setMessage(t('@name was updated.', $args))
+        ->setMessage(t('@name was deleted.', $args))
         ->setPreviousState($original_state)
         ->setCurrentState(NULL);
       return TRUE;
@@ -55,4 +57,11 @@ class User implements EventSubscriberInterface {
     return FALSE;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getEntityType() {
+    return 'user';
+  }
+
 }
diff --git a/src/Plugin/views/field/AuditLogTargetViewLink.php b/src/Plugin/views/field/AuditLogTargetViewLink.php
new file mode 100644
index 0000000..43525da
--- /dev/null
+++ b/src/Plugin/views/field/AuditLogTargetViewLink.php
@@ -0,0 +1,33 @@
+<?php
+
+namespace Drupal\audit_log\Plugin\views\field;
+
+use Drupal\views\Plugin\views\field\FieldPluginBase;
+use Drupal\views\ResultRow;
+
+/**
+ * Provides a target entity view link.
+ *
+ * @ViewsField("audit_log_target_view_link")
+ */
+class AuditLogTargetViewLink extends FieldPluginBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function render(ResultRow $row) {
+    $entity = $this->getEntity($row);
+
+    $target_entity = \Drupal::entityTypeManager()->getStorage($entity->entity_type->value)->load($entity->entity_id->target_id);
+
+    if (isset($target_entity)) {
+      return $target_entity->toLink($entity->label())->toRenderable();
+    }
+    else {
+      return [
+        '#markup' => $entity->label(),
+      ];
+    }
+  }
+
+}
diff --git a/src/Plugin/views/filter/AuditLogDate.php b/src/Plugin/views/filter/AuditLogDate.php
new file mode 100644
index 0000000..4ea4fc0
--- /dev/null
+++ b/src/Plugin/views/filter/AuditLogDate.php
@@ -0,0 +1,34 @@
+<?php
+
+namespace Drupal\audit_log\Plugin\views\filter;
+
+use Drupal\views\Plugin\views\filter\Date;
+
+/**
+ * Filter to handle dates stored as a timestamp.
+ *
+ * @ingroup views_filter_handlers
+ *
+ * @ViewsFilter("audit_log_date")
+ */
+class AuditLogDate extends Date {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function opSimple($field) {
+    $a = intval(strtotime($this->value['value'], 0));
+    $b = intval(strtotime($this->value['value'], 0)) + 24 * 60 * 60;
+
+    if ($this->value['type'] == 'offset') {
+      // Keep sign.
+      $a = '***CURRENT_TIME***' . sprintf('%+d', $a);
+      // Keep sign.
+      $b = '***CURRENT_TIME***' . sprintf('%+d', $b);
+    }
+
+    $operator = strtoupper('between');
+    $this->query->addWhereExpression($this->options['group'], "$field $operator $a AND $b");
+  }
+
+}
diff --git a/src/StorageBackend/Database.php b/src/StorageBackend/Database.php
index b78f81e..6548c0e 100644
--- a/src/StorageBackend/Database.php
+++ b/src/StorageBackend/Database.php
@@ -3,6 +3,7 @@
 namespace Drupal\audit_log\StorageBackend;
 
 use Drupal\audit_log\AuditLogEventInterface;
+use Drupal\audit_log\Entity\AuditLog;
 
 /**
  * Writes audit events to a custom database table.
@@ -15,22 +16,18 @@ class Database implements StorageBackendInterface {
    * {@inheritdoc}
    */
   public function save(AuditLogEventInterface $event) {
-    $connection = \Drupal::database();
+    $values = [
+      'entity_id' => $event->getEntity()->id(),
+      'entity_type' => $event->getEntity()->getEntityTypeId(),
+      'event' => $event->getEventType(),
+      'previous_state' => $event->getPreviousState(),
+      'current_state' => $event->getCurrentState(),
+      'message' => $event->getMessage(),
+    ];
 
-    $connection
-      ->insert('audit_log')
-      ->fields([
-        'entity_id' => $event->getEntity()->id(),
-        'entity_type' => $event->getEntity()->getEntityTypeId(),
-        'user_id' => $event->getUser()->id(),
-        'event' => $event->getEventType(),
-        'previous_state' => $event->getPreviousState(),
-        'current_state' => $event->getCurrentState(),
-        'message' => $event->getMessage(),
-        'variables' => serialize($event->getMessagePlaceholders()),
-        'timestamp' => $event->getRequestTime(),
-      ])
-      ->execute();
+    \Drupal::moduleHandler()->alter('audit_log_save', $values, $event);
+
+    AuditLog::create($values)->save();
   }
 
 }
diff --git a/templates/audit_log.html.twig b/templates/audit_log.html.twig
new file mode 100644
index 0000000..da5e07b
--- /dev/null
+++ b/templates/audit_log.html.twig
@@ -0,0 +1,22 @@
+{#
+/**
+ * @file audit_log.html.twig
+ * Default theme implementation to present Audit log data.
+ *
+ * This template is used when viewing Audit log pages.
+ *
+ *
+ * Available variables:
+ * - content: A list of content items. Use 'content' to print all content, or
+ * - attributes: HTML attributes for the container element.
+ *
+ * @see template_preprocess_audit_log()
+ *
+ * @ingroup themeable
+ */
+#}
+<div{{ attributes.addClass('audit_log') }}>
+  {% if content %}
+    {{- content -}}
+  {% endif %}
+</div>
diff --git a/tests/src/Behat/behat.yml b/tests/src/Behat/behat.yml
new file mode 100644
index 0000000..848c123
--- /dev/null
+++ b/tests/src/Behat/behat.yml
@@ -0,0 +1,38 @@
+default:
+  suites:
+    default:
+      contexts:
+        - AuditLogFeatureContext
+        - Drupal\DrupalExtension\Context\DrupalContext
+        - Drupal\DrupalExtension\Context\MinkContext
+        - Drupal\DrupalExtension\Context\MessageContext
+  extensions:
+    Behat\MinkExtension:
+      goutte: ~
+      selenium2: ~
+      base_url: http://localhost
+      sessions:
+        default:
+          goutte: ~
+        javascript:
+          selenium2:
+            browser: phantomjs
+            wd_host: http://localhost:8910/wd/hub
+    Drupal\DrupalExtension:
+      blackbox: ~
+      api_driver: 'drupal'
+      drush:
+        alias: 'local'
+      drupal:
+        drupal_root: '/var/www/html'
+      region_map:
+        footer: "#footer"
+      selectors:
+        message_selector: '.messages'
+        error_message_selector: '.messages--error'
+        success_message_selector: '.messages--status'
+    Bex\Behat\ScreenshotExtension:
+      screenshot_taking_mode: all_scenarios
+      image_drivers:
+        local:
+          screenshot_directory: '/var/www/html/artifacts/screenshots'
diff --git a/tests/src/Behat/example.behat.local.yml b/tests/src/Behat/example.behat.local.yml
new file mode 100644
index 0000000..19e1999
--- /dev/null
+++ b/tests/src/Behat/example.behat.local.yml
@@ -0,0 +1,31 @@
+# Local Behat configuration file.
+#
+# See the testing section of the [README.md](README.md) to learn how to use this file.
+default:
+  suites:
+    default:
+      contexts:
+        - AuditLogFeatureContext
+        - Drupal\DrupalExtension\Context\DrupalContext
+        - Drupal\DrupalExtension\Context\MinkContext
+        - Drupal\DrupalExtension\Context\MessageContext
+  extensions:
+    Behat\MinkExtension:
+      goutte: ~
+      selenium2:
+        wd_host: http://MY-IP-ADDRESS:4444/wd/hub
+      base_url: http://localhost:8080
+      browser_name: 'chrome'
+    Drupal\DrupalExtension:
+      blackbox: ~
+      api_driver: 'drupal'
+      drush:
+        alias: 'local'
+      drupal:
+        drupal_root: '/var/www/docroot'
+      region_map:
+        footer: "#footer"
+      selectors:
+        message_selector: '.messages'
+        error_message_selector: '.messages.messages--error'
+        success_message_selector: '.messages.messages--status'
diff --git a/tests/src/Behat/features/bootstrap/AuditLogFeatureContext.php b/tests/src/Behat/features/bootstrap/AuditLogFeatureContext.php
new file mode 100644
index 0000000..9aa57a5
--- /dev/null
+++ b/tests/src/Behat/features/bootstrap/AuditLogFeatureContext.php
@@ -0,0 +1,33 @@
+<?php
+
+use Behat\Behat\Context\SnippetAcceptingContext;
+use Behat\Testwork\Hook\Scope\BeforeSuiteScope;
+use Drupal\DrupalExtension\Context\RawDrupalContext;
+
+/**
+ * Behat steps for testing the audit_log module.
+ *
+ * @codingStandardsIgnoreStart
+ */
+class AuditLogFeatureContext extends RawDrupalContext implements SnippetAcceptingContext {
+
+  /**
+   * Setup for the test suite, enable some required modules and add content
+   * title.
+   *
+   * @BeforeSuite
+   */
+  public static function prepare(BeforeSuiteScope $scope) {
+    /** @var \Drupal\Core\Extension\ModuleHandler $moduleHandler */
+    $moduleHandler = \Drupal::service('module_handler');
+    if (!$moduleHandler->moduleExists('audit_log')) {
+      \Drupal::service('module_installer')->install(['audit_log']);
+    }
+
+    // Also uninstall the inline form errors module for easier testing.
+    if ($moduleHandler->moduleExists('inline_form_errors')) {
+      \Drupal::service('module_installer')->uninstall(['inline_form_errors']);
+    }
+  }
+
+}
diff --git a/tests/src/Functional/NodeTest.php b/tests/src/Functional/NodeTest.php
index 519e92b..b377bec 100644
--- a/tests/src/Functional/NodeTest.php
+++ b/tests/src/Functional/NodeTest.php
@@ -22,8 +22,11 @@ class NodeTest extends NodeTestBase {
   /**
    * {@inheritdoc}
    */
-  public static $modules = ['node_test', 'audit_log'];
+  public static $modules = ['node_test', 'audit_log', 'views'];
 
+  /**
+   * {@inheritdoc}
+   */
   protected function setUp() {
     parent::setUp();
 
@@ -35,7 +38,7 @@ class NodeTest extends NodeTestBase {
   /**
    * Tests audit log functionality on node crud operations.
    */
-  public function testNodeCRUD() {
+  public function testNodeCrud() {
     $count = db_query("SELECT COUNT(id) FROM {audit_log} WHERE entity_type = 'node'")->fetchField();
     $this->assertEquals(0, $count);
 
diff --git a/tests/src/Kernel/AuditLogDatabaseTest.php b/tests/src/Kernel/AuditLogDatabaseTest.php
index 8d1da15..5f4ee61 100644
--- a/tests/src/Kernel/AuditLogDatabaseTest.php
+++ b/tests/src/Kernel/AuditLogDatabaseTest.php
@@ -24,7 +24,7 @@ class AuditLogDatabaseTest extends KernelTestBase {
 
     $this->installSchema('system', ['sequences']);
     $this->installEntitySchema('user');
-    $this->installSchema('audit_log', ['audit_log']);
+    $this->installEntitySchema('audit_log');
   }
 
   /**
diff --git a/tests/src/Unit/AuditLogEventTest.php b/tests/src/Unit/AuditLogEventTest.php
index f39f347..deb0386 100644
--- a/tests/src/Unit/AuditLogEventTest.php
+++ b/tests/src/Unit/AuditLogEventTest.php
@@ -24,7 +24,6 @@ class AuditLogEventTest extends UnitTestCase {
     /** @var \Drupal\Core\Entity\EntityInterface $entity */
     $entity = $this->getMock(EntityInterface::class);
 
-
     $timestamp = time();
 
     $event = new AuditLogEvent();
