В процессе отладки или работы приложения часто необходимо вести лог или выдавать отладочную информацию на экран или в файл.
Можно, конечно, воспользоваться сторонними библиотеками или написать собственный класс для этого. Однако, чтобы некоторые отладочные сообщения или конструкции не попали в "релизную" версию придется их отделять конструкциями типа:
#ifdef DEBUG
//Вывод отладочного сообщения в файл или на экран
#endif
Что может сильно захламить код...
Поэтому был написан следующий модуль лишенный таких недостатков:
#ifndef CALOG_H
#define CALOG_H
/******************************************************************************
* Здесь написаны макросы для выдачи отладочных сообщений на экран или файл
*
* PRINT1 (a) - Выдает сообщение (a) на экран.
* PRINT2 (a,b) - Выдает два сообщения (a) (b) на экран.
* PRINT3 (a,b,c) - Выдает три сообщения (a) (b) (с) на экран
* Аналогично для TOLOG - только сообщения идут в файл.
* Файл задается константой logFile1
*
* Макросы будут работать если определен DEBUG
* Если нет, то нет....
*
*
* Данная реализация уверенно работает под gcc 4.4.0 и С++0x.
* Для работы с "широкими" символами std::ofstream заменить на std::wofstream
*
*
* А также можно определить:
*#define TIMETOLOG - пишет в лог время
*#define LINETOLOG - пишет в лог имя файла и номер строки
*
* Pingi-Pingi production
******************************************************************************/
#ifdef DEBUG
#ifndef LOGFILE
#define LOGFILE "Mylog.log"
#endif
#include <fstream>
#include <iostream>
#ifdef TIMETOLOG
#include <time.h>
#include <iomanip>
#endif
//Если выдаем имя файла и строку
#ifdef LINETOLOG
#define LINETO fwout <<"File:"<<__FILE__<<" Line:"<<__LINE__<<" | ";
#endif
//Если выдаем время
#ifdef TIMETOLOG
#define TIMETO \
{\
time_t rawtime;\
struct tm *timeinfo;\
time ( &rawtime );\
timeinfo = localtime ( &rawtime );\
fwout <<std::setw(2) << std::setfill ('0')\
<<timeinfo->tm_hour<<":"\
<<std::setw(2) << std::setfill ('0')\
<<timeinfo->tm_min<<":"\
<<std::setw(2) << std::setfill ('0')\
<<timeinfo->tm_sec<<" | ";\
};
#endif
#ifndef LINETO
#define LINETO
#endif
#ifndef TIMETO
#define TIMETO
#endif
#define PRINT1(a) \
{\
std::ostream &fwout=std::cout;\
TIMETO\
LINETO\
fwout << (a) << std::endl;\
};
#define PRINT2(a,b) \
{\
std::ostream &fwout=std::cout;\
TIMETO\
LINETO\
fwout << (a) << (b) << std::endl;\
};
#define PRINT3(a,b,c) \
{\
std::ostream &fwout=std::cout;\
TIMETO\
LINETO\
fwout << (a) << (b) << (c) << std::endl;\
};
#define TOLOG1(a) \
{\
std::ofstream fwout (LOGFILE,std::ios_base::out|std::ios_base::app);\
if(fwout.is_open())\
{\
TIMETO\
LINETO\
fwout << (a) << std::endl;\
fwout.close();\
}\
};
#define TOLOG2(a,b) \
{\
std::ofstream fwout (LOGFILE,std::ios_base::out|std::ios_base::app);\
if(fwout.is_open())\
{\
TIMETO\
LINETO\
fwout << (a);\
fwout << (b);\
fwout <<std::endl;\
fwout.close();\
}\
};
#define TOLOG3(a,b,c) \
{\
std::ofstream fwout (LOGFILE,std::ios_base::out|std::ios_base::app);\
if(fwout.is_open())\
{\
TIMETO\
LINETO\
fwout << (a) << (b) << (c) <<std::endl;\
fwout.close();\
}\
};
#else
#define PRINT1(a)
#define PRINT2(a,b)
#define PRINT3(a,b,c)
#define TOLOG1(a)
#define TOLOG2(a,b)
#define TOLOG3(a,b,c)
#endif
#endif
Если мы в своей программе определяем #DEBUG, то у нас работают ф-ии PRINT и TOLOG если же #DEBUG не определен, то вместо них в код будут подставлены аналогичные ф-ии пустышки.
И все...
Ниже пример использования данного модуля:
//Пример использования CALog.hpp
//pingi-pingi production
//http://pingi-pingi.blogspot.com/
#include <stdlib.h>
//Важно!
//Определяем параметры до #include "CALog.hpp"
#define DEBUG
#define LOGFILE "Mylog2.log"
#define TIMETOLOG
#include "CALog.hpp"
int main(int argc, char *argv[])
{
//пишем в файл
TOLOG1("Warrning...");
TOLOG2("Parametr count = ", 5666.3444);
//выдаем на экран (stdout)
PRINT2("Problem Here, Number is = ",300);
PRINT3("Problem Here:","Param = ",0);
system("PAUSE");
return EXIT_SUCCESS;
}
Конечно такое решение не лишено проблем...
Например, хорошо бы сделать для этого модуля свое пространство имен. т.к. используемые в этом коде переменные могут привести к конфликту с именованием переменных в основной программе. Однако оно работает и весьма успешно...