errlog.cpp

00001 /*<std-header orig-src='shore'>
00002 
00003  $Id: errlog.cpp,v 1.2 2012/01/02 21:52:27 nhall Exp $
00004 
00005 SHORE -- Scalable Heterogeneous Object REpository
00006 
00007 Copyright (c) 1994-99 Computer Sciences Department, University of
00008                       Wisconsin -- Madison
00009 All Rights Reserved.
00010 
00011 Permission to use, copy, modify and distribute this software and its
00012 documentation is hereby granted, provided that both the copyright
00013 notice and this permission notice appear in all copies of the
00014 software, derivative works or modified versions, and any portions
00015 thereof, and that both notices appear in supporting documentation.
00016 
00017 THE AUTHORS AND THE COMPUTER SCIENCES DEPARTMENT OF THE UNIVERSITY
00018 OF WISCONSIN - MADISON ALLOW FREE USE OF THIS SOFTWARE IN ITS
00019 "AS IS" CONDITION, AND THEY DISCLAIM ANY LIABILITY OF ANY KIND
00020 FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
00021 
00022 This software was developed with support by the Advanced Research
00023 Project Agency, ARPA order number 018 (formerly 8230), monitored by
00024 the U.S. Army Research Laboratory under contract DAAB07-91-C-Q518.
00025 Further funding for this work was provided by DARPA through
00026 Rome Research Laboratory Contract No. F30602-97-2-0247.
00027 
00028 */
00029 
00030 #include "w_defines.h"
00031 
00032 /*  -- do not edit anything above this line --   </std-header>*/
00033 
00034 #define __ERRLOG_C__
00035 /* errlog.cpp -- error logging functions */
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 /* A buffer large enough for any result that can fit on a page. */
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 /** \cond skip */
00078 ErrLogInfo::ErrLogInfo(ErrLog *e)
00079     : _ident(e->ident()), _e(e)
00080 
00081 { 
00082 }
00083 /** \endcond skip */
00084 
00085 // grot- have to wrap w_keyed_list_t to get its destructor
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 /**\cond skip */
00091 class errlog_dummy {
00092     // class exists *JUST* to get rid of all the logs
00093     // so that the hash_t code doesn't choke on exit().
00094     // 
00095     // ... and for debugging purposes
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 /**\endcond skip */
00131 
00132 // called by flush_and_set_prio, friend of ErrLog
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     // cerr << "tied " << ::hex((unsigned int)tied) << endl;
00142     // DEAD if(tied == &logstream::static_stream) 
00143  {
00144         l = (logstream *)&o;
00145     }
00146     if(l) {
00147         // cerr << "magic1 " << (unsigned int)l->__magic1 << endl;
00148         // cerr << "magic2 " << (unsigned int)l->__magic1 << endl;
00149         // cerr << "_prio" << l->_prio << endl;
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         // cerr << " IS log stream" << endl;
00159         return l;
00160     } else {
00161         // cerr << " NOT log stream" << endl;
00162         return (logstream *)0;
00163     }
00164 }
00165 
00166 ostream & 
00167 flush_and_setprio(ostream& o, LogPriority p)
00168 {
00169     // cerr << "flush_and_setprio o=" << &o << endl;
00170     // Not entirely thread-safe
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(<<""); } // to keep gcc quiet about _fname_debug_
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 // static
00217 LogPriority
00218 ErrLog::parse(const char *arg, bool *ok)
00219     //doesn't change *ok if no errors
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     // called in cs
00256     assert(_file != NULL);
00257     fclose(_file);
00258 }
00259 
00260 void
00261 ErrLog::_openlogfile(
00262     const char *fn      
00263 ) 
00264 {
00265     // called in cs
00266     const char *filename=fn;
00267     if(strcmp(filename, "-")==0) {
00268         // cerr << "log to stderr" << endl;
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     // called in critical section
00298     clog.init_errlog(this);
00299     w_reset_strstream(this->clog);
00300 }
00301 
00302 void
00303 ErrLog::_init2()
00304 {
00305     // called in critical section
00306     ErrLogInfo *ei;
00307     if((ei = _tab.search(this->_ident)) == 0) {
00308         ei = new ErrLogInfo(this);
00309         _tab.put_in_order(ei); // not really ordered
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,        // required
00318     LoggingDestination dest,     // required
00319     const char *filename,
00320     LogPriority level,         //  = log_error
00321     char *ownbuf,         //  = 0
00322     int  ownbufsz         //  = 0
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 = "-"; // stderr
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         // fatal error
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,        // required
00368     LoggingDestination dest,     // required
00369     FILE *file,             
00370     LogPriority level,         //  = log_error
00371     char *ownbuf,         //  = 0
00372     int  ownbufsz         //  = 0
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                 // let global destructors 
00404                 // do the close - we didn't open
00405                 // it, we shouldn't close it!
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             // remove from the list
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     // clear the slate for the next use of operator<<
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                 // fprintf(_file, "%s\n", this->clog.c_str());
00481                 fflush(_file);
00482                 break;
00483                 
00484             case log_to_ether:
00485                 break;
00486         }
00487     } 
00488     this->clog.flush();
00489 
00490     // reset to beginning of buffer
00491     w_reset_strstream(this->clog);
00492 }

Generated on Mon Jan 2 15:13:57 2012 for Shore Storage Manager by  doxygen 1.4.7