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 }