00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include "w_defines.h"
00031
00032
00033
00034 #define __ERRLOG_C__
00035
00036
00037 #include <cstdarg>
00038 #include <cstdlib>
00039 #include <cstddef>
00040 #include <cstring>
00041 #include <cassert>
00042 #include <cstdio>
00043 #include <iostream>
00044
00045 #ifdef __GNUC__
00046 #pragma implementation "errlog.h"
00047 #pragma implementation "errlog_s.h"
00048 #pragma implementation "w_debug.h"
00049 #endif
00050
00051 #include "w.h"
00052 #include "errlog.h"
00053 #include <errlog_s.h>
00054 #include <w_strstream.h>
00055
00056 #ifdef EXPLICIT_TEMPLATE
00057 template class w_list_t<ErrLogInfo,unsafe_list_dummy_lock_t>;
00058 template class w_list_i<ErrLogInfo,unsafe_list_dummy_lock_t>;
00059 template class w_keyed_list_t<ErrLogInfo,,unsafe_list_dummy_lock_t simple_string>;
00060 #endif
00061
00062
00063 ostream &operator<<(ostream &out, const simple_string x) {
00064 out << x._s;
00065 return out;
00066 }
00067
00068
00069 #if SM_PAGESIZE < 8192
00070 #define ERRLOG_BUF_SIZE 8192
00071 #else
00072 #define ERRLOG_BUF_SIZE SM_PAGESIZE
00073 #endif
00074 static char buffer[ERRLOG_BUF_SIZE];
00075
00076
00077
00078 ErrLogInfo::ErrLogInfo(ErrLog *e)
00079 : _ident(e->ident()), _e(e)
00080
00081 {
00082 }
00083
00084
00085
00086 static w_keyed_list_t<ErrLogInfo,unsafe_list_dummy_lock_t,simple_string>
00087 _tab(W_KEYED_ARG(ErrLogInfo, _ident, hash_link), unsafe_nolock);
00088
00089
00090
00091 class errlog_dummy {
00092
00093
00094
00095
00096
00097 friend class ErrLog;
00098
00099 protected:
00100 bool table_cleared;
00101
00102 public:
00103 errlog_dummy(){
00104 table_cleared = false;
00105 #ifdef ZERO_INIT
00106 memset(buffer, '\0', sizeof(buffer));
00107 #endif
00108 }
00109 ~errlog_dummy();
00110 void dump();
00111 }_d;
00112
00113 errlog_dummy::~errlog_dummy() {
00114 ErrLogInfo *ei;
00115
00116 while((ei = _tab.pop())) {
00117 delete ei;
00118 }
00119 table_cleared = true;
00120 }
00121
00122 void
00123 errlog_dummy::dump() {
00124 ErrLogInfo *ei;
00125 w_list_i <ErrLogInfo,unsafe_list_dummy_lock_t> iter(_tab);
00126 while((ei=iter.next())) {
00127 ei->dump();
00128 }
00129 }
00130
00131
00132
00133 logstream *
00134 is_logstream(std::basic_ostream<char, std::char_traits<char > > &o)
00135 {
00136 logstream *l=0;
00137 const ostream *tied = NULL;
00138 if((&o)->ios::good()) {
00139 tied = o.ios::tie();
00140 }
00141
00142
00143 {
00144 l = (logstream *)&o;
00145 }
00146 if(l) {
00147
00148
00149
00150 }
00151 if(l &&
00152 (l->__magic1 == logstream::LOGSTREAM__MAGIC) &&
00153 (l->__magic2 == logstream::LOGSTREAM__MAGIC) &&
00154 (l->_prio >= log_none) &&
00155 (l->_prio <= log_all) &&
00156 (l->_log->_magic == ErrLog::ERRORLOG__MAGIC)
00157 ) {
00158
00159 return l;
00160 } else {
00161
00162 return (logstream *)0;
00163 }
00164 }
00165
00166 ostream &
00167 flush_and_setprio(ostream& o, LogPriority p)
00168 {
00169
00170
00171 logstream *l = is_logstream(o);
00172 if(l) {
00173 l->_log->_flush();
00174 if(p != log_none) {
00175 l->_prio = p;
00176 }
00177 } else {
00178 o << flush;
00179 }
00180 return o;
00181 }
00182
00183 ostream& flushl(ostream& out)
00184 {
00185 out << endl;
00186 return flush_and_setprio(out, log_none);
00187 }
00188 ostream& emerg_prio(ostream& o){return flush_and_setprio(o, log_emerg); }
00189 ostream& fatal_prio(ostream& o){return flush_and_setprio(o, log_fatal); }
00190 ostream& internal_prio(ostream& o){ return flush_and_setprio(o, log_internal); }
00191 ostream& error_prio(ostream& o){return flush_and_setprio(o, log_error); }
00192 ostream& warning_prio(ostream& o){ return flush_and_setprio(o, log_warning); }
00193 ostream& info_prio(ostream& o){ return flush_and_setprio(o, log_info); }
00194 ostream& debug_prio(ostream& o){ return flush_and_setprio(o, log_debug); }
00195
00196 #ifdef USE_REGEX
00197 #include "regex_posix.h"
00198 #endif
00199 #include "w_debug.cpp"
00200
00201 #if W_DEBUG_LEVEL > 3
00202 void dummy() { DBG(<<""); }
00203 #endif
00204
00205 #include <critical_section.h>
00206
00207 LogPriority
00208 ErrLog::setloglevel( LogPriority prio)
00209 {
00210 CRITICAL_SECTION(cs, _errlog_mutex);
00211 LogPriority old = _level;
00212 _level = prio;
00213 return old;
00214 }
00215
00216
00217 LogPriority
00218 ErrLog::parse(const char *arg, bool *ok)
00219
00220 {
00221 LogPriority level = log_none;
00222
00223 if(strcmp(arg, "off")==0) {
00224 level = log_none;
00225 } else
00226 if(strcmp(arg, "trace")==0 || strcmp(arg,"debug")==0) {
00227 level = log_debug;
00228 } else
00229 if(strcmp(arg, "info")==0) {
00230 level = log_info;
00231 } else
00232 if(strcmp(arg, "warning")==0) {
00233 level = log_warning;
00234 } else
00235 if(strcmp(arg, "error")==0) {
00236 level = log_error;
00237 } else
00238 if(strcmp(arg, "internal")==0 || strcmp(arg,"critical")==0) {
00239 level = log_internal;
00240 } else
00241 if(strcmp(arg, "fatal")==0 || strcmp(arg,"alert")==0) {
00242 level = log_fatal;
00243 } else
00244 if(strcmp(arg, "emerg")==0) {
00245 level = log_emerg;
00246 } else {
00247 if (ok) *ok = false;
00248 }
00249 return level;
00250 }
00251
00252 void
00253 ErrLog::_closelogfile()
00254 {
00255
00256 assert(_file != NULL);
00257 fclose(_file);
00258 }
00259
00260 void
00261 ErrLog::_openlogfile(
00262 const char *fn
00263 )
00264 {
00265
00266 const char *filename=fn;
00267 if(strcmp(filename, "-")==0) {
00268
00269 _destination = log_to_stderr;
00270 _file = stderr;
00271 return;
00272 }
00273 if(filename) {
00274 _destination = log_to_unix_file;
00275 if(strncmp(filename, "unix:", 5) == 0) {
00276 filename += 5;
00277 } else if (strncmp(filename, "shore:", 6) == 0) {
00278 filename += 6;
00279 }
00280 _file = fopen(filename, "a+");
00281 if(_file == NULL) {
00282 w_rc_t e = RC(fcOS);
00283 cerr << "Cannot fopen Unix file " << filename << endl;
00284 cerr << e << endl;
00285 W_COERCE(e);
00286 }
00287 } else {
00288 cerr << "Unknown logging destination." << endl;
00289 W_FATAL(fcINTERNAL);
00290 }
00291
00292 }
00293
00294 void
00295 ErrLog::_init1()
00296 {
00297
00298 clog.init_errlog(this);
00299 w_reset_strstream(this->clog);
00300 }
00301
00302 void
00303 ErrLog::_init2()
00304 {
00305
00306 ErrLogInfo *ei;
00307 if((ei = _tab.search(this->_ident)) == 0) {
00308 ei = new ErrLogInfo(this);
00309 _tab.put_in_order(ei);
00310 } else {
00311 cerr << "An ErrLog called " << _ident << " already exists." << endl;
00312 W_FATAL(fcINTERNAL);
00313 }
00314 }
00315
00316 ErrLog::ErrLog(
00317 const char *ident,
00318 LoggingDestination dest,
00319 const char *filename,
00320 LogPriority level,
00321 char *ownbuf,
00322 int ownbufsz
00323
00324 ) :
00325 _destination(dest),
00326 _level(level),
00327 _file(0),
00328 _ident(ident),
00329 _buffer(ownbuf?ownbuf:buffer),
00330 _bufsize(ownbuf?ownbufsz:sizeof(buffer)),
00331 _magic(ERRORLOG__MAGIC),
00332 _errlog_mutex(new pthread_mutex_t),
00333 clog(ownbuf?ownbuf:buffer, ownbuf?ownbufsz:sizeof(buffer))
00334 {
00335 DO_PTHREAD(pthread_mutex_init(_errlog_mutex, NULL));
00336 CRITICAL_SECTION(cs, _errlog_mutex);
00337 _init1();
00338
00339 switch( dest ) {
00340 case log_to_unix_file:
00341 {
00342 if(!filename) {
00343 filename = "-";
00344 }
00345 _openlogfile(filename);
00346 }
00347 break;
00348
00349 case log_to_stderr:
00350 _file = stderr;
00351 break;
00352
00353 case log_to_ether:
00354 _file = 0;
00355 break;
00356
00357 default:
00358
00359 cerr << "Bad argument 2 to ErrLog constructor" <<endl;
00360 W_FATAL_MSG(fcINTERNAL, << "Bad argument 2 to ErrLog constructor");
00361 break;
00362 }
00363 _init2();
00364 }
00365
00366 ErrLog::ErrLog(
00367 const char *ident,
00368 LoggingDestination dest,
00369 FILE *file,
00370 LogPriority level,
00371 char *ownbuf,
00372 int ownbufsz
00373
00374 ) :
00375 _destination(dest),
00376 _level(level),
00377 _file(file),
00378 _ident(ident),
00379 _buffer(ownbuf?ownbuf:buffer),
00380 _bufsize(ownbuf?ownbufsz:sizeof(buffer)),
00381 _magic(ERRORLOG__MAGIC),
00382 _errlog_mutex(new pthread_mutex_t),
00383 clog(ownbuf?ownbuf:buffer, ownbuf?ownbufsz:sizeof(buffer))
00384 {
00385 DO_PTHREAD(pthread_mutex_init(_errlog_mutex, NULL));
00386 CRITICAL_SECTION(cs, _errlog_mutex);
00387 _init1();
00388 w_assert9( dest == log_to_open_file );
00389 _init2();
00390 }
00391
00392 ErrLog::~ErrLog()
00393 {
00394 {
00395 CRITICAL_SECTION(cs, _errlog_mutex);
00396 switch(_destination) {
00397 case log_to_unix_file:
00398 case log_to_open_file:
00399 _closelogfile();
00400 break;
00401
00402 case log_to_stderr:
00403
00404
00405
00406 break;
00407
00408 case log_to_ether:
00409 break;
00410 }
00411 if( !_d.table_cleared ) {
00412 ErrLogInfo *ei = _tab.search(this->_ident);
00413 assert(ei!=NULL);
00414
00415 (void) ei->hash_link.detach();
00416 delete ei;
00417 }
00418 }
00419 DO_PTHREAD(pthread_mutex_destroy(_errlog_mutex));
00420 }
00421
00422 void
00423 ErrLog::log(enum LogPriority prio, const char *format, ...)
00424 {
00425 if(_magic != ERRORLOG__MAGIC) {
00426 cerr << "Trying to use uninitialized ErrLog." <<endl;
00427 ::exit(1);
00428 }
00429 va_list ap;
00430 va_start(ap, format);
00431
00432 _flush();
00433
00434 if (prio > _level) {
00435 return;
00436 }
00437
00438 CRITICAL_SECTION(cs, _errlog_mutex);
00439 switch(_destination) {
00440
00441 case log_to_unix_file:
00442 case log_to_open_file:
00443 case log_to_stderr:
00444
00445 #if HAVE_VPRINTF
00446 (void) vfprintf(_file,format, ap);
00447 #else
00448 #error need vfprintf
00449 #endif
00450 fputc('\n', _file);
00451 fflush(_file);
00452 break;
00453
00454 case log_to_ether:
00455 break;
00456 }
00457 va_end(ap);
00458
00459
00460 w_reset_strstream(this->clog);
00461 }
00462
00463 void
00464 ErrLog::_flush()
00465 {
00466 CRITICAL_SECTION(cs, _errlog_mutex);
00467 if(_magic != ERRORLOG__MAGIC) {
00468 cerr << "Fatal error: Trying to use uninitialized ErrLog." <<endl;
00469 ::exit(1);
00470 }
00471 this->clog << ends ;
00472
00473 if (this->clog._prio <= _level) {
00474 switch(_destination) {
00475
00476 case log_to_unix_file:
00477 case log_to_open_file:
00478 case log_to_stderr:
00479 fprintf(_file, "%s", this->clog.c_str());
00480
00481 fflush(_file);
00482 break;
00483
00484 case log_to_ether:
00485 break;
00486 }
00487 }
00488 this->clog.flush();
00489
00490
00491 w_reset_strstream(this->clog);
00492 }