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 Sat Mar 13 14:55:47 2004 for WvStreams by doxygen 1.3.6-20040222