/home/tetron/hack/vos/libs/vos/vutil/log.hh
Go to the documentation of this file.00001 /* 00002 This file is part of the Virtual Object System of 00003 the Interreality project (http://interreality.org). 00004 00005 Copyright (C) 2001-2003 Peter Amstutz 00006 00007 This library is free software; you can redistribute it and/or 00008 modify it under the terms of the GNU Lesser General Public 00009 License as published by the Free Software Foundation; either 00010 version 2 of the License, or (at your option) any later version. 00011 00012 This library is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 Lesser General Public License for more details. 00016 00017 You should have received a copy of the GNU Lesser General Public 00018 License along with this library; if not, write to the Free Software 00019 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00020 00021 Peter Amstutz <http://www.interreality.org> 00022 */ 00023 #ifndef _VUTIL_LOG_HH_ 00024 #define _VUTIL_LOG_HH_ 00025 00026 /** @file 00027 Defines Log. 00028 @see LOG 00029 */ 00030 00031 #include <ctime> 00032 #include <string> 00033 #include <map> 00034 00035 #include <boost/thread/mutex.hpp> 00036 00037 #include <vos/vutil/vutildefs.hh> 00038 00039 /** @def LOG(c, l, m) log.hh vos/vos/log.hh 00040 @ingroup libvutil 00041 00042 @param c (string) the logging channel, which will be created if it does not exist 00043 @param l (int) the logging level. 0 is the highest priority, 6 00044 is the lowest priority. Generally, you should use 0 for 00045 critical errors, 1 for warnings, 2 for important information, 00046 3, 4 and 5 for different levels of debugging spew. 00047 @param m The actual log message. This is actually used as an 00048 output into a stream, so the whole C++ stream output API is available 00049 In other words, can use expressions like: 00050 @code 00051 LOG("foo", 3, "x = " << x); 00052 @endcode 00053 00054 You can control log levels using the setLevel(), 00055 setDefaultLevel(), setMasterLevel(), and also by setting the 00056 environment variables VOS_LOG, VOS_LOG_DEFAULT and VOS_LOG_MASTER. 00057 VOS_LOG sets the log level on specific channel; VOS_LOG_DEFAULT 00058 sets the default level for newly created log channels, and 00059 VOS_LOG_MASTER sets a hard cutoff that disables *all* logging 00060 above the supplied level, overriding VOS_LOG and VOS_LOG_DEFAULT). 00061 Generally you want to use VOS_LOG and VOS_LOG_DEFAULT, and avoid 00062 VOS_LOG_MASTER. 00063 00064 The format of the VOS_LOG environment variable is 00065 <code>channel1=level1,channel2=level2,...</code>. Don't use any 00066 spaces. VOS_LOG_DEFAULT and VOS_LOG_MASTER should contain a 00067 single positive integer. All environment variables are entirely 00068 optional. 00069 00070 The LOG macro firsts check the master loglevel. If the log level 00071 is greater than the master level, no logging message will be 00072 printed. Then the LOG checks to see if the channel exists. If 00073 not, it is created and set to the default level. Finally if the 00074 log level is less than or equal to the channel's current level, 00075 the message is printed. 00076 00077 Note that the log level is checked before actually creating the 00078 output text, so the logging output string isn't created unless it 00079 is actually going to be printed. 00080 */ 00081 00082 00083 00084 #ifdef USE_STRSTREAM 00085 # include <strstream> 00086 # define VOS_LOG_MAXLINELENGTH 1024 00087 # define LOG(c, l, m) { \ 00088 if(l <= VUtil::Log::masterLogLevel) { \ 00089 VUtil::Log* _lg = VUtil::Log::getLog(c); \ 00090 if(! _lg) { _lg=new VUtil::Log(c); VUtil::Log::addChannel(_lg); } \ 00091 if(_lg->getLevel() >= l) { \ 00092 char _y[VOS_LOG_MAXLINELENGTH]; \ 00093 memset(_y, 0, sizeof(_y)); \ 00094 std::ostrstream _x(_y, sizeof(_y)-1); \ 00095 _x << m; \ 00096 _lg->log(l, _x.str()); \ 00097 } \ 00098 } \ 00099 } 00100 #else 00101 # include <sstream> 00102 # define LOG(c, l, m) { \ 00103 if(l <= VUtil::Log::masterLogLevel) { \ 00104 VUtil::Log* _lg = VUtil::Log::getLog(c); \ 00105 if(! _lg) { _lg=new VUtil::Log(c); VUtil::Log::addChannel(_lg); } \ 00106 if(_lg->getLevel() >= l) { \ 00107 std::ostringstream _x; \ 00108 _x << m; \ 00109 _lg->log(l, _x.str()); \ 00110 } \ 00111 } \ 00112 } 00113 #endif 00114 00115 #ifdef NDEBUG 00116 #define VOS_DEFAULT_LOGLEVEL VUtil::LOG_WARN 00117 #else 00118 #define VOS_DEFAULT_LOGLEVEL VUtil::LOG_NOTIFY 00119 #endif 00120 00121 00122 namespace VUtil 00123 { 00124 00125 /** 00126 @ingroup libvutil 00127 Symbolic level names for use with the LOG macro. The log level threshold 00128 is typically set at LOG_NOTIFY, or LOG_DETAIL if compiled in debugging mode. 00129 */ 00130 enum LogLevelSym { 00131 00132 /// Critical, possibly fatal errors 00133 LOG_ERROR = 0, 00134 00135 /// Important warnings 00136 LOG_WARN, 00137 00138 /// Important information about program state or progress. 00139 LOG_NOTIFY, 00140 00141 /// Details about program state or progress, which may be useful for users 00142 LOG_DETAIL, 00143 00144 /** Verbose program debugging, useful for developers, and details about VOS 00145 state or progress. 00146 */ 00147 LOG_DEBUG, 00148 00149 /// Very verbose program debugging, and VOS debugging info. 00150 LOG_VOS_DEBUG, 00151 00152 /// Contents of VOS messages. 00153 LOG_VOS_MSGDATA 00154 }; 00155 00156 /** @class Log log.hh vos/vos/log.hh 00157 @ingroup libvutil 00158 00159 The logging class. The main user interface to this class is the 00160 macro LOG(), but you can set some global options using the static 00161 methods in this class as well as you can set properties of individual 00162 channels. 00163 */ 00164 class VUTIL_API Log 00165 { 00166 private: 00167 std::string channelname; 00168 std::ostream* output; 00169 int loglevel; 00170 static int defaultloglevel; 00171 static bool didReadEnv; 00172 static std::ostream* defaultostream; 00173 00174 class StrCmp { 00175 public: 00176 inline bool operator()(const char* p, const char* q) const { 00177 return (strcmp(p, q) < 0); 00178 }; 00179 }; 00180 00181 00182 static boost::mutex& channels_mutex(); 00183 static std::map<const char*, Log*, StrCmp>& channels(); 00184 static boost::mutex defaultostream_mutex; 00185 static boost::mutex& log_io_mutex(); 00186 00187 public: 00188 00189 /** A level that applies to all channels. (default is 10) */ 00190 static int masterLogLevel; 00191 00192 /** Construct a new logging channel. Usually you 00193 don't need to call this, as it will be created automatically 00194 when a new channel is refered to. 00195 @param channel the channel name that will select this log object 00196 @param outputstream the output stream this log will write to 00197 @internal 00198 */ 00199 Log(const std::string& channel, std::ostream* outputstream); 00200 00201 /** Construct a new logging channel. Usually you 00202 don't need to call this, as it will be created automatically 00203 when a new channel is refered to. 00204 @param channel the channel name that will select this log object 00205 @internal 00206 */ 00207 Log(const std::string& channel); 00208 00209 /** Write a line to the log stream. You probably want to be 00210 using LOG(), however. 00211 @param level the level to log at. If the logging channel 00212 level is lower than this level, the log message will be suppressed 00213 @param message the message std::string to print 00214 @internal 00215 */ 00216 void log(int level, const std::string& message); 00217 00218 /** Set the log level for this channel. Log levels for channels 00219 can also be set with an environment variable VOS_LOG, which 00220 takes the format "channel1=level1,channel1=level1,..." -- 00221 where channel is the name of a log channel, and level is the 00222 integer level for that channel. 00223 00224 @param loglevel the level, messages with a level higher than this will be suppressed. 00225 */ 00226 void setLevel(int loglevel); 00227 00228 /** Get the log level for this channel 00229 @returns loglevel the level, messages with a level higher than this will be suppressed. 00230 */ 00231 int getLevel(); 00232 00233 /** Log to a particular channel, which will be created if it does 00234 not exist. You probably want to be using LOG(), however. 00235 @param channel the channel to log in 00236 @param level the level to log at. If the logging channel 00237 level is lower than this level, the log message will be suppressed 00238 @param message the message std::string to print 00239 @internal 00240 */ 00241 static void log(const char* channel, int level, const std::string& message); 00242 static void log(const std::string& channel, int level, const std::string& message); 00243 00244 /** Obtain the log object for a particular channel 00245 @param channel the channel desired. 00246 @returns the log object desired, or 0 if it does not exist 00247 */ 00248 static Log* getLog(const std::string& channel); 00249 00250 /** Obtain the log object for a particular channel 00251 @param channel the channel desired. 00252 @returns the log object desired, or 0 if it does not exist 00253 */ 00254 static Log* getLog(const char* channel); 00255 00256 /** Add a new channel to the channel table. 00257 @param l the log channel 00258 */ 00259 static void addChannel(Log* l); 00260 00261 /** Sets the default output stream for new log objects. The 00262 starting default output stream is "clog" (which is generally 00263 an alias for stderr.) 00264 @param o the output stream 00265 */ 00266 static void setDefaultOutputStream(std::ostream* o); 00267 00268 /** Sets the default log level for new log channels. 00269 @param loglevel the level, messages with a level higher than 00270 this will be suppressed. 00271 */ 00272 static void setDefaultLevel(int loglevel); 00273 00274 /** Returns the default log level for new log channels. */ 00275 static int getDefaultLevel(); 00276 00277 /** Sets the master log level for all log objects. The master log 00278 level applies to all logging statements, regardless of channel 00279 name. 00280 @param loglevel the new level. Messages with a level higher 00281 than this will be suppressed. 00282 */ 00283 static void setMasterLevel(int loglevel); 00284 00285 /** Returns the master log level. */ 00286 static int getMasterLevel(); 00287 00288 /** Read the environment variable VOS_LOG and set/create the 00289 appropriate log channels to the specified levels. 00290 @note This is called exactly once automatically by getLog() so 00291 you probably don't ever have to call this. 00292 */ 00293 static void readEnvironment(); 00294 00295 /** Redirect all existing channels to use the supplied output 00296 stream and make this stream the default output stream. 00297 */ 00298 static void setStreamForAllChannels(std::ostream* o); 00299 00300 /** Sets the log level for all channels and make this the 00301 new default log level 00302 */ 00303 static void setLevelForAllChannels(int level); 00304 }; 00305 } 00306 00307 #endif