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