dlvhex  2.1.0
include/dlvhex2/Logger.h
Go to the documentation of this file.
00001 /* dlvhex -- Answer-Set Programming with external interfaces.
00002  * Copyright (C) 2005, 2006, 2007 Roman Schindlauer
00003  * Copyright (C) 2006, 2007, 2008, 2009, 2010 Thomas Krennwallner
00004  * Copyright (C) 2009, 2010 Peter Schüller
00005  * 
00006  * This file is part of dlvhex.
00007  *
00008  * dlvhex is free software; you can redistribute it and/or modify it
00009  * under the terms of the GNU Lesser General Public License as
00010  * published by the Free Software Foundation; either version 2.1 of
00011  * the License, or (at your option) any later version.
00012  *
00013  * dlvhex is distributed in the hope that it will be useful, but
00014  * WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  * Lesser General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with dlvhex; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
00021  * 02110-1301 USA.
00022  */
00023 
00031 #ifndef LOGGER_HPP_INCLUDED__17092010
00032 #define LOGGER_HPP_INCLUDED__17092010
00033 #include <boost/preprocessor/cat.hpp>
00034 #include <boost/optional.hpp>
00035 #include <boost/cstdint.hpp>
00036 
00037 #include <boost/thread/mutex.hpp>
00038 #include <boost/thread/tss.hpp>
00039 
00040 #ifndef NDEBUG
00041 # define LOG_SCOPED_LOCK(varname) boost::mutex::scoped_lock varname(Logger::Mutex());
00042 #else
00043 # define LOG_SCOPED_LOCK(varname) do { } while(false)
00044 #endif
00045 
00046 #include <iostream>
00047 #include <iomanip>
00048 #include <sstream>
00049 
00050 // singleton logger class
00051 class Logger
00052 {
00053 public:
00054   // levels are specified and can be activated via bitmasks
00055   // (all 32 bits may be used)
00056   // logger itself logs on DBG
00057   typedef uint32_t Levels;
00058   static const Levels DBG =     0x01;
00059   static const Levels INFO =    0x02;
00060   static const Levels WARNING = 0x04;
00061   static const Levels ERROR =   0x08;
00062 
00063   // this is now very dlvhex-specific
00064   static const Levels PLUGIN =  0x10; // plugin related things
00065   static const Levels ANALYZE = 0x20; // program analysis
00066   static const Levels MODELB =  0x40; // model building
00067   static const Levels STATS  =  0x80; // statistic information
00068 
00069 private:
00070   std::ostream& out;
00071 //  std::string indent;
00072   boost::thread_specific_ptr<std::string> indent;
00073   Levels printlevels;
00074   // width of field for level printing, if 0, level is not printed
00075   int levelwidth;
00076 
00077 private:
00078   // default output is std::cerr, change this later with stream() = ...
00079   // default output is all output levels, change this later with printlevels() = ...
00080   // default output is i hex character of level printed, change this later with levelwidth() = ...
00081   Logger():
00082     out(std::cerr), printlevels(~static_cast<Levels>(0)), levelwidth(1) {}
00083 
00084   ~Logger()
00085     {
00086       stream() << std::endl;
00087       startline(DBG);
00088       #ifndef NDEBUG
00089       stream() << "clean exit!" << std::endl;
00090       #endif
00091     }
00092 
00093 public:
00094   static Logger& Instance();
00095   static boost::mutex& Mutex();
00096 
00097   inline std::ostream& stream()
00098     { return out; }
00099 
00100   void setPrintLevels(Levels levels);
00101   void setPrintLevelWidth(int width);
00102   Levels getPrintLevels() const;
00103 
00104   // this method does not ask shallPrint!
00105   inline void startline(Levels forlevel)
00106     {
00107       if (!indent.get()) indent.reset(new std::string(""));
00108       if( levelwidth == 0 ){
00109         out << *indent;
00110       }else{
00111         out << std::hex << std::setw(levelwidth) << forlevel << std::dec << " " << *indent;
00112       }
00113     }
00114 
00115   inline bool shallPrint(Levels forlevel)
00116     { return (printlevels & forlevel) != 0; }
00117 
00118   friend class Closure;
00119   class Closure
00120   {
00121   private:
00122     Logger& l;
00123     Levels level;
00124     unsigned cutoff;
00125     bool message;
00126 
00127     inline void sayHello()
00128     {
00129       // hello message
00130       if( message )
00131       {
00132         l.startline(level);
00133         l.stream() << "ENTRY" << std::endl;
00134       }
00135     }
00136 
00137     inline void sayGoodbye()
00138     {
00139       // goodbye message
00140       if( message )
00141       {
00142         l.startline(level);
00143         l.stream() << "EXIT" << std::endl;
00144       }
00145     }
00146 
00147   public:
00148     // generic
00149     Closure(Logger& l, Levels level, const std::string& str, bool message):
00150       l(l), level(level), message(message)
00151     {
00152       if (!l.indent.get()) l.indent.reset(new std::string(""));
00153       cutoff = l.indent->size();
00154 
00155       if( l.shallPrint(level) )
00156       {
00157         LOG_SCOPED_LOCK(lock);
00158         *l.indent += str + " ";
00159         sayHello();
00160       }
00161     }
00162 
00163     // with value (converted/reinterpret-casted to const void* const)
00164     Closure(Logger& l, Levels level, const std::string& str, const void* const val, bool message):
00165       l(l), level(level), message(message)
00166     {
00167       if (!l.indent.get()) l.indent.reset(new std::string(""));
00168       cutoff = l.indent->size();
00169 
00170       if( l.shallPrint(level) )
00171       {
00172         LOG_SCOPED_LOCK(lock);
00173         std::stringstream ss;
00174         ss << str << "/" << val << " ";
00175         *l.indent += ss.str();
00176         sayHello();
00177       }
00178     }
00179 
00180     ~Closure()
00181     {
00182       if (!l.indent.get()) l.indent.reset(new std::string(""));
00183       if( l.shallPrint(level) )
00184       {
00185         LOG_SCOPED_LOCK(lock);
00186         sayGoodbye();
00187         // restore indentation level
00188         l.indent->erase(cutoff);
00189       }
00190     }
00191   };
00192 
00193   class Init
00194   {
00195   public:
00196     Init(Levels levels)
00197     {
00198       Logger::Instance().setPrintLevels(levels);
00199     }
00200   };
00201 };
00202 
00203 // the following will always be realized
00204 //#ifndef NDEBUG
00205 #  define LOG(level,streamout) do { LOG_SCOPED_LOCK(lock); \
00206      if( Logger::Instance().shallPrint(Logger:: level) ) { \
00207        Logger::Instance().startline(Logger:: level); \
00208        Logger::Instance().stream() << streamout << std::endl; \
00209      } } while(false);
00210 #    define LOG_CLOSURE_ID BOOST_PP_CAT(log_closure_,__LINE__)
00211 #  define LOG_INDENT(level)              Logger::Closure LOG_CLOSURE_ID (Logger::Instance(), Logger:: level, "  ", false)
00212 #  define LOG_SCOPE(level,name,msg)      Logger::Closure LOG_CLOSURE_ID (Logger::Instance(), Logger:: level, name, msg)
00213 #  define LOG_VSCOPE(level,name,val,msg) Logger::Closure LOG_CLOSURE_ID (Logger::Instance(), Logger:: level, name, reinterpret_cast<const void* const>(val), msg)
00214 /*
00215 #else
00216 #  define LOG(level,streamout)          do { } while(false)
00217 #  define LOG_CLOSURE_ID BOOST_PP_CAT(log_closure_,__LINE__) do { } while(false)
00218 #  define LOG_INDENT(level)                 do { } while(false)
00219 #  define LOG_SCOPE(level,name,msg)         do { } while(false)
00220 #  define LOG_VSCOPE(level,name,val,msg)    do { } while(false)
00221 #endif
00222 */
00223 
00224 #  define LOG_INIT(setlevel)             namespace { Logger::Init LOG_CLOSURE_ID (setlevel); }
00225 
00226 
00227 // the following are debug-flag dependant
00228 #ifndef NDEBUG
00229 #  define DBGLOG(level,streamout)           LOG(level,streamout)
00230 #  define DBGLOG_INDENT(level)              LOG_INDENT(level)
00231 #  define DBGLOG_SCOPE(level,name,msg)      LOG_SCOPE(level,name,msg)
00232 #  define DBGLOG_VSCOPE(level,name,val,msg) LOG_VSCOPE(level,name,val,msg)
00233 #else
00234 #  define DBGLOG(level,streamout)           do { } while(false)
00235 #  define DBGLOG_INDENT(level)              do { } while(false)
00236 #  define DBGLOG_SCOPE(level,name,msg)      do { } while(false)
00237 #  define DBGLOG_VSCOPE(level,name,val,msg) do { } while(false)
00238 #endif
00239 
00240 #endif // LOGGER_HPP_INCLUDED__17092010