Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

wvlog.cc

Go to the documentation of this file.
00001 /* 00002 * Worldvisions Weaver Software: 00003 * Copyright (C) 1997-2002 Net Integration Technologies, Inc. 00004 * 00005 * Functions needed to implement general WvLog class. 00006 * 00007 * See wvlog.h for more information. 00008 */ 00009 #include "wvlogrcv.h" 00010 #include "wvstringlist.h" 00011 #include "strutils.h" 00012 #include <ctype.h> 00013 00014 #ifdef _WIN32 00015 #include <io.h> 00016 #define snprintf _snprintf 00017 #endif 00018 00019 WvLogRcvBaseList WvLog::receivers; 00020 int WvLog::num_receivers = 0, WvLog::num_logs = 0; 00021 WvLogRcvBase *WvLog::default_receiver = NULL; 00022 00023 char *WvLogRcv::loglevels[WvLog::NUM_LOGLEVELS] = { 00024 "Crit", 00025 "Err", 00026 "Warn", 00027 "Notice", 00028 "Info", 00029 "*1", 00030 "*2", 00031 "*3", 00032 "*4", 00033 "*5", 00034 }; 00035 00036 00037 00038 /////////////////////////////////////// WvLog 00039 00040 00041 00042 WvLog::WvLog(WvStringParm _app, LogLevel _loglevel, const WvLog *par) 00043 : app(_app) 00044 { 00045 parent = par; 00046 loglevel = _loglevel; 00047 num_logs++; 00048 } 00049 00050 00051 WvLog::WvLog(const WvLog &l) 00052 { 00053 parent = l.parent ? l.parent : &l; 00054 app = parent->app; 00055 loglevel = parent->loglevel; 00056 num_logs++; 00057 } 00058 00059 00060 WvLog::~WvLog() 00061 { 00062 num_logs--; 00063 if (!num_logs && default_receiver) 00064 { 00065 num_receivers++; // deleting default does not really reduce 00066 delete default_receiver; 00067 default_receiver = NULL; 00068 } 00069 } 00070 00071 00072 bool WvLog::isok() const 00073 { 00074 return true; 00075 } 00076 00077 00078 bool WvLog::pre_select(SelectInfo &si) 00079 { 00080 // a wvlog is always writable... 00081 if (si.wants.writable) 00082 return true; 00083 else 00084 return WvStream::pre_select(si); 00085 } 00086 00087 00088 size_t WvLog::uwrite(const void *_buf, size_t len) 00089 { 00090 if (!num_receivers) 00091 { 00092 if (!default_receiver) 00093 { 00094 // nobody's listening -- create a receiver on the console 00095 default_receiver = new WvLogConsole(dup(2)); 00096 num_receivers--; // default does not qualify! 00097 } 00098 default_receiver->log(parent ? parent : this, loglevel, 00099 (const char *)_buf, len); 00100 return len; 00101 } 00102 else if (default_receiver) 00103 { 00104 // no longer empty list -- delete our default to stderr 00105 num_receivers++; // deleting default does not really reduce 00106 delete default_receiver; 00107 default_receiver = NULL; 00108 } 00109 00110 WvLogRcvBaseList::Iter i(receivers); 00111 for (i.rewind(); i.next(); ) 00112 { 00113 WvLogRcvBase &rc = *i; 00114 rc.log(parent ? parent : this, loglevel, (const char *)_buf, len); 00115 } 00116 00117 return len; 00118 } 00119 00120 00121 00122 ///////////////////////////////////// WvLogRcvBase 00123 00124 00125 00126 WvLogRcvBase::WvLogRcvBase() 00127 { 00128 WvLog::receivers.append(this, false); 00129 WvLog::num_receivers++; 00130 } 00131 00132 00133 WvLogRcvBase::~WvLogRcvBase() 00134 { 00135 WvLog::receivers.unlink(this); 00136 WvLog::num_receivers--; 00137 } 00138 00139 00140 const char *WvLogRcvBase::appname(const WvLog *log) const 00141 { 00142 return log->app; 00143 } 00144 00145 00146 00147 //////////////////////////////////// WvLogRcv 00148 00149 00150 00151 WvLogRcv::WvLogRcv(WvLog::LogLevel _max_level) : custom_levels(5) 00152 { 00153 last_source = NULL; 00154 last_level = WvLog::NUM_LOGLEVELS; 00155 max_level = _max_level; 00156 at_newline = true; 00157 } 00158 00159 00160 WvLogRcv::~WvLogRcv() 00161 { 00162 } 00163 00164 00165 void WvLogRcv::_make_prefix() 00166 { 00167 prefix = WvString("%s<%s>: ", 00168 appname(last_source), loglevels[last_level]); 00169 prelen = prefix.len(); 00170 } 00171 00172 00173 void WvLogRcv::_begin_line() 00174 { 00175 mid_line(prefix, prelen); 00176 } 00177 00178 00179 void WvLogRcv::_end_line() 00180 { 00181 // do nothing 00182 } 00183 00184 00185 // like isprint(), but always treats chars >128 as printable, because they 00186 // always are (even if they're meaningless) 00187 static bool my_isprint(char _c) 00188 { 00189 unsigned char c = _c; 00190 if (isprint(c) || c >= 128) 00191 return true; 00192 else 00193 return false; 00194 } 00195 00196 00197 void WvLogRcv::log(const WvLog *source, int _loglevel, 00198 const char *_buf, size_t len) 00199 { 00200 WvLog::LogLevel loglevel = (WvLog::LogLevel)_loglevel; 00201 char hex[5]; 00202 WvLog::LogLevel threshold = max_level; 00203 WvString srcname = source->app; 00204 strlwr(srcname.edit()); 00205 00206 Src_LvlDict::Iter i(custom_levels); 00207 i.rewind(); 00208 00209 // Check if the debug level for the source has been overridden 00210 while (i.next()) 00211 { 00212 if (strstr(srcname, i->src)) 00213 { 00214 threshold = i->lvl; 00215 break; 00216 } 00217 } 00218 00219 if (loglevel > threshold) 00220 return; 00221 00222 // only need to start a new line with new headers if they headers have 00223 // changed. if the source and level are the same as before, just continue 00224 // the previous log entry. 00225 if (source != last_source || loglevel != last_level) 00226 { 00227 end_line(); 00228 last_source = source; 00229 last_level = loglevel; 00230 _make_prefix(); 00231 } 00232 00233 const char *buf = (const char *)_buf, *bufend = buf + len, *cptr; 00234 00235 // loop through the buffer, printing each character or its [hex] equivalent 00236 // if it is unprintable. Also eat newlines unless they are appropriate. 00237 while (buf < bufend) 00238 { 00239 if (buf[0] == '\n' || buf[0] == '\r') 00240 { 00241 end_line(); 00242 buf++; 00243 continue; 00244 } 00245 00246 begin_line(); 00247 00248 if (buf[0] == '\t') 00249 { 00250 mid_line(" ", 1); 00251 buf++; 00252 continue; 00253 } 00254 else if (!my_isprint(buf[0])) 00255 { 00256 snprintf(hex, 5, "[%02x]", buf[0]); 00257 mid_line(hex, 4); 00258 buf++; 00259 continue; 00260 } 00261 00262 // like strchr, but size-limited instead of null-terminated 00263 for (cptr = buf; cptr < bufend; cptr++) 00264 { 00265 if (*cptr == '\n' || !my_isprint(*cptr)) 00266 break; 00267 } 00268 00269 if (*cptr == '\n') // end of line 00270 { 00271 mid_line((const char *)buf, cptr - buf); 00272 buf = cptr; 00273 } 00274 else if (!my_isprint(*cptr)) 00275 { 00276 mid_line(buf, cptr - buf); 00277 buf = cptr; 00278 } 00279 else // end of buffer 00280 { 00281 mid_line(buf, bufend - buf); 00282 buf = bufend; 00283 } 00284 } 00285 } 00286 00287 // input format: name=number, name=number, name=number, etc. 00288 // 'name' is the name of a log service 00289 // 'number' is the number of the log level to use. 00290 bool WvLogRcv::set_custom_levels(WvString descr) 00291 { 00292 custom_levels.zap(); 00293 00294 // Parse the filter line into individual rules 00295 WvStringList lst; 00296 WvStringList::Iter i(lst); 00297 lst.split(descr, ",= "); 00298 if (!lst.count()) 00299 return true; 00300 WvString src(""); 00301 00302 for (i.rewind(); i.next(); ) 00303 { 00304 if (src != "") 00305 { 00306 if (atoi(*i) > 0 && atoi(*i) <= WvLog::NUM_LOGLEVELS) 00307 { 00308 custom_levels.add(new Src_Lvl(src, atoi(*i)), true); 00309 src = ""; 00310 } 00311 else 00312 return false; 00313 } 00314 else 00315 { 00316 src = *i; 00317 strlwr(trim_string(src.edit())); 00318 } 00319 } 00320 if (src != "") 00321 return false; 00322 00323 return true; 00324 } 00325 00326 00327 ///////////////////////////////////// WvLogConsole 00328 00329 00330 00331 WvLogConsole::WvLogConsole(int _fd, WvLog::LogLevel _max_level) : 00332 WvFDStream(_fd), WvLogRcv(_max_level) 00333 { 00334 } 00335 00336 00337 WvLogConsole::~WvLogConsole() 00338 { 00339 end_line(); 00340 } 00341 00342 00343 void WvLogConsole::_mid_line(const char *str, size_t len) 00344 { 00345 uwrite(str, len); 00346 }

Generated on Tue Oct 5 01:09:20 2004 for WvStreams by doxygen 1.3.7