interreality.org [VOS]
[Home] [About]
[Screenshots]
[Download]
[News]
[Community]
[Documentation] [Manual]
[Bugs & Requests] [Wiki]

/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