Log.h

00001 #ifndef __LOG_CLASS_HEADER__
00002 #define __LOG_CLASS_HEADER__
00003 
00004 /**
00005  * This file contains class for logging and filtering output.
00006  * This header file also includes a debug macro which
00007  * tracks any possible memory leaks within the program.
00008  *
00009  * @author Tomasz Przedzinski
00010  * @date 14 November 2009
00011  */
00012 
00013 #include <iostream>
00014 #include <string>
00015 #include <sstream>
00016 #include <stdlib.h>
00017 #include <cstring>
00018 #include <list>
00019 
00020 using std::stringstream;
00021 using std::string;
00022 using std::streambuf;
00023 using std::ostream;
00024 using std::list;
00025 using std::cout;
00026 using std::endl;
00027 
00028 namespace Tauolapp
00029 {
00030 
00031 class Log
00032 {
00033 public:
00034   /** Shows the summary of all messages. */
00035   static void Summary();
00036 
00037   /** Shows the summary at the end of the program. */
00038   static void SummaryAtExit()              { atexit(Summary);      }
00039 
00040   /** Adds the decay to the counter. The type is:
00041       0 - gun, 1 - no mothers & grandmothers, 2 - no mothers, 3 - ok. */
00042   static void AddDecay(int type);
00043 
00044   /** Four logging entries. Usage:
00045             Log::Info()<<"Logging some info: "<<8<<" > "<<7.9<<endl;
00046       Use Log::Info(false) if you don't want the message to be counted.*/
00047   static ostream& Debug(unsigned short int code=0, bool count=true);
00048   static ostream& Info(bool count=true);
00049   static ostream& Warning(bool count=true);
00050   static ostream& Error(bool count=true);
00051 
00052   /** Turns off or on particular types of messages
00053       By default, only debugging messages are turned off. */
00054   static void LogInfo   (bool flag=true)  { iAction=flag;         }
00055   static void LogWarning(bool flag=true)  { wAction=flag;         }
00056   static void LogError  (bool flag=true)  { eAction=flag;         }
00057 
00058   static void LogAll    (bool flag=true)  { iAction=wAction=eAction=flag; dRangeS=0; dRangeE=65535; }
00059 
00060         /** Sets the range of debug codes that will be printed.
00061             By default, the debug messages are turned off. */
00062   static void LogDebug(unsigned short s=0,unsigned short e=65535)         { dRangeS=s; dRangeE=e;   }
00063 
00064   /** Asserts logical value. If the assertion fails, the default message or 'text'
00065             will be printed and the program will terminate.
00066             Program termination can be suppressed by Log::IgnoreFailedAsserts(); */
00067   static void Assert(bool check, char *text=NULL);
00068 
00069   /** Terminates the program with added default message or 'text'.
00070             It can be suppressed by Log::IgnoreFatal(); */
00071   static void Fatal(string text, unsigned short int code=0);
00072   static void Fatal(unsigned short int code=0)                            { Fatal("",code);       }
00073 
00074   /** Redirects output to log. Redirection can be done for a block of code
00075       or for one function only. Redirection can be turned off by using
00076       Log::IgnoreRedirection(); If the target is one of the log streams
00077       (for example): Log::RedirectOutput( someFunction, Log::Info() );
00078       You can turn the function's messages off by turning the apropriate
00079       log entries off. The redirected code will still be executed,
00080       only messages are redirected. */
00081   static void RedirectOutput(void (*func)(), ostream& where=*out);
00082   static void RedirectOutput(ostream& where=*out);
00083   /** WARNING! If you're redirecting more than one function, do not forget
00084       to use RevertOutput() afterwards. */
00085   static void RevertOutput()                      { std::cout.rdbuf(bCout); std::cerr.rdbuf(bCerr); }
00086 
00087   /** Do not exit when Log::Assert() check is false.
00088       The number of failed asserts will be listed in the summary. */
00089   static void IgnoreFailedAssert(bool flag=true)                           { asAction=!flag;        }
00090 
00091   /** Ignores redirections of functions' output.
00092       The function will still be called in a normal way. */
00093   static void IgnoreRedirection(bool flag=true)                            { rAction=!flag;         }
00094 
00095   /** Do not exit when Log::Fatal() with the code within the provided range is called.
00096             The number of ignored fatal errors will be listed in the summary. */
00097   static void IgnoreFatal(unsigned short s=0,unsigned short e=65535) { faRangeS=s; faRangeE=e; }
00098 
00099   /** Change the output of the logged messages.
00100       Log::SetOutput(cerr);                    //changes the output to cerr
00101       Log::SetOutput(new ofstream("log.txt")); //changes the output to a file "log.txt" */
00102   static void SetOutput(ostream *newOut)                                    { out=newOut;           }
00103   static void SetOutput(ostream &newOut)                                    { out=&newOut;          }
00104 
00105   /** Change the limit of warnings that will be displayed. Set to 0 for no limit. */
00106   static void SetWarningLimit(int x)                                        { warnLimit=x;          }
00107 
00108 protected:
00109   static streambuf *bCout,*bCerr;
00110   static ostream *out;
00111   static stringstream buf;
00112   static int  warnLimit;
00113   static int  decays[4];
00114   static int  dCount,dRangeS,dRangeE,faCount,faRangeS,faRangeE;
00115   static int  iCount, wCount, eCount, asCount, asFailedCount;
00116   static bool iAction,wAction,eAction,asAction,rAction;
00117 /**
00118   Memory leak tracking section. Compile with #define _LOG_DEBUG_MODE_ to turn it on.
00119   WARNING! Increases execution time significantly. Useful only for debug purposes.
00120 */
00121 protected:
00122   typedef struct
00123   {
00124     unsigned long address;
00125     unsigned long size;
00126     char  file[64];
00127     unsigned long line;
00128   } Pointer;
00129   static list<Pointer*> *PointerList;
00130 public:
00131 #ifdef _LOG_DEBUG_MODE_
00132   static void NewPointer(unsigned long address,  unsigned long size,  const char *file, unsigned long line)
00133   {
00134     if(!PointerList)
00135     {
00136       PointerList = new list<Pointer *>();
00137       atexit(PrintAllocatedPointers);
00138     }
00139     Pointer *info = new Pointer();
00140     info->address = address;
00141     info->size    = size;
00142     info->line    = line;
00143     strncpy(info->file, file, 63);
00144     PointerList->push_front(info);
00145   }
00146   static void DeletePointer(unsigned long address)
00147   {
00148     if(!PointerList) return;
00149     for(list<Pointer*>::iterator i = PointerList->begin(); i!=PointerList->end(); i++)
00150     {
00151       if((*i)->address == address)
00152       {
00153         PointerList->remove((*i));
00154         break;
00155       }
00156     }
00157   }
00158   static bool PointerCompare(Pointer *one, Pointer *two)
00159   {
00160     int eq = strcmp(one->file,two->file);
00161     if(eq<0) return true;
00162     else if(eq>0) return false;
00163     return (one->line <= two->line);
00164   }
00165   static void PrintAllocatedPointers()
00166   {
00167     if(!PointerList) return;
00168     int pointers=0,buf=0;
00169     unsigned long total=0;
00170     char *lastS=" ";
00171     int lastL=0;
00172     if(PointerList->size()==0)
00173     {
00174       cout<<"----------------------------UNFREED MEMORY POINTERS----------------------------\n";
00175       cout<<"                                 ... NONE ...\n";
00176       cout<<"-------------------------------------------------------------------------------\n";
00177       return;
00178     }
00179     PointerList->sort(PointerCompare);
00180     cout<<"---------------------------UNFREED MEMORY POINTERS---------------------------\n";
00181     for(list<Pointer*>::iterator i = PointerList->begin(); i!=PointerList->end(); i++)
00182     {
00183       total+=(*i)->size;
00184       ++pointers;
00185       if(strcmp(lastS,(*i)->file)==0)
00186       {
00187         if(lastL==(*i)->line)
00188         {
00189           printf("%56s%10lub (%lu)\n"," ",(*i)->size,(*i)->address);
00190           continue;
00191         }
00192       }
00193       lastS=(*i)->file;
00194       lastL=(*i)->line;
00195       printf("%s%n:",(*i)->file,&buf);
00196       printf("%-*lu%10lub (%lu)\n",55-buf,(*i)->line,(*i)->size,(*i)->address);
00197     }
00198     cout<<endl<<total<<"\tbytes"<<endl;
00199     cout<<pointers<<"\tpointers"<<endl;
00200     cout<<"-------------------------------------------------------------------------------\n";
00201   };
00202 #endif //_LOG_DEBUG_MODE_
00203 };
00204 
00205 #ifdef _LOG_DEBUG_MODE_
00206 
00207 /**
00208     Redeclare new and delete to use the tracking feature.
00209     To use __FILE__ and __LINE__ macro efficiently this header file
00210     should be included in all separately compiled libraries.
00211 */
00212 
00213 inline void* operator new(size_t size, const char *filename, int line)
00214 {
00215   void *ptr = (void *)malloc(size);
00216   Log::NewPointer((unsigned long)ptr, size, filename, line);
00217   return(ptr);
00218 }
00219 
00220 inline void  operator delete(void *p)
00221 {
00222   Log::DeletePointer((unsigned long)p);
00223   free(p);
00224 }
00225 
00226 #define new new(__FILE__, __LINE__)
00227 
00228 #endif //_LOG_DEBUG_MODE_
00229 
00230 } // namespace Tauolapp
00231 #endif
Generated on Sun Oct 20 20:24:08 2013 for C++InterfacetoTauola by  doxygen 1.6.3