diff --git a/composer.json b/composer.json
index 770472dce61194c6f44ba1a8a72568e19e2066b7..b35e00f55b75ce7dbeed89b86490c657e3c6d05a 100644
--- a/composer.json
+++ b/composer.json
@@ -8,7 +8,8 @@
     ],
     "require": {
         "php": ">=5.6",
-        "psr/log": "^1.0.1"
+        "psr/log": "^1.0.1",
+        "monolog/monolog": "^1.23"
     },
     "require-dev": {
         "phpunit/phpunit": "<7",
diff --git a/src/BasicLoggerFactory.php b/src/BasicLoggerFactory.php
new file mode 100644
index 0000000000000000000000000000000000000000..e9d1dd3ef2102cd36a8f69a6780ff6fc09dcac70
--- /dev/null
+++ b/src/BasicLoggerFactory.php
@@ -0,0 +1,50 @@
+<?php
+
+namespace WPDesk\Logger;
+
+use Monolog\Handler\HandlerInterface;
+use Monolog\Logger;
+use Monolog\Registry;
+
+/**
+ * Manages and facilitates creation of logger
+ *
+ * @package WPDesk\Logger
+ */
+class BasicLoggerFactory implements LoggerFactory
+{
+    /** @var string Last created logger name/channel */
+    private static $lastLoggerChannel;
+
+    /**
+     * Creates logger for plugin
+     *
+     * @param string $channel The logging channel
+     * @param HandlerInterface[] $handlers Optional stack of handlers, the first one in the array is called first, etc.
+     * @param callable[] $processors Optional array of processors
+     * @return Logger
+     */
+    public function createLogger($channel, $handlers = array(), array $processors = array())
+    {
+        if (Registry::hasLogger($channel)) {
+            return Registry::getInstance($channel);
+        }
+        self::$lastLoggerChannel = $channel;
+
+        $logger = new Logger($channel, $handlers, $processors);
+
+        Registry::addLogger($logger);
+
+        return $logger;
+    }
+
+    /**
+     * Returns created Logger
+     *
+     * @return Logger
+     */
+    public function getLogger()
+    {
+        return Registry::getInstance(self::$lastLoggerChannel);
+    }
+}
diff --git a/src/LoggerFacade.php b/src/LoggerFacade.php
new file mode 100644
index 0000000000000000000000000000000000000000..a7e867984460b669facff0bac1a1bd12a1183367
--- /dev/null
+++ b/src/LoggerFacade.php
@@ -0,0 +1,104 @@
+<?php
+
+namespace WPDesk\Logger;
+
+use Monolog\Logger;
+use Psr\Log\LogLevel;
+use WP_Error;
+use Exception;
+
+/**
+ * Facilitates creation of logger with default WPDesk settings
+ *
+ * @package WPDesk\Logger
+ */
+class LoggerFacade
+{
+    const BACKTRACE_FILENAME_KEY = 'file';
+
+    /** @var LoggerFactory */
+    private static $factory;
+
+    /**
+     * @return Logger
+     */
+    public static function getLogger()
+    {
+        if (self::$factory === null) {
+            self::$factory = new WPDeskLoggerFactory();
+        }
+        return self::$factory->createWPDeskLogger();
+    }
+
+    /**
+     * Snake case alias for getLogger
+     *
+     * @return Logger
+     */
+    public static function get_logger()
+    {
+        return self::getLogger();
+    }
+
+    /**
+     * Log this exception into WPDesk logger
+     *
+     * @param WP_Error $e Error to log.
+     * @param array $backtrace Backtrace information with snapshot of error env.
+     * @param string $level Level of error.
+     *
+     * @see http://php.net/manual/en/function.debug-backtrace.php
+     */
+    public static function log_wp_error(WP_Error $e, array $backtrace, $level = LogLevel::ERROR)
+    {
+        $message = 'Error: ' . get_class($e) . ' Code: ' . $e->get_error_code() . ' Message: ' . $e->get_error_message();
+
+        self::log_message_backtrace($message, $backtrace, $level);
+    }
+
+    /**
+     * Log this exception into WPDesk logger
+     *
+     * @param Exception $e Exception to log.
+     * @param string $level Level of error.
+     */
+    public static function log_exception(Exception $e, $level = LogLevel::ERROR)
+    {
+        $message = 'Exception: ' . get_class($e) . ' Code: ' . $e->getCode() . ' Message: ' . $e->getMessage() . ' Stack: ' . $e->getTraceAsString();
+
+        self::log_message($message, ['exception' => $e], $e->getFile(), $level);
+    }
+
+    /**
+     * Log message into WPDesk logger
+     *
+     * @param string $message Message to log.
+     * @param array $context Context to log
+     * @param string $source Source of the message - can be file name, class name or whatever.
+     * @param string $level Level of error.
+     */
+    public static function log_message(
+        $message,
+        array $context = array(),
+        $source = 'unknown',
+        $level = LogLevel::DEBUG
+    ) {
+        $logger = self::getLogger();
+
+        $logger->log($level, $message, array_merge($context, ['source' => $source]));
+    }
+
+    /**
+     * Log message into WPDesk logger
+     *
+     * @param string $message Message to log.
+     * @param array $backtrace Backtrace information with snapshot of error env.
+     * @param string $level Level of error.
+     */
+    public static function log_message_backtrace($message, array $backtrace, $level = LogLevel::DEBUG)
+    {
+        $message .= ' Backtrace: ' . json_encode($backtrace);
+
+        self::log_message($message, $backtrace[self::BACKTRACE_FILENAME_KEY], $level);
+    }
+}
diff --git a/src/LoggerFactory.php b/src/LoggerFactory.php
new file mode 100644
index 0000000000000000000000000000000000000000..653099085080f98df6ac49fd424d39945442e5f9
--- /dev/null
+++ b/src/LoggerFactory.php
@@ -0,0 +1,18 @@
+<?php
+
+namespace WPDesk\Logger;
+
+use Monolog\Logger;
+
+/*
+ * @package WPDesk\Logger
+ */
+interface LoggerFactory
+{
+    /**
+     * Returns created Logger
+     *
+     * @return Logger
+     */
+    public function getLogger();
+}
diff --git a/src/WC/Exception/WCLoggerAlreadyCaptured.php b/src/WC/Exception/WCLoggerAlreadyCaptured.php
new file mode 100644
index 0000000000000000000000000000000000000000..a1826f7f255b147a59520f26111b84f2c0b3d661
--- /dev/null
+++ b/src/WC/Exception/WCLoggerAlreadyCaptured.php
@@ -0,0 +1,10 @@
+<?php
+
+
+namespace WPDesk\Logger\WP\Exception;
+
+
+class WCLoggerAlreadyCaptured extends \RuntimeException
+{
+
+}
\ No newline at end of file
diff --git a/src/WC/WooCommerceCapture.php b/src/WC/WooCommerceCapture.php
new file mode 100644
index 0000000000000000000000000000000000000000..e8d4fd6d930287317976e4979c5718597aaa8a56
--- /dev/null
+++ b/src/WC/WooCommerceCapture.php
@@ -0,0 +1,135 @@
+<?php
+
+namespace WPDesk\Logger\WP;
+
+use Monolog\Logger;
+use WPDesk\Logger\WP\Exception\WCLoggerAlreadyCaptured;
+
+/**
+ * Can capture default WooCommerce logger
+ *
+ * @package WPDesk\Logger
+ */
+class WooCommerceCapture
+{
+    const WOOCOMMERCE_LOGGER_FILTER = 'woocommerce_logging_class';
+    const WOOCOMMERCE_AFTER_IS_LOADED_ACTION = 'woocommerce_loaded';
+
+    /**
+     * Is logger filter captured by library.
+     *
+     * @var bool
+     */
+    private static $WCLoggerCaptured = false;
+
+    /**
+     * Our monolog
+     *
+     * @var Logger
+     */
+    private $monolog;
+
+    /**
+     * Original WC Logger
+     *
+     * @var \WC_Logger_Interface
+     */
+    private $originalWCLogger;
+
+    /**
+     * WordPress hook function to return our logger
+     *
+     * @var ?callable
+     */
+    private $captureHookFunction;
+
+    /**
+     * WordPress hook function to return original wc logger
+     *
+     * @var ?callable
+     */
+    private $freeHookFunction;
+
+    public function __construct(Logger $monolog)
+    {
+        $this->monolog = $monolog;
+    }
+
+    /**
+     * Prepares callable property captureHookFunction.
+     * For it to work WC have to be loaded
+     */
+    private function prepareCaptureHookCallable()
+    {
+        $monolog = $this->monolog;
+
+        if ($this->captureHookFunction === null) {
+            $this->captureHookFunction = function () use ($monolog) {
+                return new WooCommerceMonologPlugin($monolog);
+            };
+            $this->monolog->pushHandler(new WooCommerceHandler($this->originalWCLogger));
+        }
+    }
+
+    /**
+     * Capture WooCommerce logger and inject our decorated Logger
+     */
+    public function captureWcLogger()
+    {
+        if (self::$WCLoggerCaptured) {
+            throw new WCLoggerAlreadyCaptured('Try to free wc logger first.');
+        }
+
+        if ($this->isWooCommerceLoggerAvailable()) {
+            $this->prepareFreeHookCallable();
+            $this->prepareCaptureHookCallable();
+
+            remove_filter(self::WOOCOMMERCE_LOGGER_FILTER, $this->freeHookFunction);
+            add_filter(self::WOOCOMMERCE_LOGGER_FILTER, $this->captureHookFunction);
+
+            self::$WCLoggerCaptured = true;
+        } elseif (function_exists('add_action')) {
+            add_action(self::WOOCOMMERCE_AFTER_IS_LOADED_ACTION, [$this, 'captureWcLogger']);
+        } else {
+            $this->monolog->alert('Cannot capture WC - WordPress is not available.');
+        }
+    }
+
+    /**
+     * Can i fetch WC Logger?
+     *
+     * @return bool
+     */
+    private function isWooCommerceLoggerAvailable()
+    {
+        return function_exists('wc_get_logger');
+    }
+
+    /**
+     * Prepares callable property freeHookFunction.
+     * For it to work WC have to be loaded
+     */
+    private function prepareFreeHookCallable()
+    {
+        if ($this->freeHookFunction === null) {
+            $this->originalWCLogger = $logger = wc_get_logger();
+
+            $this->freeHookFunction = function () use ($logger) {
+                return $logger;
+            };
+        }
+    }
+
+    /**
+     * Remove WooCommerce logger injection
+     */
+    public function freeWcLogger()
+    {
+        if (self::$WCLoggerCaptured) {
+            remove_filter(self::WOOCOMMERCE_LOGGER_FILTER, $this->captureHookFunction);
+            add_filter(self::WOOCOMMERCE_LOGGER_FILTER, $this->freeHookFunction);
+
+            self::$WCLoggerCaptured = false;
+        }
+    }
+}
diff --git a/src/WC/WooCommerceHandler.php b/src/WC/WooCommerceHandler.php
new file mode 100644
index 0000000000000000000000000000000000000000..35a31da47a37363fa60129641ad3c217cd59dbd1
--- /dev/null
+++ b/src/WC/WooCommerceHandler.php
@@ -0,0 +1,35 @@
+<?php
+
+namespace WPDesk\Logger\WP;
+
+use Monolog\Handler\AbstractProcessingHandler;
+
+/**
+ * Class WooCommerceFactory
+ */
+class WooCommerceHandler extends AbstractProcessingHandler {
+    const DEFAULT_WC_SOURCE = 'wpdesk-logger';
+
+	/** @var \WC_Logger_Interface */
+	private $wc_logger;
+
+    /**
+     * Writes the record down to the log of the implementing handler
+     *
+     * @param  array $record
+     * @return void
+     */
+    protected function write(array $record)
+    {
+	    $context = array_merge([
+            'source' => self::DEFAULT_WC_SOURCE
+        ], $record['extra'], $record['context']);
+
+	    $this->wc_logger->log($record['level'], $record['message'], $context);
+	}
+
+	public function __construct(\WC_Logger_Interface $originalWcLogger) {
+		parent::__construct();
+		$this->wc_logger = $originalWcLogger;
+	}
+}
diff --git a/src/WC/WooCommerceMonologPlugin.php b/src/WC/WooCommerceMonologPlugin.php
new file mode 100644
index 0000000000000000000000000000000000000000..0996d53fb526b797b9c6917cc9007a8fd8bf7f35
--- /dev/null
+++ b/src/WC/WooCommerceMonologPlugin.php
@@ -0,0 +1,157 @@
+<?php
+
+namespace WPDesk\Logger\WP;
+
+use Monolog\Logger;
+use Psr\Log\LogLevel;
+use WC_Log_Levels;
+
+
+/**
+ * Can decorate monolog with WC_Logger_Interface
+ *
+ * @package WPDesk\Logger
+ */
+class WooCommerceMonologPlugin implements \WC_Logger_Interface {
+
+	/** @var Logger */
+	private $monolog;
+
+	public function __construct( Logger $monolog ) {
+		$this->monolog = $monolog;
+	}
+
+    /**
+     * Method for compatibility reason. Do not use.
+     *
+     * @param string $handle
+     * @param string $message
+     * @param string $level
+     * @return bool|void
+     *
+     * @deprecated
+     */
+	public function add( $handle, $message, $level = WC_Log_Levels::NOTICE ) {
+		$this->log($message, $level);
+	}
+
+	/**
+	 * System is unusable.
+	 *
+	 * @param string $message
+	 * @param array  $context
+	 *
+	 * @return void
+	 */
+	public function emergency($message, $context = array())
+	{
+		$this->log(LogLevel::EMERGENCY, $message, $context);
+	}
+
+	public function log( $level, $message, $context = [] ) {
+		$this->monolog->log($level, $message, $context);
+	}
+
+	/**
+	 * Action must be taken immediately.
+	 *
+	 * Example: Entire website down, database unavailable, etc. This should
+	 * trigger the SMS alerts and wake you up.
+	 *
+	 * @param string $message
+	 * @param array  $context
+	 *
+	 * @return void
+	 */
+	public function alert($message, $context = array())
+	{
+		$this->log(LogLevel::ALERT, $message, $context);
+	}
+
+	/**
+	 * Critical conditions.
+	 *
+	 * Example: Application component unavailable, unexpected exception.
+	 *
+	 * @param string $message
+	 * @param array  $context
+	 *
+	 * @return void
+	 */
+	public function critical($message, $context = array())
+	{
+		$this->log(LogLevel::CRITICAL, $message, $context);
+	}
+
+	/**
+	 * Runtime errors that do not require immediate action but should typically
+	 * be logged and monitored.
+	 *
+	 * @param string $message
+	 * @param array  $context
+	 *
+	 * @return void
+	 */
+	public function error($message, $context = array())
+	{
+		$this->log(LogLevel::ERROR, $message, $context);
+	}
+
+	/**
+	 * Exceptional occurrences that are not errors.
+	 *
+	 * Example: Use of deprecated APIs, poor use of an API, undesirable things
+	 * that are not necessarily wrong.
+	 *
+	 * @param string $message
+	 * @param array  $context
+	 *
+	 * @return void
+	 */
+	public function warning($message, $context = array())
+	{
+		$this->log(LogLevel::WARNING, $message, $context);
+	}
+
+	/**
+	 * Normal but significant events.
+	 *
+	 * @param string $message
+	 * @param array  $context
+	 *
+	 * @return void
+	 */
+	public function notice($message, $context = array())
+	{
+		$this->log(LogLevel::NOTICE, $message, $context);
+	}
+
+	/**
+	 * Interesting events.
+	 *
+	 * Example: User logs in, SQL logs.
+	 *
+	 * @param string $message
+	 * @param array  $context
+	 *
+	 * @return void
+	 */
+	public function info($message, $context = array())
+	{
+		$this->log(LogLevel::INFO, $message, $context);
+	}
+
+	/**
+	 * Detailed debug information.
+	 *
+	 * @param string $message
+	 * @param array  $context
+	 *
+	 * @return void
+	 */
+	public function debug($message, $context = array())
+	{
+		$this->log(LogLevel::DEBUG, $message, $context);
+	}
+
+}
diff --git a/src/WPDeskLoggerFactory.php b/src/WPDeskLoggerFactory.php
new file mode 100644
index 0000000000000000000000000000000000000000..8f7b1195e897ba5d87a039d2f76cb3d220e55a24
--- /dev/null
+++ b/src/WPDeskLoggerFactory.php
@@ -0,0 +1,144 @@
+<?php
+
+namespace WPDesk\Logger;
+
+use Monolog\Logger;
+use Monolog\Registry;
+use Monolog\ErrorHandler;
+use Monolog\Handler\StreamHandler;
+use Psr\Log\LogLevel;
+use WPDesk\Logger\WP\WooCommerceCapture;
+
+/**
+ * Manages and facilitates creation of logger
+ *
+ * @package WPDesk\Logger
+ */
+class WPDeskLoggerFactory extends BasicLoggerFactory
+{
+    const WPDESK_LOGGER_CHANNEL_NAME = 'wpdesk';
+
+    /** @var string Log to file when level is */
+    const LEVEL_WPDESK_FILE = LogLevel::DEBUG;
+
+    /** @var string Log to wc logger when level is */
+    const LEVEL_WC = LogLevel::ERROR;
+
+    /** @var bool */
+    private static $isWpdeskLogWorking = false;
+
+    /**
+     * Creates default WPDesk logger.
+     *
+     * Requirements:
+     * - get_option, add/remove_action, add/remove filter and WP_CONTENT_DIR should be available for logger.
+     *
+     * Assumptions:
+     * - logger is actively working when 'wpdesk_helper_options' has 'debug_log' set to '1';
+     * - fatal errors, exception and standard errors are recorded but in a transparent way;
+     * - WooCommerce logger is captured and returns this logger;
+     * - logs are still correctly written to WooCommerce subsystem in a transparent way;
+     * - all recorded errors are written to WPDesk file.
+     *
+     * @return Logger
+     */
+    public function createWPDeskLogger()
+    {
+        if (Registry::hasLogger(self::WPDESK_LOGGER_CHANNEL_NAME)) {
+            return Registry::getInstance(self::WPDESK_LOGGER_CHANNEL_NAME);
+        }
+        $logger = $this->createLogger(self::WPDESK_LOGGER_CHANNEL_NAME);
+        if ($this->shouldInitializeLoggerHandles()) {
+            $this->captureWooCommerce($logger);
+            $this->captureWordPressHandle($logger);
+            try {
+                $this->appendWPDeskHandle($logger);
+                $logger->debug('WPDesk handle is active');
+                self::$isWpdeskLogWorking = true;
+            } catch (\InvalidArgumentException $e) {
+                $logger->emergency('WPDesk log could not be created - invalid filename.');
+            } catch (\Exception $e) {
+                $logger->emergency('WPDesk log could not be written.');
+            }
+        }
+
+        return $logger;
+    }
+
+    /**
+     * is WPDesk file log is working(writable, exists, connected).
+     *
+     * @return bool
+     */
+    public function isWPDeskLogWorking()
+    {
+        return self::$isWpdeskLogWorking;
+    }
+
+    /**
+     * Returns WPDesk filename with path.
+     *
+     * @return string
+     */
+    public function getWPDeskFileName()
+    {
+        return WP_CONTENT_DIR . '/uploads/wpdesk-logs/wpdesk_debug.log';
+    }
+
+    /**
+     * According to WPDesk - use logger only when debug mode is enabled.
+     *
+     * @return bool
+     */
+    private function shouldInitializeLoggerHandles()
+    {
+        if (function_exists('get_option')) {
+            $options = get_option('wpdesk_helper_options');
+            return is_array($options) && isset($options['debug_log']) && $options['debug_log'] === '1';
+        }
+        return false;
+    }
+
+    /**
+     * Capture WooCommerce and add handle
+     *
+     * @param Logger $logger
+     */
+    private function captureWooCommerce(Logger $logger)
+    {
+        if (!defined('WC_LOG_THRESHOLD')) {
+            define('WC_LOG_THRESHOLD', self::LEVEL_WC);
+        }
+
+        $wcIntegration = new WooCommerceCapture($logger);
+        $wcIntegration->captureWcLogger();
+    }
+
+    /**
+     * Add WordPress(standard PHP) errors handle
+     *
+     * @param Logger $logger
+     */
+    private function captureWordPressHandle(Logger $logger)
+    {
+        $errorHandler = new ErrorHandler($logger);
+
+        $errorHandler->registerErrorHandler();
+        $errorHandler->registerFatalHandler();
+        $errorHandler->registerExceptionHandler();
+    }
+
+    /**
+     * Add WPDesk log file handle
+     *
+     * @param Logger $logger
+     *
+     * @throws \Exception                If a missing directory is not buildable
+     * @throws \InvalidArgumentException If stream is not a resource or string
+     */
+    private function appendWPDeskHandle(Logger $logger)
+    {
+        $filename = $this->getWPDeskFileName();
+        $logger->pushHandler(new StreamHandler($filename, self::LEVEL_WPDESK_FILE));
+    }
+}