C++ Utils  0.1
utils/logger.h
Go to the documentation of this file.
00001 
00037 #ifndef UTILS_LOGGER_H
00038 #define UTILS_LOGGER_H
00039 
00040 #include "utils/timeutils.h"
00041 
00042 #include <algorithm>
00043 #include <cstdlib>
00044 #include <ctime>
00045 #include <execinfo.h>
00046 #include <iostream>
00047 #include <sstream>
00048 #include <vector>
00049 
00050 #ifndef LOG_LEVEL
00051 #ifdef NDEBUG
00052 #define LOG_LEVEL 2
00053 #else // NDEBUG
00054 #define LOG_LEVEL 3
00055 #endif // NDEBUG
00056 #endif // LOG_LEVEL
00057 
00058 #ifndef LOG_PREFIX
00059 #define LOG_PREFIX "%a %b %d %X"
00060 #endif // DEBUG_PRFIX
00061 
00062 #ifndef LOG_ABORT
00063 #ifdef MPI_VERSION
00064 #define LOG_ABORT MPI_Abort(MPI_COMM_WORLD, -1)
00065 #else // MPI_VERSION
00066 #define LOG_ABORT abort()
00067 #endif // MPI_VERSION
00068 #endif // LOG_ABORT
00069 
00070 #ifndef BACKTRACE_SIZE
00071 #define BACKTRACE_SIZE 50
00072 #endif // BACKTRACE_SIZE
00073 
00077 namespace utils
00078 {
00079 
00085 class Logger
00086 {
00087 public:
00089         enum DebugType {
00091                 DEBUG,
00093                 INFO,
00095                 WARNING,
00097                 ERROR
00098         };
00099 private:
00101         struct Stream {
00103                 DebugType type;
00105                 int rank;
00107                 int ref;
00109                 std::stringstream buffer;
00111                 bool space;
00112 
00116                 Stream(DebugType t, int r)
00117                         : type(t), rank(r), ref(1),
00118                         buffer(std::stringstream::out),
00119                         space(true) { }
00120         } *stream;
00124 public:
00132         Logger(DebugType t, int rank)
00133                 : stream(new Stream(t, rank))
00134         {
00135                 stream->buffer << utils::TimeUtils::timeAsString(LOG_PREFIX);
00136 
00137                 switch (t) {
00138                 case DEBUG:
00139                         stream->buffer << ", Debug: ";
00140                         break;
00141                 case INFO:
00142                         stream->buffer << ", Info:  ";
00143                         break;
00144                 case WARNING:
00145                         stream->buffer << ", Warn:  ";
00146                         break;
00147                 case ERROR:
00148                         stream->buffer << ", Error: ";
00149                         break;
00150                 }
00151         }
00155         Logger(const Logger& o) : stream(o.stream) { stream->ref++; };
00156         ~Logger()
00157         {
00158                 if (!--stream->ref) {
00159                         if (stream->rank == 0) {
00160                                 if (stream->type == INFO)
00161                                         std::cout << stream->buffer.str() << std::endl;
00162                                 else
00163                                         std::cerr << stream->buffer.str() << std::endl;
00164                         }
00165 
00166                         if (stream->type == ERROR) {
00167                                 delete stream;
00168                                 stream = 0L;    // Avoid double free if LOG_ABORT does
00169                                                                 // does not exit the program
00170 
00171                                 // Backtrace
00172                                 if (BACKTRACE_SIZE > 0) {
00173                                         void *buffer[BACKTRACE_SIZE];
00174                                         int nptrs = backtrace(buffer, BACKTRACE_SIZE);
00175                                         char** strings = backtrace_symbols(buffer, nptrs);
00176 
00177                                         // Buffer output to avoid interlacing with other processes
00178                                         std::stringstream outputBuffer;
00179                                         outputBuffer << "Backtrace:" << std::endl;
00180                                         for (int i = 0; i < nptrs; i++)
00181                                                 outputBuffer << strings[i] << std::endl;
00182                                         free(strings);
00183 
00184                                         // Write backtrace to stderr
00185                                         std::cerr << outputBuffer.str() << std::flush;
00186                                 }
00187 
00188                                 LOG_ABORT;
00189                         }
00190 
00191                         delete stream;
00192                 }
00193         }
00194 
00198         Logger &operator=(const Logger& other)
00199         {
00200                 if (this != &other) {
00201                         Logger copy(other);
00202                         std::swap(stream, copy.stream);
00203                 }
00204                 return *this;
00205         }
00206 
00207 
00208         /********* Space handling *********/
00209 
00213         Logger &space()
00214         {
00215                 stream->space = true;
00216                 stream->buffer << ' ';
00217                 return *this;
00218         }
00222         Logger &nospace()
00223         {
00224                 stream->space = false;
00225                 return *this;
00226         }
00230         Logger &maybeSpace()
00231         {
00232                 if (stream->space)
00233                         stream->buffer << ' ';
00234                 return *this;
00235         }
00236 
00240         template<typename T>
00241         Logger &operator<<(T t)
00242         {
00243                 stream->buffer << t;
00244                 return maybeSpace();
00245         }
00246 
00250         Logger &operator<<(const std::string& t)
00251         {
00252                 stream->buffer << '"' << t << '"';
00253                 return maybeSpace();
00254         }
00255 
00259         Logger &operator<<(std::string& t)
00260         {
00261                 stream->buffer << '"' << t << '"';
00262                 return maybeSpace();
00263         }
00264 
00268         Logger &operator<<(std::ostream& (*func)(std::ostream&))
00269         {
00270                 stream->buffer << func;
00271                 return *this; // No space in this case
00272         }
00273 
00277         Logger &operator<<(Logger& (*func)(Logger&))
00278         {
00279                 func(*this);
00280                 return *this;
00281         }
00282 };
00283 
00292 inline Logger& space(Logger &logger)
00293 {
00294         return logger.space();
00295 }
00296 
00303 inline Logger& nospace(Logger &logger)
00304 {
00305         return logger.nospace();
00306 }
00307 
00311 class NoLogger
00312 {
00313 public:
00314         NoLogger() {};
00315         ~NoLogger() {};
00316 
00320         template<typename T>
00321         NoLogger &operator<<(const T&)
00322         {
00323                 return *this;
00324         }
00325 
00329         NoLogger &operator<<(std::ostream& (*func)(std::ostream&))
00330         {
00331                 return *this;
00332         }
00333 
00338         NoLogger &operator<<(Logger& (*func)(Logger&))
00339         {
00340                 return *this;
00341         }
00342 };
00343 
00349 template <typename T>
00350 inline Logger &operator<<(Logger debug, const std::vector<T> &list)
00351 {
00352         debug.nospace() << '(';
00353         for (size_t i = 0; i < list.size(); i++) {
00354                 if (i)
00355                         debug << ", ";
00356                 debug << list[i];
00357         }
00358         debug << ')';
00359 
00360         return debug.space();
00361 }
00362 
00363 }
00364 
00365 // Define global functions
00366 
00372 inline
00373 utils::Logger logError()
00374 {
00375         return utils::Logger(utils::Logger::ERROR, 0);
00376 }
00377 
00378 #if LOG_LEVEL >= 1
00379 
00384 inline
00385 utils::Logger logWarning( int rank = 0 )
00386 {
00387         return utils::Logger(utils::Logger::WARNING, rank);
00388 }
00389 #else // LOG_LEVEL >= 1
00390 
00395 inline
00396 utils::NoLogger logWarning( int = 0 ) { return utils::NoLogger(); }
00397 #endif // LOG_LEVEL >= 1
00398 
00399 #if LOG_LEVEL >= 2
00400 
00405 inline
00406 utils::Logger logInfo( int rank = 0 )
00407 {
00408         return utils::Logger(utils::Logger::INFO, rank);
00409 }
00410 #else // LOG_LEVEL >= 2
00411 
00416 inline
00417 utils::NoLogger logInfo( int = 0 ) { return utils::NoLogger(); }
00418 #endif // LOG_LEVEL >= 2
00419 
00420 #if LOG_LEVEL >= 3
00421 
00426 inline
00427 utils::Logger logDebug( int rank = 0 )
00428 {
00429         return utils::Logger(utils::Logger::DEBUG, rank);
00430 }
00431 #else // LOG_LEVEL >= 3
00432 
00437 inline
00438 utils::NoLogger logDebug( int = 0 ) { return utils::NoLogger(); }
00439 #endif // LOG_LEVEL >= 3
00440 
00441 
00442 // Use for variables unused when compiling with NDEBUG
00443 #ifdef NDEBUG
00444 #define NDBG_UNUSED(x) ((void) x)
00445 #else // NDEBUG
00446 #define NDBG_UNUSED(x)
00447 #endif // NDEBUG
00448 
00449 #endif // UTILS_LOGGER_H
 All Classes Namespaces Files Functions Variables Enumerations Enumerator Defines