Ведение лога

Часто приходится вести отладочную информацию, чаще всего, в простых случаях это делается в консоль. Но гораздо чаще необходимо вести лог и в консоль, и в файл.
Поведаю Вам о простом классике логирования, который симулирует стандартные cout, cerr, используя шаблонную функцию-оператор <<. Расскажу о некоторых специфичных моментах с которыми столкнулся.

[spoiler]
Log.h
/*http://esate.ru, Flashhell*/

#ifndef LOG_H
#define LOG_H

#include <fstream>
#include <iostream>

namespace support
{

class Log
{
public:
  Log();
  ~Log();

  template <class T>
  Log& operator<<(const T& p)
  {
   #ifdef _DEBUG
    std::cerr<<p;
   #endif
   log_file<<p;
   log_file.flush();
   return *this;
  }

private: 
  std::ofstream log_file;
};

extern Log LogOut;

}// end namespace
#endif


Как видно из шаблонной функции(operator<<;) она просто, принимает шаблонный параметр и в случаи дебажной сборки отправляет его на стандартный вывод std::cerr. Думаю в релизе консоли уже не будет. std::cerr я использовал потому, что он не буферизирован, это дает надежду, что выведется все что можно перед закрытием приложения. Также параметр сразу записывает в файл log_file. Файлу сразу же делаем flush(), чтоб все что есть в буфере было записано. Оператор возвращает ссылку на объект, что позволяет использовать его неоднократно, как cout: cout<<"вывод"<<"еще вывод".

/*http://esate.ru, Flashhell*/

extern Log LogOut;
Описываем объект LogOut extern-ом, а сам глобальный объект будет определятся в .cpp. Это сделано по примеру объектов cout, cerr, для того, чтобы был один глобальный объект и к нему можно легко обращаться из любого места где подключен заголовочный файл Log.h. Объект будет жив до конца работы программы.
[/code]
Log.cpp
/*http://esate.ru, Flashhell*/

#include "Log.h"

namespace support
{

Log LogOut;

Log::Log()
:log_file("Log.txt")
{
}

Log::~Log()
{
  log_file.close();
}

}//end namespace


Здесь все просто в конструкторе открываем файл, со стандартным именем. А в деструкторе его закрываем.


Использование:
/*http://esate.ru, Flashhell*/

#include "Log.h"

int main(int argc, char** argv)
{
  support::LogOut<<"Hello log! "<<"\n";
  support::LogOut<<2389<<" ";
  support::LogOut<<2389.23<<"\n";
  return 0;
}


К минусам, этого подхода можно отнести, невозможность использовать манипуляторы потока, такие, как std::endl. А также, то что запись происходит в основном, единственном потоке, что может негативно сказаться, в случаи реалтайм приложения, которое постоянно введет лог. Знаю об этом не понаслышке, так как у меня ноутбук с экономичный по энергопотреблению жестким диском, который вечно паркуют головки.>( И поэтому некоторые написанные мной игры вечно лагают зависают, на небольшие промежутки времени(пока шпиндель снова раскрутится). К счастью на компьютерах, или ноутбуках не с такими как у меня HDD, эти лаги могут напрочь отсутствовать.

Надеюсь кому нибудь пригодится. Об ошибках пишите в личку.
0       2835        10.02.2013

^