dlvhex  2.5.0
include/dlvhex2/Logger.h
Go to the documentation of this file.
00001 /* dlvhex -- Answer-Set Programming with external interfaces.
00002  * Copyright (C) 2005-2007 Roman Schindlauer
00003  * Copyright (C) 2006-2015 Thomas Krennwallner
00004  * Copyright (C) 2009-2016 Peter Schüller
00005  * Copyright (C) 2011-2016 Christoph Redl
00006  * Copyright (C) 2015-2016 Tobias Kaminski
00007  * Copyright (C) 2015-2016 Antonius Weinzierl
00008  *
00009  * This file is part of dlvhex.
00010  *
00011  * dlvhex is free software; you can redistribute it and/or modify it
00012  * under the terms of the GNU Lesser General Public License as
00013  * published by the Free Software Foundation; either version 2.1 of
00014  * the License, or (at your option) any later version.
00015  *
00016  * dlvhex is distributed in the hope that it will be useful, but
00017  * WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019  * Lesser General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU Lesser General Public
00022  * License along with dlvhex; if not, write to the Free Software
00023  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
00024  * 02110-1301 USA.
00025  */
00026 
00034 #ifndef LOGGER_HPP_INCLUDED__17092010
00035 #define LOGGER_HPP_INCLUDED__17092010
00036 
00037 #ifdef HAVE_CONFIG_H
00038 #include "config.h"
00039 #endif
00040 
00041 #include "dlvhex2/PlatformDefinitions.h"
00042 
00043 #include <boost/preprocessor/cat.hpp>
00044 #include <boost/optional.hpp>
00045 #include <boost/cstdint.hpp>
00046 
00047 #include <boost/thread/mutex.hpp>
00048 #include <boost/thread/tss.hpp>
00049 
00050 #ifndef NDEBUG
00051 # define LOG_SCOPED_LOCK(varname) boost::mutex::scoped_lock varname(Logger::Mutex());
00052 #else
00053 # define LOG_SCOPED_LOCK(varname) do { } while(false)
00054 #endif
00055 
00056 #include <iostream>
00057 #include <iomanip>
00058 #include <sstream>
00059 
00061 class DLVHEX_EXPORT Logger
00062 {
00063     public:
00066         typedef uint32_t Levels;
00068         static const Levels DBG =     0x01;
00070         static const Levels INFO =    0x02;
00072         static const Levels WARNING = 0x04;
00074         static const Levels ERROR =   0x08;
00075 
00076         // this is now very dlvhex-specific
00078         static const Levels PLUGIN =  0x10;
00080         static const Levels ANALYZE = 0x20;
00082         static const Levels MODELB =  0x40;
00084         static const Levels STATS  =  0x80;
00085 
00086     private:
00088         std::ostream& out;
00090         boost::thread_specific_ptr<std::string> indent;
00092         Levels printlevels;
00094         int levelwidth;
00095 
00096     private:
00102         Logger():
00103         out(std::cerr), printlevels(~static_cast<Levels>(0)), levelwidth(1) {}
00104 
00106         ~Logger() {
00107             stream() << std::endl;
00108             startline(DBG);
00109         #ifndef NDEBUG
00110             stream() << "clean exit!" << std::endl;
00111         #endif
00112         }
00113 
00114     public:
00117         static Logger& Instance();
00120         static boost::mutex& Mutex();
00121 
00124         inline std::ostream& stream()
00125             { return out; }
00126 
00129         void setPrintLevels(Levels levels);
00132         void setPrintLevelWidth(int width);
00135         Levels getPrintLevels() const;
00136 
00141         inline void startline(Levels forlevel) {
00142             if (!indent.get()) indent.reset(new std::string(""));
00143             if( levelwidth == 0 ) {
00144                 out << *indent;
00145             }
00146             else {
00147                 out << std::hex << std::setw(levelwidth) << forlevel << std::dec << " " << *indent;
00148             }
00149         }
00150 
00154         inline bool shallPrint(Levels forlevel)
00155             { return (printlevels & forlevel) != 0; }
00156 
00157         friend class Closure;
00159         class Closure
00160         {
00161             private:
00163                 Logger& l;
00165                 Levels level;
00167                 unsigned cutoff;
00169                 bool message;
00170 
00172                 inline void sayHello() {
00173                     // hello message
00174                     if( message ) {
00175                         l.startline(level);
00176                         l.stream() << "ENTRY" << std::endl;
00177                     }
00178                 }
00179 
00181                 inline void sayGoodbye() {
00182                     // goodbye message
00183                     if( message ) {
00184                         l.startline(level);
00185                         l.stream() << "EXIT" << std::endl;
00186                     }
00187                 }
00188 
00189             public:
00197                 Closure(Logger& l, Levels level, const std::string& str, bool message):
00198                 l(l), level(level), message(message) {
00199                     if (!l.indent.get()) l.indent.reset(new std::string(""));
00200                     cutoff = l.indent->size();
00201 
00202                     if( l.shallPrint(level) ) {
00203                         LOG_SCOPED_LOCK(lock);
00204                         *l.indent += str + " ";
00205                         sayHello();
00206                     }
00207                 }
00208 
00217                 Closure(Logger& l, Levels level, const std::string& str, const void* const val, bool message):
00218                 l(l), level(level), message(message) {
00219                     if (!l.indent.get()) l.indent.reset(new std::string(""));
00220                     cutoff = l.indent->size();
00221 
00222                     if( l.shallPrint(level) ) {
00223                         LOG_SCOPED_LOCK(lock);
00224                         std::stringstream ss;
00225                         ss << str << "/" << val << " ";
00226                         *l.indent += ss.str();
00227                         sayHello();
00228                     }
00229                 }
00230 
00232                 ~Closure() {
00233                     if (!l.indent.get()) l.indent.reset(new std::string(""));
00234                     if( l.shallPrint(level) ) {
00235                         LOG_SCOPED_LOCK(lock);
00236                         sayGoodbye();
00237                         // restore indentation level
00238                         l.indent->erase(cutoff);
00239                     }
00240                 }
00241         };
00242 
00244         class Init
00245         {
00246             public:
00249                 Init(Levels levels) {
00250                     Logger::Instance().setPrintLevels(levels);
00251                 }
00252         };
00253 };
00254 
00255 // the following will always be realized
00256 //#ifndef NDEBUG
00257 #  define LOG(level,streamout) do { LOG_SCOPED_LOCK(lock); \
00258         if( Logger::Instance().shallPrint(Logger:: level) ) \
00259         { \
00260             Logger::Instance().startline(Logger:: level); \
00261             Logger::Instance().stream() << streamout << std::endl; \
00262         } \
00263     } while(false);
00264 #    define LOG_CLOSURE_ID BOOST_PP_CAT(log_closure_,__LINE__)
00265 #  define LOG_INDENT(level)              Logger::Closure LOG_CLOSURE_ID (Logger::Instance(), Logger:: level, "  ", false)
00266 #  define LOG_SCOPE(level,name,msg)      Logger::Closure LOG_CLOSURE_ID (Logger::Instance(), Logger:: level, name, msg)
00267 #  define LOG_VSCOPE(level,name,val,msg) Logger::Closure LOG_CLOSURE_ID (Logger::Instance(), Logger:: level, name, reinterpret_cast<const void* const>(val), msg)
00268     /*
00269     #else
00270     #  define LOG(level,streamout)          do { } while(false)
00271     #  define LOG_CLOSURE_ID BOOST_PP_CAT(log_closure_,__LINE__) do { } while(false)
00272     #  define LOG_INDENT(level)                 do { } while(false)
00273     #  define LOG_SCOPE(level,name,msg)         do { } while(false)
00274     #  define LOG_VSCOPE(level,name,val,msg)    do { } while(false)
00275     #endif
00276     */
00277 
00278 #  define LOG_INIT(setlevel)             namespace { Logger::Init LOG_CLOSURE_ID (setlevel); }
00279 
00280     // the following are debug-flag dependant
00281 #ifndef NDEBUG
00282 #  define DBGLOG(level,streamout)           LOG(level,streamout)
00283 #  define DBGLOG_INDENT(level)              LOG_INDENT(level)
00284 #  define DBGLOG_SCOPE(level,name,msg)      LOG_SCOPE(level,name,msg)
00285 #  define DBGLOG_VSCOPE(level,name,val,msg) LOG_VSCOPE(level,name,val,msg)
00286 #else
00287 #  define DBGLOG(level,streamout)           do { } while(false)
00288 #  define DBGLOG_INDENT(level)              do { } while(false)
00289 #  define DBGLOG_SCOPE(level,name,msg)      do { } while(false)
00290 #  define DBGLOG_VSCOPE(level,name,val,msg) do { } while(false)
00291 #endif
00292 #endif                           // LOGGER_HPP_INCLUDED__17092010
00293 
00294 // vim:expandtab:ts=4:sw=4:
00295 // mode: C++
00296 // End: