00001
00002
00003
00004
00005
00006
00007
00008
00009 #include "wvlogrcv.h"
00010 #include "wvstringlist.h"
00011 #include "strutils.h"
00012 #include "wvfork.h"
00013
00014 #include <ctype.h>
00015
00016 #ifdef _WIN32
00017 #define snprintf _snprintf
00018 #endif
00019
00020 WvLogRcvBaseList *WvLog::receivers;
00021 int WvLog::num_receivers = 0, WvLog::num_logs = 0;
00022 WvLogRcvBase *WvLog::default_receiver = NULL;
00023
00024 char *WvLogRcv::loglevels[WvLog::NUM_LOGLEVELS] = {
00025 "Crit",
00026 "Err",
00027 "Warn",
00028 "Notice",
00029 "Info",
00030 "*1",
00031 "*2",
00032 "*3",
00033 "*4",
00034 "*5",
00035 };
00036
00037
00038
00040
00041
00042
00043 WvLog::WvLog(WvStringParm _app, LogLevel _loglevel, WvLogFilter* _filter)
00044 : app(_app), loglevel(_loglevel), filter(_filter)
00045 {
00046
00047 num_logs++;
00048 set_wsname(app);
00049 }
00050
00051
00052 WvLog::WvLog(const WvLog &l)
00053 : app(l.app), loglevel(l.loglevel), filter(l.filter)
00054 {
00055
00056 num_logs++;
00057 set_wsname(app);
00058 }
00059
00060
00061 WvLog::~WvLog()
00062 {
00063 num_logs--;
00064 if (!num_logs && default_receiver)
00065 {
00066 num_receivers++;
00067 delete default_receiver;
00068 default_receiver = NULL;
00069 }
00070
00071
00072 }
00073
00074
00075 bool WvLog::isok() const
00076 {
00077 return true;
00078 }
00079
00080
00081 void WvLog::pre_select(SelectInfo &si)
00082 {
00083
00084 if (si.wants.writable)
00085 si.msec_timeout = 0;
00086 else
00087 WvStream::pre_select(si);
00088 }
00089
00090
00091 bool WvLog::post_select(SelectInfo &si)
00092 {
00093
00094 if (si.wants.writable)
00095 return true;
00096 else
00097 return WvStream::post_select(si);
00098 }
00099
00100
00101 size_t WvLog::uwrite(const void *_buf, size_t len)
00102 {
00103
00104
00105 static const int recursion_max = 8;
00106 static int recursion_count = 0;
00107 static WvString recursion_msg("Too many extra log messages written while "
00108 "writing to the log. Suppressing additional messages.\n");
00109
00110 ++recursion_count;
00111
00112 if (!num_receivers)
00113 {
00114 if (!default_receiver)
00115 {
00116
00117 int xfd = dup(2);
00118 default_receiver = new WvLogConsole(xfd);
00119 num_receivers--;
00120 }
00121
00122 if (recursion_count < recursion_max)
00123 default_receiver->log(app, loglevel, (const char *)_buf, len);
00124 else if (recursion_count == recursion_max)
00125 default_receiver->log(app, WvLog::Warning, recursion_msg.cstr(),
00126 recursion_msg.len());
00127
00128 --recursion_count;
00129 return len;
00130 }
00131 else if (default_receiver)
00132 {
00133
00134 num_receivers++;
00135 delete default_receiver;
00136 default_receiver = NULL;
00137 }
00138
00139 assert(receivers);
00140 WvLogRcvBaseList::Iter i(*receivers);
00141 for (i.rewind(); i.next(); )
00142 {
00143 WvLogRcvBase &rc = *i;
00144
00145 if (recursion_count < recursion_max)
00146 rc.log(app, loglevel, (const char *)_buf, len);
00147 else if (recursion_count == recursion_max)
00148 rc.log(app, WvLog::Warning, recursion_msg.cstr(),
00149 recursion_msg.len());
00150 }
00151
00152 --recursion_count;
00153 return len;
00154 }
00155
00156
00157
00159
00160
00161
00162 WvLogRcvBase::WvLogRcvBase()
00163 {
00164 static_init();
00165 WvLogRcvBase::force_new_line = false;
00166 if (!WvLog::receivers)
00167 WvLog::receivers = new WvLogRcvBaseList;
00168 WvLog::receivers->append(this, false);
00169 WvLog::num_receivers++;
00170 }
00171
00172
00173 WvLogRcvBase::~WvLogRcvBase()
00174 {
00175 assert(WvLog::receivers);
00176 WvLog::receivers->unlink(this);
00177 if (WvLog::receivers->isempty())
00178 {
00179 delete WvLog::receivers;
00180 WvLog::receivers = NULL;
00181 }
00182 WvLog::num_receivers--;
00183 }
00184
00185
00186 const char *WvLogRcvBase::appname(WvStringParm log) const
00187 {
00188 if (log)
00189 return log;
00190 else
00191 return "unknown";
00192 }
00193
00194
00195 void WvLogRcvBase::static_init()
00196 {
00197 static bool init = false;
00198 if (!init)
00199 {
00200 #ifndef _WIN32
00201 add_wvfork_callback(WvLogRcvBase::cleanup_on_fork);
00202 #endif
00203 init = true;
00204 }
00205 }
00206
00207
00208 void WvLogRcvBase::cleanup_on_fork(pid_t p)
00209 {
00210 if (p) return;
00211
00212 if (WvLog::receivers)
00213 WvLog::receivers->zap();
00214 delete WvLog::default_receiver;
00215 WvLog::default_receiver = NULL;
00216 WvLog::num_receivers = 0;
00217 }
00218
00219
00220
00222
00223
00224
00225 WvLogRcv::WvLogRcv(WvLog::LogLevel _max_level) : custom_levels(5)
00226 {
00227 last_source = WvString();
00228 last_level = WvLog::NUM_LOGLEVELS;
00229 last_time = 0;
00230 max_level = _max_level;
00231 at_newline = true;
00232 }
00233
00234
00235 WvLogRcv::~WvLogRcv()
00236 {
00237 }
00238
00239
00240 void WvLogRcv::_make_prefix(time_t now)
00241 {
00242 prefix = WvString("%s<%s>: ",
00243 last_source, loglevels[last_level]);
00244 prelen = prefix.len();
00245 }
00246
00247
00248 void WvLogRcv::_begin_line()
00249 {
00250 mid_line(prefix, prelen);
00251 }
00252
00253
00254 void WvLogRcv::_end_line()
00255 {
00256
00257 }
00258
00259
00260
00261
00262 static bool my_isprint(char _c)
00263 {
00264 unsigned char c = _c;
00265 if (isprint(c) || c >= 128)
00266 return true;
00267 else
00268 return false;
00269 }
00270
00271
00272 void WvLogRcv::log(WvStringParm source, int _loglevel,
00273 const char *_buf, size_t len)
00274 {
00275 WvLog::LogLevel loglevel = (WvLog::LogLevel)_loglevel;
00276 char hex[5];
00277 WvLog::LogLevel threshold = max_level;
00278 WvString srcname(source);
00279 strlwr(srcname.edit());
00280
00281 Src_LvlDict::Iter i(custom_levels);
00282 i.rewind();
00283
00284
00285 while (i.next())
00286 {
00287 if (strstr(srcname, i->src))
00288 {
00289 threshold = i->lvl;
00290 break;
00291 }
00292 }
00293
00294 if (loglevel > threshold)
00295 return;
00296
00297
00298
00299
00300 time_t now = wvtime().tv_sec;
00301 if (source != last_source
00302 || loglevel != last_level
00303 || WvLogRcvBase::force_new_line)
00304 {
00305 end_line();
00306 last_source = source;
00307 last_level = loglevel;
00308 last_time = now;
00309 _make_prefix(now);
00310 }
00311 else if (last_time == 0 || now != last_time)
00312 {
00313
00314
00315
00316
00317 last_time = now;
00318 if (at_newline)
00319 _make_prefix(now);
00320 }
00321
00322 const char *buf = (const char *)_buf, *bufend = buf + len, *cptr;
00323
00324
00325
00326 while (buf < bufend)
00327 {
00328 if (buf[0] == '\n' || buf[0] == '\r')
00329 {
00330 end_line();
00331 buf++;
00332 continue;
00333 }
00334
00335 begin_line();
00336
00337 if (buf[0] == '\t')
00338 {
00339 mid_line(" ", 1);
00340 buf++;
00341 continue;
00342 }
00343 else if (!my_isprint(buf[0]))
00344 {
00345 snprintf(hex, 5, "[%02x]", buf[0]);
00346 mid_line(hex, 4);
00347 buf++;
00348 continue;
00349 }
00350
00351
00352 for (cptr = buf; cptr < bufend; cptr++)
00353 {
00354 if (*cptr == '\n' || !my_isprint(*cptr))
00355 break;
00356 }
00357
00358 if (cptr >= bufend)
00359 {
00360 mid_line(buf, bufend - buf);
00361 buf = bufend;
00362 }
00363 else if (*cptr == '\n')
00364 {
00365 mid_line((const char *)buf, cptr - buf);
00366 buf = cptr;
00367 }
00368 else
00369 {
00370 mid_line(buf, cptr - buf);
00371 buf = cptr;
00372 }
00373 }
00374 }
00375
00376
00377
00378
00379 bool WvLogRcv::set_custom_levels(WvString descr)
00380 {
00381 custom_levels.zap();
00382
00383
00384 WvStringList lst;
00385 WvStringList::Iter i(lst);
00386 lst.split(descr, ",= ");
00387 if (lst.isempty())
00388 return true;
00389 WvString src("");
00390
00391 for (i.rewind(); i.next(); )
00392 {
00393 if (src != "")
00394 {
00395 if (atoi(*i) > 0 && atoi(*i) <= WvLog::NUM_LOGLEVELS)
00396 {
00397 custom_levels.add(new Src_Lvl(src, atoi(*i)), true);
00398 src = "";
00399 }
00400 else
00401 return false;
00402 }
00403 else
00404 {
00405 src = *i;
00406 strlwr(trim_string(src.edit()));
00407 }
00408 }
00409 if (src != "")
00410 return false;
00411
00412 return true;
00413 }
00414
00415
00417
00418
00419
00420 WvLogConsole::WvLogConsole(int _fd, WvLog::LogLevel _max_level) :
00421 WvFDStream(_fd), WvLogRcv(_max_level)
00422 {
00423 }
00424
00425
00426 WvLogConsole::~WvLogConsole()
00427 {
00428 end_line();
00429 }
00430
00431
00432 void WvLogConsole::_mid_line(const char *str, size_t len)
00433 {
00434 uwrite(str, len);
00435 }