среда, 21 августа 2013 г.

logger extension

logger extension
/** Продолжение предыдущих постов про logger */

/* Давайте не много порассуждаем: зачем макросы? что значит легко
   используем? что значит расширяем? а эффективен ли?*/

/** Макросы. В данном случае они действительно необходимы. Во-первых,
    это компактно выглядит. Хотя вы можете сказать, что сложного
    сделать так? */
typedef logger<std::ostream> std_logger;
std_logger mylogger()
{
  return std_logger(std::cout);
}

/** и использовать так: */
mylogger().get() << "Hello, world!" << 123;

/** Вы правы. Но в макросах у нас идёт ещё и проверка уровня
    лога. Проверку уровня лога нельзя выносить в функцию, так как
    понадобится излишнее конструирование сообщения, а если это
    DEBUG-сообщение, а уровень выводимых сообщений ERROR, то будет
    происходить лишние вычисления сообщения. Если условие ложное, то
    тело условия не вычисляется. Ещё один аргумент в пользу макросов -
    возможность указать местоположение в коде с помощью _FILE_ и
    _LINE_ и т. д. */

/** Легко используем.  За счёт использования шаблона, можно подставить
    не только std::ostream, но и вообще любой другой класс,
    поддерживающий операцию "<<", даже
    boost::archive::text_oarchive. */

/** Легко расширяем.  Допустим понадобилось синхронизовать сообщения
    между различными тредами в файл. Делается просто с помощью
    boost::mutex. Создадим тредобезопачный логгер: */

template <typename Out, typename Mutex>
struct logger_safe: logger<Out>
{
  logger_safe(Out& out, Mutex& mutex)
    : logger<Out>(out)
    , m_locker(mutex) {}

private:
  boost::unique_lock<Mutex> m_locker;
};

/** При создании он будет лочить мьютекс, который ему
    подаётся. Использование: */

typedef logger_safe<std::ostream, boost::mutex> std_logger_safe;

boost::mutex mutex;
std_logger_safe(std::cout, mutex).get() << "Hello, world! Safely!";

/** То есть мютекс лочится на время существования объекта, когда мы
    вводим цельную строку и разлочивается автоматически после
    окончания ввода */

/** Эффективность.  Обычно логгеры формируют строку, чаще std::string,
    которую ещё надо сформировать. Этот логгер обращается
    непосредственно к объекту вывода и не требует промежуточной
    временной строки, это быстро и очень удобно.  */

/** Заключение.  Я не говорю, что этот логгер подходит для любого
    проекта, но на основе него и его принципов можно написать гораздо
    более мощные логгеры. Позже я покажу как выводить в несколько
    файлов/потоков одновременно, учитывая уровень сообщений. */

Комментариев нет:

Отправить комментарий