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