|
dlvhex
2.1.0
|
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