diff --git a/CRM/Civirules/Utils/HookInvoker.php b/CRM/Civirules/Utils/HookInvoker.php
new file mode 100644
index 0000000000000000000000000000000000000000..d7f9708c1d345d10e53d5b323c2bc95a6aef26f7
--- /dev/null
+++ b/CRM/Civirules/Utils/HookInvoker.php
@@ -0,0 +1,48 @@
+<?php
+
+/**
+ * Class CRM_Civirules_Utils_HookInvoker
+ *
+ * This class invokes hooks through the civicrm core hook invoker functionality
+ */
+class CRM_Civirules_Utils_HookInvoker {
+
+  private static $singleton;
+
+  private function __construct() {
+
+  }
+
+  public static function singleton() {
+    if (!self::$singleton) {
+      self::$singleton = new CRM_Civirules_Utils_HookInvoker();
+    }
+    return self::$singleton;
+  }
+
+  /**
+   * hook_civicrm_civirules_logger
+   *
+   * @param \Psr\Log\LoggerInterface|NULL $logger
+   *
+   * This hook could set a logger class for Civirules
+   */
+  public function hook_civirules_getlogger(&$logger = null) {
+    $this->invoke('civirules_logger', 1, $logger);
+    if ($logger && !$logger instanceof \Psr\Log\LoggerInterface) {
+      $logger = null;
+    }
+  }
+
+  private function invoke($fnSuffix, $numParams, &$arg1 = null, &$arg2 = null, &$arg3 = null, &$arg4 = null, &$arg5 = null) {
+    $hook =  CRM_Utils_Hook::singleton();
+    $civiVersion = CRM_Core_BAO_Domain::version();
+    if (version_compare('4.4', $civiVersion, '<=')) {
+      //in CiviCRM 4.4 the invoke function has 5 arguments maximum
+      return $hook->invoke($numParams, $arg1, $arg2, $arg3, $arg4, $arg5, $fnSuffix);
+    }
+    //in CiviCRM 4.5 and later the invoke function has 6 arguments
+    return $hook->invoke($numParams, $arg1, $arg2, $arg3, $arg4, $arg5, null, $fnSuffix);
+  }
+
+}
\ No newline at end of file
diff --git a/CRM/Civirules/Utils/LoggerFactory.php b/CRM/Civirules/Utils/LoggerFactory.php
new file mode 100644
index 0000000000000000000000000000000000000000..4cfce4c579ebc4152237bd45391f6e14bcbe7fba
--- /dev/null
+++ b/CRM/Civirules/Utils/LoggerFactory.php
@@ -0,0 +1,35 @@
+<?php
+
+class CRM_Civirules_Utils_LoggerFactory {
+
+  private static $logger = null;
+
+  private static $loggerHookInvoked = false;
+
+  /**
+   * @return \Psr\Log\LoggerInterface|NULL
+   */
+  public static function getLogger() {
+    if (empty(self::$logger) && self::$loggerHookInvoked === false) {
+      $hook = CRM_Civirules_Utils_HookInvoker::singleton();
+      $hook->hook_civirules_getlogger(self::$logger);
+      self::$loggerHookInvoked = true;
+    }
+    return self::$logger;
+  }
+
+  public static function logError($reason, $original_error, CRM_Civirules_EventData_EventData $eventData, $context=array()) {
+    $logger = CRM_Civirules_Utils_LoggerFactory::getLogger();
+    if (empty($logger)) {
+      return;
+    }
+    $error = "Rule: '{rule_title}' with id {rule_id} failed for contact {contact_id} because of {reason}";
+    $context['rule_id'] = $eventData->getEvent()->getRuleId();
+    $context['rule_title'] = $eventData->getEvent()->getRuleTitle();
+    $context['original_error'] = $original_error;
+    $context['contact_id'] = $eventData->getContactId();
+    $context['reason'] = $reason;
+    $logger->error($error, $context);
+  }
+
+}
\ No newline at end of file