понедельник, 11 октября 2010 г.

Простое ведение лога на С++

В процессе отладки или работы приложения часто необходимо вести лог или выдавать отладочную информацию на экран или в файл.
Можно, конечно, воспользоваться сторонними библиотеками или написать собственный класс для этого. Однако, чтобы некоторые отладочные сообщения или конструкции не попали в "релизную" версию придется их отделять конструкциями типа:

#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;
} 

Конечно такое решение не лишено проблем...
Например, хорошо бы сделать для этого модуля свое пространство имен. т.к. используемые в этом коде переменные  могут привести к конфликту с именованием переменных в основной программе. Однако оно работает и весьма успешно...

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

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