00001 /* 00002 This file is part of the Virtual Object System of 00003 the Interreality project (http://interreality.org). 00004 00005 Copyright (C) 2001, 2002 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 <tetron@interreality.org> 00022 */ 00023 #ifndef _LOG_HH_ 00024 #define _LOG_HH_ 00025 00026 /** @file 00027 Defines Log. 00028 @see LOG 00029 */ 00030 00031 #include <vos/corelibs/vos/vosdefs.hh> 00032 00033 #include <string> 00034 #include <map> 00035 00036 /** @def LOG(c, l, m) log.hh vos/corelibs/vos/log.hh 00037 00038 @param c (string) the logging channel, which will be created if it does not exist 00039 @param l (int) the logging level (0 is the highest priority, 5 00040 being the lowest priority. 00041 @param m The actual log message. This is actually used as an 00042 output into a stream, so the whole C++ stream output API is available 00043 In other words, can use expressions like: 00044 @code 00045 LOG("foo", 3, "x = " << x << "\n"); 00046 @endcode 00047 00048 You can control log levels using the setLevel(), setDefaultLevel(), setMasterLevel(), and 00049 also by setting an environment variables named <code>VOS_LOG</code> and <code>VOS_MASTER_LOGLEVEL</code>. 00050 The LOG macro first checks the master loglevel. If (l) is greater than the master level, no logging message will be printed. 00051 Next, LOG checks the level for the channel. if (l) is less than or equal to the channel's level, the message is printed. 00052 00053 The format of the <code>VOS_LOG</code> environment variable is <code>channel1=level1,channel2=level2,...</code>. 00054 Don't use any spaces. 00055 <code>VOS_MASTER_LOGLEVEL</code> should contain a single (positive) integer. 00056 Both environment variables are entirely optional. 00057 00058 LOG must be a macro because of the way output streams are used (believe 00059 me, I tried other ways...) Note that also, because it is a macro, 00060 you pay no penalty related to creating output the if string if it isn't going 00061 be printed; the log level is checked beforehand. 00062 */ 00063 00064 #define LOG_MAXLINELENGTH 1024 00065 00066 #ifdef USE_STRSTREAM 00067 #include <strstream> 00068 #define LOG(c, l, m) { \ 00069 if(l <= Log::masterLogLevel) { \ 00070 Log* _lg = Log::getLog(c); \ 00071 if(! _lg) { _lg=new Log(c); Log::addChannel(_lg); } \ 00072 if(_lg->getLevel() >= l) { \ 00073 char _y[LOG_MAXLINELENGTH]; \ 00074 memset(_y, 0, sizeof(_y)); \ 00075 ostrstream _x(_y, sizeof(_y)-1); \ 00076 _x << m; \ 00077 _lg->log(l, _x.str()); \ 00078 } \ 00079 } \ 00080 } 00081 #else 00082 #include <sstream> 00083 #define LOG(c, l, m) { \ 00084 if(l <= Log::masterLogLevel) { \ 00085 Log* _lg = Log::getLog(c); \ 00086 if(! _lg) { _lg=new Log(c); Log::addChannel(_lg); } \ 00087 if(_lg->getLevel() >= l) { \ 00088 ostringstream _x; \ 00089 _x << m; \ 00090 _lg->log(l, _x.str()); \ 00091 } \ 00092 } \ 00093 } 00094 #endif 00095 00096 namespace VOS 00097 { 00098 /** @class Log log.hh vos/corelibs/vos/log.hh 00099 * 00100 * The logging class. The main user interface to this class is the macro LOG(), 00101 * but you can set some global options using the static methods in this class, 00102 * and you can set properties of individual channels using this class. 00103 */ 00104 class VOS_API Log 00105 { 00106 private: 00107 string channelname; 00108 std::ostream* output; 00109 int loglevel; 00110 00111 class StrCmp { 00112 public: 00113 inline bool operator()(const char* p, const char* q) const { 00114 return (strcmp(p, q) < 0); 00115 }; 00116 }; 00117 00118 static map<const char*, Log*, StrCmp> channels; 00119 static std::ostream* defaultostream; 00120 static int defaultloglevel; 00121 static bool didReadEnv; 00122 public: 00123 00124 /** A level that applies to all channels. (default is 10) */ 00125 static int masterLogLevel; 00126 00127 static boost::mutex log_io_mutex; 00128 00129 /** Construct a new logging channel. Usually you 00130 don't need to call this, as it will be created automatically 00131 when a new channel is refered to. 00132 @param channel the channel name that will select this log object 00133 @param outputstream the output stream this log will write to 00134 @internal 00135 */ 00136 Log(const string& channel, std::ostream* outputstream); 00137 00138 /** Construct a new logging channel. Usually you 00139 don't need to call this, as it will be created automatically 00140 when a new channel is refered to. 00141 @param channel the channel name that will select this log object 00142 @internal 00143 */ 00144 Log(const string& channel); 00145 00146 /** Write a line to the logfile. You probably want to be 00147 using LOG(), however. 00148 @param level the level to log at. If the logging channel 00149 level is lower than this level, the log message will be suppressed 00150 @param message the message string to print 00151 @internal 00152 */ 00153 void log(int level, const string& message); 00154 00155 /** Set the log level for this channel. Log levels for channels can also be set with an environment variable VOS_LOG, which takes the format channel:level,channel:level, etc. -- channel is the name of a log channel, and level is the integer level for that channel. 00156 @param loglevel the level, messages with a level higher than this will be suppressed. 00157 */ 00158 void setLevel(int loglevel); 00159 00160 /** Get the log level for this channel 00161 @returns loglevel the level, messages with a level higher than this will be suppressed. 00162 */ 00163 int getLevel(); 00164 00165 /** Log to a particular channel, which will be created if it does 00166 not exist. You probably want to be using LOG(), however. 00167 @param channel the channel to log in 00168 @param level the level to log at. If the logging channel 00169 level is lower than this level, the log message will be suppressed 00170 @param message the message string to print 00171 @internal 00172 */ 00173 static void log(const char* channel, int level, const string& message); 00174 static void log(const string& channel, int level, const string& message); 00175 00176 /** Obtain the log object for a particular channel 00177 @param channel the channel desired. 00178 @returns the log object desired, or 0 if it does not exist 00179 */ 00180 static Log* getLog(const string& channel); 00181 00182 /** Obtain the log object for a particular channel 00183 @param channel the channel desired. 00184 @returns the log object desired, or 0 if it does not exist 00185 */ 00186 static Log* getLog(const char* channel); 00187 00188 /** Add a new channel to the channel table. 00189 @param l the log channel 00190 */ 00191 static void addChannel(Log* l); 00192 00193 /** Sets the default output stream for new log objects. The 00194 starting default output stream is "clog" (which is generally 00195 an alias for stderr.) 00196 @param o the output stream 00197 */ 00198 static void setDefaultOutputStream(std::ostream* o); 00199 00200 /** Sets the default log level for new log channels. 00201 @param loglevel the level, messages with a level higher than this will be suppressed. 00202 */ 00203 static void setDefaultLevel(int loglevel); 00204 00205 /** Returns the default log level for new log channels. */ 00206 static int getDefaultLevel(); 00207 00208 /** Sets the master log level for all log objects. The master log level applies to all 00209 logging statements, regardless of channel name. 00210 @param loglevel the new level. Messages with a level higher than this will be suppressed. 00211 */ 00212 static void setMasterLevel(int loglevel); 00213 00214 /** Returns the master log level. */ 00215 static int getMasterLevel(); 00216 00217 /** Read the environment variable VOS_LOG and set/create the 00218 appropriate log channels to the specified levels. 00219 @note This is called exactly once automatically by getLog() so 00220 you probably don't ever have to call this. 00221 */ 00222 00223 static void readEnvironment(); 00224 00225 /** Close all channels. */ 00226 static void closeAllChannels(); 00227 }; 00228 } 00229 00230 #endif