diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..097a96ec64504fd39fe73067ca807dc809660d25
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,31 @@
+PROJECT(spejd)
+
+cmake_minimum_required(VERSION 3.5.0)
+set(CMAKE_CXX_STANDARD 14)
+
+set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMakeScripts)
+
+find_package(wsnlp 1.0.0 REQUIRED)
+set(LIBS ${LIBS} ${WSNLP_LIBRARY})
+
+find_package(spejd REQUIRED)
+#include_directories(${SPEJD_INCLUDE_DIR})
+set(LIBS ${LIBS} ${SPEJD_LIBRARY})
+message("${SPEJD_INCLUDE_DIR}") 
+message("${SPEJD_LIBRARY}")
+
+find_package(
+    Boost COMPONENTS
+    program_options random system thread
+    filesystem chrono atomic date_time regex)
+link_directories(${Boost_LIBRARY_DIRS})
+set(LIBS ${LIBS} ${Boost_LIBRARIES})
+
+find_package(amqpcpp REQUIRED)
+set(LIBS ${LIBS} amqpcpp)
+
+include_directories("include")
+add_executable(spejd src/spejd_service.cpp)
+target_link_libraries(spejd ${LIBS})
+
+SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/../bin)
diff --git a/CMakeScripts/Findamqpcpp.cmake b/CMakeScripts/Findamqpcpp.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..164efd87f8099e2a4de3ed2a779ab11bda30f61b
--- /dev/null
+++ b/CMakeScripts/Findamqpcpp.cmake
@@ -0,0 +1,20 @@
+# Find the Rabbitmq C library
+
+SET(_AMQP_REQUIRED_VARS  AMQP_INCLUDE_DIR AMQP_LIBRARY )
+
+# Find the include directories
+FIND_PATH(AMQP_INCLUDE_DIR
+	NAMES amqpcpp.h
+    HINTS ${AMQP_DIR}/include /usr/include/amqpcpp
+)
+
+FIND_LIBRARY(AMQP_LIBRARY
+	NAMES amqpcpp 
+    HINTS ${AMQP_DIR}/lib /usr/lib/
+)
+
+SET(AMQP_PROCESS_INCLUDES AMQP_INCLUDE_DIR)
+SET(AMQP_PROCESS_LIBS AMQP_LIBRARY)
+
+include(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(AMQP DEFAULT_MSG ${_AMQP_REQUIRED_VARS})
\ No newline at end of file
diff --git a/CMakeScripts/Findspejd.cmake b/CMakeScripts/Findspejd.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..8a701baa1c89f3c3477098d5d6d9c1d6a1232703
--- /dev/null
+++ b/CMakeScripts/Findspejd.cmake
@@ -0,0 +1,19 @@
+SET(_SPEJD_REQUIRED_VARS SPEJD_INCLUDE_DIR SPEJD_LIBRARY)
+
+# Find the include directories
+FIND_PATH(SPEJD_INCLUDE_DIR
+	NAMES spejd.h
+    HINTS ${SPEJD_DIR}/include /usr/include/ /usr/local/include/spejd
+)
+
+FIND_LIBRARY(SPEJD_LIBRARY
+	NAMES spejd
+    HINTS ${SPEJD_DIR}/lib /usr/lib/ /usr/local/lib
+)
+
+SET(SPEJD_PROCESS_INCLUDES SPEJD_INCLUDE_DIR)
+SET(SPEJD_PROCESS_LIBS SPEJD_LIBRARY)
+
+include(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(SPEJD DEFAULT_MSG ${_SPEJD_REQUIRED_VARS})
+
diff --git a/CMakeScripts/Findwsnlp.cmake b/CMakeScripts/Findwsnlp.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..49ba7c659738bbc51802afbdf364c69a0271acdd
--- /dev/null
+++ b/CMakeScripts/Findwsnlp.cmake
@@ -0,0 +1,20 @@
+# Find the Rabbitmq C library
+
+SET(_WSNLP_REQUIRED_VARS  WSNLP_INCLUDE_DIR WSNLP_LIBRARY )
+
+# Find the include directories
+FIND_PATH(WSNLP_INCLUDE_DIR
+	NAMES nlpworker.h
+    HINTS ${WSNLP_DIR}/include /usr/include/wsnlp
+)
+
+FIND_LIBRARY(WSNLP_LIBRARY
+	NAMES wsnlp 
+    HINTS ${WSNLP_DIR}/lib /usr/lib/
+)
+
+SET(WSNLP_PROCESS_INCLUDES ${WSNLP_INCLUDE_DIR})
+SET(WSNLP_PROCESS_LIBS ${WSNLP_LIBRARY})
+
+include(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(WSNLP DEFAULT_MSG ${_WSNLP_REQUIRED_VARS})
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..06efd245477a5fe1e71d57ec19ce3dd4fe4bf4a1
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,47 @@
+FROM clarinpl/cpp
+
+RUN apt-get update && \
+    apt-get install -y \
+        zlib1g-dev \ 
+		software-properties-common \
+        pkg-config \
+        libxml++2.6-dev
+
+RUN locale-gen en_US.UTF-8
+ENV LANG en_US.UTF-8 
+ENV LC_ALL en_US.UTF-8
+
+WORKDIR /home/install
+RUN wget http://tools.clarin-pl.eu/share/morfeusz-SGJP-linux64-20130413.tar.bz2 && \
+    tar -jxvf morfeusz-SGJP-linux64-20130413.tar.bz2 && \
+    mv libmorfeusz* /usr/local/lib/ && \
+    mv morfeusz /usr/local/bin/ && \
+    mv morfeusz.h /usr/local/include/ && \
+    ldconfig && \
+    cd /home/install && \
+    rm -rf morfeusz-sgjp
+
+WORKDIR /home/install
+RUN wget https://minio.clarin-pl.eu/public/share/spejd-1.4.0.tar.gz && \
+    tar -xzf spejd-1.4.0.tar.gz && \
+    cd spejd-1.4.0 && \
+    ./configure --without-tcmalloc && \
+    make && make install && \
+    cd /home/install
+#   rm -rf spejd-1.4.0*
+
+WORKDIR /home/install/spejd
+COPY src/ src/
+COPY include/ include/
+COPY ./CMakeLists.txt ./CMakeLists.txt
+COPY CMakeScripts/ CMakeScripts/
+RUN mkdir build && \
+    cd build && \
+    cmake .. && \
+    make
+
+WORKDIR /home/worker
+COPY model/ model/
+RUN mv /home/install/spejd/bin/spejd .
+    #cd /home && rm -rf /home/install
+
diff --git a/config.ini b/config.ini
index d1642b10b74e1495ee81c52443748578f8521ec7..280e7e1fddd90909d516cdd3715759a075c794dc 100644
--- a/config.ini
+++ b/config.ini
@@ -2,18 +2,13 @@
 ; Plik zawiera konfiguracj� zar�wno Api us�ugi sieciowej jak i narz�dzia.
 ;
 ;       Autor: Tomasz Walkowiak
-;       email: tomasz.walkowiak@pwr.edu.pl
-
-; --------- CZʌ� DLA Serwisu ---------
 [service]
-#root = /mnt2/requests/
 root = /samba/requests/
-tool = spejd
+tool = spejd_test
 rabbit_host =10.17.0.85
 rabbit_user =clarin
 rabbit_password =clarin123
 
-; --------- CZʌ� DLA Narzedzia ---------
 [tool]
 workers_number = 4
-model = /home/tomekw/nlpworkers/spejd/model/config.ini
+model = model/config.ini
diff --git a/dependancies.txt b/dependancies.txt
deleted file mode 100644
index e75c68236cf15da92f8376c4b9af716c7fc54c8d..0000000000000000000000000000000000000000
--- a/dependancies.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-AMQP-CPP
-	https://github.com/CopernicaMarketingSoftware/AMQP-CPP
-	git clone https://github.com/CopernicaMarketingSoftware/AMQP-CPP.git
-	
-	gcc >=4.8
-	
-	
\ No newline at end of file
diff --git a/include/spejd_service.hpp b/include/spejd_service.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..d03d36ce7660b006eeb5357dbc2faaa04f42c102
--- /dev/null
+++ b/include/spejd_service.hpp
@@ -0,0 +1,24 @@
+#include "nlpworker.h"
+
+#include <boost/property_tree/json_parser.hpp>
+#include <boost/property_tree/ini_parser.hpp> 
+#include <boost/foreach.hpp>
+#include <boost/thread.hpp>
+#include <boost/filesystem.hpp>
+#define BOOST_NO_CXX11_SCOPED_ENUMS
+
+#include <string>
+#include <fstream>
+#include <streambuf>
+#include <spejd.h>
+
+using namespace libspejd;
+using ptree = boost::property_tree::ptree;
+
+class SpejdWorker: public NLPWorker
+{
+    void static_init(boost::property_tree::ptree config);
+    void process(std::string task_path, ptree &options, std::string output_path);
+    void process(ptree &data, ptree &options);
+	static spejd *engine;
+};
diff --git a/src/asiohandler.cpp b/src/asiohandler.cpp
deleted file mode 100644
index 4dec3358b9011a1e07765edcb85d5eb5892dd9b7..0000000000000000000000000000000000000000
--- a/src/asiohandler.cpp
+++ /dev/null
@@ -1,222 +0,0 @@
-#include <iostream>
-
-#include "asiohandler.h"
-
-using boost::asio::ip::tcp;
-
-class AmqpBuffer
-{
-public:
-    AmqpBuffer(size_t size) :
-            _data(size, 0),
-            _use(0)
-    {
-    }
-
-    size_t write(const char* data, size_t size)
-    {
-        if (_use == _data.size())
-        {
-            return 0;
-        }
-
-        const size_t length = (size + _use);
-        size_t write = length < _data.size() ? size : _data.size() - _use;
-        memcpy(_data.data() + _use, data, write);
-        _use += write;
-        return write;
-    }
-
-    void drain()
-    {
-        _use = 0;
-    }
-
-    size_t available() const
-    {
-        return _use;
-    }
-
-    const char* data() const
-    {
-        return _data.data();
-    }
-
-    void shl(size_t count)
-    {
-        assert(count < _use);
-
-        const size_t diff = _use - count;
-        std::memmove(_data.data(), _data.data() + count, diff);
-        _use = _use - count;
-    }
-
-private:
-    std::vector<char> _data;
-    size_t _use;
-};
-
-AsioHandler::AsioHandler(boost::asio::io_service& ioService) :
-        _ioService(ioService),
-        _socket(ioService),
-        _timer(ioService),
-        _asioInputBuffer(ASIO_INPUT_BUFFER_SIZE, 0),
-        _amqpBuffer(new AmqpBuffer(ASIO_INPUT_BUFFER_SIZE * 2)),
-        _connection(nullptr),
-        _writeInProgress(false),
-        _connected(false),
-        _quit(false)
-{
-}
-
-AsioHandler::~AsioHandler()
-{
-}
-
-void AsioHandler::connect(const std::string& host, uint16_t port)
-{
-    doConnect(host, port);
-}
-
-void AsioHandler::doConnect(const std::string& host, uint16_t port)
-{
-    tcp::resolver::query query(host, std::to_string(port));
-    tcp::resolver::iterator iter = tcp::resolver(_ioService).resolve(query);
-    _timer.expires_from_now(boost::posix_time::seconds(15));
-    _timer.async_wait([this](const boost::system::error_code& ec){
-        if(!ec && !_connected)
-        {
-            std::cerr<<"Connection timed out";
-            _socket.cancel();
-            exit(1);
-        }
-    });
-
-    boost::asio::async_connect(_socket, iter,
-            [this](boost::system::error_code ec, tcp::resolver::iterator)
-            {
-                _connected = true;
-                if (!ec)
-                {
-                    doRead();
-
-                    if(!_outputBuffer.empty())
-                    {
-                        doWrite();
-                    }
-                }
-                else
-                {
-                    std::cerr<<"Connection error:"<<ec<<std::endl;
-                    exit(1);
-                }
-            });
-
-}
-
-void AsioHandler::onData(
-        AMQP::Connection *connection, const char *data, size_t size)
-{
-    _connection = connection;
-
-    _outputBuffer.push_back(std::vector<char>(data, data + size));
-    if (!_writeInProgress && _connected)
-    {
-        doWrite();
-    }
-}
-
-void AsioHandler::doRead()
-{
-    _socket.async_receive(boost::asio::buffer(_asioInputBuffer),
-            [this](boost::system::error_code ec, std::size_t length)
-            {
-                if (!ec)
-                {
-                    _amqpBuffer->write(_asioInputBuffer.data(), length);
-                    parseData();
-                    doRead();
-                }
-                else
-                {
-                    std::cerr<<"Error reading:"<<ec<<std::endl;
-                    exit(1);
-                }
-            });
-}
-
-void AsioHandler::doWrite()
-{
-    _writeInProgress = true;
-    boost::asio::async_write(_socket,
-            boost::asio::buffer(_outputBuffer.front()),
-            [this](boost::system::error_code ec, std::size_t length )
-            {
-                if(!ec)
-                {
-                    _outputBuffer.pop_front();
-                    if(!_outputBuffer.empty())
-                    {
-                        doWrite();
-                    }
-                    else
-                    {
-                        _writeInProgress = false;
-                    }
-
-                    if(_quit)
-                    {
-                        _socket.close();
-                    }
-                }
-                else
-                {
-                    std::cerr<<"Error writing:"<<ec<<std::endl;
-                    _socket.close();
-                    exit(1);
-                }
-            });
-}
-
-void AsioHandler::parseData()
-{
-    if (_connection == nullptr)
-    {
-        return;
-    }
-
-    const size_t count = _connection->parse(_amqpBuffer->data(),
-            _amqpBuffer->available());
-
-    if (count == _amqpBuffer->available())
-    {
-        _amqpBuffer->drain();
-    }
-    else if (count > 0)
-    {
-        _amqpBuffer->shl(count);
-    }
-}
-
-void AsioHandler::onConnected(AMQP::Connection *connection)
-{
-}
-bool AsioHandler::connected() const
-{
-    return _connected;
-}
-
-void AsioHandler::onError(AMQP::Connection *connection, const char *message)
-{
-    std::cerr << "AMQP error " << message << std::endl;
-}
-
-void AsioHandler::onClosed(AMQP::Connection *connection)
-{
-    std::cout << "AMQP closed connection" << std::endl;
-    _quit = true;
-    if (!_writeInProgress)
-    {
-        _socket.close();
-    }
-}
diff --git a/src/asiohandler.h b/src/asiohandler.h
deleted file mode 100644
index 490e20fbf531765686d5743e2f720f923efcf850..0000000000000000000000000000000000000000
--- a/src/asiohandler.h
+++ /dev/null
@@ -1,59 +0,0 @@
-#pragma once
-
-#include <deque>
-#include <vector>
-#include <memory>
-
-#include <amqpcpp.h>
-#include <boost/asio.hpp>
-
-class AmqpBuffer;
-class AsioHandler: public AMQP::ConnectionHandler
-{
-private:
-
-    typedef std::deque<std::vector<char>> OutputBuffers;
-
-    virtual void onData(AMQP::Connection *connection, const char *data, size_t size);
-    virtual void onConnected(AMQP::Connection *connection);
-    virtual void onError(AMQP::Connection *connection, const char *message);
-    virtual void onClosed(AMQP::Connection *connection);
-
-    void doConnect(const std::string& host, uint16_t port);
-
-    void doRead();
-
-    void doWrite();
-
-    void parseData();
-
-private:
-
-    boost::asio::io_service& _ioService;
-    boost::asio::ip::tcp::socket _socket;
-    boost::asio::deadline_timer _timer;
-
-    std::vector<char> _asioInputBuffer;
-    std::shared_ptr<AmqpBuffer> _amqpBuffer;
-    AMQP::Connection* _connection;
-    OutputBuffers _outputBuffer;
-    bool _writeInProgress;
-    bool _connected;
-    bool _quit;
-
-public:
-
-    static constexpr size_t ASIO_INPUT_BUFFER_SIZE = 4*1024; //4kb
-
-    AsioHandler(boost::asio::io_service& ioService);
-
-    void connect(const std::string& host, uint16_t port);
-
-    virtual ~AsioHandler();
-
-    AsioHandler(const AsioHandler&) = delete;
-    AsioHandler& operator=(const AsioHandler&)=delete;
-
-    bool connected()const;
-};
-
diff --git a/src/asiohandler.o b/src/asiohandler.o
deleted file mode 100644
index 2e4fef15e77f5c28982ca1848e285ef1c450eb64..0000000000000000000000000000000000000000
Binary files a/src/asiohandler.o and /dev/null differ
diff --git a/src/config.ini b/src/config.ini
deleted file mode 100644
index d2a9861ea61b1ade2beb1b37c59035469d7ab9d4..0000000000000000000000000000000000000000
--- a/src/config.ini
+++ /dev/null
@@ -1,19 +0,0 @@
-; PLIK KONFIGURACYJNY  WORKERA
-; Plik zawiera konfiguracj� zar�wno Api us�ugi sieciowej jak i narz�dzia.
-;
-;       Autor: Tomasz Walkowiak
-;       email: tomasz.walkowiak@pwr.edu.pl
-
-; --------- CZʌ� DLA Serwisu ---------
-[service]
-#root = /mnt2/requests/
-root = /samba/requests/
-tool = spejd
-rabbit_host =10.17.0.85
-rabbit_user =clarin
-rabbit_password =clarin123
-
-; --------- CZʌ� DLA Narzedzia ---------
-[tool]
-workers_number = 8
-model = /home/tomekw/nlpworkers/spejd/model/config.ini
diff --git a/src/easylogging++.h b/src/easylogging++.h
deleted file mode 100644
index f9a67feb8f84bf6ce7432b3263da80ddc4edbfa5..0000000000000000000000000000000000000000
--- a/src/easylogging++.h
+++ /dev/null
@@ -1,6663 +0,0 @@
-//
-//  Easylogging++ v9.80
-//  Single-header only, cross-platform logging library for C++ applications
-//
-//  Copyright (c) 2015 muflihun.com
-//
-//  This library is released under the MIT Licence.
-//  http://easylogging.muflihun.com/licence.php
-//
-//  easylogging@muflihun.com
-//
-//  https://github.com/easylogging/easyloggingpp
-//  http://easylogging.muflihun.com
-//  http://muflihun.com
-//
-#ifndef EASYLOGGINGPP_H
-#define EASYLOGGINGPP_H
-// Compilers and C++0x/C++11 Evaluation
-#if defined(__GNUC__)
-#   define ELPP_COMPILER_GCC 1
-#   define ELPP_GCC_VERSION (__GNUC__ * 10000 \
-                               + __GNUC_MINOR__ * 100 \
-                               + __GNUC_PATCHLEVEL__)
-#   if defined(__GXX_EXPERIMENTAL_CXX0X__)
-#      define ELPP_CXX0X 1
-#   elif(ELPP_GCC_VERSION >= 40801)
-#      define ELPP_CXX11 1
-#   endif  // defined(__GXX_EXPERIMENTAL_CXX0X__)
-#endif  // defined(__GNUC__)
-// Visual C++
-#if defined(_MSC_VER)
-#   define ELPP_COMPILER_MSVC 1
-#   define ELPP_CRT_DBG_WARNINGS 1
-#   if (_MSC_VER == 1600)
-#      define ELPP_CXX0X 1
-#   elif(_MSC_VER >= 1700)
-#      define ELPP_CXX11 1
-#   endif  // (_MSC_VER == 1600)
-#endif  // defined(_MSC_VER)
-// Clang++
-#if defined(__clang__) && (__clang__ == 1)
-#   define ELPP_COMPILER_CLANG 1
-#   define ELPP_CLANG_VERSION (__clang_major__ * 10000 \
-                                + __clang_minor__ * 100 \
-                                + __clang_patchlevel__)
-#   if (ELPP_CLANG_VERSION >= 30300)
-#      define ELPP_CXX11 1
-#   endif  // (ELPP_CLANG_VERSION >= 30300)
-#endif  // defined(__clang__) && (__clang__ == 1)
-// MinGW
-#if defined(__MINGW32__) || defined(__MINGW64__)
-#   define ELPP_MINGW 1
-#endif  // defined(__MINGW32__) || defined(__MINGW64__)
-// Cygwin
-#if defined(__CYGWIN__) && (__CYGWIN__ == 1)
-#   define ELPP_CYGWIN 1
-#endif  // defined(__CYGWIN__) && (__CYGWIN__ == 1)
-// Intel C++
-#if defined(__INTEL_COMPILER)
-#   define ELPP_COMPILER_INTEL 1
-#endif
-// Operating System Evaluation
-// Windows
-#if defined(_WIN32) || defined(_WIN64)
-#   define ELPP_OS_WINDOWS 1
-#endif  // defined(_WIN32) || defined(_WIN64)
-// Linux
-#if (defined(__linux) || defined(__linux__))
-#   define ELPP_OS_LINUX 1
-#endif  // (defined(__linux) || defined(__linux__))
-// Mac
-#if defined(__APPLE__)
-#   define ELPP_OS_MAC 1
-#endif  // defined(__APPLE__)
-// FreeBSD
-#if defined(__FreeBSD__)
-#   define ELPP_OS_FREEBSD 1
-#endif
-// Solaris
-#if defined(__sun)
-#   define ELPP_OS_SOLARIS 1
-#endif
-// Unix
-#if ((ELPP_OS_LINUX || ELPP_OS_MAC || ELPP_OS_FREEBSD || ELPP_OS_SOLARIS) && (!ELPP_OS_WINDOWS))
-#   define ELPP_OS_UNIX 1
-#endif  // ((ELPP_OS_LINUX || ELPP_OS_MAC || ELPP_OS_FREEBSD || ELPP_OS_SOLARIS) && (!ELPP_OS_WINDOWS))
-// Android
-#if defined(__ANDROID__)
-#   define ELPP_OS_ANDROID 1
-#endif  // defined(__ANDROID__)
-// Evaluating Cygwin as *nix OS
-#if !ELPP_OS_UNIX && !ELPP_OS_WINDOWS && ELPP_CYGWIN
-#   undef ELPP_OS_UNIX
-#   undef ELPP_OS_LINUX
-#   define ELPP_OS_UNIX 1
-#   define ELPP_OS_LINUX 1
-#endif //  !ELPP_OS_UNIX && !ELPP_OS_WINDOWS && ELPP_CYGWIN
-#if !defined(ELPP_INTERNAL_DEBUGGING_OUT_INFO)
-#   define ELPP_INTERNAL_DEBUGGING_OUT_INFO std::cout
-#endif // !defined(ELPP_INTERNAL_DEBUGGING_OUT)
-#if !defined(ELPP_INTERNAL_DEBUGGING_OUT_ERROR)
-#   define ELPP_INTERNAL_DEBUGGING_OUT_ERROR std::cerr
-#endif // !defined(ELPP_INTERNAL_DEBUGGING_OUT)
-#if !defined(ELPP_INTERNAL_DEBUGGING_ENDL)
-#   define ELPP_INTERNAL_DEBUGGING_ENDL std::endl
-#endif // !defined(ELPP_INTERNAL_DEBUGGING_OUT)
-#if !defined(ELPP_INTERNAL_DEBUGGING_MSG)
-#   define ELPP_INTERNAL_DEBUGGING_MSG(msg) msg
-#endif // !defined(ELPP_INTERNAL_DEBUGGING_OUT)
-// Internal Assertions and errors
-#if !defined(ELPP_DISABLE_ASSERT)
-#   if (defined(ELPP_DEBUG_ASSERT_FAILURE))
-#      define ELPP_ASSERT(expr, msg) if (!(expr)) { \
-          std::stringstream internalInfoStream; internalInfoStream << msg; \
-          ELPP_INTERNAL_DEBUGGING_OUT_ERROR \
-              << "EASYLOGGING++ ASSERTION FAILED (LINE: " << __LINE__ << ") [" #expr << "] WITH MESSAGE \"" \
-              << ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStream.str()) << "\"" << ELPP_INTERNAL_DEBUGGING_ENDL; base::utils::abort(1, \
-                  "ELPP Assertion failure, please define ELPP_DEBUG_ASSERT_FAILURE"); }
-#   else
-#      define ELPP_ASSERT(expr, msg) if (!(expr)) { \
-          std::stringstream internalInfoStream; internalInfoStream << msg; \
-          ELPP_INTERNAL_DEBUGGING_OUT_ERROR\
-             << "ASSERTION FAILURE FROM EASYLOGGING++ (LINE: " \
-             << __LINE__ << ") [" #expr << "] WITH MESSAGE \"" << ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStream.str()) << "\"" \
-             << ELPP_INTERNAL_DEBUGGING_ENDL; }
-#   endif  // (defined(ELPP_DEBUG_ASSERT_FAILURE))
-#else
-#   define ELPP_ASSERT(x, y)
-#endif  //(!defined(ELPP_DISABLE_ASSERT)
-#if ELPP_COMPILER_MSVC
-#   define ELPP_INTERNAL_DEBUGGING_WRITE_PERROR \
-       { char buff[256]; strerror_s(buff, 256, errno); \
-       ELPP_INTERNAL_DEBUGGING_OUT_ERROR << ": " << buff << " [" << errno << "]";} (void)0
-#else
-#   define ELPP_INTERNAL_DEBUGGING_WRITE_PERROR \
-        ELPP_INTERNAL_DEBUGGING_OUT_ERROR << ": " << strerror(errno) << " [" << errno << "]"; (void)0
-#endif  // ELPP_COMPILER_MSVC
-#if defined(ELPP_DEBUG_ERRORS)
-#   if !defined(ELPP_INTERNAL_ERROR)
-#      define ELPP_INTERNAL_ERROR(msg, pe) { \
-          std::stringstream internalInfoStream; internalInfoStream << "<ERROR> " << msg; \
-          ELPP_INTERNAL_DEBUGGING_OUT_ERROR \
-          << "ERROR FROM EASYLOGGING++ (LINE: " << __LINE__ << ") " \
-          << ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStream.str()) << ELPP_INTERNAL_DEBUGGING_ENDL; \
-          if (pe) { ELPP_INTERNAL_DEBUGGING_OUT_ERROR << "    "; ELPP_INTERNAL_DEBUGGING_WRITE_PERROR; }} (void)0
-#   endif
-#else
-#   undef ELPP_INTERNAL_INFO
-#   define ELPP_INTERNAL_ERROR(msg, pe)
-#endif  // defined(ELPP_DEBUG_ERRORS)
-#if (defined(ELPP_DEBUG_INFO))
-#   if !(defined(ELPP_INTERNAL_INFO_LEVEL))
-#      define ELPP_INTERNAL_INFO_LEVEL 9
-#   endif  // !(defined(ELPP_INTERNAL_INFO_LEVEL))
-#   if !defined(ELPP_INTERNAL_INFO)
-#      define ELPP_INTERNAL_INFO(lvl, msg) { if (lvl <= ELPP_INTERNAL_INFO_LEVEL) { \
-          std::stringstream internalInfoStream; internalInfoStream << "<INFO> " << msg; \
-          ELPP_INTERNAL_DEBUGGING_OUT_INFO << ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStream.str()) \
-             << ELPP_INTERNAL_DEBUGGING_ENDL; }}
-#   endif
-#else
-#   undef ELPP_INTERNAL_INFO
-#   define ELPP_INTERNAL_INFO(lvl, msg)
-#endif  // (defined(ELPP_DEBUG_INFO))
-#if defined(ELPP_STACKTRACE_ON_CRASH)
-#   if (ELPP_COMPILER_GCC && !ELPP_MINGW)
-#      define ELPP_STACKTRACE 1
-#   else
-#      if ELPP_COMPILER_MSVC
-#         pragma message("Stack trace not available for this compiler")
-#      else
-#         warning "Stack trace not available for this compiler";
-#      endif  // ELPP_COMPILER_MSVC
-#   endif  // ELPP_COMPILER_GCC
-#endif  // (defined(ELPP_STACKTRACE_ON_CRASH))
-// Miscellaneous macros
-#define ELPP_UNUSED(x) (void)x
-#if ELPP_OS_UNIX
-// Log file permissions for unix-based systems
-#   define ELPP_LOG_PERMS S_IRUSR | S_IWUSR | S_IXUSR | S_IWGRP | S_IRGRP | S_IXGRP | S_IWOTH | S_IXOTH
-#endif  // ELPP_OS_UNIX
-#if defined(ELPP_AS_DLL) && ELPP_COMPILER_MSVC
-#   if defined(ELPP_EXPORT_SYMBOLS)
-#      define ELPP_EXPORT __declspec(dllexport)
-#   else
-#      define ELPP_EXPORT __declspec(dllimport)
-#   endif  // defined(ELPP_EXPORT_SYMBOLS)
-#else
-#   define ELPP_EXPORT
-#endif  // defined(ELPP_AS_DLL) && ELPP_COMPILER_MSVC
-// Some special functions that are VC++ specific
-#undef STRTOK
-#undef STRERROR
-#undef STRCAT
-#undef STRCPY
-#if ELPP_CRT_DBG_WARNINGS
-#   define STRTOK(a, b, c) strtok_s(a, b, c)
-#   define STRERROR(a, b, c) strerror_s(a, b, c)
-#   define STRCAT(a, b, len) strcat_s(a, len, b)
-#   define STRCPY(a, b, len) strcpy_s(a, len, b)
-#else
-#   define STRTOK(a, b, c) strtok(a, b)
-#   define STRERROR(a, b, c) strerror(c)
-#   define STRCAT(a, b, len) strcat(a, b)
-#   define STRCPY(a, b, len) strcpy(a, b)
-#endif
-// Compiler specific support evaluations
-#if (!ELPP_MINGW && !ELPP_COMPILER_CLANG) || defined(ELPP_FORCE_USE_STD_THREAD)
-#   define ELPP_USE_STD_THREADING 1
-#endif  // (!ELPP_MINGW && !ELPP_COMPILER_CLANG) || defined(ELPP_FORCE_USE_STD_THREAD)
-#undef ELPP_FINAL
-#if ELPP_COMPILER_INTEL || (ELPP_GCC_VERSION < 40702)
-#   define ELPP_FINAL
-#else
-#   define ELPP_FINAL final
-#endif  // ELPP_COMPILER_INTEL || (ELPP_GCC_VERSION < 40702)
-#if defined(ELPP_EXPERIMENTAL_ASYNC)
-#   define ELPP_ASYNC_LOGGING 1
-#else
-#   define ELPP_ASYNC_LOGGING 0
-#endif  // defined(ELPP_EXPERIMENTAL_ASYNC)
-#if defined(ELPP_THREAD_SAFE) || ELPP_ASYNC_LOGGING
-#   define ELPP_THREADING_ENABLED 1
-#endif  // defined(ELPP_THREAD_SAFE) || ELPP_ASYNC_LOGGING
-// Function macro ELPP_FUNC
-#undef ELPP_FUNC
-#if ELPP_COMPILER_MSVC  // Visual C++
-#   define ELPP_FUNC __FUNCSIG__
-#elif ELPP_COMPILER_GCC  // GCC
-#   define ELPP_FUNC __PRETTY_FUNCTION__
-#elif ELPP_COMPILER_INTEL  // Intel C++
-#   define ELPP_FUNC __PRETTY_FUNCTION__
-#elif ELPP_COMPILER_CLANG  // Clang++
-#   define ELPP_FUNC __PRETTY_FUNCTION__
-#else
-#   if defined(__func__)
-#      define ELPP_FUNC __func__
-#   else
-#      define ELPP_FUNC ""
-#   endif  // defined(__func__)
-#endif  // defined(_MSC_VER)
-#undef ELPP_VARIADIC_TEMPLATES_SUPPORTED
-// Keep following line commented until features are fixed
-#if ELPP_COMPILER_GCC || ELPP_COMPILER_CLANG || ELPP_COMPILER_INTEL || (ELPP_COMPILER_MSVC && _MSC_VER >= 1800)
-#   define ELPP_VARIADIC_TEMPLATES_SUPPORTED 1
-#endif  // ELPP_COMPILER_GCC || ELPP_COMPILER_CLANG || ELPP_COMPILER_INTEL || (ELPP_COMPILER_MSVC && _MSC_VER >= 1800)
-// Logging Enable/Disable macros
-#if (!defined(ELPP_DISABLE_LOGS))
-#   define ELPP_LOGGING_ENABLED 1
-#endif  // (!defined(ELPP_DISABLE_LOGS))
-#if (!defined(ELPP_DISABLE_DEBUG_LOGS) && (ELPP_LOGGING_ENABLED) && ((defined(_DEBUG)) || (!defined(NDEBUG))))
-#   define ELPP_DEBUG_LOG 1
-#else
-#   define ELPP_DEBUG_LOG 0
-#endif  // (!defined(ELPP_DISABLE_DEBUG_LOGS) && (ELPP_LOGGING_ENABLED) && ((defined(_DEBUG)) || (!defined(NDEBUG))))
-#if (!defined(ELPP_DISABLE_INFO_LOGS) && (ELPP_LOGGING_ENABLED))
-#   define ELPP_INFO_LOG 1
-#else
-#   define ELPP_INFO_LOG 0
-#endif  // (!defined(ELPP_DISABLE_INFO_LOGS) && (ELPP_LOGGING_ENABLED))
-#if (!defined(ELPP_DISABLE_WARNING_LOGS) && (ELPP_LOGGING_ENABLED))
-#   define ELPP_WARNING_LOG 1
-#else
-#   define ELPP_WARNING_LOG 0
-#endif  // (!defined(ELPP_DISABLE_WARNING_LOGS) && (ELPP_LOGGING_ENABLED))
-#if (!defined(ELPP_DISABLE_ERROR_LOGS) && (ELPP_LOGGING_ENABLED))
-#   define ELPP_ERROR_LOG 1
-#else
-#   define ELPP_ERROR_LOG 0
-#endif  // (!defined(ELPP_DISABLE_ERROR_LOGS) && (ELPP_LOGGING_ENABLED))
-#if (!defined(ELPP_DISABLE_FATAL_LOGS) && (ELPP_LOGGING_ENABLED))
-#   define ELPP_FATAL_LOG 1
-#else
-#   define ELPP_FATAL_LOG 0
-#endif  // (!defined(ELPP_DISABLE_FATAL_LOGS) && (ELPP_LOGGING_ENABLED))
-#if (!defined(ELPP_DISABLE_TRACE_LOGS) && (ELPP_LOGGING_ENABLED))
-#   define ELPP_TRACE_LOG 1
-#else
-#   define ELPP_TRACE_LOG 0
-#endif  // (!defined(ELPP_DISABLE_TRACE_LOGS) && (ELPP_LOGGING_ENABLED))
-#if (!defined(ELPP_DISABLE_VERBOSE_LOGS) && (ELPP_LOGGING_ENABLED))
-#   define ELPP_VERBOSE_LOG 1
-#else
-#   define ELPP_VERBOSE_LOG 0
-#endif  // (!defined(ELPP_DISABLE_VERBOSE_LOGS) && (ELPP_LOGGING_ENABLED))
-#if (!(ELPP_CXX0X || ELPP_CXX11))
-#   error "Easylogging++ 9.0+ is only compatible with C++0x (or higher) compliant compiler"
-#endif  // (!(ELPP_CXX0X || ELPP_CXX11))
-// Headers
-#if defined(ELPP_SYSLOG)
-#   include <syslog.h>
-#endif  // defined(ELPP_SYSLOG)
-#include <ctime>
-#include <cstring>
-#include <cstdlib>
-#include <cctype>
-#include <cwchar>
-#include <csignal>
-#include <cerrno>
-#include <cstdarg>
-#if defined(ELPP_UNICODE)
-#   include <locale>
-#   if ELPP_OS_WINDOWS
-#      include <codecvt>
-#   endif // ELPP_OS_WINDOWS
-#endif  // defined(ELPP_UNICODE)
-#if ELPP_STACKTRACE
-#   include <cxxabi.h>
-#   include <execinfo.h>
-#endif  // ELPP_STACKTRACE
-#if ELPP_OS_ANDROID
-#   include <sys/system_properties.h>
-#endif  // ELPP_OS_ANDROID
-#if ELPP_OS_UNIX
-#   include <sys/stat.h>
-#   include <sys/time.h>
-#elif ELPP_OS_WINDOWS
-#   include <direct.h>
-#   include <windows.h>
-#   if defined(WIN32_LEAN_AND_MEAN)
-#      if defined(ELPP_WINSOCK2)
-#         include <winsock2.h>
-#	   else
-#         include <winsock.h>
-#      endif // defined(ELPP_WINSOCK2)
-#   endif // defined(WIN32_LEAN_AND_MEAN)
-#endif  // ELPP_OS_UNIX
-#include <string>
-#include <vector>
-#include <map>
-#include <utility>
-#include <functional>
-#include <algorithm>
-#include <fstream>
-#include <iostream>
-#include <sstream>
-#include <memory>
-#include <type_traits>
-#if ELPP_THREADING_ENABLED
-#   if ELPP_USE_STD_THREADING
-#      include <mutex>
-#      include <thread>
-#   else
-#      if ELPP_OS_UNIX
-#         include <pthread.h>
-#      endif  // ELPP_OS_UNIX
-#   endif  // ELPP_USE_STD_THREADING
-#endif  // ELPP_THREADING_ENABLED
-#if ELPP_ASYNC_LOGGING
-#   include <thread>
-#   include <queue>
-#   include <condition_variable>
-#endif  // ELPP_ASYNC_LOGGING 
-#if defined(ELPP_STL_LOGGING)
-// For logging STL based templates
-#   include <list>
-#   include <queue>
-#   include <deque>
-#   include <set>
-#   include <bitset>
-#   include <stack>
-#   if defined(ELPP_LOG_STD_ARRAY)
-#      include <array>
-#   endif  // defined(ELPP_LOG_STD_ARRAY)
-#   if defined(ELPP_LOG_UNORDERED_MAP)
-#      include <unordered_map>
-#   endif  // defined(ELPP_LOG_UNORDERED_MAP)
-#   if defined(ELPP_LOG_UNORDERED_SET)
-#      include <unordered_set>
-#   endif  // defined(ELPP_UNORDERED_SET)
-#endif  // defined(ELPP_STL_LOGGING)
-#if defined(ELPP_QT_LOGGING)
-// For logging Qt based classes & templates
-#   include <QString>
-#   include <QByteArray>
-#   include <QVector>
-#   include <QList>
-#   include <QPair>
-#   include <QMap>
-#   include <QQueue>
-#   include <QSet>
-#   include <QLinkedList>
-#   include <QHash>
-#   include <QMultiHash>
-#   include <QStack>
-#endif  // defined(ELPP_QT_LOGGING)
-#if defined(ELPP_BOOST_LOGGING)
-// For logging boost based classes & templates
-#   include <boost/container/vector.hpp>
-#   include <boost/container/stable_vector.hpp>
-#   include <boost/container/list.hpp>
-#   include <boost/container/deque.hpp>
-#   include <boost/container/map.hpp>
-#   include <boost/container/flat_map.hpp>
-#   include <boost/container/set.hpp>
-#   include <boost/container/flat_set.hpp>
-#endif  // defined(ELPP_BOOST_LOGGING)
-#if defined(ELPP_WXWIDGETS_LOGGING)
-// For logging wxWidgets based classes & templates
-#   include <wx/vector.h>
-#endif  // defined(ELPP_WXWIDGETS_LOGGING)
-// Forward declarations
-namespace el {
-class Logger;
-class LogMessage;
-class PerformanceTrackingData;
-class Loggers;
-class Helpers;
-template <typename T> class Callback;
-class LogDispatchCallback;
-class PerformanceTrackingCallback;
-class LogDispatchData;
-namespace base {
-class Storage;
-class RegisteredLoggers;
-class PerformanceTracker;
-class MessageBuilder;
-class Writer;
-class PErrorWriter;
-class LogDispatcher;
-class DefaultLogBuilder;
-class DefaultLogDispatchCallback;
-#if ELPP_ASYNC_LOGGING
-class AsyncLogDispatchCallback;
-class AsyncDispatchWorker;
-#endif // ELPP_ASYNC_LOGGING
-class DefaultPerformanceTrackingCallback;
-}  // namespace base
-}  // namespace el
-/// @brief Easylogging++ entry namespace
-namespace el {
-/// @brief Namespace containing base/internal functionality used by Easylogging++
-namespace base {
-/// @brief Data types used by Easylogging++
-namespace type {
-#undef ELPP_LITERAL
-#undef ELPP_STRLEN
-#undef ELPP_COUT
-#if defined(ELPP_UNICODE)
-#   define ELPP_LITERAL(txt) L##txt
-#   define ELPP_STRLEN wcslen
-#   if defined ELPP_CUSTOM_COUT
-#      define ELPP_COUT ELPP_CUSTOM_COUT
-#   else
-#      define ELPP_COUT std::wcout
-#   endif  // defined ELPP_CUSTOM_COUT
-typedef wchar_t char_t;
-typedef std::wstring string_t;
-typedef std::wstringstream stringstream_t;
-typedef std::wfstream fstream_t;
-typedef std::wostream ostream_t;
-#else
-#   define ELPP_LITERAL(txt) txt
-#   define ELPP_STRLEN strlen
-#   if defined ELPP_CUSTOM_COUT
-#      define ELPP_COUT ELPP_CUSTOM_COUT
-#   else
-#      define ELPP_COUT std::cout
-#   endif  // defined ELPP_CUSTOM_COUT
-typedef char char_t;
-typedef std::string string_t;
-typedef std::stringstream stringstream_t;
-typedef std::fstream fstream_t;
-typedef std::ostream ostream_t;
-#endif  // defined(ELPP_UNICODE)
-#if defined(ELPP_CUSTOM_COUT_LINE)
-#   define ELPP_COUT_LINE(logLine) ELPP_CUSTOM_COUT_LINE(logLine)
-#else
-#   define ELPP_COUT_LINE(logLine) logLine << std::flush
-#endif // defined(ELPP_CUSTOM_COUT_LINE)
-typedef unsigned short EnumType;
-typedef std::shared_ptr<base::Storage> StoragePointer;
-typedef int VerboseLevel;
-typedef std::shared_ptr<LogDispatchCallback> LogDispatchCallbackPtr;
-typedef std::shared_ptr<PerformanceTrackingCallback> PerformanceTrackingCallbackPtr;
-}  // namespace type
-/// @brief Internal helper class that prevent copy constructor for class
-///
-/// @detail When using this class simply inherit it privately
-class NoCopy {
-protected:
-    NoCopy(void) {}
-private:
-    NoCopy(const NoCopy&);
-    NoCopy& operator=(const NoCopy&);
-};
-/// @brief Internal helper class that makes all default constructors private.
-///
-/// @detail This prevents initializing class making it static unless an explicit constructor is declared.
-/// When using this class simply inherit it privately
-class StaticClass {
-private:
-    StaticClass(void);
-    StaticClass(const StaticClass&);
-    StaticClass& operator=(const StaticClass&);
-};
-}  // namespace base
-/// @brief Represents enumeration for severity level used to determine level of logging
-///
-/// @detail With Easylogging++, developers may disable or enable any level regardless of
-/// what the severity is. Or they can choose to log using hierarchical logging flag
-enum class Level : base::type::EnumType {
-        /// @brief Generic level that represents all the levels. Useful when setting global configuration for all levels
-        Global = 1,
-        /// @brief Information that can be useful to back-trace certain events - mostly useful than debug logs.
-        Trace = 2,
-        /// @brief Informational events most useful for developers to debug application
-        Debug = 4,
-        /// @brief Severe error information that will presumably abort application
-        Fatal = 8, 
-        /// @brief Information representing errors in application but application will keep running
-        Error = 16,
-        /// @brief Useful when application has potentially harmful situtaions
-        Warning = 32, 
-        /// @brief Information that can be highly useful and vary with verbose logging level.
-        Verbose = 64,
-        /// @brief Mainly useful to represent current progress of application
-        Info = 128, 
-        /// @brief Represents unknown level
-        Unknown = 1010
-};
-/// @brief Static class that contains helper functions for el::Level
-class LevelHelper : base::StaticClass {
-public:
-    /// @brief Represents minimum valid level. Useful when iterating through enum.
-    static const base::type::EnumType kMinValid = static_cast<base::type::EnumType>(Level::Trace);
-    /// @brief Represents maximum valid level. This is used internally and you should not need it.
-    static const base::type::EnumType kMaxValid = static_cast<base::type::EnumType>(Level::Info);
-    /// @brief Casts level to int, useful for iterating through enum.
-    static base::type::EnumType castToInt(Level level) {
-        return static_cast<base::type::EnumType>(level);
-    }
-    /// @brief Casts int(ushort) to level, useful for iterating through enum.
-    static Level castFromInt(base::type::EnumType l) {
-        return static_cast<Level>(l);
-    }
-    /// @brief Converts level to associated const char*
-    /// @return Upper case string based level.
-    static const char* convertToString(Level level) {
-       // Do not use switch over strongly typed enums because Intel C++ compilers dont support them yet.
-        if (level == Level::Global) return "GLOBAL";
-        if (level == Level::Debug) return "DEBUG";
-        if (level == Level::Info) return "INFO";
-        if (level == Level::Warning) return "WARNING";
-        if (level == Level::Error) return "ERROR";
-        if (level == Level::Fatal) return "FATAL";
-        if (level == Level::Verbose) return "VERBOSE";
-        if (level == Level::Trace) return "TRACE";
-        return "UNKNOWN";
-    }
-    /// @brief Converts from levelStr to Level
-    /// @param levelStr Upper case string based level.
-    ///        Lower case is also valid but providing upper case is recommended.
-    static Level convertFromString(const char* levelStr) {
-        if ((strcmp(levelStr, "GLOBAL") == 0) || (strcmp(levelStr, "global") == 0))
-            return Level::Global;
-        if ((strcmp(levelStr, "DEBUG") == 0) || (strcmp(levelStr, "debug") == 0))
-            return Level::Debug;
-        if ((strcmp(levelStr, "INFO") == 0) || (strcmp(levelStr, "info") == 0))
-            return Level::Info;
-        if ((strcmp(levelStr, "WARNING") == 0) || (strcmp(levelStr, "warning") == 0))
-            return Level::Warning;
-        if ((strcmp(levelStr, "ERROR") == 0) || (strcmp(levelStr, "error") == 0))
-            return Level::Error;
-        if ((strcmp(levelStr, "FATAL") == 0) || (strcmp(levelStr, "fatal") == 0))
-            return Level::Fatal;
-        if ((strcmp(levelStr, "VERBOSE") == 0) || (strcmp(levelStr, "verbose") == 0))
-            return Level::Verbose;
-        if ((strcmp(levelStr, "TRACE") == 0) || (strcmp(levelStr, "trace") == 0))
-            return Level::Trace;
-        return Level::Unknown;
-    }
-    /// @brief Applies specified function to each level starting from startIndex
-    /// @param startIndex initial value to start the iteration from. This is passed as pointer and 
-    ///        is left-shifted so this can be used inside function (fn) to represent current level.
-    /// @param fn function to apply with each level. This bool represent whether or not to stop iterating through levels.
-    static inline void forEachLevel(base::type::EnumType* startIndex, const std::function<bool(void)>& fn) {
-        base::type::EnumType lIndexMax = LevelHelper::kMaxValid;
-        do {
-            if (fn()) {
-                break;
-            }
-            *startIndex = static_cast<base::type::EnumType>(*startIndex << 1);
-        } while (*startIndex <= lIndexMax);
-    }
-};
-/// @brief Represents enumeration of ConfigurationType used to configure or access certain aspect
-/// of logging
-enum class ConfigurationType : base::type::EnumType {
-   /// @brief Determines whether or not corresponding level and logger of logging is enabled
-   /// You may disable all logs by using el::Level::Global
-    Enabled = 1,
-   /// @brief Whether or not to write corresponding log to log file
-    ToFile = 2,
-   /// @brief Whether or not to write corresponding level and logger log to standard output.
-   /// By standard output meaning termnal, command prompt etc
-    ToStandardOutput = 4,
-   /// @brief Determines format of logging corresponding level and logger.
-    Format = 8,
-   /// @brief Determines log file (full path) to write logs to for correponding level and logger
-    Filename = 16,
-   /// @brief Specifies milliseconds width. Width can be within range (1-6)
-    MillisecondsWidth = 32,
-   /// @brief Determines whether or not performance tracking is enabled.
-   ///
-   /// @detail This does not depend on logger or level. Performance tracking always uses 'performance' logger
-    PerformanceTracking = 64,
-   /// @brief Specifies log file max size.
-   ///
-   /// @detail If file size of corresponding log file (for corresponding level) is >= specified size, log file will 
-   /// be truncated and re-initiated.
-    MaxLogFileSize = 128,
-   /// @brief Specifies number of log entries to hold until we flush pending log data
-    LogFlushThreshold = 256,
-   /// @brief Represents unknown configuration
-    Unknown = 1010
-};
-/// @brief Static class that contains helper functions for el::ConfigurationType
-class ConfigurationTypeHelper : base::StaticClass {
-public:
-    /// @brief Represents minimum valid configuration type. Useful when iterating through enum.
-    static const base::type::EnumType kMinValid = static_cast<base::type::EnumType>(ConfigurationType::Enabled);
-    /// @brief Represents maximum valid configuration type. This is used internally and you should not need it.
-    static const base::type::EnumType kMaxValid = static_cast<base::type::EnumType>(ConfigurationType::MaxLogFileSize);
-    /// @brief Casts configuration type to int, useful for iterating through enum.
-    static base::type::EnumType castToInt(ConfigurationType configurationType) {
-        return static_cast<base::type::EnumType>(configurationType);
-    }
-    /// @brief Casts int(ushort) to configurationt type, useful for iterating through enum.
-    static ConfigurationType castFromInt(base::type::EnumType c) {
-        return static_cast<ConfigurationType>(c);
-    }
-    /// @brief Converts configuration type to associated const char*
-    /// @returns Upper case string based configuration type.
-    static const char* convertToString(ConfigurationType configurationType) {
-        // Do not use switch over strongly typed enums because Intel C++ compilers dont support them yet.
-        if (configurationType == ConfigurationType::Enabled) return "ENABLED";
-        if (configurationType == ConfigurationType::Filename) return "FILENAME";
-        if (configurationType == ConfigurationType::Format) return "FORMAT";
-        if (configurationType == ConfigurationType::ToFile) return "TO_FILE";
-        if (configurationType == ConfigurationType::ToStandardOutput) return "TO_STANDARD_OUTPUT";
-        if (configurationType == ConfigurationType::MillisecondsWidth) return "MILLISECONDS_WIDTH";
-        if (configurationType == ConfigurationType::PerformanceTracking) return "PERFORMANCE_TRACKING";
-        if (configurationType == ConfigurationType::MaxLogFileSize) return "MAX_LOG_FILE_SIZE";
-        if (configurationType == ConfigurationType::LogFlushThreshold) return "LOG_FLUSH_THRESHOLD";
-        return "UNKNOWN";
-    }
-    /// @brief Converts from configStr to ConfigurationType
-    /// @param configStr Upper case string based configuration type.
-    ///        Lower case is also valid but providing upper case is recommended.
-    static ConfigurationType convertFromString(const char* configStr) {
-        if ((strcmp(configStr, "ENABLED") == 0) || (strcmp(configStr, "enabled") == 0))
-            return ConfigurationType::Enabled;
-        if ((strcmp(configStr, "TO_FILE") == 0) || (strcmp(configStr, "to_file") == 0))
-            return ConfigurationType::ToFile;
-        if ((strcmp(configStr, "TO_STANDARD_OUTPUT") == 0) || (strcmp(configStr, "to_standard_output") == 0))
-            return ConfigurationType::ToStandardOutput;
-        if ((strcmp(configStr, "FORMAT") == 0) || (strcmp(configStr, "format") == 0))
-            return ConfigurationType::Format;
-        if ((strcmp(configStr, "FILENAME") == 0) || (strcmp(configStr, "filename") == 0))
-            return ConfigurationType::Filename;
-        if ((strcmp(configStr, "MILLISECONDS_WIDTH") == 0) || (strcmp(configStr, "milliseconds_width") == 0))
-            return ConfigurationType::MillisecondsWidth;
-        if ((strcmp(configStr, "PERFORMANCE_TRACKING") == 0) || (strcmp(configStr, "performance_tracking") == 0))
-            return ConfigurationType::PerformanceTracking;
-        if ((strcmp(configStr, "MAX_LOG_FILE_SIZE") == 0) || (strcmp(configStr, "max_log_file_size") == 0))
-            return ConfigurationType::MaxLogFileSize;
-        if ((strcmp(configStr, "LOG_FLUSH_THRESHOLD") == 0) || (strcmp(configStr, "log_flush_threshold") == 0))
-            return ConfigurationType::LogFlushThreshold;
-        return ConfigurationType::Unknown;
-    }
-    /// @brief Applies specified function to each configuration type starting from startIndex
-    /// @param startIndex initial value to start the iteration from. This is passed by pointer and is left-shifted
-    ///        so this can be used inside function (fn) to represent current configuration type.
-    /// @param fn function to apply with each configuration type. 
-    ///        This bool represent whether or not to stop iterating through configurations.
-    static inline void forEachConfigType(base::type::EnumType* startIndex, const std::function<bool(void)>& fn) {
-        base::type::EnumType cIndexMax = ConfigurationTypeHelper::kMaxValid;
-        do {
-            if (fn()) {
-                break;
-            }
-            *startIndex = static_cast<base::type::EnumType>(*startIndex << 1);
-        } while (*startIndex <= cIndexMax);
-    }
-};
-/// @brief Flags used while writing logs. This flags are set by user
-enum class LoggingFlag : base::type::EnumType {
-    /// @brief Makes sure we have new line for each container log entry
-    NewLineForContainer = 1,
-    /// @brief Makes sure if -vmodule is used and does not specifies a module, then verbose
-    /// logging is allowed via that module.
-    AllowVerboseIfModuleNotSpecified = 2,
-    /// @brief When handling crashes by default, detailed crash reason will be logged as well
-    LogDetailedCrashReason = 4,
-    /// @brief Allows to disable application abortion when logged using FATAL level
-    DisableApplicationAbortOnFatalLog = 8,
-    /// @brief Flushes log with every log-entry (performance sensative) - Disabled by default
-    ImmediateFlush = 16,
-    /// @brief Enables strict file rolling
-    StrictLogFileSizeCheck = 32,
-    /// @brief Make terminal output colorful for supported terminals
-    ColoredTerminalOutput = 64,
-    /// @brief Supports use of multiple logging in same macro, e.g, CLOG(INFO, "default", "network")
-    MultiLoggerSupport = 128,
-    /// @brief Disables comparing performance tracker's checkpoints
-    DisablePerformanceTrackingCheckpointComparison = 256,
-    /// @brief Disable VModules
-    DisableVModules = 512,
-    /// @brief Disable VModules extensions
-    DisableVModulesExtensions = 1024,
-    /// @brief Enables hierarchical logging
-    HierarchicalLogging = 2048,
-    /// @brief Creates logger automatically when not available
-    CreateLoggerAutomatically = 4096,
-    /// @brief Adds spaces b/w logs that separated by left-shift operator
-    AutoSpacing = 8192,
-    /// @brief Preserves time format and does not convert it to sec, hour etc (performance tracking only)
-    FixedTimeFormat = 16384
-};
-namespace base {
-/// @brief Namespace containing constants used internally.
-namespace consts {
-    // Level log values - These are values that are replaced in place of %level format specifier
-    static const base::type::char_t* kInfoLevelLogValue     =   ELPP_LITERAL("INFO ");
-    static const base::type::char_t* kDebugLevelLogValue    =   ELPP_LITERAL("DEBUG");
-    static const base::type::char_t* kWarningLevelLogValue  =   ELPP_LITERAL("WARN ");
-    static const base::type::char_t* kErrorLevelLogValue    =   ELPP_LITERAL("ERROR");
-    static const base::type::char_t* kFatalLevelLogValue    =   ELPP_LITERAL("FATAL");
-    static const base::type::char_t* kVerboseLevelLogValue  =   ELPP_LITERAL("VER");
-    static const base::type::char_t* kTraceLevelLogValue    =   ELPP_LITERAL("TRACE");
-    static const base::type::char_t* kInfoLevelShortLogValue     =   ELPP_LITERAL("I");
-    static const base::type::char_t* kDebugLevelShortLogValue    =   ELPP_LITERAL("D");
-    static const base::type::char_t* kWarningLevelShortLogValue  =   ELPP_LITERAL("W");
-    static const base::type::char_t* kErrorLevelShortLogValue    =   ELPP_LITERAL("E");
-    static const base::type::char_t* kFatalLevelShortLogValue    =   ELPP_LITERAL("F");
-    static const base::type::char_t* kVerboseLevelShortLogValue  =   ELPP_LITERAL("V");
-    static const base::type::char_t* kTraceLevelShortLogValue    =   ELPP_LITERAL("T");
-    // Format specifiers - These are used to define log format
-    static const base::type::char_t* kAppNameFormatSpecifier          =      ELPP_LITERAL("%app");
-    static const base::type::char_t* kLoggerIdFormatSpecifier         =      ELPP_LITERAL("%logger");
-    static const base::type::char_t* kThreadIdFormatSpecifier         =      ELPP_LITERAL("%thread");
-    static const base::type::char_t* kSeverityLevelFormatSpecifier    =      ELPP_LITERAL("%level");
-    static const base::type::char_t* kSeverityLevelShortFormatSpecifier    =      ELPP_LITERAL("%levshort");
-    static const base::type::char_t* kDateTimeFormatSpecifier         =      ELPP_LITERAL("%datetime");
-    static const base::type::char_t* kLogFileFormatSpecifier          =      ELPP_LITERAL("%file");
-    static const base::type::char_t* kLogFileBaseFormatSpecifier      =      ELPP_LITERAL("%fbase");
-    static const base::type::char_t* kLogLineFormatSpecifier          =      ELPP_LITERAL("%line");
-    static const base::type::char_t* kLogLocationFormatSpecifier      =      ELPP_LITERAL("%loc");
-    static const base::type::char_t* kLogFunctionFormatSpecifier      =      ELPP_LITERAL("%func");
-    static const base::type::char_t* kCurrentUserFormatSpecifier      =      ELPP_LITERAL("%user");
-    static const base::type::char_t* kCurrentHostFormatSpecifier      =      ELPP_LITERAL("%host");
-    static const base::type::char_t* kMessageFormatSpecifier          =      ELPP_LITERAL("%msg");
-    static const base::type::char_t* kVerboseLevelFormatSpecifier     =      ELPP_LITERAL("%vlevel");
-    static const char* kDateTimeFormatSpecifierForFilename            =      "%datetime";
-    // Date/time
-    static const char* kDays[7]                         =      { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
-    static const char* kDaysAbbrev[7]                   =      { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
-    static const char* kMonths[12]                      =      { "January", "February", "March", "Apri", "May", "June", "July", "August",
-            "September", "October", "November", "December" };
-    static const char* kMonthsAbbrev[12]                =      { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
-    static const char* kDefaultDateTimeFormat           =      "%Y-%M-%d %H:%m:%s,%g";
-    static const char* kDefaultDateTimeFormatInFilename =      "%Y-%M-%d_%H-%m";
-    static const int kYearBase                          =      1900;
-    static const char* kAm                              =      "AM";
-    static const char* kPm                              =      "PM";
-    // Miscellaneous constants
-    static const char* kDefaultLoggerId                        =      "default";
-    static const char* kPerformanceLoggerId                    =      "performance";
-    static const char* kSysLogLoggerId                         =      "syslog";
-    static const char* kNullPointer                            =      "nullptr";
-    static const char  kFormatSpecifierChar                    =      '%';
-#if ELPP_VARIADIC_TEMPLATES_SUPPORTED
-    static const char  kFormatSpecifierCharValue               =      'v';
-#endif  // ELPP_VARIADIC_TEMPLATES_SUPPORTED
-    static const unsigned int kMaxLogPerContainer              =      100;
-    static const unsigned int kMaxLogPerCounter                =      100000;
-    static const unsigned int  kDefaultMillisecondsWidth       =      3;
-    static const base::type::VerboseLevel kMaxVerboseLevel     =      9;
-    static const char* kUnknownUser                            =      "user";
-    static const char* kUnknownHost                            =      "unknown-host";
-#if defined(ELPP_DEFAULT_LOG_FILE)
-    static const char* kDefaultLogFile                         =      ELPP_DEFAULT_LOG_FILE;
-#else
-#   if ELPP_OS_UNIX
-#      if ELPP_OS_ANDROID
-    static const char* kDefaultLogFile                         =      "logs/myeasylog.log";
-#      else
-    static const char* kDefaultLogFile                         =      "logs/myeasylog.log";
-#      endif  // ELPP_OS_ANDROID
-#   elif ELPP_OS_WINDOWS
-    static const char* kDefaultLogFile                         =      "logs\\myeasylog.log";
-#   endif  // ELPP_OS_UNIX
-#endif  // defined(ELPP_DEFAULT_LOG_FILE)
-#if !defined(ELPP_DISABLE_LOG_FILE_FROM_ARG)
-    static const char* kDefaultLogFileParam                    =      "--default-log-file";
-#endif  // !defined(ELPP_DISABLE_LOG_FILE_FROM_ARG)
-#if defined(ELPP_LOGGING_FLAGS_FROM_ARG)
-    static const char* kLoggingFlagsParam                      =      "--logging-flags";
-#endif  // defined(ELPP_LOGGING_FLAGS_FROM_ARG)
-#if ELPP_OS_WINDOWS
-    static const char* kFilePathSeperator                      =      "\\";
-#else
-    static const char* kFilePathSeperator                      =      "/";
-#endif  // ELPP_OS_WINDOWS
-    static const char* kValidLoggerIdSymbols                   =      "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._";
-    static const char* kConfigurationComment                   =      "##";
-    static const char* kConfigurationLevel                     =      "*";
-    static const char* kConfigurationLoggerId                  =      "--";
-    static const std::size_t kSourceFilenameMaxLength          =      100;
-    static const std::size_t kSourceLineMaxLength              =      10;
-    static const Level kPerformanceTrackerDefaultLevel         =      Level::Info;
-    const struct {
-        double value;
-        const base::type::char_t* unit;
-    } kTimeFormats[] = {
-       { 1000.0f, ELPP_LITERAL("mis") },
-       { 1000.0f, ELPP_LITERAL("ms") },
-       { 60.0f, ELPP_LITERAL("seconds") },
-       { 60.0f, ELPP_LITERAL("minutes") },
-       { 24.0f, ELPP_LITERAL("hours") },
-       { 7.0f, ELPP_LITERAL("days") }
-    };
-    static const int kTimeFormatsCount                           =      sizeof(kTimeFormats) / sizeof(kTimeFormats[0]);
-    const struct {
-        int numb;
-        const char* name;
-        const char* brief;
-        const char* detail;
-    } kCrashSignals[] = {
-        // NOTE: Do not re-order, if you do please check CrashHandler(bool) constructor and CrashHandler::setHandler(..)
-        { SIGABRT, "SIGABRT", "Abnormal termination",
-                "Program was abnormally terminated." },
-        { SIGFPE, "SIGFPE", "Erroneous arithmetic operation",
-                "Arithemetic operation issue such as division by zero or operation resulting in overflow." },
-        { SIGILL, "SIGILL", "Illegal instruction",
-                "Generally due to a corruption in the code or to an attempt to execute data."},
-        { SIGSEGV, "SIGSEGV", "Invalid access to memory",
-                "Program is trying to read an invalid (unallocated, deleted or corrupted) or inaccessible memory." },
-        { SIGINT, "SIGINT", "Interactive attention signal",
-                 "Interruption generated (generally) by user or operating system." },
-    };
-    static const int kCrashSignalsCount                          =      sizeof(kCrashSignals) / sizeof(kCrashSignals[0]);
-}  // namespace consts
-}  // namespace base
-typedef std::function<void(const char*, std::size_t)> PreRollOutCallback;
-namespace base {
-static inline void defaultPreRollOutCallback(const char*, std::size_t) {}
-/// @brief Enum to represent timestamp unit
-enum class TimestampUnit : base::type::EnumType {
-    Microsecond = 0, Millisecond = 1, Second = 2, Minute = 3, Hour = 4, Day = 5
-};
-/// @brief Format flags used to determine specifiers that are active for performance improvements.
-enum class FormatFlags : base::type::EnumType {
-    DateTime = 1<<1, LoggerId = 1<<2, File = 1<<3, Line = 1<<4, Location = 1<<5, Function = 1<<6,
-    User = 1<<7, Host = 1<<8, LogMessage = 1<<9, VerboseLevel = 1<<10, AppName = 1<<11, ThreadId = 1<<12,
-    Level = 1<<13, FileBase = 1<<14, LevelShort = 1<<15
-};
-/// @brief A milliseconds width class containing actual width and offset for date/time
-class MillisecondsWidth {
-public:
-    MillisecondsWidth(void) { init(base::consts::kDefaultMillisecondsWidth); }
-    explicit MillisecondsWidth(int width) { init(width); }
-    bool operator==(const MillisecondsWidth& msWidth) { return m_width == msWidth.m_width && m_offset == msWidth.m_offset; }
-    int m_width; unsigned int m_offset;
-private:
-    void init(int width) {
-        if (width < 1 || width > 6) {
-            width = base::consts::kDefaultMillisecondsWidth;
-        }
-        m_width = width;
-        switch (m_width) {
-        case 3: m_offset = 1000; break;
-        case 4: m_offset = 100; break;
-        case 5: m_offset = 10; break;
-        case 6: m_offset = 1; break;
-        default: m_offset = 1000; break;
-        }
-    }
-};
-/// @brief Namespace containing utility functions/static classes used internally
-namespace utils {
-/// @brief Deletes memory safely and points to null
-template <typename T>
-static inline
-typename std::enable_if<std::is_pointer<T*>::value, void>::type
-safeDelete(T*& pointer) {
-    if (pointer == nullptr)
-        return;
-    delete pointer;
-    pointer = nullptr;
-}
-/// @brief Gets value of const char* but if it is nullptr, a string nullptr is returned
-static inline const char* charPtrVal(const char* pointer) {
-    return pointer == nullptr ? base::consts::kNullPointer : pointer;
-}
-/// @brief Aborts application due with user-defined status
-static inline void abort(int status, const std::string& reason = std::string()) {
-    // Both status and reason params are there for debugging with tools like gdb etc
-    ELPP_UNUSED(status);
-    ELPP_UNUSED(reason);
-#if defined(ELPP_COMPILER_MSVC) && defined(_M_IX86) && defined(_DEBUG)
-   // Ignore msvc critical error dialog - break instead (on debug mode)
-    _asm int 3
-#else
-    ::abort();
-#endif  // defined(ELPP_COMPILER_MSVC) && defined(_M_IX86) && defined(_DEBUG)
-}
-/// @brief Bitwise operations for C++11 strong enum class. This casts e into Flag_T and returns value after bitwise operation
-/// Use these function as <pre>flag = bitwise::Or<MyEnum>(MyEnum::val1, flag);</pre>
-namespace bitwise {
-template <typename Enum>
-static inline base::type::EnumType And(Enum e, base::type::EnumType flag) {
-    return static_cast<base::type::EnumType>(flag) & static_cast<base::type::EnumType>(e);
-}
-template <typename Enum>
-static inline base::type::EnumType Not(Enum e, base::type::EnumType flag) {
-    return static_cast<base::type::EnumType>(flag) & ~(static_cast<base::type::EnumType>(e));
-}
-template <typename Enum>
-static inline base::type::EnumType Or(Enum e, base::type::EnumType flag) {
-    return static_cast<base::type::EnumType>(flag) | static_cast<base::type::EnumType>(e);
-}
-}  // namespace bitwise
-template <typename Enum>
-static inline void addFlag(Enum e, base::type::EnumType* flag) {
-    *flag = base::utils::bitwise::Or<Enum>(e, *flag);
-}
-template <typename Enum>
-static inline void removeFlag(Enum e, base::type::EnumType* flag) {
-    *flag = base::utils::bitwise::Not<Enum>(e, *flag);
-}
-template <typename Enum>
-static inline bool hasFlag(Enum e, base::type::EnumType flag) {
-    return base::utils::bitwise::And<Enum>(e, flag) > 0x0;
-}
-}  // namespace utils
-namespace threading {
-#if ELPP_THREADING_ENABLED
-#   if !ELPP_USE_STD_THREADING
-namespace internal {
-/// @brief A mutex wrapper for compiler that dont yet support std::mutex
-class Mutex : base::NoCopy {
-public:
-    Mutex(void) {
-#   if ELPP_OS_UNIX
-        pthread_mutex_init(&m_underlyingMutex, nullptr);
-#   elif ELPP_OS_WINDOWS
-        InitializeCriticalSection(&m_underlyingMutex);
-#   endif  // ELPP_OS_UNIX
-    }
-
-    virtual ~Mutex(void) {
-#   if ELPP_OS_UNIX
-        pthread_mutex_destroy(&m_underlyingMutex);
-#   elif ELPP_OS_WINDOWS
-        DeleteCriticalSection(&m_underlyingMutex);
-#   endif  // ELPP_OS_UNIX
-    }
-
-    inline void lock(void) {
-#   if ELPP_OS_UNIX
-        pthread_mutex_lock(&m_underlyingMutex);
-#   elif ELPP_OS_WINDOWS
-        EnterCriticalSection(&m_underlyingMutex);
-#   endif  // ELPP_OS_UNIX
-    }
-
-    inline bool try_lock(void) {
-#   if ELPP_OS_UNIX
-        return (pthread_mutex_trylock(&m_underlyingMutex) == 0);
-#   elif ELPP_OS_WINDOWS
-        return TryEnterCriticalSection(&m_underlyingMutex);
-#   endif  // ELPP_OS_UNIX
-    }
-
-    inline void unlock(void) {
-#   if ELPP_OS_UNIX
-        pthread_mutex_unlock(&m_underlyingMutex);
-#   elif ELPP_OS_WINDOWS
-        LeaveCriticalSection(&m_underlyingMutex);
-#   endif  // ELPP_OS_UNIX
-    }
-
-private:
-#   if ELPP_OS_UNIX
-    pthread_mutex_t m_underlyingMutex;
-#   elif ELPP_OS_WINDOWS
-    CRITICAL_SECTION m_underlyingMutex;
-#   endif  // ELPP_OS_UNIX
-};
-/// @brief Scoped lock for compiler that dont yet support std::lock_guard
-template <typename M>
-class ScopedLock : base::NoCopy {
-public:
-    explicit ScopedLock(M& mutex) {
-        m_mutex = &mutex;
-        m_mutex->lock();
-    }
-
-    virtual ~ScopedLock(void) {
-        m_mutex->unlock();
-    }
-private:
-    M* m_mutex;
-    ScopedLock(void);
-};
-} // namespace internal
-/// @brief Gets ID of currently running threading in windows systems. On unix, nothing is returned.
-static inline std::string getCurrentThreadId(void) {
-    std::stringstream ss;
-#      if (ELPP_OS_WINDOWS)
-    ss << GetCurrentThreadId();
-#      endif  // (ELPP_OS_WINDOWS)
-    return ss.str();
-}
-static inline void msleep(int) {
-    // No implementation for non std::thread version
-}
-typedef base::threading::internal::Mutex Mutex;
-typedef base::threading::internal::ScopedLock<base::threading::Mutex> ScopedLock;
-#   else
-/// @brief Gets ID of currently running threading using std::this_thread::get_id()
-static inline std::string getCurrentThreadId(void) {
-    std::stringstream ss;
-    ss << std::this_thread::get_id();
-    return ss.str();
-}
-static inline void msleep(int ms) {
-    // Only when async logging enabled - this is because async is strict on compiler
-#if ELPP_ASYNC_LOGGING
-    std::this_thread::sleep_for(std::chrono::milliseconds(ms));
-#endif  // ELPP_ASYNC_LOGGING
-}
-typedef std::mutex Mutex;
-typedef std::lock_guard<std::mutex> ScopedLock;
-#   endif  // !ELPP_USE_STD_THREADING
-#else
-namespace internal {
-/// @brief Mutex wrapper used when multi-threading is disabled.
-class NoMutex : base::NoCopy {
-public:
-    NoMutex(void) {}
-    inline void lock(void) {}
-    inline bool try_lock(void) { return true; }
-    inline void unlock(void) {}
-};
-/// @brief Lock guard wrapper used when multi-threading is disabled.
-template <typename Mutex>
-class NoScopedLock : base::NoCopy {
-public:
-    explicit NoScopedLock(Mutex&) {
-    }
-    virtual ~NoScopedLock(void) {
-    }
-private:
-    NoScopedLock(void);
-};
-}  // namespace internal
-static inline std::string getCurrentThreadId(void) {
-    return std::string();
-}
-static inline void msleep(int) {
-    // No custom implementation
-}
-typedef base::threading::internal::NoMutex Mutex;
-typedef base::threading::internal::NoScopedLock<base::threading::Mutex> ScopedLock;
-#endif  // ELPP_THREADING_ENABLED
-/// @brief Base of thread safe class, this class is inheritable-only
-class ThreadSafe {
-public:
-    virtual inline void acquireLock(void) ELPP_FINAL { m_mutex.lock(); }
-    virtual inline void releaseLock(void) ELPP_FINAL { m_mutex.unlock(); }
-    virtual inline base::threading::Mutex& lock(void) ELPP_FINAL { return m_mutex; }
-protected:
-    ThreadSafe(void) {}
-    virtual ~ThreadSafe(void) {}
-private:
-    base::threading::Mutex m_mutex;
-};
-}  // namespace threading
-namespace utils {
-class File : base::StaticClass {
-public:
-    /// @brief Creates new out file stream for specified filename.
-    /// @return Pointer to newly created fstream or nullptr
-    static base::type::fstream_t* newFileStream(const std::string& filename) {
-        base::type::fstream_t *fs = new base::type::fstream_t(filename.c_str(), 
-            base::type::fstream_t::out | base::type::fstream_t::app);
-#if defined(ELPP_UNICODE)
-        std::locale elppUnicodeLocale("");
-#if ELPP_OS_WINDOWS
-        std::locale elppUnicodeLocaleWindows(elppUnicodeLocale, new std::codecvt_utf8_utf16<wchar_t>);
-        elppUnicodeLocale = elppUnicodeLocaleWindows;
-#endif
-        fs->imbue(elppUnicodeLocale);
-#endif  // defined(ELPP_UNICODE)
-        if (fs->is_open()) {
-            fs->flush();
-        } else {
-            base::utils::safeDelete(fs);
-            ELPP_INTERNAL_ERROR("Bad file [" << filename << "]", true);
-        }
-        return fs;
-    }
-
-    /// @brief Gets size of file provided in stream
-    static std::size_t getSizeOfFile(base::type::fstream_t* fs) {
-        if (fs == nullptr) {
-            return 0;
-        }
-        std::streampos currPos = fs->tellg();
-        fs->seekg(0, fs->end);
-        std::size_t size = static_cast<std::size_t>(fs->tellg());
-        fs->seekg(currPos);
-        return size;
-    }
-
-    /// @brief Determines whether or not provided path exist in current file system
-    static inline bool pathExists(const char* path, bool considerFile = false) {
-        if (path == nullptr) {
-            return false;
-        }
-#if ELPP_OS_UNIX
-        ELPP_UNUSED(considerFile);
-        struct stat st;
-        return (stat(path, &st) == 0);
-#elif ELPP_OS_WINDOWS
-        DWORD fileType = GetFileAttributesA(path);
-        if (fileType == INVALID_FILE_ATTRIBUTES) {
-            return false;
-        }
-        return considerFile ? true : ((fileType & FILE_ATTRIBUTE_DIRECTORY) == 0 ? false : true);
-#endif  // ELPP_OS_UNIX
-    }
-
-    /// @brief Creates specified path on file system
-    /// @param path Path to create.
-    static bool createPath(const std::string& path) {
-        if (path.empty()) {
-            return false;
-        }
-        if (base::utils::File::pathExists(path.c_str())) {
-            return true;
-        }
-        int status = -1;
-
-        char* currPath = const_cast<char*>(path.c_str());
-        std::string builtPath = std::string();
-#if ELPP_OS_UNIX
-        if (path[0] == '/') {
-            builtPath = "/";
-        }
-        currPath = STRTOK(currPath, base::consts::kFilePathSeperator, 0);
-#elif ELPP_OS_WINDOWS
-        // Use secure functions API
-        char* nextTok_ = nullptr;
-        currPath = STRTOK(currPath, base::consts::kFilePathSeperator, &nextTok_);
-        ELPP_UNUSED(nextTok_);
-#endif  // ELPP_OS_UNIX
-        while (currPath != nullptr) {
-            builtPath.append(currPath);
-            builtPath.append(base::consts::kFilePathSeperator);
-#if ELPP_OS_UNIX
-            status = mkdir(builtPath.c_str(), ELPP_LOG_PERMS);
-            currPath = STRTOK(nullptr, base::consts::kFilePathSeperator, 0);
-#elif ELPP_OS_WINDOWS
-            status = _mkdir(builtPath.c_str());
-            currPath = STRTOK(nullptr, base::consts::kFilePathSeperator, &nextTok_);
-#endif  // ELPP_OS_UNIX
-        }
-        if (status == -1) {
-            ELPP_INTERNAL_ERROR("Error while creating path [" << path << "]", true);
-            return false;
-        }
-        return true;
-    }
-    /// @brief Extracts path of filename with leading slash
-    static std::string extractPathFromFilename(const std::string& fullPath,
-            const char* seperator = base::consts::kFilePathSeperator) {
-        if ((fullPath == "") || (fullPath.find(seperator) == std::string::npos)) {
-            return fullPath;
-        }
-        std::size_t lastSlashAt = fullPath.find_last_of(seperator);
-        if (lastSlashAt == 0) {
-            return std::string(seperator);
-        }
-        return fullPath.substr(0, lastSlashAt + 1);
-    }
-    /// @brief builds stripped filename and puts it in buff
-    static void buildStrippedFilename(const char* filename, char buff[], 
-            std::size_t limit = base::consts::kSourceFilenameMaxLength) {
-        std::size_t sizeOfFilename = strlen(filename);
-        if (sizeOfFilename >= limit) {
-            filename += (sizeOfFilename - limit);
-            if (filename[0] != '.' && filename[1] != '.') {  // prepend if not already
-                filename += 3;  // 3 = '..'
-                STRCAT(buff, "..", limit);
-            }
-        }
-        STRCAT(buff, filename, limit);
-    }
-    /// @brief builds base filename and puts it in buff
-    static void buildBaseFilename(const std::string& fullPath, char buff[], 
-            std::size_t limit = base::consts::kSourceFilenameMaxLength,
-            const char* seperator = base::consts::kFilePathSeperator) {
-        const char *filename = fullPath.c_str();
-        std::size_t lastSlashAt = fullPath.find_last_of(seperator);
-        filename += lastSlashAt ? lastSlashAt+1 : 0;
-        std::size_t sizeOfFilename = strlen(filename);
-        if (sizeOfFilename >= limit) {
-            filename += (sizeOfFilename - limit);
-            if (filename[0] != '.' && filename[1] != '.') {  // prepend if not already
-                filename += 3;  // 3 = '..'
-                STRCAT(buff, "..", limit);
-            }
-        }
-        STRCAT(buff, filename, limit);
-    }
-};
-/// @brief String utilities helper class used internally. You should not use it.
-class Str : base::StaticClass {
-public:
-    /// @brief Checks if character is digit. Dont use libc implementation of it to prevent locale issues.
-    static inline bool isDigit(char c) {
-        return c >= '0' && c <= '9';
-    }
-
-    /// @brief Matches wildcards, '*' and '?' only supported.
-    static bool wildCardMatch(const char* str, const char* pattern) {
-        while (*pattern) {
-            switch (*pattern) {
-            case '?':
-                if (!*str)
-                    return false;
-                ++str;
-                ++pattern;
-                break;
-            case '*':
-                if (wildCardMatch(str, pattern + 1))
-                    return true;
-                if (*str && wildCardMatch(str + 1, pattern))
-                    return true;
-                return false;
-                break;
-            default:
-                if (*str++ != *pattern++)
-                    return false;
-                break;
-            }
-        }
-        return !*str && !*pattern;
-    }
-
-    /// @brief Trims string from start
-    /// @param [in,out] str String to trim
-    static inline std::string& ltrim(std::string& str) {
-        str.erase(str.begin(), std::find_if(str.begin(), str.end(), std::not1(std::ptr_fun<int, int>(&std::isspace))));
-        return str;
-    }
-
-    /// @brief Trim string from end
-    /// @param [in,out] str String to trim
-    static inline std::string& rtrim(std::string& str) {
-        str.erase(std::find_if(str.rbegin(), str.rend(), std::not1(std::ptr_fun<int, int>(&std::isspace))).base(), str.end());
-        return str;
-    }
-
-    /// @brief Trims string from left and right
-    /// @param [in,out] str String to trim
-    static inline std::string& trim(std::string& str) {
-        return ltrim(rtrim(str));
-    }
-
-    /// @brief Determines whether or not str starts with specified string
-    /// @param str String to check
-    /// @param start String to check against
-    /// @return Returns true if starts with specified string, false otherwise
-    static inline bool startsWith(const std::string& str, const std::string& start) {
-        return (str.length() >= start.length()) && (str.compare(0, start.length(), start) == 0);
-    }
-
-    /// @brief Determines whether or not str ends with specified string
-    /// @param str String to check
-    /// @param end String to check against
-    /// @return Returns true if ends with specified string, false otherwise
-    static inline bool endsWith(const std::string& str, const std::string& end) {
-        return (str.length() >= end.length()) && (str.compare(str.length() - end.length(), end.length(), end) == 0);
-    }
-
-    /// @brief Replaces all instances of replaceWhat with 'replaceWith'. Original variable is changed for performance.
-    /// @param [in,out] str String to replace from
-    /// @param replaceWhat Character to replace
-    /// @param replaceWith Character to replace with
-    /// @return Modified version of str
-    static inline std::string& replaceAll(std::string& str, char replaceWhat, char replaceWith) {
-        std::replace(str.begin(), str.end(), replaceWhat, replaceWith);
-        return str;
-    }
-
-    /// @brief Replaces all instances of 'replaceWhat' with 'replaceWith'. (String version) Replaces in place
-    /// @param str String to replace from
-    /// @param replaceWhat Character to replace
-    /// @param replaceWith Character to replace with
-    /// @return Modified (original) str
-    static inline std::string& replaceAll(std::string& str, const std::string& replaceWhat, // NOLINT
-            const std::string& replaceWith) {
-        if (replaceWhat == replaceWith)
-            return str;
-        std::size_t foundAt = std::string::npos;
-        while ((foundAt = str.find(replaceWhat, foundAt + 1)) != std::string::npos) {
-            str.replace(foundAt, replaceWhat.length(), replaceWith);
-        }
-        return str;
-    }
-
-    static void replaceFirstWithEscape(base::type::string_t& str, const base::type::string_t& replaceWhat, // NOLINT
-            const base::type::string_t& replaceWith) {
-        std::size_t foundAt = base::type::string_t::npos;
-        while ((foundAt = str.find(replaceWhat, foundAt + 1)) != base::type::string_t::npos) {
-            if (foundAt > 0 && str[foundAt - 1] == base::consts::kFormatSpecifierChar) {
-                str.erase(foundAt > 0 ? foundAt - 1 : 0, 1);
-                ++foundAt;
-            } else {
-                str.replace(foundAt, replaceWhat.length(), replaceWith);
-                return;
-            }
-        }
-    }
-#if defined(ELPP_UNICODE)
-    static void replaceFirstWithEscape(base::type::string_t& str, const base::type::string_t& replaceWhat, // NOLINT
-            const std::string& replaceWith) {
-        replaceFirstWithEscape(str, replaceWhat, base::type::string_t(replaceWith.begin(), replaceWith.end()));
-    }
-#endif  // defined(ELPP_UNICODE)
-    /// @brief Converts string to uppercase
-    /// @param str String to convert
-    /// @return Uppercase string
-    static inline std::string& toUpper(std::string& str) {
-        std::transform(str.begin(), str.end(), str.begin(), ::toupper);
-        return str;
-    }
-
-    /// @brief Compares cstring equality - uses strcmp
-    static inline bool cStringEq(const char* s1, const char* s2) {
-        if (s1 == nullptr && s2 == nullptr) return true;
-        if (s1 == nullptr || s2 == nullptr) return false;
-        return strcmp(s1, s2) == 0;
-    }
-
-    /// @brief Compares cstring equality (case-insensitive) - uses toupper(char)
-    /// Dont use strcasecmp because of CRT (VC++)
-    static bool cStringCaseEq(const char* s1, const char* s2) {
-        if (s1 == nullptr && s2 == nullptr) return true;
-        if (s1 == nullptr || s2 == nullptr) return false;
-        if (strlen(s1) != strlen(s2)) return false;
-        while (*s1 != '\0' && *s2 != '\0') {
-            if (::toupper(*s1) != ::toupper(*s2)) return false;
-            ++s1;
-            ++s2;
-        }
-        return true;
-    }
-
-    /// @brief Returns true if c exist in str
-    static inline bool contains(const char* str, char c) {
-        for (; *str; ++str) {
-            if (*str == c)
-                return true;
-        }
-        return false;
-    }
-
-    static inline char* convertAndAddToBuff(std::size_t n, int len, char* buf, const char* bufLim, bool zeroPadded = true) {
-        char localBuff[10] = "";
-        char* p = localBuff + sizeof(localBuff) - 2;
-        if (n > 0) {
-            for (; n > 0 && p > localBuff && len > 0; n /= 10, --len)
-                *--p = static_cast<char>(n % 10 + '0');
-        } else {
-            *--p = '0';
-            --len;
-        }
-        if (zeroPadded)
-            while (p > localBuff && len-- > 0) *--p = static_cast<char>('0');
-        return addToBuff(p, buf, bufLim);
-    }
-
-    static inline char* addToBuff(const char* str, char* buf, const char* bufLim) {
-        while ((buf < bufLim) && ((*buf = *str++) != '\0'))
-            ++buf;
-        return buf;
-    }
-
-    static inline char* clearBuff(char buff[], std::size_t lim) {
-        STRCPY(buff, "", lim);
-        ELPP_UNUSED(lim);  // For *nix we dont have anything using lim in above STRCPY macro
-        return buff;
-    }
-
-    /// @brief Converst wchar* to char*
-    ///        NOTE: Need to free return value after use!
-    static char* wcharPtrToCharPtr(const wchar_t* line) {
-        std::size_t len_ = wcslen(line) + 1;
-        char* buff_ = static_cast<char*>(malloc(len_ + 1));
-#      if ELPP_OS_UNIX || (ELPP_OS_WINDOWS && !ELPP_CRT_DBG_WARNINGS)
-        std::wcstombs(buff_, line, len_);
-#      elif ELPP_OS_WINDOWS
-        std::size_t convCount_ = 0;
-        mbstate_t mbState_;
-        ::memset(static_cast<void*>(&mbState_), 0, sizeof(mbState_));
-        wcsrtombs_s(&convCount_, buff_, len_, &line, len_, &mbState_);
-#      endif  // ELPP_OS_UNIX || (ELPP_OS_WINDOWS && !ELPP_CRT_DBG_WARNINGS)
-       return buff_;
-    }
-};
-/// @brief Operating System helper static class used internally. You should not use it.
-class OS : base::StaticClass {
-public:
-#if ELPP_OS_WINDOWS
-    /// @brief Gets environment variables for Windows based OS. 
-    ///        We are not using <code>getenv(const char*)</code> because of CRT deprecation
-    /// @param varname Variable name to get environment variable value for
-    /// @return If variable exist the value of it otherwise nullptr
-    static const char* getWindowsEnvironmentVariable(const char* varname) {
-        const DWORD bufferLen = 50;
-        static char buffer[bufferLen];
-        if (GetEnvironmentVariableA(varname, buffer, bufferLen)) {
-            return buffer;
-        }
-        return nullptr;
-    }
-#endif  // ELPP_OS_WINDOWS
-#if ELPP_OS_ANDROID
-    /// @brief Reads android property value
-    static inline std::string getProperty(const char* prop) {
-        char propVal[PROP_VALUE_MAX + 1];
-        int ret = __system_property_get(prop, propVal);
-        return ret == 0 ? std::string() : std::string(propVal);
-    }
-
-    /// @brief Reads android device name
-    static std::string getDeviceName(void) {
-        std::stringstream ss;
-        std::string manufacturer = getProperty("ro.product.manufacturer");
-        std::string model = getProperty("ro.product.model");
-        if (manufacturer.empty() || model.empty()) {
-            return std::string();
-        }
-        ss << manufacturer << "-" << model;
-        return ss.str();
-    }
-#endif  // ELPP_OS_ANDROID
-
-    /// @brief Runs command on terminal and returns the output.
-    ///
-    /// @detail This is applicable only on unix based systems, for all other OS, an empty string is returned.
-    /// @param command Bash command
-    /// @return Result of bash output or empty string if no result found.
-    static const std::string getBashOutput(const char* command) {
-#if (ELPP_OS_UNIX && !ELPP_OS_ANDROID && !ELPP_CYGWIN)
-        if (command == nullptr) {
-            return std::string();
-        }
-        FILE* proc = nullptr;
-        if ((proc = popen(command, "r")) == nullptr) {
-            ELPP_INTERNAL_ERROR("\nUnable to run command [" << command << "]", true);
-            return std::string();
-        }
-        char hBuff[4096];
-        if (fgets(hBuff, sizeof(hBuff), proc) != nullptr) {
-            pclose(proc);
-            if (hBuff[strlen(hBuff) - 1] == '\n') {
-                hBuff[strlen(hBuff) - 1] = '\0';
-            }
-            return std::string(hBuff);
-        }
-        return std::string();
-#else
-        ELPP_UNUSED(command);
-        return std::string();
-#endif  // (ELPP_OS_UNIX && !ELPP_OS_ANDROID && !ELPP_CYGWIN)
-    }
-
-    /// @brief Gets environment variable. This is cross-platform and CRT safe (for VC++)
-    /// @param variableName Environment variable name
-    /// @param defaultVal If no environment variable or value found the value to return by default
-    /// @param alternativeBashCommand If environment variable not found what would be alternative bash command
-    ///        in order to look for value user is looking for. E.g, for 'user' alternative command will 'whoami'
-    static std::string getEnvironmentVariable(const char* variableName, const char* defaultVal, const char* alternativeBashCommand = nullptr) {
-#if ELPP_OS_UNIX
-        const char* val = getenv(variableName);
-#elif ELPP_OS_WINDOWS
-        const char* val = getWindowsEnvironmentVariable(variableName);
-#endif  // ELPP_OS_UNIX
-        if ((val == nullptr) || ((strcmp(val, "") == 0))) {
-#if ELPP_OS_UNIX && defined(ELPP_FORCE_ENV_VAR_FROM_BASH)
-           // Try harder on unix-based systems
-            std::string valBash = base::utils::OS::getBashOutput(alternativeBashCommand);
-            if (valBash.empty()) {
-                return std::string(defaultVal);
-            } else {
-                return valBash;
-            }
-#elif ELPP_OS_WINDOWS || ELPP_OS_UNIX
-            ELPP_UNUSED(alternativeBashCommand);
-            return std::string(defaultVal);
-#endif  // ELPP_OS_UNIX && defined(ELPP_FORCE_ENV_VAR_FROM_BASH)
-        }
-        return std::string(val);
-    }
-   /// @brief Gets current username.
-    static inline std::string currentUser(void) {
-#if ELPP_OS_UNIX && !ELPP_OS_ANDROID
-        return getEnvironmentVariable("USER", base::consts::kUnknownUser, "whoami");
-#elif ELPP_OS_WINDOWS
-        return getEnvironmentVariable("USERNAME", base::consts::kUnknownUser);
-#elif ELPP_OS_ANDROID
-        ELPP_UNUSED(base::consts::kUnknownUser);
-        return std::string("android");
-#else
-        return std::string();
-#endif  // ELPP_OS_UNIX && !ELPP_OS_ANDROID
-    }
-
-    /// @brief Gets current host name or computer name.
-    ///
-    /// @detail For android systems this is device name with its manufacturer and model seperated by hyphen
-    static inline std::string currentHost(void) {
-#if ELPP_OS_UNIX && !ELPP_OS_ANDROID
-        return getEnvironmentVariable("HOSTNAME", base::consts::kUnknownHost, "hostname");
-#elif ELPP_OS_WINDOWS
-        return getEnvironmentVariable("COMPUTERNAME", base::consts::kUnknownHost);
-#elif ELPP_OS_ANDROID
-        ELPP_UNUSED(base::consts::kUnknownHost);
-        return getDeviceName();
-#else
-        return std::string();
-#endif  // ELPP_OS_UNIX && !ELPP_OS_ANDROID
-    }
-    /// @brief Whether or not terminal supports colors
-    static inline bool termSupportsColor(void) {
-        std::string term = getEnvironmentVariable("TERM", "");
-        return term == "xterm" || term == "xterm-color" || term == "xterm-256color" ||
-                              term == "screen" || term == "linux" || term == "cygwin";
-    }
-};
-extern std::string s_currentUser;
-extern std::string s_currentHost;
-extern bool s_termSupportsColor;
-#define ELPP_INITI_BASIC_DECLR \
-    namespace el {\
-        namespace base {\
-            namespace utils {\
-                std::string s_currentUser = el::base::utils::OS::currentUser(); \
-                std::string s_currentHost = el::base::utils::OS::currentHost(); \
-                bool s_termSupportsColor = el::base::utils::OS::termSupportsColor(); \
-            }\
-        }\
-   }
-/// @brief Contains utilities for cross-platform date/time. This class make use of el::base::utils::Str
-class DateTime : base::StaticClass {
-public:
-    /// @brief Cross platform gettimeofday for Windows and unix platform. This can be used to determine current millisecond.
-    ///
-    /// @detail For unix system it uses gettimeofday(timeval*, timezone*) and for Windows, a seperate implementation is provided
-    /// @param [in,out] tv Pointer that gets updated
-    static void gettimeofday(struct timeval* tv) {
-#if ELPP_OS_WINDOWS
-        if (tv != nullptr) {
-#   if ELPP_COMPILER_MSVC || defined(_MSC_EXTENSIONS)
-            const unsigned __int64 delta_ = 11644473600000000Ui64;
-#   else
-            const unsigned __int64 delta_ = 11644473600000000ULL;
-#   endif  // ELPP_COMPILER_MSVC || defined(_MSC_EXTENSIONS)
-            const double secOffSet = 0.000001;
-            const unsigned long usecOffSet = 1000000;
-            FILETIME fileTime;
-            GetSystemTimeAsFileTime(&fileTime);
-            unsigned __int64 present = 0;
-            present |= fileTime.dwHighDateTime;
-            present = present << 32;
-            present |= fileTime.dwLowDateTime;
-            present /= 10;  // mic-sec
-           // Subtract the difference
-            present -= delta_;
-            tv->tv_sec = static_cast<long>(present * secOffSet);
-            tv->tv_usec = static_cast<long>(present % usecOffSet);
-        }
-#else
-        ::gettimeofday(tv, nullptr);
-#endif  // ELPP_OS_WINDOWS
-    }
-
-    /// @brief Gets current date and time with milliseconds.
-    /// @param format User provided date/time format
-    /// @param msWidth A pointer to base::MillisecondsWidth from configuration (non-null)
-    /// @returns string based date time in specified format.
-    static inline std::string getDateTime(const char* format, const base::MillisecondsWidth* msWidth) {
-        struct timeval currTime;
-        gettimeofday(&currTime);
-        struct ::tm timeInfo;
-        buildTimeInfo(&currTime, &timeInfo);
-        const int kBuffSize = 30;
-        char buff_[kBuffSize] = "";
-        parseFormat(buff_, kBuffSize, format, &timeInfo, static_cast<std::size_t>(currTime.tv_usec / msWidth->m_offset), msWidth);
-        return std::string(buff_);
-    }
-
-    /// @brief Formats time to get unit accordingly, units like second if > 1000 or minutes if > 60000 etc
-    static base::type::string_t formatTime(unsigned long long time, base::TimestampUnit timestampUnit) {
-        double result = static_cast<double>(time);
-        base::type::EnumType start = static_cast<base::type::EnumType>(timestampUnit);
-        const base::type::char_t* unit = base::consts::kTimeFormats[start].unit;
-        for (base::type::EnumType i = start; i < base::consts::kTimeFormatsCount - 1; ++i) {
-            if (result <= base::consts::kTimeFormats[i].value) {
-                break;
-            }
-            result /= base::consts::kTimeFormats[i].value;
-            unit = base::consts::kTimeFormats[i + 1].unit;
-        }
-        base::type::stringstream_t ss;
-        ss << result << " " << unit;
-        return ss.str();
-    }
-
-    /// @brief Gets time difference in milli/micro second depending on timestampUnit
-    static inline unsigned long long getTimeDifference(const struct timeval& endTime, const struct timeval& startTime, base::TimestampUnit timestampUnit) {
-        if (timestampUnit == base::TimestampUnit::Microsecond) {
-            return static_cast<unsigned long long>(static_cast<unsigned long long>(1000000 * endTime.tv_sec + endTime.tv_usec) -
-                    static_cast<unsigned long long>(1000000 * startTime.tv_sec + startTime.tv_usec));
-        } else {
-            return static_cast<unsigned long long>((((endTime.tv_sec - startTime.tv_sec) * 1000000) + (endTime.tv_usec - startTime.tv_usec)) / 1000);
-        }
-    }
-
-private:
-    static inline struct ::tm* buildTimeInfo(struct timeval* currTime, struct ::tm* timeInfo) {
-#if ELPP_OS_UNIX
-        time_t rawTime = currTime->tv_sec;
-        ::localtime_r(&rawTime, timeInfo);
-        return timeInfo;
-#else
-#   if ELPP_COMPILER_MSVC
-        ELPP_UNUSED(currTime);
-        time_t t;
-        _time64(&t);
-        localtime_s(timeInfo, &t);
-        return timeInfo;
-#   else
-        // For any other compilers that don't have CRT warnings issue e.g, MinGW or TDM GCC- we use different method
-        time_t rawTime = currTime->tv_sec;
-        struct tm* tmInf = localtime(&rawTime);
-        *timeInfo = *tmInf;
-        return timeInfo;
-#   endif  // ELPP_COMPILER_MSVC
-#endif  // ELPP_OS_UNIX
-    }
-    static char* parseFormat(char* buf, std::size_t bufSz, const char* format, const struct tm* tInfo,
-            std::size_t msec, const base::MillisecondsWidth* msWidth) {
-        const char* bufLim = buf + bufSz;
-        for (; *format; ++format) {
-            if (*format == base::consts::kFormatSpecifierChar) {
-                switch (*++format) {
-                case base::consts::kFormatSpecifierChar:  // Escape
-                    break;
-                case '\0':  // End
-                    --format;
-                    break;
-                case 'd':  // Day
-                    buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_mday, 2, buf, bufLim);
-                    continue;
-                case 'a':  // Day of week (short)
-                    buf = base::utils::Str::addToBuff(base::consts::kDaysAbbrev[tInfo->tm_wday], buf, bufLim);
-                    continue;
-                case 'A':  // Day of week (long)
-                    buf = base::utils::Str::addToBuff(base::consts::kDays[tInfo->tm_wday], buf, bufLim);
-                    continue;
-                case 'M':  // month
-                    buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_mon + 1, 2, buf, bufLim);
-                    continue;
-                case 'b':  // month (short)
-                    buf = base::utils::Str::addToBuff(base::consts::kMonthsAbbrev[tInfo->tm_mon], buf, bufLim);
-                    continue;
-                case 'B':  // month (long)
-                    buf = base::utils::Str::addToBuff(base::consts::kMonths[tInfo->tm_mon], buf, bufLim);
-                    continue;
-                case 'y':  // year (two digits)
-                    buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_year + base::consts::kYearBase, 2, buf, bufLim);
-                    continue;
-                case 'Y':  // year (four digits)
-                    buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_year + base::consts::kYearBase, 4, buf, bufLim);
-                    continue;
-                case 'h':  // hour (12-hour)
-                    buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_hour % 12, 2, buf, bufLim);
-                    continue;
-                case 'H':  // hour (24-hour)
-                    buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_hour, 2, buf, bufLim);
-                    continue;
-                case 'm':  // minute
-                    buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_min, 2, buf, bufLim);
-                    continue;
-                case 's':  // second
-                    buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_sec, 2, buf, bufLim);
-                    continue;
-                case 'z':  // milliseconds
-                case 'g':
-                    buf = base::utils::Str::convertAndAddToBuff(msec, msWidth->m_width, buf, bufLim);
-                    continue;
-                case 'F':  // AM/PM
-                    buf = base::utils::Str::addToBuff((tInfo->tm_hour >= 12) ? base::consts::kPm : base::consts::kAm, buf, bufLim);
-                    continue;
-                default:
-                    continue;
-                }
-            }
-            if (buf == bufLim) break;
-            *buf++ = *format;
-        }
-        return buf;
-    }
-};
-/// @brief Command line arguments for application if specified using el::Helpers::setArgs(..) or START_EASYLOGGINGPP(..)
-class CommandLineArgs {
-public:
-    CommandLineArgs(void) {
-        setArgs(0, static_cast<char**>(nullptr));
-    }
-    CommandLineArgs(int argc, const char** argv) {
-        setArgs(argc, argv);
-    }
-    CommandLineArgs(int argc, char** argv) {
-        setArgs(argc, argv);
-    }
-    virtual ~CommandLineArgs(void) {}
-    /// @brief Sets arguments and parses them
-    inline void setArgs(int argc, const char** argv) {
-        setArgs(argc, const_cast<char**>(argv));
-    }
-    /// @brief Sets arguments and parses them
-    inline void setArgs(int argc, char** argv) {
-        m_params.clear();
-        m_paramsWithValue.clear();
-        if (argc == 0 || argv == nullptr) {
-            return;
-        }
-        m_argc = argc;
-        m_argv = argv;
-        for (int i = 1; i < m_argc; ++i) {
-            const char* v = (strstr(m_argv[i], "="));
-            if (v != nullptr && strlen(v) > 0) {
-                std::string key = std::string(m_argv[i]);
-                key = key.substr(0, key.find_first_of('='));
-                if (hasParamWithValue(key.c_str())) {
-                    ELPP_INTERNAL_INFO(1, "Skipping [" << key << "] arg since it already has value [" 
-                        << getParamValue(key.c_str()) << "]");
-                } else {
-                    m_paramsWithValue.insert(std::make_pair(key, std::string(v + 1)));
-                }
-            }
-            if (v == nullptr) {
-                if (hasParam(m_argv[i])) {
-                    ELPP_INTERNAL_INFO(1, "Skipping [" << m_argv[i] << "] arg since it already exists");
-                } else {
-                    m_params.push_back(std::string(m_argv[i]));
-                }
-            }
-        }
-    }
-    /// @brief Returns true if arguments contain paramKey with a value (seperated by '=')
-    inline bool hasParamWithValue(const char* paramKey) const {
-        return m_paramsWithValue.find(std::string(paramKey)) != m_paramsWithValue.end();
-    }
-    /// @brief Returns value of arguments
-    /// @see hasParamWithValue(const char*)
-    inline const char* getParamValue(const char* paramKey) const {
-        return m_paramsWithValue.find(std::string(paramKey))->second.c_str();
-    }
-    /// @brief Return true if arguments has a param (not having a value) i,e without '='
-    inline bool hasParam(const char* paramKey) const {
-        return std::find(m_params.begin(), m_params.end(), std::string(paramKey)) != m_params.end();
-    }
-    /// @brief Returns true if no params available. This exclude argv[0]
-    inline bool empty(void) const {
-        return m_params.empty() && m_paramsWithValue.empty();
-    }
-    /// @brief Returns total number of arguments. This exclude argv[0]
-    inline std::size_t size(void) const {
-        return m_params.size() + m_paramsWithValue.size();
-    }
-    inline friend base::type::ostream_t& operator<<(base::type::ostream_t& os, const CommandLineArgs& c) {
-        for (int i = 1; i < c.m_argc; ++i) {
-            os << ELPP_LITERAL("[") << c.m_argv[i] << ELPP_LITERAL("]");
-            if (i < c.m_argc - 1) {
-                os << ELPP_LITERAL(" ");
-            }
-        }
-        return os;
-    }
-
-private:
-    int m_argc;
-    char** m_argv;
-    std::map<std::string, std::string> m_paramsWithValue;
-    std::vector<std::string> m_params;
-};
-/// @brief Abstract registry (aka repository) that provides basic interface for pointer repository specified by T_Ptr type.
-///
-/// @detail Most of the functions are virtual final methods but anything implementing this abstract class should implement
-/// unregisterAll() and deepCopy(const AbstractRegistry<T_Ptr, Container>&) and write registerNew() method according to container
-/// and few more methods; get() to find element, unregister() to unregister single entry.
-/// Please note that this is thread-unsafe and should also implement thread-safety mechanisms in implementation.
-template <typename T_Ptr, typename Container>
-class AbstractRegistry : public base::threading::ThreadSafe {
-public:
-    typedef typename Container::iterator iterator;
-    typedef typename Container::const_iterator const_iterator;
-
-    /// @brief Default constructor
-    AbstractRegistry(void) {}
-
-    /// @brief Move constructor that is useful for base classes
-    AbstractRegistry(AbstractRegistry&& sr) {
-        if (this == &sr) {
-            return;
-        }
-        unregisterAll();
-        m_list = std::move(sr.m_list);
-    }
-
-    bool operator==(const AbstractRegistry<T_Ptr, Container>& other) {
-        if (size() != other.size()) {
-            return false;
-        }
-        for (std::size_t i = 0; i < m_list.size(); ++i) {
-            if (m_list.at(i) != other.m_list.at(i)) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    bool operator!=(const AbstractRegistry<T_Ptr, Container>& other) {
-        if (size() != other.size()) {
-            return true;
-        }
-        for (std::size_t i = 0; i < m_list.size(); ++i) {
-            if (m_list.at(i) != other.m_list.at(i)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /// @brief Assignment move operator
-    AbstractRegistry& operator=(AbstractRegistry&& sr) {
-        if (this == &sr) {
-            return *this;
-        }
-        unregisterAll();
-        m_list = std::move(sr.m_list);
-        return *this;
-    }
-
-    virtual ~AbstractRegistry(void) {
-    }
-
-    /// @return Iterator pointer from start of repository
-    virtual inline iterator begin(void) ELPP_FINAL {
-        return m_list.begin();
-    }
-
-    /// @return Iterator pointer from end of repository
-    virtual inline iterator end(void) ELPP_FINAL {
-        return m_list.end();
-    }
-
-
-    /// @return Constant iterator pointer from start of repository
-    virtual inline const_iterator cbegin(void) const ELPP_FINAL {
-        return m_list.cbegin();
-    }
-
-    /// @return End of repository
-    virtual inline const_iterator cend(void) const ELPP_FINAL {
-        return m_list.cend();
-    }
-
-    /// @return Whether or not repository is empty
-    virtual inline bool empty(void) const ELPP_FINAL {
-        return m_list.empty();
-    }
-
-    /// @return Size of repository
-    virtual inline std::size_t size(void) const ELPP_FINAL {
-        return m_list.size();
-    }
-
-    /// @brief Returns underlying container by reference
-    virtual inline Container& list(void) ELPP_FINAL {
-        return m_list;
-    }
-
-    /// @brief Returns underlying container by constant reference.
-    virtual inline const Container& list(void) const ELPP_FINAL {
-        return m_list;
-    }
-
-    /// @brief Unregisters all the pointers from current repository.
-    virtual void unregisterAll(void) = 0;
-
-protected:
-    virtual void deepCopy(const AbstractRegistry<T_Ptr, Container>&) = 0;
-    void reinitDeepCopy(const AbstractRegistry<T_Ptr, Container>& sr) {
-        unregisterAll();
-        deepCopy(sr);
-    }
-
-private:
-    Container m_list;
-};
-
-/// @brief A pointer registry mechanism to manage memory and provide search functionalities. (non-predicate version)
-///
-/// @detail NOTE: This is thread-unsafe implementation (although it contains lock function, it does not use these functions)
-///         of AbstractRegistry<T_Ptr, Container>. Any implementation of this class should be  
-///         explicitly (by using lock functions)
-template <typename T_Ptr, typename T_Key = const char*>
-class Registry : public AbstractRegistry<T_Ptr, std::map<T_Key, T_Ptr*>> {
-public:
-    typedef typename Registry<T_Ptr, T_Key>::iterator iterator;
-    typedef typename Registry<T_Ptr, T_Key>::const_iterator const_iterator;
-
-    Registry(void) {}
-
-    /// @brief Copy constructor that is useful for base classes. Try to avoid this constructor, use move constructor.
-    Registry(const Registry& sr) : AbstractRegistry<T_Ptr, std::vector<T_Ptr*>>() {
-        if (this == &sr) {
-            return;
-        }
-        this->reinitDeepCopy(sr);
-    }
-
-    /// @brief Assignment operator that unregisters all the existing registeries and deeply copies each of repo element
-    /// @see unregisterAll()
-    /// @see deepCopy(const AbstractRegistry&)
-    Registry& operator=(const Registry& sr) {
-        if (this == &sr) {
-            return *this;
-        }
-        this->reinitDeepCopy(sr);
-        return *this;
-    }
-
-    virtual ~Registry(void) {
-        unregisterAll();
-    }
-
-protected:
-    virtual inline void unregisterAll(void) ELPP_FINAL {
-        if (!this->empty()) {
-            for (auto&& curr : this->list()) {
-                base::utils::safeDelete(curr.second);
-            }
-            this->list().clear();
-        }
-    }
-
-    /// @brief Registers new registry to repository.
-    virtual inline void registerNew(const T_Key& uniqKey, T_Ptr* ptr) ELPP_FINAL {
-        unregister(uniqKey);
-        this->list().insert(std::make_pair(uniqKey, ptr));
-    }
-
-    /// @brief Unregisters single entry mapped to specified unique key
-    inline void unregister(const T_Key& uniqKey) {
-        T_Ptr* existing = get(uniqKey);
-        if (existing != nullptr) {
-            base::utils::safeDelete(existing);
-            this->list().erase(uniqKey);
-        }
-    }
-
-    /// @brief Gets pointer from repository. If none found, nullptr is returned.
-    inline T_Ptr* get(const T_Key& uniqKey) {
-        iterator it = this->list().find(uniqKey);
-        return it == this->list().end()
-                ? nullptr
-                : it->second;
-    }
-
-private:
-    virtual inline void deepCopy(const AbstractRegistry<T_Ptr, std::map<T_Key, T_Ptr*>>& sr) ELPP_FINAL {
-        for (const_iterator it = sr.cbegin(); it != sr.cend(); ++it) {
-            registerNew(it->first, new T_Ptr(*it->second));
-        }
-    }
-};
-
-/// @brief A pointer registry mechanism to manage memory and provide search functionalities. (predicate version)
-///
-/// @detail NOTE: This is thread-unsafe implementation of AbstractRegistry<T_Ptr, Container>. Any implementation of this class
-/// should be made thread-safe explicitly
-template <typename T_Ptr, typename Pred>
-class RegistryWithPred : public AbstractRegistry<T_Ptr, std::vector<T_Ptr*>> {
-public:
-    typedef typename RegistryWithPred<T_Ptr, Pred>::iterator iterator;
-    typedef typename RegistryWithPred<T_Ptr, Pred>::const_iterator const_iterator;
-
-    RegistryWithPred(void) {
-    }
-
-    virtual ~RegistryWithPred(void) {
-        unregisterAll();
-    }
-
-    /// @brief Copy constructor that is useful for base classes. Try to avoid this constructor, use move constructor.
-    RegistryWithPred(const RegistryWithPred& sr) : AbstractRegistry<T_Ptr, std::vector<T_Ptr*>>() {
-        if (this == &sr) {
-            return;
-        }
-        this->reinitDeepCopy(sr);
-    }
-
-    /// @brief Assignment operator that unregisters all the existing registeries and deeply copies each of repo element
-    /// @see unregisterAll()
-    /// @see deepCopy(const AbstractRegistry&)
-    RegistryWithPred& operator=(const RegistryWithPred& sr) {
-        if (this == &sr) {
-            return *this;
-        }
-        this->reinitDeepCopy(sr);
-        return *this;
-    }
-
-    friend inline base::type::ostream_t& operator<<(base::type::ostream_t& os, const RegistryWithPred& sr) {
-        for (const_iterator it = sr.list().begin(); it != sr.list().end(); ++it) {
-            os << ELPP_LITERAL("    ") << **it << ELPP_LITERAL("\n");
-        }
-        return os;
-    }
-
-protected:
-    virtual inline void unregisterAll(void) ELPP_FINAL {
-        if (!this->empty()) {
-            for (auto&& curr : this->list()) {
-                base::utils::safeDelete(curr);
-            }
-            this->list().clear();
-        }
-    }
-
-    virtual void unregister(T_Ptr*& ptr) ELPP_FINAL {
-        if (ptr) {
-            iterator iter = this->begin();
-            for (; iter != this->end(); ++iter) {
-                if (ptr == *iter) {
-                    break;
-                }
-            }
-            if (iter != this->end() && *iter != nullptr) {
-                this->list().erase(iter);
-                base::utils::safeDelete(*iter);
-            }
-        }
-    }
-
-    virtual inline void registerNew(T_Ptr* ptr) ELPP_FINAL {
-        this->list().push_back(ptr);
-    }
-
-    /// @brief Gets pointer from repository with speicifed arguments. Arguments are passed to predicate
-    /// in order to validate pointer.
-    template <typename T, typename T2>
-    inline T_Ptr* get(const T& arg1, const T2 arg2) {
-        iterator iter = std::find_if(this->list().begin(), this->list().end(), Pred(arg1, arg2));
-        if (iter != this->list().end() && *iter != nullptr) {
-            return *iter;
-        }
-        return nullptr;
-    }
-
-private:
-    virtual inline void deepCopy(const AbstractRegistry<T_Ptr, std::vector<T_Ptr*>>& sr) {
-        for (const_iterator it = sr.list().begin(); it != sr.list().end(); ++it) {
-            registerNew(new T_Ptr(**it));
-        }
-    }
-};
-
-}  // namespace utils
-} // namespace base
-/// @brief Base of Easylogging++ friendly class
-///
-/// @detail After inheriting this class publicly, implement pure-virtual function `void log(std::ostream&) const`
-class Loggable {
-public:
-    virtual ~Loggable(void) {}
-    virtual void log(el::base::type::ostream_t&) const = 0;
-private:
-    friend inline el::base::type::ostream_t& operator<<(el::base::type::ostream_t& os, const Loggable& loggable) {
-        loggable.log(os);
-        return os;
-    }
-};
-namespace base {
-/// @brief Represents log format containing flags and date format. This is used internally to start initial log
-class LogFormat : public Loggable {
-public:
-    LogFormat(void) :
-        m_level(Level::Unknown),
-        m_userFormat(base::type::string_t()),
-        m_format(base::type::string_t()),
-        m_dateTimeFormat(std::string()),
-        m_flags(0x0) {
-    }
-
-    LogFormat(Level level, const base::type::string_t& format)
-            : m_level(level), m_userFormat(format) {
-        parseFromFormat(m_userFormat);
-    }
-
-    LogFormat(const LogFormat& logFormat) {
-        m_level = logFormat.m_level;
-        m_userFormat = logFormat.m_userFormat;
-        m_format = logFormat.m_format;
-        m_dateTimeFormat = logFormat.m_dateTimeFormat;
-        m_flags = logFormat.m_flags;
-    }
-
-    LogFormat(LogFormat&& logFormat) {
-        m_level = std::move(logFormat.m_level);
-        m_userFormat = std::move(logFormat.m_userFormat);
-        m_format = std::move(logFormat.m_format);
-        m_dateTimeFormat = std::move(logFormat.m_dateTimeFormat);
-        m_flags = std::move(logFormat.m_flags);
-    }
-
-    LogFormat& operator=(const LogFormat& logFormat) {
-        m_level = logFormat.m_level;
-        m_userFormat = logFormat.m_userFormat;
-        m_dateTimeFormat = logFormat.m_dateTimeFormat;
-        m_flags = logFormat.m_flags;
-        return *this;
-    }
-
-    virtual ~LogFormat(void) {
-    }
-
-    inline bool operator==(const LogFormat& other) {
-        return m_level == other.m_level && m_userFormat == other.m_userFormat && m_format == other.m_format &&
-                m_dateTimeFormat == other.m_dateTimeFormat && m_flags == other.m_flags;
-    }
-
-    /// @brief Updates format to be used while logging.
-    /// @param userFormat User provided format
-    void parseFromFormat(const base::type::string_t& userFormat) {
-        // We make copy because we will be changing the format
-        // i.e, removing user provided date format from original format
-        // and then storing it.
-        base::type::string_t formatCopy = userFormat;
-        m_flags = 0x0;
-        auto conditionalAddFlag = [&](const base::type::char_t* specifier, base::FormatFlags flag) {
-            std::size_t foundAt = base::type::string_t::npos;
-            while ((foundAt = formatCopy.find(specifier, foundAt + 1)) != base::type::string_t::npos){
-                if (foundAt > 0 && formatCopy[foundAt - 1] == base::consts::kFormatSpecifierChar) {
-                    if (hasFlag(flag)) {
-                        // If we already have flag we remove the escape chars so that '%%' is turned to '%'
-                        // even after specifier resolution - this is because we only replaceFirst specifier
-                        formatCopy.erase(foundAt > 0 ? foundAt - 1 : 0, 1);
-                        ++foundAt;
-                    }
-                } else {
-                    if (!hasFlag(flag)) addFlag(flag);
-                }
-            }
-        };
-        conditionalAddFlag(base::consts::kAppNameFormatSpecifier, base::FormatFlags::AppName);
-        conditionalAddFlag(base::consts::kSeverityLevelFormatSpecifier, base::FormatFlags::Level);
-        conditionalAddFlag(base::consts::kSeverityLevelShortFormatSpecifier, base::FormatFlags::LevelShort);
-        conditionalAddFlag(base::consts::kLoggerIdFormatSpecifier, base::FormatFlags::LoggerId);
-        conditionalAddFlag(base::consts::kThreadIdFormatSpecifier, base::FormatFlags::ThreadId);
-        conditionalAddFlag(base::consts::kLogFileFormatSpecifier, base::FormatFlags::File);
-        conditionalAddFlag(base::consts::kLogFileBaseFormatSpecifier, base::FormatFlags::FileBase);
-        conditionalAddFlag(base::consts::kLogLineFormatSpecifier, base::FormatFlags::Line);
-        conditionalAddFlag(base::consts::kLogLocationFormatSpecifier, base::FormatFlags::Location);
-        conditionalAddFlag(base::consts::kLogFunctionFormatSpecifier, base::FormatFlags::Function);
-        conditionalAddFlag(base::consts::kCurrentUserFormatSpecifier, base::FormatFlags::User);
-        conditionalAddFlag(base::consts::kCurrentHostFormatSpecifier, base::FormatFlags::Host);
-        conditionalAddFlag(base::consts::kMessageFormatSpecifier, base::FormatFlags::LogMessage);
-        conditionalAddFlag(base::consts::kVerboseLevelFormatSpecifier, base::FormatFlags::VerboseLevel);
-        // For date/time we need to extract user's date format first
-        std::size_t dateIndex = std::string::npos;
-        if ((dateIndex = formatCopy.find(base::consts::kDateTimeFormatSpecifier)) != std::string::npos) {
-            while (dateIndex > 0 && formatCopy[dateIndex - 1] == base::consts::kFormatSpecifierChar) {
-                dateIndex = formatCopy.find(base::consts::kDateTimeFormatSpecifier, dateIndex + 1);
-            }
-            if (dateIndex != std::string::npos) {
-                addFlag(base::FormatFlags::DateTime);
-                updateDateFormat(dateIndex, formatCopy);
-            }
-        }
-        m_format = formatCopy;
-        updateFormatSpec();
-    }
-
-    inline Level level(void) const {
-        return m_level;
-    }
-
-    inline const base::type::string_t& userFormat(void) const {
-        return m_userFormat;
-    }
-
-    inline const base::type::string_t& format(void) const {
-       return m_format;
-    }
-
-    inline const std::string& dateTimeFormat(void) const {
-       return m_dateTimeFormat;
-    }
-
-    inline base::type::EnumType flags(void) const {
-       return m_flags;
-    }
-
-    inline bool hasFlag(base::FormatFlags flag) const {
-        return base::utils::hasFlag(flag, m_flags);
-    }
-
-    virtual void log(el::base::type::ostream_t& os) const {
-        os << m_format;
-    }
-
-protected:
-    /// @brief Updates date time format if available in currFormat.
-    /// @param index Index where %datetime, %date or %time was found
-    /// @param [in,out] currFormat current format that is being used to format
-    virtual void updateDateFormat(std::size_t index, base::type::string_t& currFormat) ELPP_FINAL {
-        if (hasFlag(base::FormatFlags::DateTime)) {
-            index += ELPP_STRLEN(base::consts::kDateTimeFormatSpecifier);
-        }
-        const base::type::char_t* ptr = currFormat.c_str() + index;
-        if ((currFormat.size() > index) && (ptr[0] == '{')) {
-            // User has provided format for date/time
-            ++ptr;
-            int count = 1;  // Start by 1 in order to remove starting brace
-            std::stringstream ss;
-            for (; *ptr; ++ptr, ++count) {
-                if (*ptr == '}') {
-                    ++count;  // In order to remove ending brace
-                    break;
-                }
-                ss << *ptr;
-            }
-            currFormat.erase(index, count);
-            m_dateTimeFormat = ss.str();
-        } else {
-            // No format provided, use default
-            if (hasFlag(base::FormatFlags::DateTime)) {
-                m_dateTimeFormat = std::string(base::consts::kDefaultDateTimeFormat);
-            }
-        }
-    }
-
-    /// @brief Updates %level from format. This is so that we dont have to do it at log-writing-time. It uses m_format and m_level
-    virtual void updateFormatSpec(void) ELPP_FINAL {
-        // Do not use switch over strongly typed enums because Intel C++ compilers dont support them yet.
-        if (m_level == Level::Debug) {
-            base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelFormatSpecifier,
-                    base::consts::kDebugLevelLogValue);
-            base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelShortFormatSpecifier,
-                    base::consts::kDebugLevelShortLogValue);
-        } else if (m_level == Level::Info) {
-            base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelFormatSpecifier,
-                    base::consts::kInfoLevelLogValue);
-            base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelShortFormatSpecifier,
-                    base::consts::kInfoLevelShortLogValue);
-        } else if (m_level == Level::Warning) {
-            base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelFormatSpecifier,
-                    base::consts::kWarningLevelLogValue);
-            base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelShortFormatSpecifier,
-                    base::consts::kWarningLevelShortLogValue);
-        } else if (m_level == Level::Error) {
-            base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelFormatSpecifier,
-                    base::consts::kErrorLevelLogValue);
-            base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelShortFormatSpecifier,
-                    base::consts::kErrorLevelShortLogValue);
-        } else if (m_level == Level::Fatal) {
-            base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelFormatSpecifier,
-                    base::consts::kFatalLevelLogValue);
-            base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelShortFormatSpecifier,
-                    base::consts::kFatalLevelShortLogValue);
-        } else if (m_level == Level::Verbose) {
-            base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelFormatSpecifier,
-                    base::consts::kVerboseLevelLogValue);
-            base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelShortFormatSpecifier,
-                    base::consts::kVerboseLevelShortLogValue);
-        } else if (m_level == Level::Trace) {
-            base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelFormatSpecifier,
-                    base::consts::kTraceLevelLogValue);
-            base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelShortFormatSpecifier,
-                    base::consts::kTraceLevelShortLogValue);
-        }
-        if (hasFlag(base::FormatFlags::User)) {
-            std::string s = base::utils::s_currentUser;
-            base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kCurrentUserFormatSpecifier,
-                    base::utils::s_currentUser);
-        }
-        if (hasFlag(base::FormatFlags::Host)) {
-            base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kCurrentHostFormatSpecifier,
-                    base::utils::s_currentHost);
-        }
-        // Ignore Level::Global and Level::Unknown
-    }
-
-    inline void addFlag(base::FormatFlags flag) {
-        base::utils::addFlag(flag, &m_flags);
-    }
-
-private:
-    Level m_level;
-    base::type::string_t m_userFormat;
-    base::type::string_t m_format;
-    std::string m_dateTimeFormat;
-    base::type::EnumType m_flags;
-    friend class el::Logger;  // To resolve loggerId format specifier easily
-};
-}  // namespace base
-/// @brief Resolving function for format specifier
-typedef std::function<const char*(void)> FormatSpecifierValueResolver;
-/// @brief User-provided custom format specifier
-/// @see el::Helpers::installCustomFormatSpecifier
-/// @see FormatSpecifierValueResolver
-class CustomFormatSpecifier {
-public:
-    CustomFormatSpecifier(const char* formatSpecifier, const FormatSpecifierValueResolver& resolver) :
-        m_formatSpecifier(formatSpecifier), m_resolver(resolver) {}
-    inline const char* formatSpecifier(void) const { return m_formatSpecifier; }
-    inline const FormatSpecifierValueResolver& resolver(void) const { return m_resolver; }
-    inline bool operator==(const char* formatSpecifier) {
-        return strcmp(m_formatSpecifier, formatSpecifier) == 0;
-    }
-
-private:
-    const char* m_formatSpecifier;
-    FormatSpecifierValueResolver m_resolver;
-};
-/// @brief Represents single configuration that has representing level, configuration type and a string based value.
-///
-/// @detail String based value means any value either its boolean, integer or string itself, it will be embedded inside quotes
-/// and will be parsed later.
-///
-/// Consider some examples below:
-///   * el::Configuration confEnabledInfo(el::Level::Info, el::ConfigurationType::Enabled, "true");
-///   * el::Configuration confMaxLogFileSizeInfo(el::Level::Info, el::ConfigurationType::MaxLogFileSize, "2048");
-///   * el::Configuration confFilenameInfo(el::Level::Info, el::ConfigurationType::Filename, "/var/log/my.log");
-class Configuration : public Loggable {
-public:
-    Configuration(const Configuration& c) :
-            m_level(c.m_level),
-            m_configurationType(c.m_configurationType),
-            m_value(c.m_value) {
-    }
-
-    Configuration& operator=(const Configuration& c) {
-        m_level = c.m_level;
-        m_configurationType = c.m_configurationType;
-        m_value = c.m_value;
-        return *this;
-    }
-
-    virtual ~Configuration(void) {
-    }
-
-    /// @brief Full constructor used to sets value of configuration
-    Configuration(Level level, ConfigurationType configurationType, const std::string& value) :
-        m_level(level),
-        m_configurationType(configurationType),
-        m_value(value) {
-    }
-
-    /// @brief Gets level of current configuration
-    inline Level level(void) const {
-        return m_level;
-    }
-
-    /// @brief Gets configuration type of current configuration
-    inline ConfigurationType configurationType(void) const {
-        return m_configurationType;
-    }
-
-    /// @brief Gets string based configuration value
-    inline const std::string& value(void) const {
-        return m_value;
-    }
-
-    /// @brief Set string based configuration value
-    /// @param value Value to set. Values have to be std::string; For boolean values use "true", "false", for any integral values
-    ///        use them in quotes. They will be parsed when configuring
-    inline void setValue(const std::string& value) {
-        m_value = value;
-    }
-
-    virtual inline void log(el::base::type::ostream_t& os) const {
-        os << LevelHelper::convertToString(m_level)
-            << ELPP_LITERAL(" ") << ConfigurationTypeHelper::convertToString(m_configurationType)
-            << ELPP_LITERAL(" = ") << m_value.c_str();
-    }
-
-    /// @brief Used to find configuration from configuration (pointers) repository. Avoid using it.
-    class Predicate {
-    public:
-        Predicate(Level level, ConfigurationType configurationType) :
-            m_level(level),
-            m_configurationType(configurationType) {
-        }
-
-        inline bool operator()(const Configuration* conf) const {
-            return ((conf != nullptr) && (conf->level() == m_level) && (conf->configurationType() == m_configurationType));
-        }
-
-    private:
-        Level m_level;
-        ConfigurationType m_configurationType;
-    };
-
-private:
-    Level m_level;
-    ConfigurationType m_configurationType;
-    std::string m_value;
-};
-
-/// @brief Thread-safe Configuration repository
-///
-/// @detail This repository represents configurations for all the levels and configuration type mapped to a value.
-class Configurations : public base::utils::RegistryWithPred<Configuration, Configuration::Predicate> {
-public:
-    /// @brief Default constructor with empty repository
-    Configurations(void) :
-            m_configurationFile(std::string()),
-            m_isFromFile(false) {
-    }
-
-    /// @brief Constructor used to set configurations using configuration file.
-    /// @param configurationFile Full path to configuration file
-    /// @param useDefaultsForRemaining Lets you set the remaining configurations to default.
-    /// @param base If provided, this configuration will be based off existing repository that this argument is pointing to.
-    /// @see parseFromFile(const std::string&, Configurations* base)
-    /// @see setRemainingToDefault()
-    Configurations(const std::string& configurationFile, bool useDefaultsForRemaining = true, Configurations* base = nullptr) :
-            m_configurationFile(configurationFile),
-            m_isFromFile(false) {
-        parseFromFile(configurationFile, base);
-        if (useDefaultsForRemaining) {
-            setRemainingToDefault();
-        }
-    }
-
-    virtual ~Configurations(void) {
-    }
-
-    /// @brief Parses configuration from file.
-    /// @param configurationFile Full path to configuration file
-    /// @param base Configurations to base new configuration repository off. This value is used when you want to use
-    ///        existing Configurations to base all the values and then set rest of configuration via configuration file.
-    /// @return True if successfully parsed, false otherwise. You may define 'ELPP_DEBUG_ASSERT_FAILURE' to make sure you
-    ///         do not proceed without successful parse.
-    inline bool parseFromFile(const std::string& configurationFile, Configurations* base = nullptr) {
-        // We initial assertion with true because if we have assertion diabled, we want to pass this
-        // check and if assertion is enabled we will have values re-assigned any way.
-        bool assertionPassed = true;
-        ELPP_ASSERT((assertionPassed = base::utils::File::pathExists(configurationFile.c_str(), true)),
-                "Configuration file [" << configurationFile << "] does not exist!");
-        if (!assertionPassed) {
-            return false;
-        }
-        bool success = Parser::parseFromFile(configurationFile, this, base);
-        m_isFromFile = success;
-        return success;
-    }
-
-    /// @brief Parse configurations from configuration string.
-    ///
-    /// @detail This configuration string has same syntax as configuration file contents. Make sure all the necessary
-    /// new line characters are provided.
-    /// @param base Configurations to base new configuration repository off. This value is used when you want to use
-    ///        existing Configurations to base all the values and then set rest of configuration via configuration text.
-    /// @return True if successfully parsed, false otherwise. You may define 'ELPP_DEBUG_ASSERT_FAILURE' to make sure you
-    ///         do not proceed without successful parse.
-    inline bool parseFromText(const std::string& configurationsString, Configurations* base = nullptr) {
-        bool success = Parser::parseFromText(configurationsString, this, base);
-        if (success) {
-            m_isFromFile = false;
-        }
-        return success;
-    }
-
-    /// @brief Sets configuration based-off an existing configurations.
-    /// @param base Pointer to existing configurations.
-    inline void setFromBase(Configurations* base) {
-        if (base == nullptr || base == this) {
-            return;
-        }
-        base::threading::ScopedLock scopedLock(base->lock());
-        for (Configuration*& conf : base->list()) {
-            set(conf);
-        }
-    }
-
-    /// @brief Determines whether or not specified configuration type exists in the repository.
-    ///
-    /// @detail Returns as soon as first level is found.
-    /// @param configurationType Type of configuration to check existence for.
-    bool hasConfiguration(ConfigurationType configurationType) {
-        base::type::EnumType lIndex = LevelHelper::kMinValid;
-        bool result = false;
-        LevelHelper::forEachLevel(&lIndex, [&](void) -> bool {
-            if (hasConfiguration(LevelHelper::castFromInt(lIndex), configurationType)) {
-                result = true;
-            }
-            return result;
-        });
-        return result;
-    }
-
-    /// @brief Determines whether or not specified configuration type exists for specified level
-    /// @param level Level to check
-    /// @param configurationType Type of configuration to check existence for.
-    inline bool hasConfiguration(Level level, ConfigurationType configurationType) {
-        base::threading::ScopedLock scopedLock(lock());
-#if ELPP_COMPILER_INTEL
-        // We cant specify template types here, Intel C++ throws compilation error
-        // "error: type name is not allowed"
-        return RegistryWithPred::get(level, configurationType) != nullptr;
-#else
-        return RegistryWithPred<Configuration, Configuration::Predicate>::get(level, configurationType) != nullptr;
-#endif  // ELPP_COMPILER_INTEL
-    }
-
-    /// @brief Sets value of configuration for specified level.
-    ///
-    /// @detail Any existing configuration for specified level will be replaced. Also note that configuration types
-    /// ConfigurationType::MillisecondsWidth and ConfigurationType::PerformanceTracking will be ignored if not set for
-    /// Level::Global because these configurations are not dependant on level.
-    /// @param level Level to set configuration for (el::Level).
-    /// @param configurationType Type of configuration (el::ConfigurationType)
-    /// @param value A string based value. Regardless of what the data type of configuration is, it will always be string
-    /// from users' point of view. This is then parsed later to be used internally.
-    /// @see Configuration::setValue(const std::string& value)
-    /// @see el::Level
-    /// @see el::ConfigurationType
-    inline void set(Level level, ConfigurationType configurationType, const std::string& value) {
-        base::threading::ScopedLock scopedLock(lock());
-        unsafeSet(level, configurationType, value);  // This is not unsafe anymore as we have locked mutex
-        if (level == Level::Global) {
-            unsafeSetGlobally(configurationType, value, false);  // Again this is not unsafe either
-        }
-    }
-
-    /// @brief Sets single configuration based on other single configuration.
-    /// @see set(Level level, ConfigurationType configurationType, const std::string& value)
-    inline void set(Configuration* conf) {
-        if (conf == nullptr) {
-            return;
-        }
-        set(conf->level(), conf->configurationType(), conf->value());
-    }
-
-    inline Configuration* get(Level level, ConfigurationType configurationType) {
-        base::threading::ScopedLock scopedLock(lock());
-        return RegistryWithPred<Configuration, Configuration::Predicate>::get(level, configurationType);
-    }
-
-    /// @brief Sets configuration for all levels.
-    /// @param configurationType Type of configuration
-    /// @param value String based value
-    /// @see Configurations::set(Level level, ConfigurationType configurationType, const std::string& value)
-    inline void setGlobally(ConfigurationType configurationType, const std::string& value) {
-        setGlobally(configurationType, value, false);
-    }
-
-    /// @brief Clears repository so that all the configurations are unset
-    inline void clear(void) {
-        base::threading::ScopedLock scopedLock(lock());
-        unregisterAll();
-    }
-
-    /// @brief Gets configuration file used in parsing this configurations.
-    ///
-    /// @detail If this repository was set manually or by text this returns empty string.
-    inline const std::string& configurationFile(void) const {
-        return m_configurationFile;
-    }
-
-    /// @brief Sets configurations to "factory based" configurations.
-    void setToDefault(void) {
-        setGlobally(ConfigurationType::Enabled, std::string("true"), true);
-#if !defined(ELPP_NO_DEFAULT_LOG_FILE)
-        setGlobally(ConfigurationType::Filename, std::string(base::consts::kDefaultLogFile), true);
-#else
-        ELPP_UNUSED(base::consts::kDefaultLogFile);
-#endif  // !defined(ELPP_NO_DEFAULT_LOG_FILE)
-        setGlobally(ConfigurationType::ToFile, std::string("true"), true);
-        setGlobally(ConfigurationType::ToStandardOutput, std::string("true"), true);
-        setGlobally(ConfigurationType::MillisecondsWidth, std::string("3"), true);
-        setGlobally(ConfigurationType::PerformanceTracking, std::string("true"), true);
-        setGlobally(ConfigurationType::MaxLogFileSize, std::string("0"), true);
-        setGlobally(ConfigurationType::LogFlushThreshold, std::string("0"), true);
-
-        setGlobally(ConfigurationType::Format, std::string("%datetime %level [%logger] %msg"), true);
-        set(Level::Debug, ConfigurationType::Format, std::string("%datetime %level [%logger] [%user@%host] [%func] [%loc] %msg"));
-        // INFO and WARNING are set to default by Level::Global
-        set(Level::Error, ConfigurationType::Format, std::string("%datetime %level [%logger] %msg"));
-        set(Level::Fatal, ConfigurationType::Format, std::string("%datetime %level [%logger] %msg"));
-        set(Level::Verbose, ConfigurationType::Format, std::string("%datetime %level-%vlevel [%logger] %msg"));
-        set(Level::Trace, ConfigurationType::Format, std::string("%datetime %level [%logger] [%func] [%loc] %msg"));
-    }
-
-    /// @brief Lets you set the remaining configurations to default.
-    ///
-    /// @detail By remaining, it means that the level/type a configuration does not exist for.
-    /// This function is useful when you want to minimize chances of failures, e.g, if you have a configuration file that sets
-    /// configuration for all the configurations except for Enabled or not, we use this so that ENABLED is set to default i.e,
-    /// true. If you dont do this explicitley (either by calling this function or by using second param in Constructor
-    /// and try to access a value, an error is thrown
-    void setRemainingToDefault(void) {
-        base::threading::ScopedLock scopedLock(lock());
-        unsafeSetIfNotExist(Level::Global, ConfigurationType::Enabled, std::string("true"));
-#if !defined(ELPP_NO_DEFAULT_LOG_FILE)
-        unsafeSetIfNotExist(Level::Global, ConfigurationType::Filename, std::string(base::consts::kDefaultLogFile));
-#endif  // !defined(ELPP_NO_DEFAULT_LOG_FILE)
-        unsafeSetIfNotExist(Level::Global, ConfigurationType::ToFile, std::string("true"));
-        unsafeSetIfNotExist(Level::Global, ConfigurationType::ToStandardOutput, std::string("true"));
-        unsafeSetIfNotExist(Level::Global, ConfigurationType::MillisecondsWidth, std::string("3"));
-        unsafeSetIfNotExist(Level::Global, ConfigurationType::PerformanceTracking, std::string("true"));
-        unsafeSetIfNotExist(Level::Global, ConfigurationType::MaxLogFileSize, std::string("0"));
-        unsafeSetIfNotExist(Level::Global, ConfigurationType::Format, std::string("%datetime %level [%logger] %msg"));
-        unsafeSetIfNotExist(Level::Debug, ConfigurationType::Format, 
-            std::string("%datetime %level [%logger] [%user@%host] [%func] [%loc] %msg"));
-        // INFO and WARNING are set to default by Level::Global
-        unsafeSetIfNotExist(Level::Error, ConfigurationType::Format, std::string("%datetime %level [%logger] %msg"));
-        unsafeSetIfNotExist(Level::Fatal, ConfigurationType::Format, std::string("%datetime %level [%logger] %msg"));
-        unsafeSetIfNotExist(Level::Verbose, ConfigurationType::Format, std::string("%datetime %level-%vlevel [%logger] %msg"));
-        unsafeSetIfNotExist(Level::Trace, ConfigurationType::Format, std::string("%datetime %level [%logger] [%func] [%loc] %msg"));
-    }
-
-    /// @brief Parser used internally to parse configurations from file or text.
-    ///
-    /// @detail This class makes use of base::utils::Str.
-    /// You should not need this unless you are working on some tool for Easylogging++
-    class Parser : base::StaticClass {
-    public:
-        /// @brief Parses configuration from file.
-        /// @param configurationFile Full path to configuration file
-        /// @param sender Sender configurations pointer. Usually 'this' is used from calling class
-        /// @param base Configurations to base new configuration repository off. This value is used when you want to use
-        ///        existing Configurations to base all the values and then set rest of configuration via configuration file.
-        /// @return True if successfully parsed, false otherwise. You may define '_STOP_ON_FIRSTELPP_ASSERTION' to make sure you
-        ///         do not proceed without successful parse.
-        static bool parseFromFile(const std::string& configurationFile, Configurations* sender, Configurations* base = nullptr) {
-            sender->setFromBase(base);
-            std::ifstream fileStream_(configurationFile.c_str(), std::ifstream::in);
-            ELPP_ASSERT(fileStream_.is_open(), "Unable to open configuration file [" << configurationFile << "] for parsing.");
-            bool parsedSuccessfully = false;
-            std::string line = std::string();
-            Level currLevel = Level::Unknown;
-            std::string currConfigStr = std::string();
-            std::string currLevelStr = std::string();
-            while (fileStream_.good()) {
-                std::getline(fileStream_, line);
-                parsedSuccessfully = parseLine(&line, &currConfigStr, &currLevelStr, &currLevel, sender);
-                ELPP_ASSERT(parsedSuccessfully, "Unable to parse configuration line: " << line);
-            }
-            return parsedSuccessfully;
-        }
-
-        /// @brief Parse configurations from configuration string.
-        ///
-        /// @detail This configuration string has same syntax as configuration file contents. Make sure all the necessary
-        /// new line characters are provided. You may define '_STOP_ON_FIRSTELPP_ASSERTION' to make sure you
-        /// do not proceed without successful parse (This is recommended)
-        /// @param configurationsString
-        /// @param sender Sender configurations pointer. Usually 'this' is used from calling class
-        /// @param base Configurations to base new configuration repository off. This value is used when you want to use
-        ///        existing Configurations to base all the values and then set rest of configuration via configuration text.
-        /// @return True if successfully parsed, false otherwise.
-        static bool parseFromText(const std::string& configurationsString, Configurations* sender, Configurations* base = nullptr) {
-            sender->setFromBase(base);
-            bool parsedSuccessfully = false;
-            std::stringstream ss(configurationsString);
-            std::string line = std::string();
-            Level currLevel = Level::Unknown;
-            std::string currConfigStr = std::string();
-            std::string currLevelStr = std::string();
-            while (std::getline(ss, line)) {
-                parsedSuccessfully = parseLine(&line, &currConfigStr, &currLevelStr, &currLevel, sender);
-                ELPP_ASSERT(parsedSuccessfully, "Unable to parse configuration line: " << line);
-            }
-            return parsedSuccessfully;
-        }
-
-    private:
-        friend class el::Loggers;
-        static void ignoreComments(std::string* line) {
-            std::size_t foundAt = 0;
-            std::size_t quotesStart = line->find("\"");
-            std::size_t quotesEnd = std::string::npos;
-            if (quotesStart != std::string::npos) {
-                quotesEnd = line->find("\"", quotesStart + 1);
-                while (quotesEnd != std::string::npos && line->at(quotesEnd - 1) == '\\') {
-                    // Do not erase slash yet - we will erase it in parseLine(..) while loop
-                    quotesEnd = line->find("\"", quotesEnd + 2);
-                }
-            }
-            if ((foundAt = line->find(base::consts::kConfigurationComment)) != std::string::npos) {
-                if (foundAt < quotesEnd) {
-                    foundAt = line->find(base::consts::kConfigurationComment, quotesEnd + 1);
-                }
-                *line = line->substr(0, foundAt);
-            }
-        }
-        static inline bool isLevel(const std::string& line) {
-            return base::utils::Str::startsWith(line, std::string(base::consts::kConfigurationLevel));
-        }
-
-        static inline bool isComment(const std::string& line) {
-            return base::utils::Str::startsWith(line, std::string(base::consts::kConfigurationComment));
-        }
-
-        static inline bool isConfig(const std::string& line) {
-            std::size_t assignment = line.find('=');
-            return line != "" &&
-                    (line[0] >= 65 || line[0] <= 90 || line[0] >= 97 || line[0] <= 122) &&
-                    (assignment != std::string::npos) &&
-                    (line.size() > assignment);
-        }
-
-        static bool parseLine(std::string* line, std::string* currConfigStr, std::string* currLevelStr, Level* currLevel, Configurations* conf) {
-            ConfigurationType currConfig = ConfigurationType::Unknown;
-            std::string currValue = std::string();
-            *line = base::utils::Str::trim(*line);
-            if (isComment(*line)) return true;
-            ignoreComments(line);
-            *line = base::utils::Str::trim(*line);
-            if (line->empty()) {
-                // Comment ignored
-                return true;
-            }
-            if (isLevel(*line)) {
-                if (line->size() <= 2) {
-                    return true;
-                }
-                *currLevelStr = line->substr(1, line->size() - 2);
-                *currLevelStr = base::utils::Str::toUpper(*currLevelStr);
-                *currLevelStr = base::utils::Str::trim(*currLevelStr);
-                *currLevel = LevelHelper::convertFromString(currLevelStr->c_str());
-                return true;
-            }
-            if (isConfig(*line)) {
-                std::size_t assignment = line->find('=');
-                *currConfigStr = line->substr(0, assignment);
-                *currConfigStr = base::utils::Str::toUpper(*currConfigStr);
-                *currConfigStr = base::utils::Str::trim(*currConfigStr);
-                currConfig = ConfigurationTypeHelper::convertFromString(currConfigStr->c_str());
-                currValue = line->substr(assignment + 1);
-                currValue = base::utils::Str::trim(currValue);
-                std::size_t quotesStart = currValue.find("\"", 0);
-                std::size_t quotesEnd = std::string::npos;
-                if (quotesStart != std::string::npos) {
-                    quotesEnd = currValue.find("\"", quotesStart + 1);
-                    while (quotesEnd != std::string::npos && currValue.at(quotesEnd - 1) == '\\') {
-                        currValue = currValue.erase(quotesEnd - 1, 1);
-                        quotesEnd = currValue.find("\"", quotesEnd + 2);
-                    }
-                }
-                if (quotesStart != std::string::npos && quotesEnd != std::string::npos) {
-                    // Quote provided - check and strip if valid
-                    ELPP_ASSERT((quotesStart < quotesEnd), "Configuration error - No ending quote found in [" 
-                        << currConfigStr << "]");
-                    ELPP_ASSERT((quotesStart + 1 != quotesEnd), "Empty configuration value for [" << currConfigStr << "]");
-                    if ((quotesStart != quotesEnd) && (quotesStart + 1 != quotesEnd)) {
-                        // Explicit check in case if assertion is disabled
-                        currValue = currValue.substr(quotesStart + 1, quotesEnd - 1);
-                    }
-                }
-            }
-            ELPP_ASSERT(*currLevel != Level::Unknown, "Unrecognized severity level [" << *currLevelStr << "]");
-            ELPP_ASSERT(currConfig != ConfigurationType::Unknown, "Unrecognized configuration [" << *currConfigStr << "]");
-            if (*currLevel == Level::Unknown || currConfig == ConfigurationType::Unknown) {
-                return false;  // unrecognizable level or config
-            }
-            conf->set(*currLevel, currConfig, currValue);
-            return true;
-        }
-    };
-
-private:
-    std::string m_configurationFile;
-    bool m_isFromFile;
-    friend class el::Loggers;
-
-    /// @brief Unsafely sets configuration if does not already exist
-    void unsafeSetIfNotExist(Level level, ConfigurationType configurationType, const std::string& value) {
-        Configuration* conf = RegistryWithPred<Configuration, Configuration::Predicate>::get(level, configurationType);
-        if (conf == nullptr) {
-            unsafeSet(level, configurationType, value);
-        }
-    }
-
-    /// @brief Thread unsafe set
-    void unsafeSet(Level level, ConfigurationType configurationType, const std::string& value) {
-        Configuration* conf = RegistryWithPred<Configuration, Configuration::Predicate>::get(level, configurationType);
-        if (conf == nullptr) {
-            registerNew(new Configuration(level, configurationType, value));
-        } else {
-            conf->setValue(value);
-        }
-        if (level == Level::Global) {
-            unsafeSetGlobally(configurationType, value, false);
-        }
-    }
-
-    /// @brief Sets configurations for all levels including Level::Global if includeGlobalLevel is true
-    /// @see Configurations::setGlobally(ConfigurationType configurationType, const std::string& value)
-    void setGlobally(ConfigurationType configurationType, const std::string& value, bool includeGlobalLevel) {
-        if (includeGlobalLevel) {
-            set(Level::Global, configurationType, value);
-        }
-        base::type::EnumType lIndex = LevelHelper::kMinValid;
-        LevelHelper::forEachLevel(&lIndex, [&](void) -> bool {
-            set(LevelHelper::castFromInt(lIndex), configurationType, value);
-            return false;  // Do not break lambda function yet as we need to set all levels regardless
-        });
-    }
-
-    /// @brief Sets configurations (Unsafely) for all levels including Level::Global if includeGlobalLevel is true
-    /// @see Configurations::setGlobally(ConfigurationType configurationType, const std::string& value)
-    void unsafeSetGlobally(ConfigurationType configurationType, const std::string& value, bool includeGlobalLevel) {
-        if (includeGlobalLevel) {
-            unsafeSet(Level::Global, configurationType, value);
-        }
-        base::type::EnumType lIndex = LevelHelper::kMinValid;
-        LevelHelper::forEachLevel(&lIndex, [&](void) -> bool  {
-            unsafeSet(LevelHelper::castFromInt(lIndex), configurationType, value);
-            return false;  // Do not break lambda function yet as we need to set all levels regardless
-        });
-    }
-};
-
-namespace base {
-typedef std::shared_ptr<base::type::fstream_t> FileStreamPtr;
-typedef std::map<std::string, FileStreamPtr> LogStreamsReferenceMap;
-/// @brief Configurations with data types.
-///
-/// @detail el::Configurations have string based values. This is whats used internally in order to read correct configurations.
-/// This is to perform faster while writing logs using correct configurations.
-///
-/// This is thread safe and final class containing non-virtual destructor (means nothing should inherit this class)
-class TypedConfigurations : public base::threading::ThreadSafe {
-public:
-    /// @brief Constructor to initialize (construct) the object off el::Configurations
-    /// @param configurations Configurations pointer/reference to base this typed configurations off.
-    /// @param logStreamsReference Use ELPP->registeredLoggers()->logStreamsReference()
-    TypedConfigurations(Configurations* configurations, base::LogStreamsReferenceMap* logStreamsReference) {
-        m_configurations = configurations;
-        m_logStreamsReference = logStreamsReference;
-        build(m_configurations);
-    }
-
-    TypedConfigurations(const TypedConfigurations& other) {
-        this->m_configurations = other.m_configurations;
-        this->m_logStreamsReference = other.m_logStreamsReference;
-        build(m_configurations);
-    }
-
-    virtual ~TypedConfigurations(void) {
-    }
-
-    const Configurations* configurations(void) const {
-        return m_configurations;
-    }
-
-    inline bool enabled(Level level) {
-        return getConfigByVal<bool>(level, &m_enabledMap, "enabled");
-    }
-
-    inline bool toFile(Level level) {
-        return getConfigByVal<bool>(level, &m_toFileMap, "toFile");
-    }
-
-    inline const std::string& filename(Level level) {
-        return getConfigByRef<std::string>(level, &m_filenameMap, "filename");
-    }
-
-    inline bool toStandardOutput(Level level) {
-        return getConfigByVal<bool>(level, &m_toStandardOutputMap, "toStandardOutput");
-    }
-
-    inline const base::LogFormat& logFormat(Level level) {
-        return getConfigByRef<base::LogFormat>(level, &m_logFormatMap, "logFormat");
-    }
-
-    inline const base::MillisecondsWidth& millisecondsWidth(Level level = Level::Global) {
-        return getConfigByRef<base::MillisecondsWidth>(level, &m_millisecondsWidthMap, "millisecondsWidth");
-    }
-
-    inline bool performanceTracking(Level level = Level::Global) {
-        return getConfigByVal<bool>(level, &m_performanceTrackingMap, "performanceTracking");
-    }
-
-    inline base::type::fstream_t* fileStream(Level level) {
-        return getConfigByRef<base::FileStreamPtr>(level, &m_fileStreamMap, "fileStream").get();
-    }
-
-    inline std::size_t maxLogFileSize(Level level) {
-        return getConfigByVal<std::size_t>(level, &m_maxLogFileSizeMap, "maxLogFileSize");
-    }
-
-    inline std::size_t logFlushThreshold(Level level) {
-        return getConfigByVal<std::size_t>(level, &m_logFlushThresholdMap, "logFlushThreshold");
-    }
-
-private:
-    Configurations* m_configurations;
-    std::map<Level, bool> m_enabledMap;
-    std::map<Level, bool> m_toFileMap;
-    std::map<Level, std::string> m_filenameMap;
-    std::map<Level, bool> m_toStandardOutputMap;
-    std::map<Level, base::LogFormat> m_logFormatMap;
-    std::map<Level, base::MillisecondsWidth> m_millisecondsWidthMap;
-    std::map<Level, bool> m_performanceTrackingMap;
-    std::map<Level, base::FileStreamPtr> m_fileStreamMap;
-    std::map<Level, std::size_t> m_maxLogFileSizeMap;
-    std::map<Level, std::size_t> m_logFlushThresholdMap;
-    base::LogStreamsReferenceMap* m_logStreamsReference;
-
-    friend class el::Helpers;
-    friend class el::base::MessageBuilder;
-    friend class el::base::Writer;
-    friend class el::base::DefaultLogDispatchCallback;
-    friend class el::base::LogDispatcher;
-
-    template <typename Conf_T>
-    inline Conf_T getConfigByVal(Level level, const std::map<Level, Conf_T>* confMap, const char* confName) {
-        base::threading::ScopedLock scopedLock(lock());
-        return unsafeGetConfigByVal(level, confMap, confName);  // This is not unsafe anymore - mutex locked in scope
-    }
-
-    template <typename Conf_T>
-    inline Conf_T& getConfigByRef(Level level, std::map<Level, Conf_T>* confMap, const char* confName) {
-        base::threading::ScopedLock scopedLock(lock());
-        return unsafeGetConfigByRef(level, confMap, confName);  // This is not unsafe anymore - mutex locked in scope
-    }
-
-    template <typename Conf_T>
-    inline Conf_T unsafeGetConfigByVal(Level level, const std::map<Level, Conf_T>* confMap, const char* confName) {
-        ELPP_UNUSED(confName);
-        typename std::map<Level, Conf_T>::const_iterator it = confMap->find(level);
-        if (it == confMap->end()) {
-            try {
-                return confMap->at(Level::Global);
-            } catch (...) {
-                ELPP_INTERNAL_ERROR("Unable to get configuration [" << confName << "] for level [" 
-                    << LevelHelper::convertToString(level) << "]"
-                        << std::endl << "Please ensure you have properly configured logger.", false);
-                return Conf_T();
-            }
-        }
-        return it->second;
-    }
-
-    template <typename Conf_T>
-    inline Conf_T& unsafeGetConfigByRef(Level level, std::map<Level, Conf_T>* confMap, const char* confName) {
-        ELPP_UNUSED(confName);
-        typename std::map<Level, Conf_T>::iterator it = confMap->find(level);
-        if (it == confMap->end()) {
-            try {
-                return confMap->at(Level::Global);
-            } catch (...) {
-                ELPP_INTERNAL_ERROR("Unable to get configuration [" << confName << "] for level [" 
-                    << LevelHelper::convertToString(level) << "]"
-                        << std::endl << "Please ensure you have properly configured logger.", false);
-            }
-        }
-        return it->second;
-    }
-
-    template <typename Conf_T>
-    void setValue(Level level, const Conf_T& value, std::map<Level, Conf_T>* confMap, bool includeGlobalLevel = true) {
-        // If map is empty and we are allowed to add into generic level (Level::Global), do it!
-        if (confMap->empty() && includeGlobalLevel) {
-            confMap->insert(std::make_pair(Level::Global, value));
-            return;
-        }
-        // If same value exist in generic level already, dont add it to explicit level
-        typename std::map<Level, Conf_T>::iterator it = confMap->find(Level::Global);
-        if (it != confMap->end() && it->second == value) {
-            return;
-        }
-        // Now make sure we dont double up values if we really need to add it to explicit level
-        it = confMap->find(level);
-        if (it == confMap->end()) {
-            // Value not found for level, add new
-            confMap->insert(std::make_pair(level, value));
-        } else {
-            // Value found, just update value
-            confMap->at(level) = value;
-        }
-    }
-
-    void build(Configurations* configurations) {
-        base::threading::ScopedLock scopedLock(lock());
-        auto getBool = [] (std::string boolStr) -> bool {  // Pass by value for trimming
-            base::utils::Str::trim(boolStr);
-            return (boolStr == "TRUE" || boolStr == "true" || boolStr == "1");
-        };
-        std::vector<Configuration*> withFileSizeLimit;
-        for (Configurations::const_iterator it = configurations->begin(); it != configurations->end(); ++it) {
-            Configuration* conf = *it;
-            // We cannot use switch on strong enums because Intel C++ dont support them yet
-            if (conf->configurationType() == ConfigurationType::Enabled) {
-                setValue(conf->level(), getBool(conf->value()), &m_enabledMap);
-            } else if (conf->configurationType() == ConfigurationType::ToFile) {
-                setValue(conf->level(), getBool(conf->value()), &m_toFileMap);
-            } else if (conf->configurationType() == ConfigurationType::ToStandardOutput) {
-                setValue(conf->level(), getBool(conf->value()), &m_toStandardOutputMap);
-            } else if (conf->configurationType() == ConfigurationType::Filename) {
-            // We do not yet configure filename but we will configure in another
-            // loop. This is because if file cannot be created, we will force ToFile
-            // to be false. Because configuring logger is not necessarily performance
-            // sensative operation, we can live with another loop; (by the way this loop
-            // is not very heavy either)
-            } else if (conf->configurationType() == ConfigurationType::Format) {
-                setValue(conf->level(), base::LogFormat(conf->level(), 
-                    base::type::string_t(conf->value().begin(), conf->value().end())), &m_logFormatMap);
-            } else if (conf->configurationType() == ConfigurationType::MillisecondsWidth) {
-                setValue(Level::Global, 
-                    base::MillisecondsWidth(static_cast<int>(getULong(conf->value()))), &m_millisecondsWidthMap);
-            } else if (conf->configurationType() == ConfigurationType::PerformanceTracking) {
-                setValue(Level::Global, getBool(conf->value()), &m_performanceTrackingMap);
-            } else if (conf->configurationType() == ConfigurationType::MaxLogFileSize) {
-                setValue(conf->level(), static_cast<std::size_t>(getULong(conf->value())), &m_maxLogFileSizeMap);
-#if !defined(ELPP_NO_DEFAULT_LOG_FILE)
-                withFileSizeLimit.push_back(conf);
-#endif  // !defined(ELPP_NO_DEFAULT_LOG_FILE)
-            } else if (conf->configurationType() == ConfigurationType::LogFlushThreshold) {
-                setValue(conf->level(), static_cast<std::size_t>(getULong(conf->value())), &m_logFlushThresholdMap);
-            }
-        }
-        // As mentioned early, we will now set filename configuration in separate loop to deal with non-existent files
-        for (Configurations::const_iterator it = configurations->begin(); it != configurations->end(); ++it) {
-            Configuration* conf = *it;
-            if (conf->configurationType() == ConfigurationType::Filename) {
-                insertFile(conf->level(), conf->value());
-            }
-        }
-        for (std::vector<Configuration*>::iterator conf = withFileSizeLimit.begin();
-                conf != withFileSizeLimit.end(); ++conf) {
-                // This is not unsafe as mutex is locked in currect scope
-                unsafeValidateFileRolling((*conf)->level(), base::defaultPreRollOutCallback);
-        }
-    }
-
-    unsigned long getULong(std::string confVal) {
-        bool valid = true;
-        base::utils::Str::trim(confVal);
-        valid = !confVal.empty() && std::find_if(confVal.begin(), confVal.end(),
-                [](char c) { return !base::utils::Str::isDigit(c); }) == confVal.end();
-        if (!valid) {
-            valid = false;
-            ELPP_ASSERT(valid, "Configuration value not a valid integer [" << confVal << "]");
-            return 0;
-        }
-        return atol(confVal.c_str());
-    }
-
-    std::string resolveFilename(const std::string& filename) {
-        std::string resultingFilename = filename;
-        std::size_t dateIndex = std::string::npos;
-        std::string dateTimeFormatSpecifierStr = std::string(base::consts::kDateTimeFormatSpecifierForFilename);
-        if ((dateIndex = resultingFilename.find(dateTimeFormatSpecifierStr.c_str())) != std::string::npos) {
-            while (dateIndex > 0 && resultingFilename[dateIndex - 1] == base::consts::kFormatSpecifierChar) {
-                dateIndex = resultingFilename.find(dateTimeFormatSpecifierStr.c_str(), dateIndex + 1);
-            }
-            if (dateIndex != std::string::npos) {
-                const char* ptr = resultingFilename.c_str() + dateIndex;
-                // Goto end of specifier
-                ptr += dateTimeFormatSpecifierStr.size();
-                std::string fmt;
-                if ((resultingFilename.size() > dateIndex) && (ptr[0] == '{')) {
-                    // User has provided format for date/time
-                    ++ptr;
-                    int count = 1;  // Start by 1 in order to remove starting brace
-                    std::stringstream ss;
-                    for (; *ptr; ++ptr, ++count) {
-                        if (*ptr == '}') {
-                            ++count;  // In order to remove ending brace
-                            break;
-                        }
-                        ss << *ptr;
-                    }
-                    resultingFilename.erase(dateIndex + dateTimeFormatSpecifierStr.size(), count);
-                    fmt = ss.str();
-                } else {
-                    fmt = std::string(base::consts::kDefaultDateTimeFormatInFilename);
-                }
-                base::MillisecondsWidth msWidth(3);
-                std::string now = base::utils::DateTime::getDateTime(fmt.c_str(), &msWidth);
-                base::utils::Str::replaceAll(now, '/', '-'); // Replace path element since we are dealing with filename
-                base::utils::Str::replaceAll(resultingFilename, dateTimeFormatSpecifierStr, now);
-            }
-        }
-        return resultingFilename;
-    }
-
-    void insertFile(Level level, const std::string& fullFilename) {
-        std::string resolvedFilename = resolveFilename(fullFilename);
-        if (resolvedFilename.empty()) {
-            std::cerr << "Could not load empty file for logging, please re-check your configurations for level ["
-                    << LevelHelper::convertToString(level) << "]";
-        }
-        std::string filePath = base::utils::File::extractPathFromFilename(resolvedFilename, base::consts::kFilePathSeperator);
-        if (filePath.size() < resolvedFilename.size()) {
-            base::utils::File::createPath(filePath);
-        }
-        auto create = [&](Level level) {
-            base::LogStreamsReferenceMap::iterator filestreamIter = m_logStreamsReference->find(resolvedFilename);
-            base::type::fstream_t* fs = nullptr;
-            if (filestreamIter == m_logStreamsReference->end()) {
-                // We need a completely new stream, nothing to share with
-                fs = base::utils::File::newFileStream(resolvedFilename);
-                m_filenameMap.insert(std::make_pair(level, resolvedFilename));
-                m_fileStreamMap.insert(std::make_pair(level, base::FileStreamPtr(fs)));
-                m_logStreamsReference->insert(std::make_pair(resolvedFilename, base::FileStreamPtr(m_fileStreamMap.at(level))));
-            } else {
-                // Woops! we have an existing one, share it!
-                m_filenameMap.insert(std::make_pair(level, filestreamIter->first));
-                m_fileStreamMap.insert(std::make_pair(level, base::FileStreamPtr(filestreamIter->second)));
-                fs = filestreamIter->second.get();
-            }
-            if (fs == nullptr) {
-                // We display bad file error from newFileStream()
-                ELPP_INTERNAL_ERROR("Setting [TO_FILE] of [" 
-                    << LevelHelper::convertToString(level) << "] to FALSE", false);
-                setValue(level, false, &m_toFileMap);
-            }
-        };
-        // If we dont have file conf for any level, create it for Level::Global first
-        // otherwise create for specified level
-        create(m_filenameMap.empty() && m_fileStreamMap.empty() ? Level::Global : level);
-    }
-
-    bool unsafeValidateFileRolling(Level level, const PreRollOutCallback& PreRollOutCallback) {
-        base::type::fstream_t* fs = unsafeGetConfigByRef(level, &m_fileStreamMap, "fileStream").get();
-        if (fs == nullptr) {
-            return true;
-        }
-        std::size_t maxLogFileSize = unsafeGetConfigByVal(level, &m_maxLogFileSizeMap, "maxLogFileSize");
-        std::size_t currFileSize = base::utils::File::getSizeOfFile(fs);
-        if (maxLogFileSize != 0 && currFileSize >= maxLogFileSize) {
-            std::string fname = unsafeGetConfigByRef(level, &m_filenameMap, "filename");
-            ELPP_INTERNAL_INFO(1, "Truncating log file [" << fname << "] as a result of configurations for level ["
-                    << LevelHelper::convertToString(level) << "]");
-            fs->close();
-            PreRollOutCallback(fname.c_str(), currFileSize);
-            fs->open(fname, std::fstream::out | std::fstream::trunc);
-            return true;
-        }
-        return false;
-    }
-
-    bool validateFileRolling(Level level, const PreRollOutCallback& PreRollOutCallback) {
-        base::threading::ScopedLock scopedLock(lock());
-        return unsafeValidateFileRolling(level, PreRollOutCallback);
-    }
-};
-/// @brief Class that keeps record of current line hit for occasional logging
-class HitCounter {
-public:
-    HitCounter(void) :
-        m_filename(""),
-        m_lineNumber(0),
-        m_hitCounts(0) {
-    }
-
-    HitCounter(const char* filename, unsigned long int lineNumber) :
-        m_filename(filename),
-        m_lineNumber(lineNumber),
-        m_hitCounts(0) {
-    }
-
-    HitCounter(const HitCounter& hitCounter) :
-        m_filename(hitCounter.m_filename),
-        m_lineNumber(hitCounter.m_lineNumber),
-        m_hitCounts(hitCounter.m_hitCounts) {
-    }
-
-    HitCounter& operator=(const HitCounter& hitCounter) {
-        m_filename = hitCounter.m_filename;
-        m_lineNumber = hitCounter.m_lineNumber;
-        m_hitCounts = hitCounter.m_hitCounts;
-        return *this;
-    }
-
-    virtual ~HitCounter(void) {
-    }
-
-    /// @brief Resets location of current hit counter
-    inline void resetLocation(const char* filename, unsigned long int lineNumber) {
-        m_filename = filename;
-        m_lineNumber = lineNumber;
-    }
-
-    /// @brief Validates hit counts and resets it if necessary
-    inline void validateHitCounts(std::size_t n) {
-        if (m_hitCounts >= base::consts::kMaxLogPerCounter) {
-            m_hitCounts = (n >= 1 ? base::consts::kMaxLogPerCounter % n : 0);
-        }
-        ++m_hitCounts;
-    }
-
-    inline const char* filename(void) const {
-        return m_filename;
-    }
-
-    inline unsigned long int lineNumber(void) const {
-        return m_lineNumber;
-    }
-
-    inline std::size_t hitCounts(void) const {
-        return m_hitCounts;
-    }
-
-    inline void increment(void) {
-        ++m_hitCounts;
-    }
-
-    class Predicate {
-    public:
-        Predicate(const char* filename, unsigned long int lineNumber)
-            : m_filename(filename),
-              m_lineNumber(lineNumber) {
-        }
-        inline bool operator()(const HitCounter* counter) {
-            return ((counter != nullptr) &&
-                    (strcmp(counter->m_filename, m_filename) == 0) &&
-                    (counter->m_lineNumber == m_lineNumber));
-        }
-
-    private:
-        const char* m_filename;
-        unsigned long int m_lineNumber;
-    };
-
-private:
-    const char* m_filename;
-    unsigned long int m_lineNumber;
-    std::size_t m_hitCounts;
-};
-/// @brief Repository for hit counters used across the application
-class RegisteredHitCounters : public base::utils::RegistryWithPred<base::HitCounter, base::HitCounter::Predicate> {
-public:
-    /// @brief Validates counter for every N, i.e, registers new if does not exist otherwise updates original one
-    /// @return True if validation resulted in triggering hit. Meaning logs should be written everytime true is returned
-    bool validateEveryN(const char* filename, unsigned long int lineNumber, std::size_t n) {
-        base::threading::ScopedLock scopedLock(lock());
-        base::HitCounter* counter = get(filename, lineNumber);
-        if (counter == nullptr) {
-            registerNew(counter = new base::HitCounter(filename, lineNumber));
-        }
-        counter->validateHitCounts(n);
-        bool result = (n >= 1 && counter->hitCounts() != 0 && counter->hitCounts() % n == 0);
-        return result;
-    }
-
-    /// @brief Validates counter for hits >= N, i.e, registers new if does not exist otherwise updates original one
-    /// @return True if validation resulted in triggering hit. Meaning logs should be written everytime true is returned
-    bool validateAfterN(const char* filename, unsigned long int lineNumber, std::size_t n) {
-        base::threading::ScopedLock scopedLock(lock());
-        base::HitCounter* counter = get(filename, lineNumber);
-        if (counter == nullptr) {
-            registerNew(counter = new base::HitCounter(filename, lineNumber));
-        }
-        // Do not use validateHitCounts here since we do not want to reset counter here
-        // Note the >= instead of > because we are incrementing
-        // after this check
-        if (counter->hitCounts() >= n)
-            return true;
-        counter->increment();
-        return false;
-    }
-
-    /// @brief Validates counter for hits are <= n, i.e, registers new if does not exist otherwise updates original one
-    /// @return True if validation resulted in triggering hit. Meaning logs should be written everytime true is returned
-    bool validateNTimes(const char* filename, unsigned long int lineNumber, std::size_t n) {
-        base::threading::ScopedLock scopedLock(lock());
-        base::HitCounter* counter = get(filename, lineNumber);
-        if (counter == nullptr) {
-            registerNew(counter = new base::HitCounter(filename, lineNumber));
-        }
-        counter->increment();
-        // Do not use validateHitCounts here since we do not want to reset counter here
-        if (counter->hitCounts() <= n)
-            return true;
-        return false;
-    }
-
-    /// @brief Gets hit counter registered at specified position
-    inline const base::HitCounter* getCounter(const char* filename, unsigned long int lineNumber) {
-        base::threading::ScopedLock scopedLock(lock());
-        return get(filename, lineNumber);
-    }
-};
-/// @brief Action to be taken for dispatching
-enum class DispatchAction : base::type::EnumType {
-    None = 1, NormalLog = 2, SysLog = 4
-};
-}  // namespace base
-template <typename T>
-class Callback : protected base::threading::ThreadSafe {
-public:
-    Callback(void) : m_enabled(true) {}
-    inline bool enabled(void) const { return m_enabled; }
-    inline void setEnabled(bool enabled) {
-        base::threading::ScopedLock scopedLock(lock());
-        m_enabled = enabled;
-    }
-protected:
-    virtual void handle(const T* handlePtr) = 0;
-private:
-    bool m_enabled;
-};
-class LogDispatchData {
-public:
-    LogDispatchData() : m_logMessage(nullptr), m_dispatchAction(base::DispatchAction::None) {}
-    inline const LogMessage* logMessage(void) const { return m_logMessage; }
-    inline base::DispatchAction dispatchAction(void) const { return m_dispatchAction; }
-private:
-    LogMessage* m_logMessage;
-    base::DispatchAction m_dispatchAction;
-    friend class base::LogDispatcher;
-
-    inline void setLogMessage(LogMessage* logMessage) { m_logMessage = logMessage; }
-    inline void setDispatchAction(base::DispatchAction dispatchAction) { m_dispatchAction = dispatchAction; }
-};
-class LogDispatchCallback : public Callback<LogDispatchData> {
-private:
-    friend class base::LogDispatcher;
-};
-class PerformanceTrackingCallback : public Callback<PerformanceTrackingData> {
-private:
-    friend class base::PerformanceTracker;
-};
-class LogBuilder : base::NoCopy {
-public:
-    virtual ~LogBuilder(void) { ELPP_INTERNAL_INFO(3, "Destroying log builder...")}
-    virtual base::type::string_t build(const LogMessage* logMessage, bool appendNewLine) const = 0;
-    void convertToColoredOutput(base::type::string_t* logLine, Level level) {
-        if (!base::utils::s_termSupportsColor) return;
-        const base::type::char_t* resetColor = ELPP_LITERAL("\x1b[0m");
-        if (level == Level::Error || level == Level::Fatal)
-            *logLine = ELPP_LITERAL("\x1b[31m") + *logLine + resetColor;
-        else if (level == Level::Warning)
-            *logLine = ELPP_LITERAL("\x1b[33m") + *logLine + resetColor;
-    }
-private:
-    friend class el::base::DefaultLogDispatchCallback;
-};
-typedef std::shared_ptr<LogBuilder> LogBuilderPtr;
-/// @brief Represents a logger holding ID and configurations we need to write logs
-///
-/// @detail This class does not write logs itself instead its used by writer to read configuations from.
-class Logger : public base::threading::ThreadSafe, public Loggable {
-public:
-    Logger(const std::string& id, base::LogStreamsReferenceMap* logStreamsReference) :
-            m_id(id),
-            m_typedConfigurations(nullptr),
-            m_parentApplicationName(std::string()),
-            m_isConfigured(false),
-            m_logStreamsReference(logStreamsReference) {
-        initUnflushedCount();
-    }
-
-    Logger(const std::string& id, const Configurations& configurations, base::LogStreamsReferenceMap* logStreamsReference) :
-            m_id(id),
-            m_typedConfigurations(nullptr),
-            m_parentApplicationName(std::string()),
-            m_isConfigured(false),
-            m_logStreamsReference(logStreamsReference) {
-        initUnflushedCount();
-        configure(configurations);
-    }
-
-    Logger(const Logger& logger) {
-        base::utils::safeDelete(m_typedConfigurations);
-        m_id = logger.m_id;
-        m_typedConfigurations = logger.m_typedConfigurations;
-        m_parentApplicationName = logger.m_parentApplicationName;
-        m_isConfigured = logger.m_isConfigured;
-        m_configurations = logger.m_configurations;
-        m_unflushedCount = logger.m_unflushedCount;
-        m_logStreamsReference = logger.m_logStreamsReference;
-    }
-
-    Logger& operator=(const Logger& logger) {
-        base::utils::safeDelete(m_typedConfigurations);
-        m_id = logger.m_id;
-        m_typedConfigurations = logger.m_typedConfigurations;
-        m_parentApplicationName = logger.m_parentApplicationName;
-        m_isConfigured = logger.m_isConfigured;
-        m_configurations = logger.m_configurations;
-        m_unflushedCount = logger.m_unflushedCount;
-        m_logStreamsReference = logger.m_logStreamsReference;
-        return *this;
-    }
-
-    virtual ~Logger(void) {
-        base::utils::safeDelete(m_typedConfigurations);
-    }
-
-    virtual inline void log(el::base::type::ostream_t& os) const {
-        os << m_id.c_str();
-    }
-
-    /// @brief Configures the logger using specified configurations.
-    void configure(const Configurations& configurations) {
-        m_isConfigured = false;  // we set it to false in case if we fail
-        initUnflushedCount();
-        if (m_typedConfigurations != nullptr) {
-            Configurations* c = const_cast<Configurations*>(m_typedConfigurations->configurations());
-            if (c->hasConfiguration(Level::Global, ConfigurationType::Filename)) {
-                // This check is definitely needed for cases like ELPP_NO_DEFAULT_LOG_FILE
-                flush();
-            }
-        }
-        base::threading::ScopedLock scopedLock(lock());
-        if (m_configurations != configurations) {
-            m_configurations.setFromBase(const_cast<Configurations*>(&configurations));
-        }
-        base::utils::safeDelete(m_typedConfigurations);
-        m_typedConfigurations = new base::TypedConfigurations(&m_configurations, m_logStreamsReference);
-        resolveLoggerFormatSpec();
-        m_isConfigured = true;
-    }
-
-    /// @brief Reconfigures logger using existing configurations
-    inline void reconfigure(void) {
-        ELPP_INTERNAL_INFO(1, "Reconfiguring logger [" << m_id << "]");
-        configure(m_configurations);
-    }
-
-    inline const std::string& id(void) const {
-        return m_id;
-    }
-
-    inline const std::string& parentApplicationName(void) const {
-        return m_parentApplicationName;
-    }
-
-    inline void setParentApplicationName(const std::string& parentApplicationName) {
-        m_parentApplicationName = parentApplicationName;
-    }
-
-    inline Configurations* configurations(void) {
-        return &m_configurations;
-    }
-
-    inline base::TypedConfigurations* typedConfigurations(void) {
-        return m_typedConfigurations;
-    }
-
-    static inline bool isValidId(const std::string& id) {
-        for (std::string::const_iterator it = id.begin(); it != id.end(); ++it) {
-            if (!base::utils::Str::contains(base::consts::kValidLoggerIdSymbols, *it)) {
-                return false;
-            }
-        }
-        return true;
-    }
-    /// @brief Flushes logger to sync all log files for all levels
-    inline void flush(void) {
-        ELPP_INTERNAL_INFO(3, "Flushing logger [" << m_id << "] all levels");
-        base::threading::ScopedLock scopedLock(lock());
-        base::type::EnumType lIndex = LevelHelper::kMinValid;
-        LevelHelper::forEachLevel(&lIndex, [&](void) -> bool {
-            flush(LevelHelper::castFromInt(lIndex), nullptr);
-            return false;
-        });
-    }
-
-    inline void flush(Level level, base::type::fstream_t* fs) {
-        if (fs == nullptr && m_typedConfigurations->toFile(level)) {
-            fs = m_typedConfigurations->fileStream(level);
-        }
-        if (fs != nullptr) {
-            fs->flush();
-            m_unflushedCount.find(level)->second = 0;
-        }
-    }
-
-    inline bool isFlushNeeded(Level level) {
-        return ++m_unflushedCount.find(level)->second >= m_typedConfigurations->logFlushThreshold(level);
-    }
-
-    inline LogBuilder* logBuilder(void) const {
-        return m_logBuilder.get();
-    }
-
-    inline void setLogBuilder(const LogBuilderPtr& logBuilder) {
-        m_logBuilder = logBuilder;
-    }
-
-    inline bool enabled(Level level) const {
-        return m_typedConfigurations->enabled(level);
-    }
-    
-#if ELPP_VARIADIC_TEMPLATES_SUPPORTED
-#   define LOGGER_LEVEL_WRITERS_SIGNATURES(FUNCTION_NAME)\
-    template <typename T, typename... Args>\
-    inline void FUNCTION_NAME(const char*, const T&, const Args&...);\
-    template <typename T>\
-    inline void FUNCTION_NAME(const T&);
-
-    template <typename T, typename... Args> 
-    inline void verbose(int, const char*, const T&, const Args&...);
-
-    template <typename T> 
-    inline void verbose(int, const T&);
-
-    LOGGER_LEVEL_WRITERS_SIGNATURES(info)
-    LOGGER_LEVEL_WRITERS_SIGNATURES(debug)
-    LOGGER_LEVEL_WRITERS_SIGNATURES(warn)
-    LOGGER_LEVEL_WRITERS_SIGNATURES(error)
-    LOGGER_LEVEL_WRITERS_SIGNATURES(fatal)
-    LOGGER_LEVEL_WRITERS_SIGNATURES(trace)
-#   undef LOGGER_LEVEL_WRITERS_SIGNATURES
-#endif // ELPP_VARIADIC_TEMPLATES_SUPPORTED
-private:
-    std::string m_id;
-    base::TypedConfigurations* m_typedConfigurations;
-    base::type::stringstream_t m_stream;
-    std::string m_parentApplicationName;
-    bool m_isConfigured;
-    Configurations m_configurations;
-    std::map<Level, unsigned int> m_unflushedCount;
-    base::LogStreamsReferenceMap* m_logStreamsReference;
-    LogBuilderPtr m_logBuilder;
-
-    friend class el::LogMessage;
-    friend class el::Loggers;
-    friend class el::Helpers;
-    friend class el::base::RegisteredLoggers;
-    friend class el::base::DefaultLogDispatchCallback;
-    friend class el::base::MessageBuilder;
-    friend class el::base::Writer;
-    friend class el::base::PErrorWriter;
-    friend class el::base::Storage;
-    friend class el::base::PerformanceTracker;
-    friend class el::base::LogDispatcher;
-
-    Logger(void);
-
-#if ELPP_VARIADIC_TEMPLATES_SUPPORTED
-    template <typename T, typename... Args>
-    void log_(Level, int, const char*, const T&, const Args&...);
-
-    template <typename T>
-    inline void log_(Level, int, const T&);
-
-    template <typename T, typename... Args>
-    void log(Level, const char*, const T&, const Args&...);
-
-    template <typename T>
-    inline void log(Level, const T&);
-#endif // ELPP_VARIADIC_TEMPLATES_SUPPORTED
-
-    void initUnflushedCount(void) {
-        m_unflushedCount.clear();
-        base::type::EnumType lIndex = LevelHelper::kMinValid;
-        LevelHelper::forEachLevel(&lIndex, [&](void) -> bool {
-            m_unflushedCount.insert(std::make_pair(LevelHelper::castFromInt(lIndex), 0));
-            return false;
-        });
-    }
-
-    inline base::type::stringstream_t& stream(void) {
-        return m_stream;
-    }
-
-    void resolveLoggerFormatSpec(void) const {
-        base::type::EnumType lIndex = LevelHelper::kMinValid;
-        LevelHelper::forEachLevel(&lIndex, [&](void) -> bool {
-            base::LogFormat* logFormat = 
-                const_cast<base::LogFormat*>(&m_typedConfigurations->logFormat(LevelHelper::castFromInt(lIndex)));
-            base::utils::Str::replaceFirstWithEscape(logFormat->m_format, base::consts::kLoggerIdFormatSpecifier, m_id);
-            return false;
-        });
-    }
-};
-namespace base {
-/// @brief Loggers repository
-class RegisteredLoggers : public base::utils::Registry<Logger, std::string> {
-public:
-    explicit RegisteredLoggers(const LogBuilderPtr& defaultLogBuilder) :
-        m_defaultLogBuilder(defaultLogBuilder) {
-        m_defaultConfigurations.setToDefault();
-    }
-
-    virtual ~RegisteredLoggers(void) {
-        flushAll();
-    }
-
-    inline void setDefaultConfigurations(const Configurations& configurations) {
-        base::threading::ScopedLock scopedLock(lock());
-        m_defaultConfigurations.setFromBase(const_cast<Configurations*>(&configurations));
-    }
-
-    inline Configurations* defaultConfigurations(void) {
-        return &m_defaultConfigurations;
-    }
-
-    Logger* get(const std::string& id, bool forceCreation = true) {
-        base::threading::ScopedLock scopedLock(lock());
-        Logger* logger_ = base::utils::Registry<Logger, std::string>::get(id);
-        if (logger_ == nullptr && forceCreation) {
-            bool validId = Logger::isValidId(id);
-            if (!validId) {
-                ELPP_ASSERT(validId, "Invalid logger ID [" << id << "]. Not registering this logger.");
-                return nullptr;
-            }
-            logger_ = new Logger(id, m_defaultConfigurations, &m_logStreamsReference);
-            logger_->m_logBuilder = m_defaultLogBuilder;
-            registerNew(id, logger_);
-        }
-        return logger_;
-    }
-
-    bool remove(const std::string& id) {
-        if (id == "default") {
-            return false;
-        }
-        Logger* logger = base::utils::Registry<Logger, std::string>::get(id);
-        if (logger != nullptr) {
-            unregister(logger);
-        }
-        return true;
-    }
-
-    inline bool has(const std::string& id) {
-        return get(id, false) != nullptr;
-    }
-
-    inline void unregister(Logger*& logger) {
-        base::threading::ScopedLock scopedLock(lock());
-        base::utils::Registry<Logger, std::string>::unregister(logger->id());
-    }
-
-    inline base::LogStreamsReferenceMap* logStreamsReference(void) {
-        return &m_logStreamsReference;
-    }
-
-    inline void flushAll(void) {
-        ELPP_INTERNAL_INFO(1, "Flushing all log files");
-        base::threading::ScopedLock scopedLock(lock());
-        for (base::LogStreamsReferenceMap::iterator it = m_logStreamsReference.begin();
-                it != m_logStreamsReference.end(); ++it) {
-            if (it->second.get() == nullptr) continue;
-            it->second->flush();
-        }
-    }
-
-private:
-    LogBuilderPtr m_defaultLogBuilder;
-    Configurations m_defaultConfigurations;
-    base::LogStreamsReferenceMap m_logStreamsReference;
-    friend class el::base::Storage;
-};
-/// @brief Represents registries for verbose logging
-class VRegistry : base::NoCopy, public base::threading::ThreadSafe {
-public:
-    explicit VRegistry(base::type::VerboseLevel level, base::type::EnumType* pFlags) : m_level(level), m_pFlags(pFlags) {
-    }
-
-    /// @brief Sets verbose level. Accepted range is 0-9
-    inline void setLevel(base::type::VerboseLevel level) {
-        base::threading::ScopedLock scopedLock(lock());
-        if (level < 0)
-            m_level = 0;
-        else if (level > 9)
-            m_level = base::consts::kMaxVerboseLevel;
-        else
-            m_level = level;
-    }
-
-    inline base::type::VerboseLevel level(void) const {
-        return m_level;
-    }
-
-    inline void clearModules(void) {
-        base::threading::ScopedLock scopedLock(lock());
-        m_modules.clear();
-    }
-
-    void setModules(const char* modules) {
-        base::threading::ScopedLock scopedLock(lock());
-        auto addSuffix = [](std::stringstream& ss, const char* sfx, const char* prev) {
-            if (prev != nullptr && base::utils::Str::endsWith(ss.str(), std::string(prev))) {
-                std::string chr(ss.str().substr(0, ss.str().size() - strlen(prev)));
-                ss.str(std::string(""));
-                ss << chr;
-            }
-            if (base::utils::Str::endsWith(ss.str(), std::string(sfx))) {
-                std::string chr(ss.str().substr(0, ss.str().size() - strlen(sfx)));
-                ss.str(std::string(""));
-                ss << chr;
-            }
-            ss << sfx;
-        };
-        auto insert = [&](std::stringstream& ss, base::type::VerboseLevel level) {
-            if (!base::utils::hasFlag(LoggingFlag::DisableVModulesExtensions, *m_pFlags)) {
-                addSuffix(ss, ".h", nullptr);
-                m_modules.insert(std::make_pair(ss.str(), level));
-                addSuffix(ss, ".c", ".h");
-                m_modules.insert(std::make_pair(ss.str(), level));
-                addSuffix(ss, ".cpp", ".c");
-                m_modules.insert(std::make_pair(ss.str(), level));
-                addSuffix(ss, ".cc", ".cpp");
-                m_modules.insert(std::make_pair(ss.str(), level));
-                addSuffix(ss, ".cxx", ".cc");
-                m_modules.insert(std::make_pair(ss.str(), level));
-                addSuffix(ss, ".-inl.h", ".cxx");
-                m_modules.insert(std::make_pair(ss.str(), level));
-                addSuffix(ss, ".hxx", ".-inl.h");
-                m_modules.insert(std::make_pair(ss.str(), level));
-                addSuffix(ss, ".hpp", ".hxx");
-                m_modules.insert(std::make_pair(ss.str(), level));
-                addSuffix(ss, ".hh", ".hpp");
-            }
-            m_modules.insert(std::make_pair(ss.str(), level));
-        };
-        bool isMod = true;
-        bool isLevel = false;
-        std::stringstream ss;
-        int level = -1;
-        for (; *modules; ++modules) {
-            switch (*modules) {
-            case '=':
-                isLevel = true;
-                isMod = false;
-                break;
-            case ',':
-                isLevel = false;
-                isMod = true;
-                if (!ss.str().empty() && level != -1) {
-                    insert(ss, level);
-                    ss.str(std::string(""));
-                    level = -1;
-                }
-                break;
-            default:
-                if (isMod) {
-                    ss << *modules;
-                } else if (isLevel) {
-                    if (isdigit(*modules)) {
-                        level = static_cast<base::type::VerboseLevel>(*modules) - 48;
-                    }
-                }
-                break;
-            }
-        }
-        if (!ss.str().empty() && level != -1) {
-            insert(ss, level);
-        }
-    }
-
-    bool allowed(base::type::VerboseLevel vlevel, const char* file) {
-        base::threading::ScopedLock scopedLock(lock());
-        if (m_modules.empty() || file == nullptr) {
-            return vlevel <= m_level;
-        } else {
-            std::map<std::string, base::type::VerboseLevel>::iterator it = m_modules.begin();
-            for (; it != m_modules.end(); ++it) {
-                if (base::utils::Str::wildCardMatch(file, it->first.c_str())) {
-                    return vlevel <= it->second;
-                }
-            }
-            if (base::utils::hasFlag(LoggingFlag::AllowVerboseIfModuleNotSpecified, *m_pFlags)) {
-                return true;
-            }
-            return false;
-        }
-    }
-
-    inline const std::map<std::string, base::type::VerboseLevel>& modules(void) const {
-        return m_modules;
-    }
-
-    void setFromArgs(const base::utils::CommandLineArgs* commandLineArgs) {
-        if (commandLineArgs->hasParam("-v") || commandLineArgs->hasParam("--verbose") ||
-            commandLineArgs->hasParam("-V") || commandLineArgs->hasParam("--VERBOSE")) {
-            setLevel(base::consts::kMaxVerboseLevel);
-        } else if (commandLineArgs->hasParamWithValue("--v")) {
-            setLevel(atoi(commandLineArgs->getParamValue("--v")));
-        } else if (commandLineArgs->hasParamWithValue("--V")) {
-            setLevel(atoi(commandLineArgs->getParamValue("--V")));
-        } else if ((commandLineArgs->hasParamWithValue("-vmodule")) && vModulesEnabled()) {
-            setModules(commandLineArgs->getParamValue("-vmodule"));
-        } else if (commandLineArgs->hasParamWithValue("-VMODULE") && vModulesEnabled()) {
-            setModules(commandLineArgs->getParamValue("-VMODULE"));
-        }
-    }
-    
-    /// @brief Whether or not vModules enabled
-    inline bool vModulesEnabled(void) {
-        return !base::utils::hasFlag(LoggingFlag::DisableVModules, *m_pFlags);
-    }
-
-private:
-    base::type::VerboseLevel m_level;
-    base::type::EnumType* m_pFlags;
-    std::map<std::string, base::type::VerboseLevel> m_modules;
-};
-}  // namespace base
-class LogMessage {
-public:
-    LogMessage(Level level, const std::string& file, unsigned long int line, const std::string& func,
-                          base::type::VerboseLevel verboseLevel, Logger* logger) :
-                  m_level(level), m_file(file), m_line(line), m_func(func),
-                  m_verboseLevel(verboseLevel), m_logger(logger), m_message(std::move(logger->stream().str())) {
-    }
-    inline Level level(void) const { return m_level; }
-    inline const std::string& file(void) const { return m_file; }
-    inline unsigned long int line(void) const { return m_line; } // NOLINT
-    inline const std::string& func(void) const { return m_func; }
-    inline base::type::VerboseLevel verboseLevel(void) const { return m_verboseLevel; }
-    inline Logger* logger(void) const { return m_logger; }
-    inline const base::type::string_t& message(void) const { return m_message; }
-private:
-    Level m_level;
-    std::string m_file;
-    unsigned long int m_line;
-    std::string m_func;
-    base::type::VerboseLevel m_verboseLevel;
-    Logger* m_logger;
-    base::type::string_t m_message;
-};
-namespace base {
-#if ELPP_ASYNC_LOGGING
-class AsyncLogItem {
-public:
-    explicit AsyncLogItem(const LogMessage& logMessage, const LogDispatchData& data, const base::type::string_t& logLine)
-        : m_logMessage(logMessage), m_dispatchData(data), m_logLine(logLine) {}
-    virtual ~AsyncLogItem() {}
-    inline LogMessage* logMessage(void) { return &m_logMessage; }
-    inline LogDispatchData* data(void) { return &m_dispatchData; }
-    inline base::type::string_t logLine(void) { return m_logLine; }
-private:
-    LogMessage m_logMessage;
-    LogDispatchData m_dispatchData;
-    base::type::string_t m_logLine;
-};
-class AsyncLogQueue : public base::threading::ThreadSafe {
-public:
-    virtual ~AsyncLogQueue() {
-        ELPP_INTERNAL_INFO(6, "~AsyncLogQueue");
-    }
-    
-    inline AsyncLogItem next(void) {
-        base::threading::ScopedLock scopedLock(lock());
-        AsyncLogItem result = m_queue.front();
-        m_queue.pop();
-        return result;
-    }
-    
-    inline void push(const AsyncLogItem& item) {
-        base::threading::ScopedLock scopedLock(lock());
-        m_queue.push(item);
-    }
-    inline void pop(void) {
-        base::threading::ScopedLock scopedLock(lock());
-        m_queue.pop();
-    }
-    inline AsyncLogItem front(void) {
-        base::threading::ScopedLock scopedLock(lock());
-        return m_queue.front();
-    }
-    inline bool empty(void) {
-        base::threading::ScopedLock scopedLock(lock());
-        return m_queue.empty();
-    }
-private:
-    std::queue<AsyncLogItem> m_queue;
-};
-class IWorker {
-public:
-    virtual ~IWorker() {}
-    virtual void start() = 0;
-};
-#endif // ELPP_ASYNC_LOGGING
-/// @brief Easylogging++ management storage
-class Storage : base::NoCopy, public base::threading::ThreadSafe {
-public:
-#if ELPP_ASYNC_LOGGING
-    Storage(const LogBuilderPtr& defaultLogBuilder, base::IWorker* asyncDispatchWorker) :
-#else
-    explicit Storage(const LogBuilderPtr& defaultLogBuilder) :
-#endif  // ELPP_ASYNC_LOGGING
-        m_registeredHitCounters(new base::RegisteredHitCounters()),
-        m_registeredLoggers(new base::RegisteredLoggers(defaultLogBuilder)),
-        m_flags(0x0),
-        m_vRegistry(new base::VRegistry(0, &m_flags)),
-#if ELPP_ASYNC_LOGGING
-        m_asyncLogQueue(new base::AsyncLogQueue()),
-        m_asyncDispatchWorker(asyncDispatchWorker),
-#endif  // ELPP_ASYNC_LOGGING
-        m_preRollOutCallback(base::defaultPreRollOutCallback) {
-        // Register default logger
-        m_registeredLoggers->get(std::string(base::consts::kDefaultLoggerId));
-        // Register performance logger and reconfigure format
-        Logger* performanceLogger = m_registeredLoggers->get(std::string(base::consts::kPerformanceLoggerId));
-        performanceLogger->configurations()->setGlobally(ConfigurationType::Format, std::string("%datetime %level %msg"));
-        performanceLogger->reconfigure();
-#if defined(ELPP_SYSLOG)
-        // Register syslog logger and reconfigure format
-        Logger* sysLogLogger = m_registeredLoggers->get(std::string(base::consts::kSysLogLoggerId));
-        sysLogLogger->configurations()->setGlobally(ConfigurationType::Format, std::string("%level: %msg"));
-        sysLogLogger->reconfigure();
-#else
-        ELPP_UNUSED(base::consts::kSysLogLoggerId);
-#endif //  defined(ELPP_SYSLOG)
-        addFlag(LoggingFlag::AllowVerboseIfModuleNotSpecified);
-#if ELPP_ASYNC_LOGGING
-        installLogDispatchCallback<base::AsyncLogDispatchCallback>(std::string("AsyncLogDispatchCallback"));
-#else
-        installLogDispatchCallback<base::DefaultLogDispatchCallback>(std::string("DefaultLogDispatchCallback"));
-#endif  // ELPP_ASYNC_LOGGING
-            installPerformanceTrackingCallback<base::DefaultPerformanceTrackingCallback>(std::string("DefaultPerformanceTrackingCallback"));
-            ELPP_INTERNAL_INFO(1, "Easylogging++ has been initialized");
-#if ELPP_ASYNC_LOGGING
-        m_asyncDispatchWorker->start();
-#endif  // ELPP_ASYNC_LOGGING
-    }
-
-    virtual ~Storage(void) {
-        ELPP_INTERNAL_INFO(4, "Destroying storage");
-#if ELPP_ASYNC_LOGGING
-        ELPP_INTERNAL_INFO(5, "Replacing log dispatch callback to synchronous");
-        uninstallLogDispatchCallback<base::AsyncLogDispatchCallback>(std::string("AsyncLogDispatchCallback"));
-        installLogDispatchCallback<base::DefaultLogDispatchCallback>(std::string("DefaultLogDispatchCallback"));
-        ELPP_INTERNAL_INFO(5, "Destroying asyncDispatchWorker");
-        base::utils::safeDelete(m_asyncDispatchWorker);
-        ELPP_INTERNAL_INFO(5, "Destroying asyncLogQueue");
-        base::utils::safeDelete(m_asyncLogQueue);
-#endif  // ELPP_ASYNC_LOGGING
-        ELPP_INTERNAL_INFO(5, "Destroying registeredHitCounters");
-        base::utils::safeDelete(m_registeredHitCounters);
-        ELPP_INTERNAL_INFO(5, "Destroying registeredLoggers");
-        base::utils::safeDelete(m_registeredLoggers);
-        ELPP_INTERNAL_INFO(5, "Destroying vRegistry");
-        base::utils::safeDelete(m_vRegistry);
-    }
-
-    inline bool validateEveryNCounter(const char* filename, unsigned long int lineNumber, std::size_t occasion) {
-        return hitCounters()->validateEveryN(filename, lineNumber, occasion);
-    }
-
-    inline bool validateAfterNCounter(const char* filename, unsigned long int lineNumber, std::size_t n) { // NOLINT
-        return hitCounters()->validateAfterN(filename, lineNumber, n);
-    }
-
-    inline bool validateNTimesCounter(const char* filename, unsigned long int lineNumber, std::size_t n) { // NOLINT
-        return hitCounters()->validateNTimes(filename, lineNumber, n);
-    }
-
-    inline base::RegisteredHitCounters* hitCounters(void) const {
-        return m_registeredHitCounters;
-    }
-
-    inline base::RegisteredLoggers* registeredLoggers(void) const {
-        return m_registeredLoggers;
-    }
-    
-    inline base::VRegistry* vRegistry(void) const {
-        return m_vRegistry;
-    }
-
-#if ELPP_ASYNC_LOGGING
-    inline base::AsyncLogQueue* asyncLogQueue(void) const {
-        return m_asyncLogQueue;
-    }
-#endif  // ELPP_ASYNC_LOGGING
-
-    inline const base::utils::CommandLineArgs* commandLineArgs(void) const {
-        return &m_commandLineArgs;
-    }
-
-    inline void addFlag(LoggingFlag flag) {
-        base::utils::addFlag(flag, &m_flags);
-    }
-
-    inline void removeFlag(LoggingFlag flag) {
-        base::utils::removeFlag(flag, &m_flags);
-    }
-
-    inline bool hasFlag(LoggingFlag flag) const {
-        return base::utils::hasFlag(flag, m_flags);
-    }
-
-    inline base::type::EnumType flags(void) const {
-        return m_flags;
-    }
-
-    inline void setFlags(base::type::EnumType flags) {
-        m_flags = flags;
-    }
-
-    inline void setPreRollOutCallback(const PreRollOutCallback& callback) {
-        m_preRollOutCallback = callback;
-    }
-
-    inline void unsetPreRollOutCallback(void) {
-        m_preRollOutCallback = base::defaultPreRollOutCallback;
-    }
-
-    inline PreRollOutCallback& preRollOutCallback(void) {
-        return m_preRollOutCallback;
-    }
-
-    inline bool hasCustomFormatSpecifier(const char* formatSpecifier) {
-        base::threading::ScopedLock scopedLock(lock());
-        return std::find(m_customFormatSpecifiers.begin(), m_customFormatSpecifiers.end(),
-                formatSpecifier) != m_customFormatSpecifiers.end();
-    }
-
-    inline void installCustomFormatSpecifier(const CustomFormatSpecifier& customFormatSpecifier) {
-        if (hasCustomFormatSpecifier(customFormatSpecifier.formatSpecifier())) {
-            return;
-        }
-        base::threading::ScopedLock scopedLock(lock());
-        m_customFormatSpecifiers.push_back(customFormatSpecifier);
-    }
-
-    inline bool uninstallCustomFormatSpecifier(const char* formatSpecifier) {
-        base::threading::ScopedLock scopedLock(lock());
-        std::vector<CustomFormatSpecifier>::iterator it = std::find(m_customFormatSpecifiers.begin(),
-                m_customFormatSpecifiers.end(), formatSpecifier);
-        if (it != m_customFormatSpecifiers.end() && strcmp(formatSpecifier, it->formatSpecifier()) == 0) {
-            m_customFormatSpecifiers.erase(it);
-            return true;
-        }
-        return false;
-    }
-
-    const std::vector<CustomFormatSpecifier>* customFormatSpecifiers(void) const {
-        return &m_customFormatSpecifiers;
-    }
-
-    inline void setLoggingLevel(Level level) {
-        m_loggingLevel = level;
-    }
-
-    template <typename T>
-    inline bool installLogDispatchCallback(const std::string& id) {
-        return installCallback<T, base::type::LogDispatchCallbackPtr>(id, &m_logDispatchCallbacks);
-    }
-
-    template <typename T>
-    inline void uninstallLogDispatchCallback(const std::string& id) {
-        uninstallCallback<T, base::type::LogDispatchCallbackPtr>(id, &m_logDispatchCallbacks);
-    }
-    template <typename T>
-    inline T* logDispatchCallback(const std::string& id) {
-        return callback<T, base::type::LogDispatchCallbackPtr>(id, &m_logDispatchCallbacks);
-    }
-
-    template <typename T>
-    inline bool installPerformanceTrackingCallback(const std::string& id) {
-        return installCallback<T, base::type::PerformanceTrackingCallbackPtr>(id, &m_performanceTrackingCallbacks);
-    }
-
-    template <typename T>
-    inline void uninstallPerformanceTrackingCallback(const std::string& id) {
-         uninstallCallback<T, base::type::PerformanceTrackingCallbackPtr>(id, &m_performanceTrackingCallbacks);
-    }
-
-    template <typename T>
-    inline T* performanceTrackingCallback(const std::string& id) {
-        return callback<T, base::type::PerformanceTrackingCallbackPtr>(id, &m_performanceTrackingCallbacks);
-    }
-private:
-    base::RegisteredHitCounters* m_registeredHitCounters;
-    base::RegisteredLoggers* m_registeredLoggers;
-    base::type::EnumType m_flags;
-    base::VRegistry* m_vRegistry;
-#if ELPP_ASYNC_LOGGING
-    base::AsyncLogQueue* m_asyncLogQueue;
-    base::IWorker* m_asyncDispatchWorker;
-#endif  // ELPP_ASYNC_LOGGING
-    base::utils::CommandLineArgs m_commandLineArgs;
-    PreRollOutCallback m_preRollOutCallback;
-    std::map<std::string, base::type::LogDispatchCallbackPtr> m_logDispatchCallbacks;
-    std::map<std::string, base::type::PerformanceTrackingCallbackPtr> m_performanceTrackingCallbacks;
-    std::vector<CustomFormatSpecifier> m_customFormatSpecifiers;
-    Level m_loggingLevel;
-
-    friend class el::Helpers;
-    friend class el::base::DefaultLogDispatchCallback;
-    friend class el::LogBuilder;
-    friend class el::base::MessageBuilder;
-    friend class el::base::Writer;
-    friend class el::base::PerformanceTracker;
-    friend class el::base::LogDispatcher;
-
-    void setApplicationArguments(int argc, char** argv) {
-        m_commandLineArgs.setArgs(argc, argv);
-        m_vRegistry->setFromArgs(commandLineArgs());
-        // default log file
-#if !defined(ELPP_DISABLE_LOG_FILE_FROM_ARG)
-        if (m_commandLineArgs.hasParamWithValue(base::consts::kDefaultLogFileParam)) {
-            Configurations c;
-            c.setGlobally(ConfigurationType::Filename, std::string(m_commandLineArgs.getParamValue(base::consts::kDefaultLogFileParam)));
-            registeredLoggers()->setDefaultConfigurations(c);
-            for (base::RegisteredLoggers::iterator it = registeredLoggers()->begin();
-                    it != registeredLoggers()->end(); ++it) {
-                it->second->configure(c);
-            }
-        }
-#endif  // !defined(ELPP_DISABLE_LOG_FILE_FROM_ARG)
-#if defined(ELPP_LOGGING_FLAGS_FROM_ARG)
-        if (m_commandLineArgs.hasParamWithValue(base::consts::kLoggingFlagsParam)) {
-            m_flags = atoi(m_commandLineArgs.getParamValue(base::consts::kLoggingFlagsParam));
-        }
-#endif  // defined(ELPP_LOGGING_FLAGS_FROM_ARG)
-    }
-
-    inline void setApplicationArguments(int argc, const char** argv) {
-        setApplicationArguments(argc, const_cast<char**>(argv));
-    }
-
-    template <typename T, typename TPtr>
-    inline bool installCallback(const std::string& id, std::map<std::string, TPtr>* mapT) {
-        if (mapT->find(id) == mapT->end()) {
-            mapT->insert(std::make_pair(id, TPtr(new T())));
-            return true;
-        }
-        return false;
-    }
-
-    template <typename T, typename TPtr>
-    inline void uninstallCallback(const std::string& id, std::map<std::string, TPtr>* mapT) {
-        if (mapT->find(id) != mapT->end()) {
-            mapT->erase(id);
-        }
-    }
-
-    template <typename T, typename TPtr>
-    inline T* callback(const std::string& id, std::map<std::string, TPtr>* mapT) {
-        typename std::map<std::string, TPtr>::iterator iter = mapT->find(id);
-        if (iter != mapT->end()) {
-            return static_cast<T*>(iter->second.get());
-        }
-        return nullptr;
-    }
-};
-extern ELPP_EXPORT base::type::StoragePointer elStorage;
-#define ELPP el::base::elStorage
-class DefaultLogDispatchCallback : public LogDispatchCallback {
-protected:
-    void handle(const LogDispatchData* data) {
-        m_data = data;
-        dispatch(std::move(m_data->logMessage()->logger()->logBuilder()->build(m_data->logMessage(), 
-            m_data->dispatchAction() == base::DispatchAction::NormalLog)));
-    }
-private:
-    const LogDispatchData* m_data;
-    void dispatch(base::type::string_t&& logLine) {
-        if (m_data->dispatchAction() == base::DispatchAction::NormalLog) {
-            if (m_data->logMessage()->logger()->m_typedConfigurations->toFile(m_data->logMessage()->level())) {
-                base::type::fstream_t* fs = m_data->logMessage()->logger()->m_typedConfigurations->fileStream(m_data->logMessage()->level());
-                if (fs != nullptr) {
-                    fs->write(logLine.c_str(), logLine.size());
-                    if (fs->fail()) {
-                        ELPP_INTERNAL_ERROR("Unable to write log to file ["
-                            << m_data->logMessage()->logger()->m_typedConfigurations->filename(m_data->logMessage()->level()) << "].\n"
-                                << "Few possible reasons (could be something else):\n" << "      * Permission denied\n"
-                                << "      * Disk full\n" << "      * Disk is not writable", true);
-                    } else {
-                        if (ELPP->hasFlag(LoggingFlag::ImmediateFlush) || (m_data->logMessage()->logger()->isFlushNeeded(m_data->logMessage()->level()))) {
-                            m_data->logMessage()->logger()->flush(m_data->logMessage()->level(), fs);
-                        }
-                    }
-                } else {
-                    ELPP_INTERNAL_ERROR("Log file for [" << LevelHelper::convertToString(m_data->logMessage()->level()) << "] "
-                        << "has not been configured but [TO_FILE] is configured to TRUE. [Logger ID: " 
-                        << m_data->logMessage()->logger()->id() << "]", false);
-                }
-            }
-            if (m_data->logMessage()->logger()->m_typedConfigurations->toStandardOutput(m_data->logMessage()->level())) {
-                if (ELPP->hasFlag(LoggingFlag::ColoredTerminalOutput))
-                    m_data->logMessage()->logger()->logBuilder()->convertToColoredOutput(&logLine, m_data->logMessage()->level());
-                ELPP_COUT << ELPP_COUT_LINE(logLine);
-             }
-        }
-#if defined(ELPP_SYSLOG)
-        else if (m_data->dispatchAction() == base::DispatchAction::SysLog) {
-            // Determine syslog priority
-            int sysLogPriority = 0;
-            if (m_data->logMessage()->level() == Level::Fatal)
-                sysLogPriority = LOG_EMERG;
-            else if (m_data->logMessage()->level() == Level::Error)
-                sysLogPriority = LOG_ERR;
-            else if (m_data->logMessage()->level() == Level::Warning)
-                sysLogPriority = LOG_WARNING;
-            else if (m_data->logMessage()->level() == Level::Info)
-                sysLogPriority = LOG_INFO;
-            else if (m_data->logMessage()->level() == Level::Debug)
-                sysLogPriority = LOG_DEBUG;
-            else
-                sysLogPriority = LOG_NOTICE;
-#   if defined(ELPP_UNICODE)
-            char* line = base::utils::Str::wcharPtrToCharPtr(logLine.c_str());
-            syslog(sysLogPriority, "%s", line);
-            free(line);
-#   else
-            syslog(sysLogPriority, "%s", logLine.c_str());
-#   endif
-        }
-#endif  // defined(ELPP_SYSLOG)
-    }
-};
-#if ELPP_ASYNC_LOGGING
-class AsyncLogDispatchCallback : public LogDispatchCallback {
-protected:
-    void handle(const LogDispatchData* data) {
-        base::type::string_t logLine = data->logMessage()->logger()->logBuilder()->build(data->logMessage(), data->dispatchAction() == base::DispatchAction::NormalLog);
-        if (data->dispatchAction() == base::DispatchAction::NormalLog && data->logMessage()->logger()->typedConfigurations()->toStandardOutput(data->logMessage()->level())) {
-            if (ELPP->hasFlag(LoggingFlag::ColoredTerminalOutput))
-                data->logMessage()->logger()->logBuilder()->convertToColoredOutput(&logLine, data->logMessage()->level());
-            ELPP_COUT << ELPP_COUT_LINE(logLine);
-        }
-        // Save resources and only queue if we want to write to file otherwise just ignore handler
-        if (data->logMessage()->logger()->typedConfigurations()->toFile(data->logMessage()->level())) {
-            ELPP->asyncLogQueue()->push(AsyncLogItem(*(data->logMessage()), *data, logLine));
-        }
-    }
-};
-class AsyncDispatchWorker : public base::IWorker, public base::threading::ThreadSafe {
-public:
-    AsyncDispatchWorker() {
-        setContinueRunning(false);
-    }
-
-    virtual ~AsyncDispatchWorker() {
-        setContinueRunning(false);
-        ELPP_INTERNAL_INFO(6, "Stopping dispatch worker - Cleaning log queue");
-        clean();
-        ELPP_INTERNAL_INFO(6, "Log queue cleaned");
-    }
-
-    inline bool clean() {
-        std::mutex m;
-        std::unique_lock<std::mutex> lk(m);
-        cv.wait(lk, []{ return !ELPP->asyncLogQueue()->empty(); });
-        emptyQueue();
-        lk.unlock();
-        cv.notify_one();
-        return ELPP->asyncLogQueue()->empty();
-    }
-
-    inline void emptyQueue() {
-        while (!ELPP->asyncLogQueue()->empty()) {
-            AsyncLogItem data = ELPP->asyncLogQueue()->next();
-            handle(&data);
-            base::threading::msleep(100);
-        }
-    }
-    
-    virtual inline void start() {
-        base::threading::msleep(5000); // Wait extra few seconds
-        setContinueRunning(true);
-        std::thread t1(&AsyncDispatchWorker::runner, this);
-        t1.join();
-    }
-
-    void handle(AsyncLogItem* logItem) {
-        LogDispatchData* data = logItem->data();
-        LogMessage* logMessage = logItem->logMessage();
-        Logger* logger = logMessage->logger();
-        base::TypedConfigurations* conf = logger->typedConfigurations();
-        base::type::string_t logLine = logItem->logLine();
-        if (data->dispatchAction() == base::DispatchAction::NormalLog) {
-            if (conf->toFile(logMessage->level())) {
-                base::type::fstream_t* fs = conf->fileStream(logMessage->level());
-                if (fs != nullptr) {
-                    fs->write(logLine.c_str(), logLine.size());
-                    if (fs->fail()) {
-                        ELPP_INTERNAL_ERROR("Unable to write log to file ["
-                            << conf->filename(logMessage->level()) << "].\n"
-                                << "Few possible reasons (could be something else):\n" << "      * Permission denied\n"
-                                << "      * Disk full\n" << "      * Disk is not writable", true);
-                    } else {
-                        if (ELPP->hasFlag(LoggingFlag::ImmediateFlush) || (logger->isFlushNeeded(logMessage->level()))) {
-                            logger->flush(logMessage->level(), fs);
-                        }
-                    }
-                } else {
-                    ELPP_INTERNAL_ERROR("Log file for [" << LevelHelper::convertToString(logMessage->level()) << "] "
-                        << "has not been configured but [TO_FILE] is configured to TRUE. [Logger ID: " << logger->id() << "]", false);
-                }
-            }
-        }
-#   if defined(ELPP_SYSLOG)
-        else if (data->dispatchAction() == base::DispatchAction::SysLog) {
-            // Determine syslog priority
-            int sysLogPriority = 0;
-            if (logMessage->level() == Level::Fatal)
-                sysLogPriority = LOG_EMERG;
-            else if (logMessage->level() == Level::Error)
-                sysLogPriority = LOG_ERR;
-            else if (logMessage->level() == Level::Warning)
-                sysLogPriority = LOG_WARNING;
-            else if (logMessage->level() == Level::Info)
-                sysLogPriority = LOG_INFO;
-            else if (logMessage->level() == Level::Debug)
-                sysLogPriority = LOG_DEBUG;
-            else
-                sysLogPriority = LOG_NOTICE;
-#      if defined(ELPP_UNICODE)
-            char* line = base::utils::Str::wcharPtrToCharPtr(logLine.c_str());
-            syslog(sysLogPriority, "%s", line);
-            free(line);
-#      else
-            syslog(sysLogPriority, "%s", logLine.c_str());
-#      endif
-        }
-#   endif  // defined(ELPP_SYSLOG)
-    }
-
-    void run() {
-        while (continueRunning()) {
-            emptyQueue();
-            base::threading::msleep(10); // 10ms
-        }
-    }
-
-    static void* runner(void *context) {
-        static_cast<AsyncDispatchWorker*>(context)->run();
-        return NULL;
-    }
-    
-    void setContinueRunning(bool value) {
-        base::threading::ScopedLock scopedLock(m_continueRunningMutex);
-        m_continueRunning = value;
-    }
-    bool continueRunning(void) {
-        return m_continueRunning;
-    }
-private:
-    std::condition_variable cv;
-    bool m_continueRunning;
-    base::threading::Mutex m_continueRunningMutex;
-};
-#endif  // ELPP_ASYNC_LOGGING
-}  // namespace base
-namespace base {
-class DefaultLogBuilder : public LogBuilder {
-public:
-    base::type::string_t build(const LogMessage* logMessage, bool appendNewLine) const {
-        base::TypedConfigurations* tc = logMessage->logger()->typedConfigurations();
-        const base::LogFormat* logFormat = &tc->logFormat(logMessage->level());
-        base::type::string_t logLine = logFormat->format();
-        char buff[base::consts::kSourceFilenameMaxLength + base::consts::kSourceLineMaxLength] = "";
-        const char* bufLim = buff + sizeof(buff);
-        if (logFormat->hasFlag(base::FormatFlags::AppName)) {
-            // App name
-            base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kAppNameFormatSpecifier,
-                    logMessage->logger()->parentApplicationName());
-        }
-        if (logFormat->hasFlag(base::FormatFlags::ThreadId)) {
-            // Thread ID
-            base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kThreadIdFormatSpecifier,
-                    base::threading::getCurrentThreadId());
-        }
-        if (logFormat->hasFlag(base::FormatFlags::DateTime)) {
-            // DateTime
-            base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kDateTimeFormatSpecifier,
-                    base::utils::DateTime::getDateTime(logFormat->dateTimeFormat().c_str(), 
-                        &tc->millisecondsWidth(logMessage->level())));
-        }
-        if (logFormat->hasFlag(base::FormatFlags::Function)) {
-            // Function
-            base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kLogFunctionFormatSpecifier, logMessage->func());
-        }
-        if (logFormat->hasFlag(base::FormatFlags::File)) {
-            // File
-            char* buf = base::utils::Str::clearBuff(buff, base::consts::kSourceFilenameMaxLength);
-            base::utils::File::buildStrippedFilename(logMessage->file().c_str(), buff);
-            buf = base::utils::Str::addToBuff(buff, buf, bufLim);
-            base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kLogFileFormatSpecifier, std::string(buff));
-        }
-        if (logFormat->hasFlag(base::FormatFlags::FileBase)) {
-            // FileBase
-            char* buf = base::utils::Str::clearBuff(buff, base::consts::kSourceFilenameMaxLength);
-            base::utils::File::buildBaseFilename(logMessage->file(), buff);
-            buf = base::utils::Str::addToBuff(buff, buf, bufLim);
-            base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kLogFileBaseFormatSpecifier, std::string(buff));
-        }
-        if (logFormat->hasFlag(base::FormatFlags::Line)) {
-            // Line
-            char* buf = base::utils::Str::clearBuff(buff, base::consts::kSourceLineMaxLength);
-            buf = base::utils::Str::convertAndAddToBuff(logMessage->line(), 
-                base::consts::kSourceLineMaxLength, buf, bufLim, false);
-            base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kLogLineFormatSpecifier, std::string(buff));
-        }
-        if (logFormat->hasFlag(base::FormatFlags::Location)) {
-            // Location
-            char* buf = base::utils::Str::clearBuff(buff, 
-                base::consts::kSourceFilenameMaxLength + base::consts::kSourceLineMaxLength);
-            base::utils::File::buildStrippedFilename(logMessage->file().c_str(), buff);
-            buf = base::utils::Str::addToBuff(buff, buf, bufLim);
-            buf = base::utils::Str::addToBuff(":", buf, bufLim);
-            buf = base::utils::Str::convertAndAddToBuff(logMessage->line(), 
-                base::consts::kSourceLineMaxLength, buf, bufLim, false);
-            base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kLogLocationFormatSpecifier, std::string(buff));
-        }
-        if (logMessage->level() == Level::Verbose && logFormat->hasFlag(base::FormatFlags::VerboseLevel)) {
-            // Verbose level
-            char* buf = base::utils::Str::clearBuff(buff, 1);
-            buf = base::utils::Str::convertAndAddToBuff(logMessage->verboseLevel(), 1, buf, bufLim, false);
-            base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kVerboseLevelFormatSpecifier, std::string(buff));
-        }
-        if (logFormat->hasFlag(base::FormatFlags::LogMessage)) {
-            // Log message
-            base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kMessageFormatSpecifier, logMessage->message());
-        }
-#if !defined(ELPP_DISABLE_CUSTOM_FORMAT_SPECIFIERS)
-        for (std::vector<CustomFormatSpecifier>::const_iterator it = ELPP->customFormatSpecifiers()->begin();
-                it != ELPP->customFormatSpecifiers()->end(); ++it) {
-            std::string fs(it->formatSpecifier());
-            base::type::string_t wcsFormatSpecifier(fs.begin(), fs.end());
-            base::utils::Str::replaceFirstWithEscape(logLine, wcsFormatSpecifier, std::string(it->resolver()()));
-        }
-#endif  // !defined(ELPP_DISABLE_CUSTOM_FORMAT_SPECIFIERS)
-        if (appendNewLine) logLine += ELPP_LITERAL("\n");
-        return logLine;
-    }
-};
-/// @brief Dispatches log messages
-class LogDispatcher : base::NoCopy {
-public:
-    LogDispatcher(bool proceed, LogMessage&& logMessage, base::DispatchAction dispatchAction) :
-        m_proceed(proceed),
-        m_logMessage(std::move(logMessage)),
-        m_dispatchAction(std::move(dispatchAction)) {
-    }
-
-    void dispatch(void) {
-        if (m_proceed && m_dispatchAction == base::DispatchAction::None) {
-            m_proceed = false;
-        }
-        if (!m_proceed) {
-            return;
-        }
-        // We minimize the time of ELPP's lock - this lock is released after log is written
-        base::threading::ScopedLock scopedLock(ELPP->lock());
-        base::TypedConfigurations* tc = m_logMessage.logger()->m_typedConfigurations;
-        if (ELPP->hasFlag(LoggingFlag::StrictLogFileSizeCheck)) {
-            tc->validateFileRolling(m_logMessage.level(), ELPP->preRollOutCallback());
-        }
-        LogDispatchCallback* callback = nullptr;
-        LogDispatchData data;
-        for (const std::pair<std::string, base::type::LogDispatchCallbackPtr>& h 
-                : ELPP->m_logDispatchCallbacks) {
-            callback = h.second.get();
-            if (callback != nullptr && callback->enabled()) {
-                data.setLogMessage(&m_logMessage);
-                data.setDispatchAction(m_dispatchAction);
-                callback->acquireLock();
-                callback->handle(&data);
-                callback->releaseLock();
-            }
-        }
-    }
-
-private:
-    bool m_proceed;
-    LogMessage m_logMessage;
-    base::DispatchAction m_dispatchAction;
-};
-#if defined(ELPP_STL_LOGGING)
-/// @brief Workarounds to write some STL logs
-///
-/// @detail There is workaround needed to loop through some stl containers. In order to do that, we need iterable containers
-/// of same type and provide iterator interface and pass it on to writeIterator().
-/// Remember, this is passed by value in constructor so that we dont change original containers.
-/// This operation is as expensive as Big-O(std::min(class_.size(), base::consts::kMaxLogPerContainer))
-namespace workarounds {
-/// @brief Abstract IterableContainer template that provides interface for iterable classes of type T
-template <typename T, typename Container>
-class IterableContainer {
-public:
-    typedef typename Container::iterator iterator;
-    typedef typename Container::const_iterator const_iterator;
-    IterableContainer(void) {}
-    virtual ~IterableContainer(void) {}
-    iterator begin(void) { return getContainer().begin(); }
-    iterator end(void) { return getContainer().end(); }
-private:
-    virtual Container& getContainer(void) = 0;
-};
-/// @brief Implements IterableContainer and provides iterable std::priority_queue class
-template<typename T, typename Container = std::vector<T>, typename Comparator = std::less<typename Container::value_type>>
-class IterablePriorityQueue : public IterableContainer<T, Container>, public std::priority_queue<T, Container, Comparator> {
-public:
-    IterablePriorityQueue(std::priority_queue<T, Container, Comparator> queue_) {
-        std::size_t count_ = 0;
-        while (++count_ < base::consts::kMaxLogPerContainer && !queue_.empty()) {
-            this->push(queue_.top());
-            queue_.pop();
-        }
-    }
-private:
-    inline Container& getContainer(void) {
-        return this->c;
-    }
-};
-/// @brief Implements IterableContainer and provides iterable std::queue class
-template<typename T, typename Container = std::deque<T>>
-class IterableQueue : public IterableContainer<T, Container>, public std::queue<T, Container> {
-public:
-    IterableQueue(std::queue<T, Container> queue_) {
-        std::size_t count_ = 0;
-        while (++count_ < base::consts::kMaxLogPerContainer && !queue_.empty()) {
-            this->push(queue_.front());
-            queue_.pop();
-        }
-    }
-private:
-    inline Container& getContainer(void) {
-        return this->c;
-    }
-};
-/// @brief Implements IterableContainer and provides iterable std::stack class
-template<typename T, typename Container = std::deque<T>>
-class IterableStack : public IterableContainer<T, Container>, public std::stack<T, Container> {
-public:
-    IterableStack(std::stack<T, Container> stack_) {
-        std::size_t count_ = 0;
-        while (++count_ < base::consts::kMaxLogPerContainer && !stack_.empty()) {
-            this->push(stack_.top());
-            stack_.pop();
-        }
-    }
-private:
-    inline Container& getContainer(void) {
-        return this->c;
-    }
-};
-}  // namespace workarounds
-#endif  // defined(ELPP_STL_LOGGING)
-// Log message builder
-class MessageBuilder {
-public:
-    MessageBuilder(void) : m_logger(nullptr), m_containerLogSeperator(ELPP_LITERAL("")) {}
-    void initialize(Logger* logger) {
-        m_logger = logger;
-        m_containerLogSeperator = ELPP->hasFlag(LoggingFlag::NewLineForContainer) ? 
-            ELPP_LITERAL("\n    ") : ELPP_LITERAL(", ");
-    }
-
-#   define ELPP_SIMPLE_LOG(LOG_TYPE)\
-    inline MessageBuilder& operator<<(LOG_TYPE msg) {\
-        m_logger->stream() << msg;\
-        if (ELPP->hasFlag(LoggingFlag::AutoSpacing)) {\
-            m_logger->stream() << " ";\
-        }\
-        return *this;\
-    }
-
-    inline MessageBuilder& operator<<(const std::string& msg) {
-        return operator<<(msg.c_str());
-    }
-    ELPP_SIMPLE_LOG(char)
-    ELPP_SIMPLE_LOG(bool)
-    ELPP_SIMPLE_LOG(signed short)
-    ELPP_SIMPLE_LOG(unsigned short)
-    ELPP_SIMPLE_LOG(signed int)
-    ELPP_SIMPLE_LOG(unsigned int)
-    ELPP_SIMPLE_LOG(signed long)
-    ELPP_SIMPLE_LOG(unsigned long)
-    ELPP_SIMPLE_LOG(float)
-    ELPP_SIMPLE_LOG(double)
-    ELPP_SIMPLE_LOG(char*)
-    ELPP_SIMPLE_LOG(const char*)
-    ELPP_SIMPLE_LOG(const void*)
-    ELPP_SIMPLE_LOG(long double)
-    inline MessageBuilder& operator<<(const std::wstring& msg) {
-        return operator<<(msg.c_str());
-    }
-    inline MessageBuilder& operator<<(const wchar_t* msg) {
-        if (msg == nullptr) {
-            m_logger->stream() << base::consts::kNullPointer;
-            return *this;
-        }
-#   if defined(ELPP_UNICODE)
-        m_logger->stream() << msg;
-#   else
-        char* buff_ = base::utils::Str::wcharPtrToCharPtr(msg);
-        m_logger->stream() << buff_;
-        free(buff_);
-#   endif
-        if (ELPP->hasFlag(LoggingFlag::AutoSpacing)) {
-            m_logger->stream() << " ";
-        }
-        return *this;
-    }
-    // ostream manipulators
-    inline MessageBuilder& operator<<(std::ostream& (*OStreamMani)(std::ostream&)) {
-        m_logger->stream() << OStreamMani;
-        return *this;
-    }
-#define ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(temp)                                                    \
-    template <typename T>                                                                            \
-    inline MessageBuilder& operator<<(const temp<T>& template_inst) {                                \
-        return writeIterator(template_inst.begin(), template_inst.end(), template_inst.size());      \
-    }
-#define ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(temp)                                                    \
-    template <typename T1, typename T2>                                                              \
-    inline MessageBuilder& operator<<(const temp<T1, T2>& template_inst) {                           \
-        return writeIterator(template_inst.begin(), template_inst.end(), template_inst.size());      \
-    }
-#define ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(temp)                                                  \
-    template <typename T1, typename T2, typename T3>                                                 \
-    inline MessageBuilder& operator<<(const temp<T1, T2, T3>& template_inst) {                       \
-        return writeIterator(template_inst.begin(), template_inst.end(), template_inst.size());      \
-    }
-#define ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(temp)                                                   \
-    template <typename T1, typename T2, typename T3, typename T4>                                    \
-    inline MessageBuilder& operator<<(const temp<T1, T2, T3, T4>& template_inst) {                   \
-        return writeIterator(template_inst.begin(), template_inst.end(), template_inst.size());      \
-    }
-#define ELPP_ITERATOR_CONTAINER_LOG_FIVE_ARG(temp)                                                   \
-    template <typename T1, typename T2, typename T3, typename T4, typename T5>                       \
-    inline MessageBuilder& operator<<(const temp<T1, T2, T3, T4, T5>& template_inst) {               \
-        return writeIterator(template_inst.begin(), template_inst.end(), template_inst.size());      \
-    }
-
-#if defined(ELPP_STL_LOGGING)
-    ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(std::vector)
-    ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(std::list)
-    ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(std::deque)
-    ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(std::set)
-    ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(std::multiset)
-    ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(std::map)
-    ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(std::multimap)
-    template <class T, class Container>
-    inline MessageBuilder& operator<<(const std::queue<T, Container>& queue_) {
-        base::workarounds::IterableQueue<T, Container> iterableQueue_ =
-                static_cast<base::workarounds::IterableQueue<T, Container> >(queue_);
-        return writeIterator(iterableQueue_.begin(), iterableQueue_.end(), iterableQueue_.size());
-    }
-    template <class T, class Container>
-    inline MessageBuilder& operator<<(const std::stack<T, Container>& stack_) {
-        base::workarounds::IterableStack<T, Container> iterableStack_ =
-                static_cast<base::workarounds::IterableStack<T, Container> >(stack_);
-        return writeIterator(iterableStack_.begin(), iterableStack_.end(), iterableStack_.size());
-    }
-    template <class T, class Container, class Comparator>
-    inline MessageBuilder& operator<<(const std::priority_queue<T, Container, Comparator>& priorityQueue_) {
-        base::workarounds::IterablePriorityQueue<T, Container, Comparator> iterablePriorityQueue_ =
-                static_cast<base::workarounds::IterablePriorityQueue<T, Container, Comparator> >(priorityQueue_);
-        return writeIterator(iterablePriorityQueue_.begin(), iterablePriorityQueue_.end(), iterablePriorityQueue_.size());
-    }
-    template <class First, class Second>
-    inline MessageBuilder& operator<<(const std::pair<First, Second>& pair_) {
-        m_logger->stream() << ELPP_LITERAL("(");
-        operator << (static_cast<First>(pair_.first));
-        m_logger->stream() << ELPP_LITERAL(", ");
-        operator << (static_cast<Second>(pair_.second));
-        m_logger->stream() << ELPP_LITERAL(")");
-        return *this;
-    }
-    template <std::size_t Size>
-    inline MessageBuilder& operator<<(const std::bitset<Size>& bitset_) {
-        m_logger->stream() << ELPP_LITERAL("[");
-        operator << (bitset_.to_string());
-        m_logger->stream() << ELPP_LITERAL("]");
-        return *this;
-    }
-#   if defined(ELPP_LOG_STD_ARRAY)
-    template <class T, std::size_t Size>
-    inline MessageBuilder& operator<<(const std::array<T, Size>& array) {
-        return writeIterator(array.begin(), array.end(), array.size());
-    }
-#   endif  // defined(ELPP_LOG_STD_ARRAY)
-#   if defined(ELPP_LOG_UNORDERED_MAP)
-    ELPP_ITERATOR_CONTAINER_LOG_FIVE_ARG(std::unordered_map)
-    ELPP_ITERATOR_CONTAINER_LOG_FIVE_ARG(std::unordered_multimap)
-#   endif  // defined(ELPP_LOG_UNORDERED_MAP)
-#   if defined(ELPP_LOG_UNORDERED_SET)
-    ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(std::unordered_set)
-    ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(std::unordered_multiset)
-#   endif  // defined(ELPP_LOG_UNORDERED_SET)
-#endif  // defined(ELPP_STL_LOGGING)
-#if defined(ELPP_QT_LOGGING)
-    inline MessageBuilder& operator<<(const QString& msg) {
-#   if defined(ELPP_UNICODE)
-        m_logger->stream() << msg.toStdWString();
-#   else
-        m_logger->stream() << msg.toStdString();
-#   endif  // defined(ELPP_UNICODE)
-        return *this;
-    }
-    inline MessageBuilder& operator<<(const QByteArray& msg) {
-        return operator << (QString(msg));
-    }
-    inline MessageBuilder& operator<<(const QStringRef& msg) {
-        return operator<<(msg.toString());
-    }
-    inline MessageBuilder& operator<<(qint64 msg) {
-#   if defined(ELPP_UNICODE)
-        m_logger->stream() << QString::number(msg).toStdWString();
-#   else
-        m_logger->stream() << QString::number(msg).toStdString();
-#   endif  // defined(ELPP_UNICODE)
-        return *this;
-    }
-    inline MessageBuilder& operator<<(quint64 msg) {
-#   if defined(ELPP_UNICODE)
-        m_logger->stream() << QString::number(msg).toStdWString();
-#   else
-        m_logger->stream() << QString::number(msg).toStdString();
-#   endif  // defined(ELPP_UNICODE)
-        return *this;
-    }
-    inline MessageBuilder& operator<<(QChar msg) {
-        m_logger->stream() << msg.toLatin1();
-        return *this;
-    }
-    inline MessageBuilder& operator<<(const QLatin1String& msg) {
-        m_logger->stream() << msg.latin1();
-        return *this;
-    }
-    ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QList)
-    ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QVector)
-    ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QQueue)
-    ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QSet)
-    ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QLinkedList)
-    ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QStack)
-    template <typename First, typename Second>
-    inline MessageBuilder& operator<<(const QPair<First, Second>& pair_) {
-        m_logger->stream() << ELPP_LITERAL("(");
-        operator << (static_cast<First>(pair_.first));
-        m_logger->stream() << ELPP_LITERAL(", ");
-        operator << (static_cast<Second>(pair_.second));
-        m_logger->stream() << ELPP_LITERAL(")");
-        return *this;
-    }
-    template <typename K, typename V>
-    inline MessageBuilder& operator<<(const QMap<K, V>& map_) {
-        m_logger->stream() << ELPP_LITERAL("[");
-        QList<K> keys = map_.keys();
-        typename QList<K>::const_iterator begin = keys.begin();
-        typename QList<K>::const_iterator end = keys.end();
-        int max_ = static_cast<int>(base::consts::kMaxLogPerContainer);  // to prevent warning
-        for (int index_ = 0; begin != end && index_ < max_; ++index_, ++begin) {
-            m_logger->stream() << ELPP_LITERAL("(");
-            operator << (static_cast<K>(*begin));
-            m_logger->stream() << ELPP_LITERAL(", ");
-            operator << (static_cast<V>(map_.value(*begin)));
-            m_logger->stream() << ELPP_LITERAL(")");
-            m_logger->stream() << ((index_ < keys.size() -1) ? m_containerLogSeperator : ELPP_LITERAL(""));
-        }
-        if (begin != end) {
-            m_logger->stream() << ELPP_LITERAL("...");
-        }
-        m_logger->stream() << ELPP_LITERAL("]");
-        return *this;
-    }
-    template <typename K, typename V>
-    inline MessageBuilder& operator<<(const QMultiMap<K, V>& map_) {
-        operator << (static_cast<QMap<K, V>>(map_));
-        return *this;
-    }
-    template <typename K, typename V>
-    inline MessageBuilder& operator<<(const QHash<K, V>& hash_) {
-        m_logger->stream() << ELPP_LITERAL("[");
-        QList<K> keys = hash_.keys();
-        typename QList<K>::const_iterator begin = keys.begin();
-        typename QList<K>::const_iterator end = keys.end();
-        int max_ = static_cast<int>(base::consts::kMaxLogPerContainer);  // prevent type warning
-        for (int index_ = 0; begin != end && index_ < max_; ++index_, ++begin) {
-            m_logger->stream() << ELPP_LITERAL("(");
-            operator << (static_cast<K>(*begin));
-            m_logger->stream() << ELPP_LITERAL(", ");
-            operator << (static_cast<V>(hash_.value(*begin)));
-            m_logger->stream() << ELPP_LITERAL(")");
-            m_logger->stream() << ((index_ < keys.size() -1) ? m_containerLogSeperator : ELPP_LITERAL(""));
-        }
-        if (begin != end) {
-            m_logger->stream() << ELPP_LITERAL("...");
-        }
-        m_logger->stream() << ELPP_LITERAL("]");
-        return *this;
-    }
-    template <typename K, typename V>
-    inline MessageBuilder& operator<<(const QMultiHash<K, V>& multiHash_) {
-        operator << (static_cast<QHash<K, V>>(multiHash_));
-        return *this;
-    }
-#endif  // defined(ELPP_QT_LOGGING)
-#if defined(ELPP_BOOST_LOGGING)
-    ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(boost::container::vector)
-    ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(boost::container::stable_vector)
-    ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(boost::container::list)
-    ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(boost::container::deque)
-    ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(boost::container::map)
-    ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(boost::container::flat_map)
-    ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(boost::container::set)
-    ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(boost::container::flat_set)
-#endif  // defined(ELPP_BOOST_LOGGING)
-
-/// @brief Macro used internally that can be used externally to make containers easylogging++ friendly
-///
-/// @detail This macro expands to write an ostream& operator<< for container. This container is expected to
-///         have begin() and end() methods that return respective iterators
-/// @param ContainerType Type of container e.g, MyList from WX_DECLARE_LIST(int, MyList); in wxwidgets
-/// @param SizeMethod Method used to get size of container.
-/// @param ElementInstance Instance of element to be fed out. Insance name is "elem". See WXELPP_ENABLED macro
-///        for an example usage
-#define MAKE_CONTAINERELPP_FRIENDLY(ContainerType, SizeMethod, ElementInstance) \
-    el::base::type::ostream_t& operator<<(el::base::type::ostream_t& ss, const ContainerType& container) {\
-        const el::base::type::char_t* sep = ELPP->hasFlag(el::LoggingFlag::NewLineForContainer) ? \
-            ELPP_LITERAL("\n    ") : ELPP_LITERAL(", ");\
-        ContainerType::const_iterator elem = container.begin();\
-        ContainerType::const_iterator endElem = container.end();\
-        std::size_t size_ = container.SizeMethod; \
-        ss << ELPP_LITERAL("[");\
-        for (std::size_t i = 0; elem != endElem && i < el::base::consts::kMaxLogPerContainer; ++i, ++elem) { \
-            ss << ElementInstance;\
-            ss << ((i < size_ - 1) ? sep : ELPP_LITERAL(""));\
-        }\
-        if (elem != endElem) {\
-            ss << ELPP_LITERAL("...");\
-        }\
-        ss << ELPP_LITERAL("]");\
-        return ss;\
-    }
-#if defined(ELPP_WXWIDGETS_LOGGING)
-    ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(wxVector)
-#   define ELPP_WX_PTR_ENABLED(ContainerType) MAKE_CONTAINERELPP_FRIENDLY(ContainerType, size(), *(*elem))
-#   define ELPP_WX_ENABLED(ContainerType) MAKE_CONTAINERELPP_FRIENDLY(ContainerType, size(), (*elem))
-#   define ELPP_WX_HASH_MAP_ENABLED(ContainerType) MAKE_CONTAINERELPP_FRIENDLY(ContainerType, size(), \
-        ELPP_LITERAL("(") << elem->first << ELPP_LITERAL(", ") << elem->second << ELPP_LITERAL(")")
-#else
-#   define ELPP_WX_PTR_ENABLED(ContainerType)
-#   define ELPP_WX_ENABLED(ContainerType)
-#   define ELPP_WX_HASH_MAP_ENABLED(ContainerType)
-#endif  // defined(ELPP_WXWIDGETS_LOGGING)
-    // Other classes
-    template <class Class>
-    ELPP_SIMPLE_LOG(const Class&)
-#undef ELPP_SIMPLE_LOG
-#undef ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG
-#undef ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG
-#undef ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG
-#undef ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG
-#undef ELPP_ITERATOR_CONTAINER_LOG_FIVE_ARG
-private:
-    Logger* m_logger;
-    const base::type::char_t* m_containerLogSeperator;
-
-    template<class Iterator>
-    inline MessageBuilder& writeIterator(Iterator begin_, Iterator end_, std::size_t size_) {
-        m_logger->stream() << ELPP_LITERAL("[");
-        for (std::size_t i = 0; begin_ != end_ && i < base::consts::kMaxLogPerContainer; ++i, ++begin_) {
-            operator << (*begin_);
-            m_logger->stream() << ((i < size_ - 1) ? m_containerLogSeperator : ELPP_LITERAL(""));
-        }
-        if (begin_ != end_) {
-            m_logger->stream() << ELPP_LITERAL("...");
-        }
-        m_logger->stream() << ELPP_LITERAL("]");
-        if (ELPP->hasFlag(LoggingFlag::AutoSpacing)) {
-            m_logger->stream() << " ";
-        }
-        return *this;
-    }
-};
-/// @brief Writes nothing - Used when certain log is disabled
-class NullWriter : base::NoCopy {
-public:
-    NullWriter(void) {}
-
-    // Null manipulator
-    inline NullWriter& operator<<(std::ostream& (*)(std::ostream&)) {
-        return *this;
-    }
-
-    template <typename T>
-    inline NullWriter& operator<<(const T&) {
-        return *this;
-    }
-};
-/// @brief Main entry point of each logging
-class Writer : base::NoCopy {
-public:
-    Writer(Level level, const char* file, unsigned long int line,
-               const char* func, base::DispatchAction dispatchAction = base::DispatchAction::NormalLog,
-               base::type::VerboseLevel verboseLevel = 0) :
-                   m_level(level), m_file(file), m_line(line), m_func(func), m_verboseLevel(verboseLevel),
-                   m_proceed(false), m_dispatchAction(dispatchAction) {
-    }
-
-    virtual ~Writer(void) {
-        processDispatch();
-    }
-
-    template <typename T>
-    inline Writer& operator<<(const T& log) {
-#if ELPP_LOGGING_ENABLED
-        if (m_proceed) {
-            m_messageBuilder << log;
-        }
-#endif  // ELPP_LOGGING_ENABLED
-        return *this;
-    }
-
-    inline Writer& operator<<(std::ostream& (*log)(std::ostream&)) {
-#if ELPP_LOGGING_ENABLED
-        if (m_proceed) {
-            m_messageBuilder << log;
-        }
-#endif  // ELPP_LOGGING_ENABLED
-        return *this;
-    }
-
-    Writer& construct(Logger* logger, bool needLock = true) {
-        m_logger = logger;
-        initializeLogger(logger->id(), false, needLock);
-        m_messageBuilder.initialize(m_logger);
-        return *this;
-    }
-
-    Writer& construct(int count, const char* loggerIds, ...) {
-        if (ELPP->hasFlag(LoggingFlag::MultiLoggerSupport)) {
-            va_list loggersList;
-            va_start(loggersList, loggerIds);
-            const char* id = loggerIds;
-            for (int i = 0; i < count; ++i) {
-                m_loggerIds.push_back(std::string(id));
-                id = va_arg(loggersList, const char*);
-            }
-            va_end(loggersList);
-            initializeLogger(m_loggerIds.at(0));
-        } else {
-            initializeLogger(std::string(loggerIds));
-        }
-        m_messageBuilder.initialize(m_logger);
-        return *this;
-    }
-protected:
-    Level m_level;
-    const char* m_file;
-    const unsigned long int m_line;
-    const char* m_func;
-    base::type::VerboseLevel m_verboseLevel;
-    Logger* m_logger;
-    bool m_proceed;
-    base::MessageBuilder m_messageBuilder;
-    base::DispatchAction m_dispatchAction;
-    std::vector<std::string> m_loggerIds;
-    friend class el::Helpers;
-
-    void initializeLogger(const std::string& loggerId, bool lookup = true, bool needLock = true) {
-        if (lookup) {
-            m_logger = ELPP->registeredLoggers()->get(loggerId, ELPP->hasFlag(LoggingFlag::CreateLoggerAutomatically));
-        }
-        if (m_logger == nullptr) {
-            ELPP->acquireLock();
-            if (!ELPP->registeredLoggers()->has(std::string(base::consts::kDefaultLoggerId))) {
-                // Somehow default logger has been unregistered. Not good! Register again
-                ELPP->registeredLoggers()->get(std::string(base::consts::kDefaultLoggerId));
-            }
-            ELPP->releaseLock();  // Need to unlock it for next writer
-            Writer(Level::Debug, m_file, m_line, m_func).construct(1, base::consts::kDefaultLoggerId)
-                    << "Logger [" << loggerId << "] is not registered yet!";
-            m_proceed = false;
-        } else {
-            if (needLock) {
-                m_logger->acquireLock();  // This should not be unlocked by checking m_proceed because
-                                          // m_proceed can be changed by lines below
-            }
-            if (ELPP->hasFlag(LoggingFlag::HierarchicalLogging)) {
-                m_proceed = m_level == Level::Verbose ? m_logger->enabled(m_level) :
-                        LevelHelper::castToInt(m_level) >= LevelHelper::castToInt(ELPP->m_loggingLevel);
-            } else {
-                m_proceed = m_logger->enabled(m_level);
-            }
-        }
-    }
-    
-    void processDispatch() {
-#if ELPP_LOGGING_ENABLED
-        if (ELPP->hasFlag(LoggingFlag::MultiLoggerSupport)) {
-            bool firstDispatched = false;
-            base::type::string_t logMessage;
-            std::size_t i = 0;
-            do {
-                if (m_proceed) {
-                    if (firstDispatched) {
-                        m_logger->stream() << logMessage;
-                    } else {
-                        firstDispatched = true;
-                        if (m_loggerIds.size() > 1) {
-                            logMessage = m_logger->stream().str();
-                        }
-                    }
-                    triggerDispatch();
-                } else if (m_logger != nullptr) {
-                    m_logger->stream().str(ELPP_LITERAL(""));
-                    m_logger->releaseLock();
-                }
-                if (i + 1 < m_loggerIds.size()) {
-                    initializeLogger(m_loggerIds.at(i + 1));
-                }
-            } while (++i < m_loggerIds.size());
-        } else {
-            if (m_proceed) {
-                triggerDispatch();
-            } else if (m_logger != nullptr) {
-                m_logger->stream().str(ELPP_LITERAL(""));
-                m_logger->releaseLock();
-            }
-        }
-#else
-        if (m_logger != nullptr) {
-            m_logger->stream().str(ELPP_LITERAL(""));
-            m_logger->releaseLock();
-        }
-#endif // ELPP_LOGGING_ENABLED
-    }
-
-    void triggerDispatch(void) {
-        if (m_proceed) {
-            base::LogDispatcher(m_proceed, LogMessage(m_level, m_file, m_line, m_func, m_verboseLevel,
-                          m_logger), m_dispatchAction).dispatch();
-        }
-        if (m_logger != nullptr) {
-            m_logger->stream().str(ELPP_LITERAL(""));
-            m_logger->releaseLock();
-        }
-        if (m_proceed && m_level == Level::Fatal
-                && !ELPP->hasFlag(LoggingFlag::DisableApplicationAbortOnFatalLog)) {
-            base::Writer(Level::Warning, m_file, m_line, m_func).construct(1, base::consts::kDefaultLoggerId)
-                    << "Aborting application. Reason: Fatal log at [" << m_file << ":" << m_line << "]";
-            std::stringstream reasonStream;
-            reasonStream << "Fatal log at [" << m_file << ":" << m_line << "]"
-                << " If you wish to disable 'abort on fatal log' please use "
-                << "el::Helpers::addFlag(el::LoggingFlag::DisableApplicationAbortOnFatalLog)";
-            base::utils::abort(1, reasonStream.str());
-        }
-        m_proceed = false;
-    }
-};
-class PErrorWriter : public base::Writer {
-public:
-    PErrorWriter(Level level, const char* file, unsigned long int line,
-               const char* func, base::DispatchAction dispatchAction = base::DispatchAction::NormalLog,
-               base::type::VerboseLevel verboseLevel = 0) :
-        base::Writer(level, file, line, func, dispatchAction, verboseLevel) {
-    }
-
-    virtual ~PErrorWriter(void) {
-        if (m_proceed) {
-#if ELPP_COMPILER_MSVC
-            char buff[256];
-            strerror_s(buff, 256, errno);
-            m_logger->stream() << ": " << buff << " [" << errno << "]";
-#else
-            m_logger->stream() << ": " << strerror(errno) << " [" << errno << "]";
-#endif
-        }
-    }
-};
-}  // namespace base
-// Logging from Logger class. Why this is here? Because we have Storage and Writer class available
-#if ELPP_VARIADIC_TEMPLATES_SUPPORTED
-    template <typename T, typename... Args>
-    void Logger::log_(Level level, int vlevel, const char* s, const T& value, const Args&... args) {
-        base::MessageBuilder b;
-        b.initialize(this);
-        while (*s) {
-            if (*s == base::consts::kFormatSpecifierChar) {
-                if (*(s + 1) == base::consts::kFormatSpecifierChar) {
-                    ++s;
-                } else {
-                    if (*(s + 1) == base::consts::kFormatSpecifierCharValue) {
-                        ++s;
-                        b << value;
-                        log_(level, vlevel, ++s, args...);
-                        return;
-                    }
-                }
-            }
-            b << *s++;
-        }
-        ELPP_INTERNAL_ERROR("Too many arguments provided. Unable to handle. Please provide more format specifiers", false);
-    }
-    template <typename T> 
-    inline void Logger::log_(Level level, int vlevel, const T& log) {
-        if (level == Level::Verbose) {
-            if (ELPP->vRegistry()->allowed(vlevel, __FILE__)) {
-                base::Writer(Level::Verbose, "FILE", 0, "FUNCTION", 
-                    base::DispatchAction::NormalLog, vlevel).construct(this, false) << log;
-            } else {
-                stream().str(ELPP_LITERAL(""));
-            }
-        } else {
-            base::Writer(level, "FILE", 0, "FUNCTION").construct(this, false) << log;
-        }
-    }
-    template <typename T, typename... Args>
-    void Logger::log(Level level, const char* s, const T& value, const Args&... args) {
-        base::threading::ScopedLock scopedLock(lock());
-        log_(level, 0, s, value, args...);
-    }
-    template <typename T> 
-    inline void Logger::log(Level level, const T& log) { 
-        base::threading::ScopedLock scopedLock(lock());
-        log_(level, 0, log);
-    }
-#   if ELPP_VERBOSE_LOG
-    template <typename T, typename... Args>
-    inline void Logger::verbose(int vlevel, const char* s, const T& value, const Args&... args) {
-        base::threading::ScopedLock scopedLock(lock());
-        log_(el::Level::Verbose, vlevel, s, value, args...);
-    }
-    template <typename T>
-    inline void Logger::verbose(int vlevel, const T& log) {
-        base::threading::ScopedLock scopedLock(lock());
-        log_(el::Level::Verbose, vlevel, log);
-    }
-#   else
-    template <typename T, typename... Args>
-    inline void Logger::verbose(int, const char*, const T&, const Args&...) {
-        return;
-    }
-    template <typename T>
-    inline void Logger::verbose(int, const T&) {
-        return;
-    }
-#   endif  // ELPP_VERBOSE_LOG
-#   define LOGGER_LEVEL_WRITERS(FUNCTION_NAME, LOG_LEVEL)\
-    template <typename T, typename... Args>\
-    inline void Logger::FUNCTION_NAME(const char* s, const T& value, const Args&... args) {\
-        log(LOG_LEVEL, s, value, args...);\
-    }\
-    template <typename T>\
-    inline void Logger::FUNCTION_NAME(const T& value) {\
-        log(LOG_LEVEL, value);\
-    }
-#   define LOGGER_LEVEL_WRITERS_DISABLED(FUNCTION_NAME, LOG_LEVEL)\
-    template <typename T, typename... Args>\
-    inline void Logger::FUNCTION_NAME(const char*, const T&, const Args&...) {\
-        return;\
-    }\
-    template <typename T>\
-    inline void Logger::FUNCTION_NAME(const T&) {\
-        return;\
-    }
-
-#   if ELPP_INFO_LOG
-    LOGGER_LEVEL_WRITERS(info, Level::Info)
-#   else
-    LOGGER_LEVEL_WRITERS_DISABLED(info, Level::Info)
-#   endif // ELPP_INFO_LOG
-#   if ELPP_DEBUG_LOG
-    LOGGER_LEVEL_WRITERS(debug, Level::Debug)
-#   else
-    LOGGER_LEVEL_WRITERS_DISABLED(debug, Level::Debug)
-#   endif // ELPP_DEBUG_LOG
-#   if ELPP_WARNING_LOG
-    LOGGER_LEVEL_WRITERS(warn, Level::Warning)
-#   else
-    LOGGER_LEVEL_WRITERS_DISABLED(warn, Level::Warning)
-#   endif // ELPP_WARNING_LOG
-#   if ELPP_ERROR_LOG
-    LOGGER_LEVEL_WRITERS(error, Level::Error)
-#   else
-    LOGGER_LEVEL_WRITERS_DISABLED(error, Level::Error)
-#   endif // ELPP_ERROR_LOG
-#   if ELPP_FATAL_LOG
-    LOGGER_LEVEL_WRITERS(fatal, Level::Fatal)
-#   else
-    LOGGER_LEVEL_WRITERS_DISABLED(fatal, Level::Fatal)
-#   endif // ELPP_FATAL_LOG
-#   if ELPP_TRACE_LOG
-    LOGGER_LEVEL_WRITERS(trace, Level::Trace)
-#   else
-    LOGGER_LEVEL_WRITERS_DISABLED(trace, Level::Trace)
-#   endif // ELPP_TRACE_LOG
-#   undef LOGGER_LEVEL_WRITERS
-#   undef LOGGER_LEVEL_WRITERS_DISABLED
-#endif // ELPP_VARIADIC_TEMPLATES_SUPPORTED
-#if ELPP_COMPILER_MSVC
-#   define ELPP_VARIADIC_FUNC_MSVC(variadicFunction, variadicArgs) variadicFunction variadicArgs
-#   define ELPP_VARIADIC_FUNC_MSVC_RUN(variadicFunction, ...) ELPP_VARIADIC_FUNC_MSVC(variadicFunction, (__VA_ARGS__))
-#   define el_getVALength(...) ELPP_VARIADIC_FUNC_MSVC_RUN(el_resolveVALength, 0, ## __VA_ARGS__,\
-       10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
-#else
-#   if ELPP_COMPILER_CLANG
-#      define el_getVALength(...) el_resolveVALength(0, __VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
-#   else
-#      define el_getVALength(...) el_resolveVALength(0, ## __VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
-#   endif // ELPP_COMPILER_CLANG
-#endif // ELPP_COMPILER_MSVC
-#define el_resolveVALength(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N
-#define ELPP_WRITE_LOG(writer, level, dispatchAction, ...) \
-    writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__)
-#define ELPP_WRITE_LOG_IF(writer, condition, level, dispatchAction, ...) if (condition) \
-    writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__)
-#define ELPP_WRITE_LOG_EVERY_N(writer, occasion, level, dispatchAction, ...) \
-    if (ELPP->validateEveryNCounter(__FILE__, __LINE__, occasion)) \
-        writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__)
-#define ELPP_WRITE_LOG_AFTER_N(writer, n, level, dispatchAction, ...) \
-    if (ELPP->validateAfterNCounter(__FILE__, __LINE__, n)) \
-        writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__)
-#define ELPP_WRITE_LOG_N_TIMES(writer, n, level, dispatchAction, ...) \
-    if (ELPP->validateNTimesCounter(__FILE__, __LINE__, n)) \
-        writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__)
-#undef ELPP_CURR_FILE_PERFORMANCE_LOGGER
-#if defined(ELPP_PERFORMANCE_LOGGER)
-#   define ELPP_CURR_FILE_PERFORMANCE_LOGGER ELPP_PERFORMANCE_LOGGER
-#else
-#   define ELPP_CURR_FILE_PERFORMANCE_LOGGER el::base::consts::kPerformanceLoggerId
-#endif
-class PerformanceTrackingData {
-public:
-    enum class DataType : base::type::EnumType {
-        Checkpoint = 1, Complete = 2
-    };
-    // Do not use constructor, will run into multiple definition error, use init(PerformanceTracker*)
-    explicit PerformanceTrackingData(DataType dataType) : m_performanceTracker(nullptr), 
-        m_dataType(dataType), m_file(""), m_line(0), m_func("") {}
-    inline const std::string* blockName(void) const;
-    inline const struct timeval* startTime(void) const;
-    inline const struct timeval* endTime(void) const;
-    inline const struct timeval* lastCheckpointTime(void) const;
-    inline const base::PerformanceTracker* performanceTracker(void) const { return m_performanceTracker; }
-    inline PerformanceTrackingData::DataType dataType(void) const { return m_dataType; }
-    inline bool firstCheckpoint(void) const { return m_firstCheckpoint; }
-    inline std::string checkpointId(void) const { return m_checkpointId; }
-    inline const char* file(void) const { return m_file; }
-    inline unsigned long int line(void) const { return m_line; }
-    inline const char* func(void) const { return m_func; }
-    inline const base::type::string_t* formattedTimeTaken() const { return &m_formattedTimeTaken; }
-    inline const std::string& loggerId(void) const;
-private:
-    base::PerformanceTracker* m_performanceTracker;
-    base::type::string_t m_formattedTimeTaken;
-    PerformanceTrackingData::DataType m_dataType;
-    bool m_firstCheckpoint;
-    std::string m_checkpointId;
-    const char* m_file;
-    unsigned long int m_line;
-    const char* m_func;    
-    inline void init(base::PerformanceTracker* performanceTracker, bool firstCheckpoint = false) {
-        m_performanceTracker = performanceTracker;
-        m_firstCheckpoint = firstCheckpoint;
-    }
-
-    friend class el::base::PerformanceTracker;
-};
-namespace base {
-/// @brief Represents performanceTracker block of code that conditionally adds performance status to log
-///        either when goes outside the scope of when checkpoint() is called
-class PerformanceTracker : public base::threading::ThreadSafe, public Loggable {
-public:
-    PerformanceTracker(const std::string& blockName,
-            base::TimestampUnit timestampUnit = base::TimestampUnit::Millisecond,
-            const std::string& loggerId = std::string(ELPP_CURR_FILE_PERFORMANCE_LOGGER), 
-            bool scopedLog = true, Level level = base::consts::kPerformanceTrackerDefaultLevel) :
-        m_blockName(blockName), m_timestampUnit(timestampUnit), m_loggerId(loggerId), m_scopedLog(scopedLog),
-        m_level(level), m_hasChecked(false), m_lastCheckpointId(std::string()), m_enabled(false) {
-#if !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED
-        // We store it locally so that if user happen to change configuration by the end of scope
-        // or before calling checkpoint, we still depend on state of configuraton at time of construction
-        el::Logger* loggerPtr = ELPP->registeredLoggers()->get(loggerId, false);
-        m_enabled = loggerPtr != nullptr && loggerPtr->m_typedConfigurations->performanceTracking(m_level);
-        if (m_enabled) {
-            base::utils::DateTime::gettimeofday(&m_startTime);
-        }
-#endif  // !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED
-    }
-    /// @brief Copy constructor
-    PerformanceTracker(const PerformanceTracker& t) :
-        m_blockName(t.m_blockName), m_timestampUnit(t.m_timestampUnit), m_loggerId(t.m_loggerId), m_scopedLog(t.m_scopedLog),
-        m_level(t.m_level), m_hasChecked(t.m_hasChecked), m_lastCheckpointId(t.m_lastCheckpointId), m_enabled(t.m_enabled),
-        m_startTime(t.m_startTime), m_endTime(t.m_endTime), m_lastCheckpointTime(t.m_lastCheckpointTime) {
-    }
-    virtual ~PerformanceTracker(void) {
-#if !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED
-        if (m_enabled) {
-            base::threading::ScopedLock scopedLock(lock());
-            if (m_scopedLog) {
-                base::utils::DateTime::gettimeofday(&m_endTime);
-                base::type::string_t formattedTime = getFormattedTimeTaken();
-                PerformanceTrackingData data(PerformanceTrackingData::DataType::Complete);
-                data.init(this);
-                data.m_formattedTimeTaken = formattedTime;
-                PerformanceTrackingCallback* callback = nullptr;
-                for (const std::pair<std::string, base::type::PerformanceTrackingCallbackPtr>& h
-                        : ELPP->m_performanceTrackingCallbacks) {
-                    callback = h.second.get();
-                    if (callback != nullptr && callback->enabled()) {
-                        callback->acquireLock();
-                        callback->handle(&data);
-                        callback->releaseLock();
-                    }
-                }
-            }
-        }
-#endif  // !defined(ELPP_DISABLE_PERFORMANCE_TRACKING)
-    }
-    /// @brief A checkpoint for current performanceTracker block.
-    void checkpoint(const std::string& id = std::string(), const char* file = __FILE__, unsigned long int line = __LINE__, const char* func = "") {
-#if !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED
-        if (m_enabled) {
-            base::threading::ScopedLock scopedLock(lock());
-            base::utils::DateTime::gettimeofday(&m_endTime);            
-            base::type::string_t formattedTime = m_hasChecked ? getFormattedTimeTaken(m_lastCheckpointTime) : ELPP_LITERAL("");
-            PerformanceTrackingData data(PerformanceTrackingData::DataType::Checkpoint);
-            data.init(this);
-            data.m_checkpointId = id;
-            data.m_file = file;
-            data.m_line = line;
-            data.m_func = func;
-            data.m_formattedTimeTaken = formattedTime;
-            PerformanceTrackingCallback* callback = nullptr;
-            for (const std::pair<std::string, base::type::PerformanceTrackingCallbackPtr>& h
-                    : ELPP->m_performanceTrackingCallbacks) {
-                callback = h.second.get();
-                if (callback != nullptr && callback->enabled()) {
-                    callback->acquireLock();
-                    callback->handle(&data);
-                    callback->releaseLock();
-                }
-            }
-            base::utils::DateTime::gettimeofday(&m_lastCheckpointTime);
-            m_hasChecked = true;
-            m_lastCheckpointId = id;
-        }
-#endif  // !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED
-        ELPP_UNUSED(id);
-        ELPP_UNUSED(file);
-        ELPP_UNUSED(line);
-        ELPP_UNUSED(func);
-    }
-    inline Level level(void) const { return m_level; }
-private:
-    std::string m_blockName;
-    base::TimestampUnit m_timestampUnit;
-    std::string m_loggerId;
-    bool m_scopedLog;
-    Level m_level;
-    bool m_hasChecked;
-    std::string m_lastCheckpointId;
-    bool m_enabled;
-    struct timeval m_startTime, m_endTime, m_lastCheckpointTime;
-
-    PerformanceTracker(void);
-
-    friend class el::PerformanceTrackingData;
-    friend class base::DefaultPerformanceTrackingCallback;
-
-    const inline base::type::string_t getFormattedTimeTaken() const {
-        return getFormattedTimeTaken(m_startTime);
-    }
-    
-    const base::type::string_t getFormattedTimeTaken(struct timeval startTime) const {
-        if (ELPP->hasFlag(LoggingFlag::FixedTimeFormat)) {
-            base::type::stringstream_t ss;
-            ss << base::utils::DateTime::getTimeDifference(m_endTime,
-                startTime, m_timestampUnit) << " " << base::consts::kTimeFormats[static_cast<base::type::EnumType>(m_timestampUnit)].unit;
-            return ss.str();
-        }
-        return base::utils::DateTime::formatTime(base::utils::DateTime::getTimeDifference(m_endTime,
-                startTime, m_timestampUnit), m_timestampUnit);
-    }
-
-    virtual inline void log(el::base::type::ostream_t& os) const {
-        os << getFormattedTimeTaken();
-    }
-};
-class DefaultPerformanceTrackingCallback : public PerformanceTrackingCallback {
-protected:
-    void handle(const PerformanceTrackingData* data) {
-        m_data = data;
-        base::type::stringstream_t ss;
-        if (m_data->dataType() == PerformanceTrackingData::DataType::Complete) {
-            ss << ELPP_LITERAL("Executed [") << m_data->blockName()->c_str() << ELPP_LITERAL("] in [") << *m_data->formattedTimeTaken() << ELPP_LITERAL("]");
-        } else {
-            ss << ELPP_LITERAL("Performance checkpoint");
-            if (!m_data->checkpointId().empty()) {
-                ss << ELPP_LITERAL(" [") << m_data->checkpointId().c_str() << ELPP_LITERAL("]");
-            }
-            ss << ELPP_LITERAL(" for block [") << m_data->blockName()->c_str() << ELPP_LITERAL("] : [") << *m_data->performanceTracker();
-            if (!ELPP->hasFlag(LoggingFlag::DisablePerformanceTrackingCheckpointComparison) && m_data->performanceTracker()->m_hasChecked) {
-                ss << ELPP_LITERAL(" ([") << *m_data->formattedTimeTaken() << ELPP_LITERAL("] from ");
-                if (m_data->performanceTracker()->m_lastCheckpointId.empty()) {
-                    ss << ELPP_LITERAL("last checkpoint");
-                } else {
-                    ss << ELPP_LITERAL("checkpoint '") << m_data->performanceTracker()->m_lastCheckpointId.c_str() << ELPP_LITERAL("'");
-                }
-                ss << ELPP_LITERAL(")]");
-            } else {
-                ss << ELPP_LITERAL("]");
-            }
-        }
-        el::base::Writer(m_data->performanceTracker()->level(), m_data->file(), m_data->line(), m_data->func()).construct(1, m_data->loggerId().c_str()) << ss.str();
-    }
-private:
-    const PerformanceTrackingData* m_data;
-};
-}  // namespace base
-inline const std::string* PerformanceTrackingData::blockName() const {
-    return const_cast<const std::string*>(&m_performanceTracker->m_blockName);
-}
-inline const struct timeval* PerformanceTrackingData::startTime() const {
-    return const_cast<const struct timeval*>(&m_performanceTracker->m_startTime);
-}
-inline const struct timeval* PerformanceTrackingData::endTime() const {
-    return const_cast<const struct timeval*>(&m_performanceTracker->m_endTime);
-}
-inline const struct timeval* PerformanceTrackingData::lastCheckpointTime() const {
-    return const_cast<const struct timeval*>(&m_performanceTracker->m_lastCheckpointTime);
-}
-inline const std::string& PerformanceTrackingData::loggerId(void) const { return m_performanceTracker->m_loggerId; }
-namespace base {
-/// @brief Contains some internal debugging tools like crash handler and stack tracer
-namespace debug {
-class StackTrace : base::NoCopy {
-public:
-    static const std::size_t kMaxStack = 64;
-    static const std::size_t kStackStart = 2;  // We want to skip c'tor and StackTrace::generateNew()
-    class StackTraceEntry {
-    public:
-        StackTraceEntry(std::size_t index, const char* loc, const char* demang, const char* hex, const char* addr) {
-            m_index = index;
-            m_location = std::string(loc);
-            m_demangled = std::string(demang);
-            m_hex = std::string(hex);
-            m_addr = std::string(addr);
-        }
-        StackTraceEntry(std::size_t index, char* loc) {
-            m_index = index;
-            m_location = std::string(loc);
-        }
-        std::size_t m_index;
-        std::string m_location;
-        std::string m_demangled;
-        std::string m_hex;
-        std::string m_addr;
-        friend std::ostream& operator<<(std::ostream& ss, const StackTraceEntry& si) {
-           ss << "[" << si.m_index << "] " << si.m_location << (si.m_demangled.empty() ? "" : ":") << si.m_demangled
-                   << (si.m_hex.empty() ? "" : "+") << si.m_hex << si.m_addr;
-           return ss;
-        }
-
-    private:
-        StackTraceEntry(void);
-    };
-
-    StackTrace(void) {
-        generateNew();
-    }
-
-    virtual ~StackTrace(void) {
-    }
-
-    inline std::vector<StackTraceEntry>& getLatestStack(void) {
-        return m_stack;
-    }
-
-    friend inline std::ostream& operator<<(std::ostream& os, const StackTrace& st) {
-       std::vector<StackTraceEntry>::const_iterator it = st.m_stack.begin();
-       while (it != st.m_stack.end()) {
-           os << "    " << *it++ << "\n";
-       }
-       return os;
-    }
-
-private:
-    std::vector<StackTraceEntry> m_stack;
-
-    void generateNew(void) {
-#if ELPP_STACKTRACE
-        m_stack.clear();
-        void* stack[kMaxStack];
-        std::size_t size = backtrace(stack, kMaxStack);
-        char** strings = backtrace_symbols(stack, size);
-        if (size > kStackStart) {  // Skip StackTrace c'tor and generateNew
-            for (std::size_t i = kStackStart; i < size; ++i) {
-                char* mangName = nullptr;
-                char* hex = nullptr;
-                char* addr = nullptr;
-                for (char* c = strings[i]; *c; ++c) {
-                    switch (*c) {
-                    case '(':
-                        mangName = c;
-                        break;
-                    case '+':
-                        hex = c;
-                        break;
-                    case ')':
-                        addr = c;
-                        break;
-                    }
-                }
-                // Perform demangling if parsed properly
-                if (mangName != nullptr && hex != nullptr && addr != nullptr && mangName < hex) {
-                    *mangName++ = '\0';
-                    *hex++ = '\0';
-                    *addr++ = '\0';
-                    int status = 0;
-                    char* demangName = abi::__cxa_demangle(mangName, 0, 0, &status);
-                    // if demangling is successful, output the demangled function name
-                    if (status == 0) {
-                        // Success (see http://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-html-USERS-4.3/a01696.html)
-                        StackTraceEntry entry(i - 1, strings[i], demangName, hex, addr);
-                        m_stack.push_back(entry);
-                    } else {
-                        // Not successful - we will use mangled name
-                        StackTraceEntry entry(i - 1, strings[i], mangName, hex, addr);
-                        m_stack.push_back(entry);
-                    }
-                    free(demangName);
-                } else {
-                    StackTraceEntry entry(i - 1, strings[i]);
-                    m_stack.push_back(entry);
-                }
-            }
-        }
-        free(strings);
-#else
-        ELPP_INTERNAL_INFO(1, "Stacktrace generation not supported for selected compiler");
-#endif  // ELPP_STACKTRACE
-    }
-};
-static std::string crashReason(int sig) {
-    std::stringstream ss;
-    bool foundReason = false;
-    for (int i = 0; i < base::consts::kCrashSignalsCount; ++i) {
-        if (base::consts::kCrashSignals[i].numb == sig) {
-            ss << "Application has crashed due to [" << base::consts::kCrashSignals[i].name << "] signal";
-            if (ELPP->hasFlag(el::LoggingFlag::LogDetailedCrashReason)) {
-                ss << std::endl <<
-                      "    " << base::consts::kCrashSignals[i].brief << std::endl <<
-                      "    " << base::consts::kCrashSignals[i].detail;
-                }
-            foundReason = true;
-        }
-    }
-    if (!foundReason) {
-        ss << "Application has crashed due to unknown signal [" << sig << "]";
-    }
-    return ss.str();
-}
-/// @brief Logs reason of crash from sig
-static void logCrashReason(int sig, bool stackTraceIfAvailable, Level level, const char* logger) {
-    std::stringstream ss;
-    ss << "CRASH HANDLED; ";
-    ss << crashReason(sig);
-#if ELPP_STACKTRACE
-    if (stackTraceIfAvailable) {
-        ss << std::endl << "    ======= Backtrace: =========" << std::endl << base::debug::StackTrace();
-    }
-#else
-    ELPP_UNUSED(stackTraceIfAvailable);
-#endif  // ELPP_STACKTRACE
-    ELPP_WRITE_LOG(el::base::Writer, level, base::DispatchAction::NormalLog, logger) << ss.str();
-}
-static inline void crashAbort(int sig) {
-    base::utils::abort(sig);
-}
-/// @brief Default application crash handler
-///
-/// @detail This function writes log using 'default' logger, prints stack trace for GCC based compilers and aborts program.
-static inline void defaultCrashHandler(int sig) {
-    base::debug::logCrashReason(sig, true, Level::Fatal, base::consts::kDefaultLoggerId);
-    base::debug::crashAbort(sig);
-}
-/// @brief Handles unexpected crashes
-class CrashHandler : base::NoCopy {
-public:
-    typedef void (*Handler)(int);
-
-    explicit CrashHandler(bool useDefault) {
-        if (useDefault) {
-            setHandler(defaultCrashHandler);
-        }
-    }
-    explicit CrashHandler(const Handler& cHandler) {
-        setHandler(cHandler);
-    }
-    void setHandler(const Handler& cHandler) {
-        m_handler = cHandler;
-#if defined(ELPP_HANDLE_SIGABRT)
-            int i = 0;  // SIGABRT is at base::consts::kCrashSignals[0]
-#else
-            int i = 1;
-#endif  // defined(ELPP_HANDLE_SIGABRT)
-        for (; i < base::consts::kCrashSignalsCount; ++i) {
-            m_handler = signal(base::consts::kCrashSignals[i].numb, cHandler);
-        }
-    }
-
-private:
-    Handler m_handler;
-};
-}  // namespace debug
-}  // namespace base
-extern base::debug::CrashHandler elCrashHandler;
-#define MAKE_LOGGABLE(ClassType, ClassInstance, OutputStreamInstance) \
-    el::base::type::ostream_t& operator<<(el::base::type::ostream_t& OutputStreamInstance, const ClassType& ClassInstance)
-/// @brief Initializes syslog with process ID, options and facility. calls closelog() on d'tor
-class SysLogInitializer {
-public:
-    SysLogInitializer(const char* processIdent, int options = 0, int facility = 0) {
-#if defined(ELPP_SYSLOG)
-        openlog(processIdent, options, facility);
-#else
-        ELPP_UNUSED(processIdent);
-        ELPP_UNUSED(options);
-        ELPP_UNUSED(facility);
-#endif  // defined(ELPP_SYSLOG)
-    }
-    virtual ~SysLogInitializer(void) {
-#if defined(ELPP_SYSLOG)
-        closelog();
-#endif  // defined(ELPP_SYSLOG)
-    }
-};
-#define ELPP_INITIALIZE_SYSLOG(id, opt, fac) el::SysLogInitializer elSyslogInit(id, opt, fac)
-/// @brief Static helpers for developers
-class Helpers : base::StaticClass {
-public:
-    /// @brief Shares logging repository (base::Storage)
-    static inline void setStorage(base::type::StoragePointer storage) {
-        ELPP = storage;
-    }
-    /// @return Main storage repository
-    static inline base::type::StoragePointer storage() {
-        return ELPP;
-    }
-    /// @brief Sets application arguments and figures out whats active for logging and whats not.
-    static inline void setArgs(int argc, char** argv) {
-        ELPP->setApplicationArguments(argc, argv);
-    }
-    /// @copydoc setArgs(int argc, char** argv)
-    static inline void setArgs(int argc, const char** argv) {
-        ELPP->setApplicationArguments(argc, const_cast<char**>(argv));
-    }
-    /// @brief Overrides default crash handler and installs custom handler.
-    /// @param crashHandler A functor with no return type that takes single int argument.
-    ///        Handler is a typedef with specification: void (*Handler)(int)
-    static inline void setCrashHandler(const el::base::debug::CrashHandler::Handler& crashHandler) {
-        el::elCrashHandler.setHandler(crashHandler);
-    }
-    /// @brief Abort due to crash with signal in parameter
-    /// @param sig Crash signal
-    static inline void crashAbort(int sig, const char* sourceFile = "", unsigned int long line = 0) {
-        std::stringstream ss;
-        ss << base::debug::crashReason(sig).c_str();
-        ss << " - [Called el::Helpers::crashAbort(" << sig << ")]";
-        if (sourceFile != nullptr && strlen(sourceFile) > 0) {
-            ss << " - Source: " << sourceFile;
-            if (line > 0)
-                ss << ":" << line;
-            else
-                ss << " (line number not specified)";
-        }
-        base::utils::abort(sig, ss.str());
-    }
-    /// @brief Logs reason of crash as per sig
-    /// @param sig Crash signal
-    /// @param stackTraceIfAvailable Includes stack trace if available
-    /// @param level Logging level
-    /// @param logger Logger to use for logging
-    static inline void logCrashReason(int sig, bool stackTraceIfAvailable = false,
-            Level level = Level::Fatal, const char* logger = base::consts::kDefaultLoggerId) {
-        el::base::debug::logCrashReason(sig, stackTraceIfAvailable, level, logger);
-    }
-    /// @brief Installs pre rollout callback, this callback is triggered when log file is about to be rolled out
-    ///        (can be useful for backing up)
-    static inline void installPreRollOutCallback(const PreRollOutCallback& callback) {
-        ELPP->setPreRollOutCallback(callback);
-    }
-    /// @brief Uninstalls pre rollout callback
-    static inline void uninstallPreRollOutCallback(void) {
-        ELPP->unsetPreRollOutCallback();
-    }
-    /// @brief Installs post log dispatch callback, this callback is triggered when log is dispatched
-    template <typename T>
-    static inline bool installLogDispatchCallback(const std::string& id) {
-        return ELPP->installLogDispatchCallback<T>(id);
-    }
-    /// @brief Uninstalls log dispatch callback
-    template <typename T>
-    static inline void uninstallLogDispatchCallback(const std::string& id) {
-        ELPP->uninstallLogDispatchCallback<T>(id);
-    }
-    template <typename T>
-    static inline T* logDispatchCallback(const std::string& id) {
-        return ELPP->logDispatchCallback<T>(id);
-    }
-    /// @brief Installs post performance tracking callback, this callback is triggered when performance tracking is finished
-    template <typename T>
-    static inline bool installPerformanceTrackingCallback(const std::string& id) {
-        return ELPP->installPerformanceTrackingCallback<T>(id);
-    }
-    /// @brief Uninstalls post performance tracking handler
-    template <typename T>
-    static inline void uninstallPerformanceTrackingCallback(const std::string& id) {
-        ELPP->uninstallPerformanceTrackingCallback<T>(id);
-    }
-    template <typename T>
-    static inline T* performanceTrackingCallback(const std::string& id) {
-        return ELPP->performanceTrackingCallback<T>(id);
-    }
-    /// @brief Converts template to std::string - useful for loggable classes to log containers within log(std::ostream&) const
-    template <typename T>
-    static std::string convertTemplateToStdString(const T& templ) {
-        el::Logger* logger = 
-            ELPP->registeredLoggers()->get(el::base::consts::kDefaultLoggerId);
-        if (logger == nullptr) {
-            return std::string();
-        }
-        base::MessageBuilder b;
-        b.initialize(logger);
-        logger->acquireLock();
-        b << templ;
-#if defined(ELPP_UNICODE)
-        std::string s = std::string(logger->stream().str().begin(), logger->stream().str().end());
-#else
-        std::string s = logger->stream().str();
-#endif  // defined(ELPP_UNICODE)
-        logger->stream().str(ELPP_LITERAL(""));
-        logger->releaseLock();
-        return s;
-    }
-    /// @brief Returns command line arguments (pointer) provided to easylogging++
-    static inline const el::base::utils::CommandLineArgs* commandLineArgs(void) {
-        return ELPP->commandLineArgs();
-    }
-    /// @brief Installs user defined format specifier and handler
-    static inline void installCustomFormatSpecifier(const CustomFormatSpecifier& customFormatSpecifier) {
-        ELPP->installCustomFormatSpecifier(customFormatSpecifier);
-    }
-    /// @brief Uninstalls user defined format specifier and handler
-    static inline bool uninstallCustomFormatSpecifier(const char* formatSpecifier) {
-        return ELPP->uninstallCustomFormatSpecifier(formatSpecifier);
-    }
-    /// @brief Returns true if custom format specifier is installed
-    static inline bool hasCustomFormatSpecifier(const char* formatSpecifier) {
-        return ELPP->hasCustomFormatSpecifier(formatSpecifier);
-    }
-    static inline void validateFileRolling(Logger* logger, Level level) {
-        if (logger == nullptr) return;
-        logger->m_typedConfigurations->validateFileRolling(level, ELPP->preRollOutCallback());
-    }
-};
-/// @brief Static helpers to deal with loggers and their configurations
-class Loggers : base::StaticClass {
-public:
-    /// @brief Gets existing or registers new logger
-    static inline Logger* getLogger(const std::string& identity, bool registerIfNotAvailable = true) {
-        base::threading::ScopedLock scopedLock(ELPP->lock());
-        return ELPP->registeredLoggers()->get(identity, registerIfNotAvailable);
-    }
-    /// @brief Unregisters logger - use it only when you know what you are doing, you may unregister
-    ///        loggers initialized / used by third-party libs.
-    static inline bool unregisterLogger(const std::string& identity) {
-        base::threading::ScopedLock scopedLock(ELPP->lock());
-        return ELPP->registeredLoggers()->remove(identity);
-    }
-    /// @brief Whether or not logger with id is registered
-    static inline bool hasLogger(const std::string& identity) {
-        base::threading::ScopedLock scopedLock(ELPP->lock());
-        return ELPP->registeredLoggers()->has(identity);
-    }
-    /// @brief Reconfigures specified logger with new configurations
-    static inline Logger* reconfigureLogger(Logger* logger, const Configurations& configurations) {
-        if (!logger) return nullptr;
-        logger->configure(configurations);
-        return logger;
-    }
-    /// @brief Reconfigures logger with new configurations after looking it up using identity
-    static inline Logger* reconfigureLogger(const std::string& identity, const Configurations& configurations) {
-        return Loggers::reconfigureLogger(Loggers::getLogger(identity), configurations);
-    }
-    /// @brief Reconfigures logger's single configuration
-    static inline Logger* reconfigureLogger(const std::string& identity, ConfigurationType configurationType,
-            const std::string& value) {
-        Logger* logger = Loggers::getLogger(identity);
-        if (logger == nullptr) {
-            return nullptr;
-        }
-        logger->configurations()->set(Level::Global, configurationType, value);
-        logger->reconfigure();
-        return logger;
-    }
-    /// @brief Reconfigures all the existing loggers with new configurations
-    static inline void reconfigureAllLoggers(const Configurations& configurations) {
-        for (base::RegisteredLoggers::iterator it = ELPP->registeredLoggers()->begin();
-                it != ELPP->registeredLoggers()->end(); ++it) {
-            Loggers::reconfigureLogger(it->second, configurations);
-        }
-    }
-    /// @brief Reconfigures single configuration for all the loggers
-    static inline void reconfigureAllLoggers(ConfigurationType configurationType, const std::string& value) {
-        reconfigureAllLoggers(Level::Global, configurationType, value);
-    }
-    /// @brief Reconfigures single configuration for all the loggers for specified level
-    static inline void reconfigureAllLoggers(Level level, ConfigurationType configurationType, 
-            const std::string& value) {
-        for (base::RegisteredLoggers::iterator it = ELPP->registeredLoggers()->begin();
-                it != ELPP->registeredLoggers()->end(); ++it) {
-            Logger* logger = it->second;
-            logger->configurations()->set(level, configurationType, value);
-            logger->reconfigure();
-        }
-    }
-    /// @brief Sets default configurations. This configuration is used for future (and conditionally for existing) loggers
-    static inline void setDefaultConfigurations(const Configurations& configurations, bool reconfigureExistingLoggers = false) {
-        ELPP->registeredLoggers()->setDefaultConfigurations(configurations);
-        if (reconfigureExistingLoggers) {
-            Loggers::reconfigureAllLoggers(configurations);
-        }
-    }
-    /// @brief Returns current default
-    static inline const Configurations* defaultConfigurations(void) {
-        return ELPP->registeredLoggers()->defaultConfigurations();
-    }
-    /// @brief Returns log stream reference pointer if needed by user
-    static inline const base::LogStreamsReferenceMap* logStreamsReference(void) {
-        return ELPP->registeredLoggers()->logStreamsReference();
-    }
-    /// @brief Default typed configuration based on existing defaultConf
-    static base::TypedConfigurations defaultTypedConfigurations(void) {
-        return base::TypedConfigurations(
-            ELPP->registeredLoggers()->defaultConfigurations(),
-            ELPP->registeredLoggers()->logStreamsReference());
-    }
-    /// @brief Populates all logger IDs in current repository.
-    /// @param [out] targetList List of fill up.
-    static inline std::vector<std::string>* populateAllLoggerIds(std::vector<std::string>* targetList) {
-        targetList->clear();
-        for (base::RegisteredLoggers::iterator it = ELPP->registeredLoggers()->list().begin();
-                it != ELPP->registeredLoggers()->list().end(); ++it) {
-            targetList->push_back(it->first);
-        }
-        return targetList;
-    }
-    /// @brief Sets configurations from global configuration file.
-    static void configureFromGlobal(const char* globalConfigurationFilePath) {
-        std::ifstream gcfStream(globalConfigurationFilePath, std::ifstream::in);
-        ELPP_ASSERT(gcfStream.is_open(), "Unable to open global configuration file [" << globalConfigurationFilePath 
-            << "] for parsing.");
-        std::string line = std::string();
-        std::stringstream ss;
-        Logger* logger = nullptr;
-        auto configure = [&](void) {
-            ELPP_INTERNAL_INFO(8, "Configuring logger: '" << logger->id() << "' with configurations \n" << ss.str() 
-                << "\n--------------");
-            Configurations c;
-            c.parseFromText(ss.str());
-            logger->configure(c);
-        };
-        while (gcfStream.good()) {
-           std::getline(gcfStream, line);
-           ELPP_INTERNAL_INFO(1, "Parsing line: " << line);
-           base::utils::Str::trim(line);
-           if (Configurations::Parser::isComment(line)) continue;
-           Configurations::Parser::ignoreComments(&line);
-           base::utils::Str::trim(line);
-           if (line.size() > 2 && base::utils::Str::startsWith(line, std::string(base::consts::kConfigurationLoggerId))) {
-               if (!ss.str().empty() && logger != nullptr) {
-                   configure();
-               }
-               ss.str(std::string(""));
-               line = line.substr(2);
-               base::utils::Str::trim(line);
-               if (line.size() > 1) {
-                   ELPP_INTERNAL_INFO(1, "Getting logger: '" << line << "'");
-                   logger = getLogger(line);
-               }
-            } else {
-               ss << line << "\n";
-            }
-        }
-        if (!ss.str().empty() && logger != nullptr) {
-            configure();
-        }
-    }
-    /// @brief Configures loggers using command line arg. Ensure you have already set command line args, 
-    /// @return False if invalid argument or argument with no value provided, true if attempted to configure logger.
-    ///         If true is returned that does not mean it has been configured successfully, it only means that it
-    ///         has attempeted to configure logger using configuration file provided in argument
-    static inline bool configureFromArg(const char* argKey) {
-#if defined(ELPP_DISABLE_CONFIGURATION_FROM_PROGRAM_ARGS)
-        ELPP_UNUSED(argKey);
-#else
-        if (!Helpers::commandLineArgs()->hasParamWithValue(argKey)) {
-            return false;
-        }
-        configureFromGlobal(Helpers::commandLineArgs()->getParamValue(argKey));
-#endif  // defined(ELPP_DISABLE_CONFIGURATION_FROM_PROGRAM_ARGS)
-        return true;
-    }
-    /// @brief Flushes all loggers for all levels - Be careful if you dont know how many loggers are registered
-    static inline void flushAll(void) {
-        ELPP->registeredLoggers()->flushAll();
-    }
-    /// @brief Adds logging flag used internally.
-    static inline void addFlag(LoggingFlag flag) {
-        ELPP->addFlag(flag);
-    }
-    /// @brief Removes logging flag used internally.
-    static inline void removeFlag(LoggingFlag flag) {
-        ELPP->removeFlag(flag);
-    }
-    /// @brief Determines whether or not certain flag is active
-    static inline bool hasFlag(LoggingFlag flag) {
-        return ELPP->hasFlag(flag);
-    }
-    /// @brief Adds flag and removes it when scope goes out
-    class ScopedAddFlag {
-    public:
-        ScopedAddFlag(LoggingFlag flag) : m_flag(flag) { Loggers::addFlag(m_flag); }
-        ~ScopedAddFlag(void) { Loggers::removeFlag(m_flag); }
-    private:
-        LoggingFlag m_flag;
-    };
-    /// @brief Removes flag and add it when scope goes out
-    class ScopedRemoveFlag {
-    public:
-        ScopedRemoveFlag(LoggingFlag flag) : m_flag(flag) { Loggers::removeFlag(m_flag); }
-        ~ScopedRemoveFlag(void) { Loggers::addFlag(m_flag); }
-    private:
-        LoggingFlag m_flag;
-    };
-    /// @brief Sets hierarchy for logging. Needs to enable logging flag (HierarchicalLogging)
-    static inline void setLoggingLevel(Level level) {
-        ELPP->setLoggingLevel(level);
-    }
-    /// @brief Sets verbose level on the fly
-    static inline void setVerboseLevel(base::type::VerboseLevel level) {
-        ELPP->vRegistry()->setLevel(level);
-    }
-    /// @brief Gets current verbose level
-    static inline base::type::VerboseLevel verboseLevel(void) {
-        return ELPP->vRegistry()->level();
-    }
-	/// @brief Sets vmodules as specified (on the fly)
-    static inline void setVModules(const char* modules) {
-        if (ELPP->vRegistry()->vModulesEnabled()) {
-            ELPP->vRegistry()->setModules(modules);
-        }
-    }
-	/// @brief Clears vmodules
-    static inline void clearVModules(void) {
-        ELPP->vRegistry()->clearModules();
-    }
-};
-class VersionInfo : base::StaticClass {
-public:
-    /// @brief Current version number
-    static inline const std::string version(void) { return std::string("9.80"); }
-    /// @brief Release date of current version
-    static inline const std::string releaseDate(void) { return std::string("08-01-2015 0850hrs"); }
-};
-}  // namespace el
-#undef VLOG_IS_ON
-/// @brief Determines whether verbose logging is on for specified level current file.
-#define VLOG_IS_ON(verboseLevel) (ELPP->vRegistry()->allowed(verboseLevel, __FILE__))
-#undef TIMED_BLOCK
-#undef TIMED_SCOPE
-#undef TIMED_FUNC
-#undef ELPP_MIN_UNIT
-#if defined(ELPP_PERFORMANCE_MICROSECONDS)
-#   define ELPP_MIN_UNIT el::base::TimestampUnit::Microsecond
-#else
-#   define ELPP_MIN_UNIT el::base::TimestampUnit::Millisecond
-#endif  // (defined(ELPP_PERFORMANCE_MICROSECONDS))
-/// @brief Performance tracked scope. Performance gets written when goes out of scope using
-///        'performance' logger.
-///
-/// @detail Please note in order to check the performance at a certain time you can use obj.checkpoint();
-/// @see el::base::PerformanceTracker
-/// @see el::base::PerformanceTracker::checkpoint
-// Note: Do not surround this definition with null macro because of obj instance
-#define TIMED_SCOPE(obj, blockname) el::base::PerformanceTracker obj(blockname, ELPP_MIN_UNIT)
-#define TIMED_BLOCK(obj, blockName) for (struct { int i; el::base::PerformanceTracker timer; } obj = { 0, \
-    el::base::PerformanceTracker(blockName, ELPP_MIN_UNIT) }; obj.i < 1; ++obj.i)
-/// @brief Performance tracked function. Performance gets written when goes out of scope using
-///        'performance' logger.
-///
-/// @detail Please note in order to check the performance at a certain time you can use obj.checkpoint();
-/// @see el::base::PerformanceTracker
-/// @see el::base::PerformanceTracker::checkpoint
-#define TIMED_FUNC(obj) TIMED_SCOPE(obj, ELPP_FUNC)
-#undef PERFORMANCE_CHECKPOINT
-#undef PERFORMANCE_CHECKPOINT_WITH_ID
-#define PERFORMANCE_CHECKPOINT(obj) obj.checkpoint(std::string(), __FILE__, __LINE__, ELPP_FUNC)
-#define PERFORMANCE_CHECKPOINT_WITH_ID(obj, id) obj.checkpoint(id, __FILE__, __LINE__, ELPP_FUNC)
-#undef ELPP_COUNTER
-#undef ELPP_COUNTER_POS
-/// @brief Gets hit counter for file/line
-#define ELPP_COUNTER (ELPP->hitCounters()->getCounter(__FILE__, __LINE__))
-/// @brief Gets hit counter position for file/line, -1 if not registered yet
-#define ELPP_COUNTER_POS (ELPP_COUNTER == nullptr ? -1 : ELPP_COUNTER->hitCounts())
-// Undef levels to support LOG(LEVEL)
-#undef INFO
-#undef WARNING
-#undef DEBUG
-#undef ERROR
-#undef FATAL
-#undef TRACE
-#undef VERBOSE
-// Undef existing
-#undef CINFO
-#undef CWARNING
-#undef CDEBUG
-#undef CFATAL
-#undef CERROR
-#undef CTRACE
-#undef CVERBOSE
-#undef CINFO_IF
-#undef CWARNING_IF
-#undef CDEBUG_IF
-#undef CERROR_IF
-#undef CFATAL_IF
-#undef CTRACE_IF
-#undef CVERBOSE_IF
-#undef CINFO_EVERY_N
-#undef CWARNING_EVERY_N
-#undef CDEBUG_EVERY_N
-#undef CERROR_EVERY_N
-#undef CFATAL_EVERY_N
-#undef CTRACE_EVERY_N
-#undef CVERBOSE_EVERY_N
-#undef CINFO_AFTER_N
-#undef CWARNING_AFTER_N
-#undef CDEBUG_AFTER_N
-#undef CERROR_AFTER_N
-#undef CFATAL_AFTER_N
-#undef CTRACE_AFTER_N
-#undef CVERBOSE_AFTER_N
-#undef CINFO_N_TIMES
-#undef CWARNING_N_TIMES
-#undef CDEBUG_N_TIMES
-#undef CERROR_N_TIMES
-#undef CFATAL_N_TIMES
-#undef CTRACE_N_TIMES
-#undef CVERBOSE_N_TIMES
-// Normal logs
-#if ELPP_INFO_LOG
-#   define CINFO(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Info, dispatchAction, __VA_ARGS__)
-#else
-#   define CINFO(writer, dispatchAction, ...) el::base::NullWriter()
-#endif  // ELPP_INFO_LOG
-#if ELPP_WARNING_LOG
-#   define CWARNING(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Warning, dispatchAction, __VA_ARGS__)
-#else
-#   define CWARNING(writer, dispatchAction, ...) el::base::NullWriter()
-#endif  // ELPP_WARNING_LOG
-#if ELPP_DEBUG_LOG
-#   define CDEBUG(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Debug, dispatchAction, __VA_ARGS__)
-#else
-#   define CDEBUG(writer, dispatchAction, ...) el::base::NullWriter()
-#endif  // ELPP_DEBUG_LOG
-#if ELPP_ERROR_LOG
-#   define CERROR(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Error, dispatchAction, __VA_ARGS__)
-#else
-#   define CERROR(writer, dispatchAction, ...) el::base::NullWriter()
-#endif  // ELPP_ERROR_LOG
-#if ELPP_FATAL_LOG
-#   define CFATAL(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Fatal, dispatchAction, __VA_ARGS__)
-#else
-#   define CFATAL(writer, dispatchAction, ...) el::base::NullWriter()
-#endif  // ELPP_FATAL_LOG
-#if ELPP_TRACE_LOG
-#   define CTRACE(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Trace, dispatchAction, __VA_ARGS__)
-#else
-#   define CTRACE(writer, dispatchAction, ...) el::base::NullWriter()
-#endif  // ELPP_TRACE_LOG
-#if ELPP_VERBOSE_LOG
-#   define CVERBOSE(writer, vlevel, dispatchAction, ...) if (VLOG_IS_ON(vlevel)) writer(\
-       el::Level::Verbose, __FILE__, __LINE__, ELPP_FUNC, dispatchAction, vlevel).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__)
-#else
-#   define CVERBOSE(writer, vlevel, dispatchAction, ...) el::base::NullWriter()
-#endif  // ELPP_VERBOSE_LOG
-// Conditional logs
-#if ELPP_INFO_LOG
-#   define CINFO_IF(writer, condition_, dispatchAction, ...) \
-        ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Info, dispatchAction, __VA_ARGS__)
-#else
-#   define CINFO_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter()
-#endif  // ELPP_INFO_LOG
-#if ELPP_WARNING_LOG
-#   define CWARNING_IF(writer, condition_, dispatchAction, ...)\
-        ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Warning, dispatchAction, __VA_ARGS__)
-#else
-#   define CWARNING_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter()
-#endif  // ELPP_WARNING_LOG
-#if ELPP_DEBUG_LOG
-#   define CDEBUG_IF(writer, condition_, dispatchAction, ...)\
-        ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Debug, dispatchAction, __VA_ARGS__)
-#else
-#   define CDEBUG_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter()
-#endif  // ELPP_DEBUG_LOG
-#if ELPP_ERROR_LOG
-#   define CERROR_IF(writer, condition_, dispatchAction, ...)\
-        ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Error, dispatchAction, __VA_ARGS__)
-#else
-#   define CERROR_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter()
-#endif  // ELPP_ERROR_LOG
-#if ELPP_FATAL_LOG
-#   define CFATAL_IF(writer, condition_, dispatchAction, ...)\
-        ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Fatal, dispatchAction, __VA_ARGS__)
-#else
-#   define CFATAL_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter()
-#endif  // ELPP_FATAL_LOG
-#if ELPP_TRACE_LOG
-#   define CTRACE_IF(writer, condition_, dispatchAction, ...)\
-        ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Trace, dispatchAction, __VA_ARGS__)
-#else
-#   define CTRACE_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter()
-#endif  // ELPP_TRACE_LOG
-#if ELPP_VERBOSE_LOG
-#   define CVERBOSE_IF(writer, condition_, vlevel, dispatchAction, ...) if (VLOG_IS_ON(vlevel) && (condition_)) writer( \
-       el::Level::Verbose, __FILE__, __LINE__, ELPP_FUNC, dispatchAction, vlevel).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__)
-#else
-#   define CVERBOSE_IF(writer, condition_, vlevel, dispatchAction, ...) el::base::NullWriter()
-#endif  // ELPP_VERBOSE_LOG
-// Occasional logs
-#if ELPP_INFO_LOG
-#   define CINFO_EVERY_N(writer, occasion, dispatchAction, ...)\
-        ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Info, dispatchAction, __VA_ARGS__)
-#else
-#   define CINFO_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter()
-#endif  // ELPP_INFO_LOG
-#if ELPP_WARNING_LOG
-#   define CWARNING_EVERY_N(writer, occasion, dispatchAction, ...)\
-        ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Warning, dispatchAction, __VA_ARGS__)
-#else
-#   define CWARNING_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter()
-#endif  // ELPP_WARNING_LOG
-#if ELPP_DEBUG_LOG
-#   define CDEBUG_EVERY_N(writer, occasion, dispatchAction, ...)\
-        ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Debug, dispatchAction, __VA_ARGS__)
-#else
-#   define CDEBUG_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter()
-#endif  // ELPP_DEBUG_LOG
-#if ELPP_ERROR_LOG
-#   define CERROR_EVERY_N(writer, occasion, dispatchAction, ...)\
-        ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Error, dispatchAction, __VA_ARGS__)
-#else
-#   define CERROR_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter()
-#endif  // ELPP_ERROR_LOG
-#if ELPP_FATAL_LOG
-#   define CFATAL_EVERY_N(writer, occasion, dispatchAction, ...)\
-        ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Fatal, dispatchAction, __VA_ARGS__)
-#else
-#   define CFATAL_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter()
-#endif  // ELPP_FATAL_LOG
-#if ELPP_TRACE_LOG
-#   define CTRACE_EVERY_N(writer, occasion, dispatchAction, ...)\
-        ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Trace, dispatchAction, __VA_ARGS__)
-#else
-#   define CTRACE_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter()
-#endif  // ELPP_TRACE_LOG
-#if ELPP_VERBOSE_LOG
-#   define CVERBOSE_EVERY_N(writer, occasion, vlevel, dispatchAction, ...)\
-        CVERBOSE_IF(writer, ELPP->validateEveryNCounter(__FILE__, __LINE__, occasion), vlevel, dispatchAction, __VA_ARGS__)
-#else
-#   define CVERBOSE_EVERY_N(writer, occasion, vlevel, dispatchAction, ...) el::base::NullWriter()
-#endif  // ELPP_VERBOSE_LOG
-// After N logs
-#if ELPP_INFO_LOG
-#   define CINFO_AFTER_N(writer, n, dispatchAction, ...)\
-        ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Info, dispatchAction, __VA_ARGS__)
-#else
-#   define CINFO_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter()
-#endif  // ELPP_INFO_LOG
-#if ELPP_WARNING_LOG
-#   define CWARNING_AFTER_N(writer, n, dispatchAction, ...)\
-        ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Warning, dispatchAction, __VA_ARGS__)
-#else
-#   define CWARNING_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter()
-#endif  // ELPP_WARNING_LOG
-#if ELPP_DEBUG_LOG
-#   define CDEBUG_AFTER_N(writer, n, dispatchAction, ...)\
-        ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Debug, dispatchAction, __VA_ARGS__)
-#else
-#   define CDEBUG_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter()
-#endif  // ELPP_DEBUG_LOG
-#if ELPP_ERROR_LOG
-#   define CERROR_AFTER_N(writer, n, dispatchAction, ...)\
-        ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Error, dispatchAction, __VA_ARGS__)
-#else
-#   define CERROR_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter()
-#endif  // ELPP_ERROR_LOG
-#if ELPP_FATAL_LOG
-#   define CFATAL_AFTER_N(writer, n, dispatchAction, ...)\
-        ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Fatal, dispatchAction, __VA_ARGS__)
-#else
-#   define CFATAL_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter()
-#endif  // ELPP_FATAL_LOG
-#if ELPP_TRACE_LOG
-#   define CTRACE_AFTER_N(writer, n, dispatchAction, ...)\
-        ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Trace, dispatchAction, __VA_ARGS__)
-#else
-#   define CTRACE_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter()
-#endif  // ELPP_TRACE_LOG
-#if ELPP_VERBOSE_LOG
-#   define CVERBOSE_AFTER_N(writer, n, vlevel, dispatchAction, ...)\
-        CVERBOSE_IF(writer, ELPP->validateAfterNCounter(__FILE__, __LINE__, n), vlevel, dispatchAction, __VA_ARGS__)
-#else
-#   define CVERBOSE_AFTER_N(writer, n, vlevel, dispatchAction, ...) el::base::NullWriter()
-#endif  // ELPP_VERBOSE_LOG
-// N Times logs
-#if ELPP_INFO_LOG
-#   define CINFO_N_TIMES(writer, n, dispatchAction, ...)\
-        ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Info, dispatchAction, __VA_ARGS__)
-#else
-#   define CINFO_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter()
-#endif  // ELPP_INFO_LOG
-#if ELPP_WARNING_LOG
-#   define CWARNING_N_TIMES(writer, n, dispatchAction, ...)\
-        ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Warning, dispatchAction, __VA_ARGS__)
-#else
-#   define CWARNING_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter()
-#endif  // ELPP_WARNING_LOG
-#if ELPP_DEBUG_LOG
-#   define CDEBUG_N_TIMES(writer, n, dispatchAction, ...)\
-        ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Debug, dispatchAction, __VA_ARGS__)
-#else
-#   define CDEBUG_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter()
-#endif  // ELPP_DEBUG_LOG
-#if ELPP_ERROR_LOG
-#   define CERROR_N_TIMES(writer, n, dispatchAction, ...)\
-        ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Error, dispatchAction, __VA_ARGS__)
-#else
-#   define CERROR_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter()
-#endif  // ELPP_ERROR_LOG
-#if ELPP_FATAL_LOG
-#   define CFATAL_N_TIMES(writer, n, dispatchAction, ...)\
-        ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Fatal, dispatchAction, __VA_ARGS__)
-#else
-#   define CFATAL_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter()
-#endif  // ELPP_FATAL_LOG
-#if ELPP_TRACE_LOG
-#   define CTRACE_N_TIMES(writer, n, dispatchAction, ...)\
-        ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Trace, dispatchAction, __VA_ARGS__)
-#else
-#   define CTRACE_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter()
-#endif  // ELPP_TRACE_LOG
-#if ELPP_VERBOSE_LOG
-#   define CVERBOSE_N_TIMES(writer, n, vlevel, dispatchAction, ...)\
-        CVERBOSE_IF(writer, ELPP->validateNTimesCounter(__FILE__, __LINE__, n), vlevel, dispatchAction, __VA_ARGS__)
-#else
-#   define CVERBOSE_N_TIMES(writer, n, vlevel, dispatchAction, ...) el::base::NullWriter()
-#endif  // ELPP_VERBOSE_LOG
-//
-// Custom Loggers - Requires (level, dispatchAction, loggerId/s)
-//
-// undef existing
-#undef CLOG
-#undef CLOG_VERBOSE
-#undef CVLOG
-#undef CLOG_IF
-#undef CLOG_VERBOSE_IF
-#undef CVLOG_IF
-#undef CLOG_EVERY_N
-#undef CVLOG_EVERY_N
-#undef CLOG_AFTER_N
-#undef CVLOG_AFTER_N
-#undef CLOG_N_TIMES
-#undef CVLOG_N_TIMES
-// Normal logs
-#define CLOG(LEVEL, ...)\
-    C##LEVEL(el::base::Writer, el::base::DispatchAction::NormalLog, __VA_ARGS__)
-#define CVLOG(vlevel, ...) CVERBOSE(el::base::Writer, vlevel, el::base::DispatchAction::NormalLog, __VA_ARGS__)
-// Conditional logs
-#define CLOG_IF(condition, LEVEL, ...)\
-    C##LEVEL##_IF(el::base::Writer, condition, el::base::DispatchAction::NormalLog, __VA_ARGS__)
-#define CVLOG_IF(condition, vlevel, ...)\
-    CVERBOSE_IF(el::base::Writer, condition, vlevel, el::base::DispatchAction::NormalLog, __VA_ARGS__)
-// Hit counts based logs
-#define CLOG_EVERY_N(n, LEVEL, ...)\
-    C##LEVEL##_EVERY_N(el::base::Writer, n, el::base::DispatchAction::NormalLog, __VA_ARGS__)
-#define CVLOG_EVERY_N(n, vlevel, ...)\
-    CVERBOSE_EVERY_N(el::base::Writer, n, vlevel, el::base::DispatchAction::NormalLog, __VA_ARGS__)
-#define CLOG_AFTER_N(n, LEVEL, ...)\
-    C##LEVEL##_AFTER_N(el::base::Writer, n, el::base::DispatchAction::NormalLog, __VA_ARGS__)
-#define CVLOG_AFTER_N(n, vlevel, ...)\
-    CVERBOSE_AFTER_N(el::base::Writer, n, vlevel, el::base::DispatchAction::NormalLog, __VA_ARGS__)
-#define CLOG_N_TIMES(n, LEVEL, ...)\
-    C##LEVEL##_N_TIMES(el::base::Writer, n, el::base::DispatchAction::NormalLog, __VA_ARGS__)
-#define CVLOG_N_TIMES(n, vlevel, ...)\
-    CVERBOSE_N_TIMES(el::base::Writer, n, vlevel, el::base::DispatchAction::NormalLog, __VA_ARGS__)
-//
-// Default Loggers macro using CLOG(), CLOG_VERBOSE() and CVLOG() macros
-//
-// undef existing
-#undef LOG
-#undef VLOG
-#undef LOG_IF
-#undef VLOG_IF
-#undef LOG_EVERY_N
-#undef VLOG_EVERY_N
-#undef LOG_AFTER_N
-#undef VLOG_AFTER_N
-#undef LOG_N_TIMES
-#undef VLOG_N_TIMES
-#undef ELPP_CURR_FILE_LOGGER_ID
-#if defined(ELPP_DEFAULT_LOGGER)
-#   define ELPP_CURR_FILE_LOGGER_ID ELPP_DEFAULT_LOGGER
-#else
-#   define ELPP_CURR_FILE_LOGGER_ID el::base::consts::kDefaultLoggerId
-#endif
-#undef ELPP_TRACE
-#define ELPP_TRACE CLOG(TRACE, ELPP_CURR_FILE_LOGGER_ID)
-// Normal logs
-#define LOG(LEVEL) CLOG(LEVEL, ELPP_CURR_FILE_LOGGER_ID)
-#define VLOG(vlevel) CVLOG(vlevel, ELPP_CURR_FILE_LOGGER_ID)
-// Conditional logs
-#define LOG_IF(condition, LEVEL) CLOG_IF(condition, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
-#define VLOG_IF(condition, vlevel) CVLOG_IF(condition, vlevel, ELPP_CURR_FILE_LOGGER_ID)
-// Hit counts based logs
-#define LOG_EVERY_N(n, LEVEL) CLOG_EVERY_N(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
-#define VLOG_EVERY_N(n, vlevel) CVLOG_EVERY_N(n, vlevel, ELPP_CURR_FILE_LOGGER_ID)
-#define LOG_AFTER_N(n, LEVEL) CLOG_AFTER_N(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
-#define VLOG_AFTER_N(n, vlevel) CVLOG_AFTER_N(n, vlevel, ELPP_CURR_FILE_LOGGER_ID)
-#define LOG_N_TIMES(n, LEVEL) CLOG_N_TIMES(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
-#define VLOG_N_TIMES(n, vlevel) CVLOG_N_TIMES(n, vlevel, ELPP_CURR_FILE_LOGGER_ID)
-// Generic PLOG()
-#undef CPLOG
-#undef CPLOG_IF
-#undef PLOG
-#undef PLOG_IF
-#undef DCPLOG
-#undef DCPLOG_IF
-#undef DPLOG
-#undef DPLOG_IF
-#define CPLOG(LEVEL, ...)\
-    C##LEVEL(el::base::PErrorWriter, el::base::DispatchAction::NormalLog, __VA_ARGS__)
-#define CPLOG_IF(condition, LEVEL, ...)\
-    C##LEVEL##_IF(el::base::PErrorWriter, condition, el::base::DispatchAction::NormalLog, __VA_ARGS__)
-#define DCPLOG(LEVEL, ...)\
-    if (ELPP_DEBUG_LOG) C##LEVEL(el::base::PErrorWriter, el::base::DispatchAction::NormalLog, __VA_ARGS__)
-#define DCPLOG_IF(condition, LEVEL, ...)\
-    C##LEVEL##_IF(el::base::PErrorWriter, (ELPP_DEBUG_LOG) && (condition), el::base::DispatchAction::NormalLog, __VA_ARGS__)
-#define PLOG(LEVEL) CPLOG(LEVEL, ELPP_CURR_FILE_LOGGER_ID)
-#define PLOG_IF(condition, LEVEL) CPLOG_IF(condition, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
-#define DPLOG(LEVEL) DCPLOG(LEVEL, ELPP_CURR_FILE_LOGGER_ID)
-#define DPLOG_IF(condition, LEVEL) DCPLOG_IF(condition, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
-// Generic SYSLOG()
-#undef CSYSLOG
-#undef CSYSLOG_IF
-#undef CSYSLOG_EVERY_N
-#undef CSYSLOG_AFTER_N
-#undef CSYSLOG_N_TIMES
-#undef SYSLOG
-#undef SYSLOG_IF
-#undef SYSLOG_EVERY_N
-#undef SYSLOG_AFTER_N
-#undef SYSLOG_N_TIMES
-#undef DCSYSLOG
-#undef DCSYSLOG_IF
-#undef DCSYSLOG_EVERY_N
-#undef DCSYSLOG_AFTER_N
-#undef DCSYSLOG_N_TIMES
-#undef DSYSLOG
-#undef DSYSLOG_IF
-#undef DSYSLOG_EVERY_N
-#undef DSYSLOG_AFTER_N
-#undef DSYSLOG_N_TIMES
-#if defined(ELPP_SYSLOG)
-#   define CSYSLOG(LEVEL, ...)\
-        C##LEVEL(el::base::Writer, el::base::DispatchAction::SysLog, __VA_ARGS__)
-#   define CSYSLOG_IF(condition, LEVEL, ...)\
-        C##LEVEL##_IF(el::base::Writer, condition, el::base::DispatchAction::SysLog, __VA_ARGS__)
-#   define CSYSLOG_EVERY_N(n, LEVEL, ...) C##LEVEL##_EVERY_N(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__)
-#   define CSYSLOG_AFTER_N(n, LEVEL, ...) C##LEVEL##_AFTER_N(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__)
-#   define CSYSLOG_N_TIMES(n, LEVEL, ...) C##LEVEL##_N_TIMES(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__)
-#   define SYSLOG(LEVEL) CSYSLOG(LEVEL, el::base::consts::kSysLogLoggerId)
-#   define SYSLOG_IF(condition, LEVEL) CSYSLOG_IF(condition, LEVEL, el::base::consts::kSysLogLoggerId)
-#   define SYSLOG_EVERY_N(n, LEVEL) CSYSLOG_EVERY_N(n, LEVEL, el::base::consts::kSysLogLoggerId)
-#   define SYSLOG_AFTER_N(n, LEVEL) CSYSLOG_AFTER_N(n, LEVEL, el::base::consts::kSysLogLoggerId)
-#   define SYSLOG_N_TIMES(n, LEVEL) CSYSLOG_N_TIMES(n, LEVEL, el::base::consts::kSysLogLoggerId)
-#   define DCSYSLOG(LEVEL, ...) if (ELPP_DEBUG_LOG) C##LEVEL(el::base::Writer, el::base::DispatchAction::SysLog, __VA_ARGS__)
-#   define DCSYSLOG_IF(condition, LEVEL, ...)\
-        C##LEVEL##_IF(el::base::Writer, (ELPP_DEBUG_LOG) && (condition), el::base::DispatchAction::SysLog, __VA_ARGS__)
-#   define DCSYSLOG_EVERY_N(n, LEVEL, ...)\
-        if (ELPP_DEBUG_LOG) C##LEVEL##_EVERY_N(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__)
-#   define DCSYSLOG_AFTER_N(n, LEVEL, ...)\
-        if (ELPP_DEBUG_LOG) C##LEVEL##_AFTER_N(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__)
-#   define DCSYSLOG_N_TIMES(n, LEVEL, ...)\
-        if (ELPP_DEBUG_LOG) C##LEVEL##_EVERY_N(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__)
-#   define DSYSLOG(LEVEL) DCSYSLOG(LEVEL, el::base::consts::kSysLogLoggerId)
-#   define DSYSLOG_IF(condition, LEVEL) DCSYSLOG_IF(condition, LEVEL, el::base::consts::kSysLogLoggerId)
-#   define DSYSLOG_EVERY_N(n, LEVEL) DCSYSLOG_EVERY_N(n, LEVEL, el::base::consts::kSysLogLoggerId)
-#   define DSYSLOG_AFTER_N(n, LEVEL) DCSYSLOG_AFTER_N(n, LEVEL, el::base::consts::kSysLogLoggerId)
-#   define DSYSLOG_N_TIMES(n, LEVEL) DCSYSLOG_N_TIMES(n, LEVEL, el::base::consts::kSysLogLoggerId)
-#else
-#   define CSYSLOG(LEVEL, ...) el::base::NullWriter()
-#   define CSYSLOG_IF(condition, LEVEL, ...) el::base::NullWriter()
-#   define CSYSLOG_EVERY_N(n, LEVEL, ...) el::base::NullWriter()
-#   define CSYSLOG_AFTER_N(n, LEVEL, ...) el::base::NullWriter()
-#   define CSYSLOG_N_TIMES(n, LEVEL, ...) el::base::NullWriter()
-#   define SYSLOG(LEVEL) el::base::NullWriter()
-#   define SYSLOG_IF(condition, LEVEL) el::base::NullWriter()
-#   define SYSLOG_EVERY_N(n, LEVEL) el::base::NullWriter()
-#   define SYSLOG_AFTER_N(n, LEVEL) el::base::NullWriter()
-#   define SYSLOG_N_TIMES(n, LEVEL) el::base::NullWriter()
-#   define DCSYSLOG(LEVEL, ...) el::base::NullWriter()
-#   define DCSYSLOG_IF(condition, LEVEL, ...) el::base::NullWriter()
-#   define DCSYSLOG_EVERY_N(n, LEVEL, ...) el::base::NullWriter()
-#   define DCSYSLOG_AFTER_N(n, LEVEL, ...) el::base::NullWriter()
-#   define DCSYSLOG_N_TIMES(n, LEVEL, ...) el::base::NullWriter()
-#   define DSYSLOG(LEVEL) el::base::NullWriter()
-#   define DSYSLOG_IF(condition, LEVEL) el::base::NullWriter()
-#   define DSYSLOG_EVERY_N(n, LEVEL) el::base::NullWriter()
-#   define DSYSLOG_AFTER_N(n, LEVEL) el::base::NullWriter()
-#   define DSYSLOG_N_TIMES(n, LEVEL) el::base::NullWriter()
-#endif  // defined(ELPP_SYSLOG)
-//
-// Custom Debug Only Loggers - Requires (level, loggerId/s)
-//
-// undef existing
-#undef DCLOG
-#undef DCVLOG
-#undef DCLOG_IF
-#undef DCVLOG_IF
-#undef DCLOG_EVERY_N
-#undef DCVLOG_EVERY_N
-#undef DCLOG_AFTER_N
-#undef DCVLOG_AFTER_N
-#undef DCLOG_N_TIMES
-#undef DCVLOG_N_TIMES
-// Normal logs
-#define DCLOG(LEVEL, ...) if (ELPP_DEBUG_LOG) CLOG(LEVEL, __VA_ARGS__)
-#define DCLOG_VERBOSE(vlevel, ...) if (ELPP_DEBUG_LOG) CLOG_VERBOSE(vlevel, __VA_ARGS__)
-#define DCVLOG(vlevel, ...) if (ELPP_DEBUG_LOG) CVLOG(vlevel, __VA_ARGS__)
-// Conditional logs
-#define DCLOG_IF(condition, LEVEL, ...) if (ELPP_DEBUG_LOG) CLOG_IF(condition, LEVEL, __VA_ARGS__)
-#define DCVLOG_IF(condition, vlevel, ...) if (ELPP_DEBUG_LOG) CVLOG_IF(condition, vlevel, __VA_ARGS__)
-// Hit counts based logs
-#define DCLOG_EVERY_N(n, LEVEL, ...) if (ELPP_DEBUG_LOG) CLOG_EVERY_N(n, LEVEL, __VA_ARGS__)
-#define DCVLOG_EVERY_N(n, vlevel, ...) if (ELPP_DEBUG_LOG) CVLOG_EVERY_N(n, vlevel, __VA_ARGS__)
-#define DCLOG_AFTER_N(n, LEVEL, ...) if (ELPP_DEBUG_LOG) CLOG_AFTER_N(n, LEVEL, __VA_ARGS__)
-#define DCVLOG_AFTER_N(n, vlevel, ...) if (ELPP_DEBUG_LOG) CVLOG_AFTER_N(n, vlevel, __VA_ARGS__)
-#define DCLOG_N_TIMES(n, LEVEL, ...) if (ELPP_DEBUG_LOG) CLOG_N_TIMES(n, LEVEL, __VA_ARGS__)
-#define DCVLOG_N_TIMES(n, vlevel, ...) if (ELPP_DEBUG_LOG) CVLOG_N_TIMES(n, vlevel, __VA_ARGS__)
-//
-// Default Debug Only Loggers macro using CLOG(), CLOG_VERBOSE() and CVLOG() macros
-//
-// undef existing
-#undef DLOG
-#undef DVLOG
-#undef DLOG_IF
-#undef DVLOG_IF
-#undef DLOG_EVERY_N
-#undef DVLOG_EVERY_N
-#undef DLOG_AFTER_N
-#undef DVLOG_AFTER_N
-#undef DLOG_N_TIMES
-#undef DVLOG_N_TIMES
-// Normal logs
-#define DLOG(LEVEL) DCLOG(LEVEL, ELPP_CURR_FILE_LOGGER_ID)
-#define DVLOG(vlevel) DCVLOG(vlevel, ELPP_CURR_FILE_LOGGER_ID)
-// Conditional logs
-#define DLOG_IF(condition, LEVEL) DCLOG_IF(condition, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
-#define DVLOG_IF(condition, vlevel) DCVLOG_IF(condition, vlevel, ELPP_CURR_FILE_LOGGER_ID)
-// Hit counts based logs
-#define DLOG_EVERY_N(n, LEVEL) DCLOG_EVERY_N(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
-#define DVLOG_EVERY_N(n, vlevel) DCVLOG_EVERY_N(n, vlevel, ELPP_CURR_FILE_LOGGER_ID)
-#define DLOG_AFTER_N(n, LEVEL) DCLOG_AFTER_N(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
-#define DVLOG_AFTER_N(n, vlevel) DCVLOG_AFTER_N(n, vlevel, ELPP_CURR_FILE_LOGGER_ID)
-#define DLOG_N_TIMES(n, LEVEL) DCLOG_N_TIMES(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
-#define DVLOG_N_TIMES(n, vlevel) DCVLOG_N_TIMES(n, vlevel, ELPP_CURR_FILE_LOGGER_ID)
-// Check macros
-#undef CCHECK
-#undef CPCHECK
-#undef CCHECK_EQ
-#undef CCHECK_NE
-#undef CCHECK_LT
-#undef CCHECK_GT
-#undef CCHECK_LE
-#undef CCHECK_GE
-#undef CCHECK_BOUNDS
-#undef CCHECK_NOTNULL
-#undef CCHECK_STRCASEEQ
-#undef CCHECK_STRCASENE
-#undef CHECK
-#undef PCHECK
-#undef CHECK_EQ
-#undef CHECK_NE
-#undef CHECK_LT
-#undef CHECK_GT
-#undef CHECK_LE
-#undef CHECK_GE
-#undef CHECK_BOUNDS
-#undef CHECK_NOTNULL
-#undef CHECK_STRCASEEQ
-#undef CHECK_STRCASENE
-#define CCHECK(condition, ...) CLOG_IF(!(condition), FATAL, __VA_ARGS__) << "Check failed: [" << #condition << "] "
-#define CPCHECK(condition, ...) CPLOG_IF(!(condition), FATAL, __VA_ARGS__) << "Check failed: [" << #condition << "] "
-#define CHECK(condition) CCHECK(condition, ELPP_CURR_FILE_LOGGER_ID)
-#define PCHECK(condition) CPCHECK(condition, ELPP_CURR_FILE_LOGGER_ID)
-#define CCHECK_EQ(a, b, ...) CCHECK(a == b, __VA_ARGS__)
-#define CCHECK_NE(a, b, ...) CCHECK(a != b, __VA_ARGS__)
-#define CCHECK_LT(a, b, ...) CCHECK(a < b, __VA_ARGS__)
-#define CCHECK_GT(a, b, ...) CCHECK(a > b, __VA_ARGS__)
-#define CCHECK_LE(a, b, ...) CCHECK(a <= b, __VA_ARGS__)
-#define CCHECK_GE(a, b, ...) CCHECK(a >= b, __VA_ARGS__)
-#define CCHECK_BOUNDS(val, min, max, ...) CCHECK(val >= min && val <= max, __VA_ARGS__)
-#define CHECK_EQ(a, b) CCHECK_EQ(a, b, ELPP_CURR_FILE_LOGGER_ID)
-#define CHECK_NE(a, b) CCHECK_NE(a, b, ELPP_CURR_FILE_LOGGER_ID)
-#define CHECK_LT(a, b) CCHECK_LT(a, b, ELPP_CURR_FILE_LOGGER_ID)
-#define CHECK_GT(a, b) CCHECK_GT(a, b, ELPP_CURR_FILE_LOGGER_ID)
-#define CHECK_LE(a, b) CCHECK_LE(a, b, ELPP_CURR_FILE_LOGGER_ID)
-#define CHECK_GE(a, b) CCHECK_GE(a, b, ELPP_CURR_FILE_LOGGER_ID)
-#define CHECK_BOUNDS(val, min, max) CCHECK_BOUNDS(val, min, max, ELPP_CURR_FILE_LOGGER_ID)
-namespace el {
-namespace base {
-namespace utils {
-template <typename T>
-static T* checkNotNull(T* ptr, const char* name, const char* loggers, ...) {
-    CLOG_IF(ptr == nullptr, FATAL, loggers) << "Check failed: [" << name << " != nullptr]";
-    return ptr;
-}
-}  // namespace utils
-}  // namespace base
-}  // namespace el
-#define CCHECK_NOTNULL(ptr, ...) el::base::utils::checkNotNull(ptr, #ptr, __VA_ARGS__)
-#define CCHECK_STREQ(str1, str2, ...) CLOG_IF(!el::base::utils::Str::cStringEq(str1, str2), FATAL, __VA_ARGS__) \
-                        << "Check failed: [" << #str1 << " == " << #str2 << "] "
-#define CCHECK_STRNE(str1, str2, ...) CLOG_IF(el::base::utils::Str::cStringEq(str1, str2), FATAL, __VA_ARGS__) \
-                        << "Check failed: [" << #str1 << " != " << #str2 << "] "
-#define CCHECK_STRCASEEQ(str1, str2, ...) CLOG_IF(!el::base::utils::Str::cStringCaseEq(str1, str2), FATAL, __VA_ARGS__) \
-                        << "Check failed: [" << #str1 << " == " << #str2 << "] "
-#define CCHECK_STRCASENE(str1, str2, ...) CLOG_IF(el::base::utils::Str::cStringCaseEq(str1, str2), FATAL, __VA_ARGS__) \
-                        << "Check failed: [" << #str1 << " != " << #str2 << "] "
-#define CHECK_NOTNULL(ptr) CCHECK_NOTNULL(ptr, ELPP_CURR_FILE_LOGGER_ID)
-#define CHECK_STREQ(str1, str2) CCHECK_STREQ(str1, str2, ELPP_CURR_FILE_LOGGER_ID)
-#define CHECK_STRNE(str1, str2) CCHECK_STRNE(str1, str2, ELPP_CURR_FILE_LOGGER_ID)
-#define CHECK_STRCASEEQ(str1, str2) CCHECK_STRCASEEQ(str1, str2, ELPP_CURR_FILE_LOGGER_ID)
-#define CHECK_STRCASENE(str1, str2) CCHECK_STRCASENE(str1, str2, ELPP_CURR_FILE_LOGGER_ID)
-#undef DCCHECK
-#undef DCCHECK_EQ
-#undef DCCHECK_NE
-#undef DCCHECK_LT
-#undef DCCHECK_GT
-#undef DCCHECK_LE
-#undef DCCHECK_GE
-#undef DCCHECK_BOUNDS
-#undef DCCHECK_NOTNULL
-#undef DCCHECK_STRCASEEQ
-#undef DCCHECK_STRCASENE
-#undef DCPCHECK
-#undef DCHECK
-#undef DCHECK_EQ
-#undef DCHECK_NE
-#undef DCHECK_LT
-#undef DCHECK_GT
-#undef DCHECK_LE
-#undef DCHECK_GE
-#undef DCHECK_BOUNDS_
-#undef DCHECK_NOTNULL
-#undef DCHECK_STRCASEEQ
-#undef DCHECK_STRCASENE
-#undef DPCHECK
-#define DCCHECK(condition, ...) if (ELPP_DEBUG_LOG) CCHECK(condition, __VA_ARGS__)
-#define DCCHECK_EQ(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_EQ(a, b, __VA_ARGS__)
-#define DCCHECK_NE(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_NE(a, b, __VA_ARGS__)
-#define DCCHECK_LT(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_LT(a, b, __VA_ARGS__)
-#define DCCHECK_GT(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_GT(a, b, __VA_ARGS__)
-#define DCCHECK_LE(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_LE(a, b, __VA_ARGS__)
-#define DCCHECK_GE(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_GE(a, b, __VA_ARGS__)
-#define DCCHECK_BOUNDS(val, min, max, ...) if (ELPP_DEBUG_LOG) CCHECK_BOUNDS(val, min, max, __VA_ARGS__)
-#define DCCHECK_NOTNULL(ptr, ...) if (ELPP_DEBUG_LOG) CCHECK_NOTNULL(ptr, __VA_ARGS__)
-#define DCCHECK_STREQ(str1, str2, ...) if (ELPP_DEBUG_LOG) CCHECK_STREQ(str1, str2, __VA_ARGS__)
-#define DCCHECK_STRNE(str1, str2, ...) if (ELPP_DEBUG_LOG) CCHECK_STRNE(str1, str2, __VA_ARGS__)
-#define DCCHECK_STRCASEEQ(str1, str2, ...) if (ELPP_DEBUG_LOG) CCHECK_STRCASEEQ(str1, str2, __VA_ARGS__)
-#define DCCHECK_STRCASENE(str1, str2, ...) if (ELPP_DEBUG_LOG) CCHECK_STRCASENE(str1, str2, __VA_ARGS__)
-#define DCPCHECK(condition, ...) if (ELPP_DEBUG_LOG) CPCHECK(condition, __VA_ARGS__)
-#define DCHECK(condition) DCCHECK(condition, ELPP_CURR_FILE_LOGGER_ID)
-#define DCHECK_EQ(a, b) DCCHECK_EQ(a, b, ELPP_CURR_FILE_LOGGER_ID)
-#define DCHECK_NE(a, b) DCCHECK_NE(a, b, ELPP_CURR_FILE_LOGGER_ID)
-#define DCHECK_LT(a, b) DCCHECK_LT(a, b, ELPP_CURR_FILE_LOGGER_ID)
-#define DCHECK_GT(a, b) DCCHECK_GT(a, b, ELPP_CURR_FILE_LOGGER_ID)
-#define DCHECK_LE(a, b) DCCHECK_LE(a, b, ELPP_CURR_FILE_LOGGER_ID)
-#define DCHECK_GE(a, b) DCCHECK_GE(a, b, ELPP_CURR_FILE_LOGGER_ID)
-#define DCHECK_BOUNDS(val, min, max) DCCHECK_BOUNDS(val, min, max, ELPP_CURR_FILE_LOGGER_ID)
-#define DCHECK_NOTNULL(ptr) DCCHECK_NOTNULL(ptr, ELPP_CURR_FILE_LOGGER_ID)
-#define DCHECK_STREQ(str1, str2) DCCHECK_STREQ(str1, str2, ELPP_CURR_FILE_LOGGER_ID)
-#define DCHECK_STRNE(str1, str2) DCCHECK_STRNE(str1, str2, ELPP_CURR_FILE_LOGGER_ID)
-#define DCHECK_STRCASEEQ(str1, str2) DCCHECK_STRCASEEQ(str1, str2, ELPP_CURR_FILE_LOGGER_ID)
-#define DCHECK_STRCASENE(str1, str2) DCCHECK_STRCASENE(str1, str2, ELPP_CURR_FILE_LOGGER_ID)
-#define DPCHECK(condition) DCPCHECK(condition, ELPP_CURR_FILE_LOGGER_ID)
-#if defined(ELPP_DISABLE_DEFAULT_CRASH_HANDLING)
-#   define ELPP_USE_DEF_CRASH_HANDLER false
-#else
-#   define ELPP_USE_DEF_CRASH_HANDLER true
-#endif  // defined(ELPP_DISABLE_DEFAULT_CRASH_HANDLING)
-#define ELPP_CRASH_HANDLER_INIT
-#define ELPP_INIT_EASYLOGGINGPP(val)\
-    ELPP_INITI_BASIC_DECLR\
-    namespace el {\
-        namespace base {\
-            el::base::type::StoragePointer elStorage(val);\
-        }\
-        el::base::debug::CrashHandler elCrashHandler(ELPP_USE_DEF_CRASH_HANDLER);\
-    }
-
-#if ELPP_ASYNC_LOGGING
-#   define INITIALIZE_EASYLOGGINGPP\
-       ELPP_INIT_EASYLOGGINGPP(new el::base::Storage(el::LogBuilderPtr(new el::base::DefaultLogBuilder()),\
-                                                          new el::base::AsyncDispatchWorker()))\
-       
-#else
-#   define INITIALIZE_EASYLOGGINGPP\
-       ELPP_INIT_EASYLOGGINGPP(new el::base::Storage(el::LogBuilderPtr(new el::base::DefaultLogBuilder())))
-#endif  // ELPP_ASYNC_LOGGING
-#define INITIALIZE_NULL_EASYLOGGINGPP\
-    ELPP_INITI_BASIC_DECLR\
-    namespace el {\
-        namespace base {\
-            el::base::type::StoragePointer elStorage;\
-        }\
-        el::base::debug::CrashHandler elCrashHandler(ELPP_USE_DEF_CRASH_HANDLER);\
-    }
-// NOTE: no ELPP_INITI_BASIC_DECLR when sharing - causes double free corruption on external symbols
-#define SHARE_EASYLOGGINGPP(initializedStorage)\
-    namespace el {\
-        namespace base {\
-            el::base::type::StoragePointer elStorage(initializedStorage);\
-        }\
-        el::base::debug::CrashHandler elCrashHandler(ELPP_USE_DEF_CRASH_HANDLER);\
-    }
-
-#if defined(ELPP_UNICODE)
-#   define START_EASYLOGGINGPP(argc, argv) el::Helpers::setArgs(argc, argv); std::locale::global(std::locale(""))
-#else
-#   define START_EASYLOGGINGPP(argc, argv) el::Helpers::setArgs(argc, argv)
-#endif  // defined(ELPP_UNICODE)
-#endif // EASYLOGGINGPP_H
diff --git a/src/makefile b/src/makefile
deleted file mode 100644
index 321a049ad6de7e4b905f4aea26b0b4bd304a94e6..0000000000000000000000000000000000000000
--- a/src/makefile
+++ /dev/null
@@ -1,79 +0,0 @@
-# A sample Makefile
-# This Makefile demonstrates and explains 
-# Make Macros, Macro Expansions,
-# Rules, Targets, Dependencies, Commands, Goals
-# Artificial Targets, Pattern Rule, Dependency Rule.
-
-# Comments start with a # and go to the end of the line.
-CXXFLAGS=-g -std=c++11 -Wall -pedantic
-
-# Here is a simple Make Macro.
-LINK_TARGET = spejd_service
-
-# Here is a Make Macro that uses the backslash to extend to multiple lines.
-OBJS =  \
- asiohandler.o \
- nlpworker.o \
- spejd_service.o 
-
-# Here is a Make Macro defined by two Macro Expansions.
-# A Macro Expansion may be treated as a textual replacement of the Make Macro.
-# Macro Expansions are introduced with $ and enclosed in (parentheses).
-REBUILDABLES = $(OBJS) $(LINK_TARGET)
-
-# Here is a simple Rule (used for "cleaning" your build environment).
-# It has a Target named "clean" (left of the colon ":" on the first line),
-# no Dependencies (right of the colon),
-# and two Commands (indented by tabs on the lines that follow).
-# The space before the colon is not required but added here for clarity.
-clean :
-	rm -f $(REBUILDABLES)
-	echo Clean done
-
-# There are two standard Targets your Makefile should probably have:
-# "all" and "clean", because they are often command-line Goals.
-# Also, these are both typically Artificial Targets, because they don't typically
-# correspond to real files named "all" or "clean".  
-
-# The rule for "all" is used to incrementally build your system.
-# It does this by expressing a dependency on the results of that system,
-# which in turn have their own rules and dependencies.
-all : $(LINK_TARGET)
-	echo All done
-
-# There is no required order to the list of rules as they appear in the Makefile.
-# Make will build its own dependency tree and only execute each rule only once
-# its dependencies' rules have been executed successfully.
-
-# Here is a Rule that uses some built-in Make Macros in its command:
-# $@ expands to the rule's target, in this case "test_me.exe".
-# $^ expands to the rule's dependencies, in this case the three files
-# main.o, test1.o, and  test2.o.
-$(LINK_TARGET) :$(OBJS)
-	g++ -std=c++11 -g -o $@  $^ -lboost_system -lboost_thread -lboost_serialization -lboost_filesystem -lamqpcpp -lspejd -pthread 
-
-# Here is a Pattern Rule, often used for compile-line.
-# It says how to create a file with a .o suffix, given a file with a .cpp suffix.
-# The rule's command uses some built-in Make Macros:
-# $@ for the pattern-matched target
-# $< for the pattern-matched dependency
-%.o : %.cpp
-	g++ -std=c++11 -g -o $@ -c  $<
-
-# These are Dependency Rules, which are rules without any command.
-# Dependency Rules indicate that if any file to the right of the colon changes,
-# the target to the left of the colon should be considered out-of-date.
-# The commands for making an out-of-date target up-to-date may be found elsewhere
-# (in this case, by the Pattern Rule above).
-# Dependency Rules are often used to capture header file dependencies.
-
-asiohandler.o : asiohandler.h 
-nlpworker.o : tools.h asiohandler.h nlpworker.h
-spejd_service.o : nlpworker.h
-
-
-# Alternatively to manually capturing dependencies, several automated
-# dependency generators exist.  Here is one possibility (commented out)...
-# %.dep : %.cpp
-#   g++ -M $(FLAGS) $< > $@
-# include $(OBJS:.o=.dep)
\ No newline at end of file
diff --git a/src/nlpworker.cpp b/src/nlpworker.cpp
deleted file mode 100644
index 4a8fc7fb14e9a0f9e23454eddb7b15cf16569335..0000000000000000000000000000000000000000
--- a/src/nlpworker.cpp
+++ /dev/null
@@ -1,111 +0,0 @@
-
-#include <algorithm>
-
-
-
-
-//#include <libwcrft/tagger.h>
-
-#include <chrono>
-#include "asiohandler.h"
-#include "nlpworker.h"
-//#define BOOST_NO_CXX11_SCOPED_ENUMS
-//#include <boost/filesystem.hpp>
-
-
-
-boost::property_tree::ptree init_worker()
-{  boost::property_tree::ptree pt;
-  boost::property_tree::ini_parser::read_ini("config.ini", pt);
-  pt.get<std::string>("service.rabbit_host");
-  pt.get<std::string>("service.rabbit_user"); 
-  pt.get<std::string>("service.rabbit_password");
-  pt.get<std::string>("service.tool");
-  pt.get<std::string>("service.root");
-  
-  std::string tool=pt.get<std::string>("service.tool");
-  std::string root=pt.get<std::string>("service.root");
-  { std::string dirpath=root+tool;
-    /* 
-    boost::filesystem::path dir(dirpath);
-    if(boost::filesystem::create_directory(dir))
-    {
-        std::cerr<< "Directory Created: "<<dirpath<<std::endl;
-    } */
-  }
-  
-  return pt;
-}
-
-
-
-void worker(boost::property_tree::ptree pt,int worker_id,NLPWorker *worker)
-{       
-    std::string tool=pt.get<std::string>("service.tool");
-	std::string root=pt.get<std::string>("service.root");
-	LOG(INFO) << "Starting worker '"+tool+"' #"<<worker_id;
-	//std::cout << "Starting worker '"+tool+"' #"<<worker_id<< std::endl;
-	worker->init(pt);
-	
-    boost::asio::io_service ioService;
-    AsioHandler handler(ioService);
-    handler.connect(pt.get<std::string>("service.rabbit_host"), 5672);
-
-    AMQP::Connection connection(&handler, AMQP::Login(pt.get<std::string>("service.rabbit_user"), pt.get<std::string>("service.rabbit_password")), "/");
-
-    AMQP::Channel channel(&connection);
-    channel.setQos(1);
-
-
-    channel.declareQueue("nlp_"+tool);
-    channel.consume("").onReceived([&channel,&root,&tool,&worker,&worker_id](const AMQP::Message &message,
-            uint64_t deliveryTag,
-            bool redelivered)
-    {	clock_t start = clock();
-		boost::property_tree::ptree result;
-		const auto body = message.message();
-		try {
-		std::stringstream ss;
-		ss<<body;
-		boost::property_tree::ptree params;
-        boost::property_tree::read_json(ss, params);
-		std::string inputPath=params.get<std::string>("file");
-		std::string outputPath=root+tool+"/"+message.correlationID();
-		boost::property_tree::ptree options=params.get_child("options");
-		std::stringstream sso;write_json(sso, options);
-		LOG(DEBUG) << "Get task '"<<message.correlationID()<<" with options: "<<sso.str();
-		worker->process(inputPath,options,outputPath);
-		
-		
-		result.put<std::string>("error","");
-		result.put<std::string>("file",outputPath);
-		}
-		catch (std::exception const& e)
-		{	LOG(INFO) << "Error in task '"<<message.correlationID()<<" : "<<e.what();
-			std::string str(e.what());
-			result.put<std::string>("error",str);
-		}
-		clock_t end = clock();
-		double time = (double) (end-start) / CLOCKS_PER_SEC;
-		LOG(DEBUG) << "Finished task '"<<message.correlationID()<<" in "<<time<<" s.";
-		clock_t end2 = clock();
-		double time2 = (double) (end2-end) / CLOCKS_PER_SEC;
-		LOG(INFO) << "Finished task '"<<message.correlationID()<<" in "<<time2<<" s a";
-		result.put<double>("time",time);
-		
-		std::stringstream ssr;write_json(ssr, result);
-        AMQP::Envelope env(ssr.str());
-        env.setCorrelationID(message.correlationID());
-
-        channel.publish("", message.replyTo(), env);
-        channel.ack(deliveryTag);
-		//LOG(DEBUG) << "Returning '"<<ssr.str();
-		//std::cout << " Finished "<<worker_id<<" processing task#"<<message.correlationID()<< std::endl;
-    });
-
-    LOG(INFO) << "Started worker '"+tool+"' #"<<worker_id;
-
-    ioService.run();
-    
-}
-
diff --git a/src/nlpworker.h b/src/nlpworker.h
deleted file mode 100644
index 11995a5db0cd4e26cb7031aa2100edb1030a2552..0000000000000000000000000000000000000000
--- a/src/nlpworker.h
+++ /dev/null
@@ -1,44 +0,0 @@
-#include <iostream>
-#define BOOST_SPIRIT_THREADSAFE
-
-#include <boost/property_tree/json_parser.hpp>
-#include <boost/property_tree/ini_parser.hpp> 
-#include <boost/foreach.hpp>
-#include <boost/thread.hpp>
-#include <boost/property_tree/ptree.hpp>
-
-#define ELPP_THREAD_SAFE
-#define ELPP_DEFAULT_LOG_FILE "service.log"
-#include "easylogging++.h"
-
-
-class NLPWorker
-{ public: 
-	virtual void static_init(boost::property_tree::ptree config) {};
-	virtual void init(boost::property_tree::ptree config) {} ;
-	virtual void process(std::string task_path, boost::property_tree::ptree &options, std::string output_path) = 0;
-  
-};
-void worker(boost::property_tree::ptree pt,int worker_id,NLPWorker *worker);
-boost::property_tree::ptree init_worker();
-
-
-
-template<class WorkerClass>
-int run_workers(int argv, char* argc[])
-{ 
-  START_EASYLOGGINGPP(argv, argc);
-  boost::property_tree::ptree pt=init_worker();
-  int num=pt.get<int>("tool.workers_number");
-  boost::thread_group g;
-  
-  
-  for (int i=0;i<num;i++)
-  { WorkerClass *obj=new WorkerClass();
-    if (i==0) ((NLPWorker*) obj)->static_init(pt);
-	boost::thread *workerThread=new boost::thread(worker,pt,i,(NLPWorker*)obj);
-	g.add_thread(workerThread);
-  }
-  g.join_all();
-}
-
diff --git a/src/nlpworker.o b/src/nlpworker.o
deleted file mode 100644
index 6509d4d9c3f44a0ef95455364ad9ebda1453cd3c..0000000000000000000000000000000000000000
Binary files a/src/nlpworker.o and /dev/null differ
diff --git a/src/spejd_service b/src/spejd_service
deleted file mode 100644
index 311a4a406030e4b7569f9fcc8114f7d329c764f5..0000000000000000000000000000000000000000
Binary files a/src/spejd_service and /dev/null differ
diff --git a/src/spejd_service.cpp b/src/spejd_service.cpp
index 7fcab2696f82026012ac0c3fb9398ef90e3b7945..38e338e80c7a7ab9079cd1cb437c2c4613a4df67 100644
--- a/src/spejd_service.cpp
+++ b/src/spejd_service.cpp
@@ -1,28 +1,5 @@
-#include "nlpworker.h"
+#include "spejd_service.hpp"
 
-
-#include <boost/property_tree/json_parser.hpp>
-#include <boost/property_tree/ini_parser.hpp> 
-#include <boost/foreach.hpp>
-#include <boost/thread.hpp>
-#define BOOST_NO_CXX11_SCOPED_ENUMS
-#include <boost/filesystem.hpp>
-
-#include <string>
-#include <fstream>
-#include <streambuf>
-
-
-
-#include <spejd.h>
-using namespace libspejd;
-
-class SpejdWorker: public  NLPWorker
-{   void static_init(boost::property_tree::ptree config);
-    void process(std::string task_path, boost::property_tree::ptree &options, std::string output_path);
-	
-	static spejd *engine;
-};
 spejd *SpejdWorker::engine=NULL;
 
 bool copyFile(const char *SRC, const char* DEST)
@@ -38,7 +15,6 @@ bool CopyDir( boost::filesystem::path const & source,
 {
     try
     {
-        // Check whether the function call is valid
         if( !boost::filesystem::exists(source) ||
             !boost::filesystem::is_directory(source) )
         {
@@ -57,7 +33,6 @@ bool CopyDir( boost::filesystem::path const & source,
             return false;
         }
  
-        // Create the destination directory
         if( !boost::filesystem::create_directory( destination ) )
         {
             std::cerr << "Unable to create destination directory"
@@ -104,55 +79,33 @@ bool CopyDir( boost::filesystem::path const & source,
     return true;
 }
  
-
 void SpejdWorker::process(std::string task_path, boost::property_tree::ptree &options, std::string output_path) 
 {   
-    
-    
-	/*std::string filename=output_path+"/ann_morphosyntax.xml";
-	boost::filesystem::create_directory(output_path);
-	boost::filesystem::copy_file(task_path+"/ann_morphosyntax.xml",filename,boost::filesystem::copy_option::overwrite_if_exists);
-	*/
 	std::vector<std::string> filelist;
 	CopyDir(task_path,output_path);
 	filelist.push_back(output_path+"/ann_morphosyntax.xml.gz");
 	engine->process_files(filelist); 
-	
-	/*
-	std::ifstream t(task_path);
-	std::string str((std::istreambuf_iterator<char>(t)),
-                 std::istreambuf_iterator<char>());
-				 
-	std::cerr<<"file read"<<std::endl;
-	std::fstream file;
-	file.open(output_path);
-	std::cerr<<"start processing"<<str.length()<<std::endl;
-	std::string result=engine->process_data(str);
-	std::cerr<<"finish processing"<<std::endl;
-	file << result;
-	file.close();
-	*/
-	//this->tagger->tag_input(task_path, input_format, output_path, output_format);
-	
 }
 
 void SpejdWorker::static_init(boost::property_tree::ptree config)
 {  
 	std::string configname = config.get<std::string>("tool.model");
+    std::cout << "Hello!" << std::endl;
 	engine = spejd::create_instance();
+    std::cout << "Loading model" << std::endl;
 	engine->load_config_file(std::string(configname));
+    std::cout << "Model loaded" << std::endl;
     engine->commit_config();
 }
 
-
-
+void SpejdWorker::process(ptree &data, ptree &options) { 
+} 
 
 INITIALIZE_EASYLOGGINGPP
 
 int main(int argv, char* argc[])
 { 
- 
- run_workers<SpejdWorker>(argv,argc);
+    run_workers<SpejdWorker>(argv,argc);
 }
 
 
diff --git a/src/spejd_service.o b/src/spejd_service.o
deleted file mode 100644
index 27fed32bb7c1568fdd31a4945c50b7d5527c55d1..0000000000000000000000000000000000000000
Binary files a/src/spejd_service.o and /dev/null differ
diff --git a/src/tools.h b/src/tools.h
deleted file mode 100644
index ab185f3beb01c3668dc07217ac0b11e8a931cb95..0000000000000000000000000000000000000000
--- a/src/tools.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#pragma once
-
-#include <string>
-#include <sstream>
-
-#include <boost/uuid/uuid.hpp>
-#include <boost/uuid/uuid_io.hpp>
-#include <boost/uuid/uuid_generators.hpp>
-
-
-template<typename Iterator>
-std::string join(Iterator first, const Iterator last,
-        const std::string& separator)
-{
-    std::string str;
-    for (; first != last; ++first)
-    {
-        str.append(*first);
-        if (first != (last - 1))
-        {
-            str.append(separator);
-        }
-
-    }
-    return str;
-}
-
-std::string uuid()
-{
-    boost::uuids::random_generator generator;
-    boost::uuids::uuid uuid(generator());
-
-    std::stringstream sstr;
-    sstr<<boost::uuids::to_string(uuid);
-    return sstr.str();
-}