errlog.cpp

00001 /*<std-header orig-src='shore'>
00002 
00003  $Id: errlog.cpp,v 1.31 2010/05/26 01:20:21 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 
00043 #ifdef __GNUC__
00044 #pragma implementation "errlog.h"
00045 #pragma implementation "errlog_s.h"
00046 #pragma implementation "w_debug.h"
00047 #endif
00048 
00049 #include "w.h"
00050 #include "errlog.h"
00051 #include <errlog_s.h>
00052 
00053 #include <w_strstream.h>
00054 #include <cstdio>
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 /** \cond skip */
00063 static char __c;
00064 w_ostrstream  logstream::static_stream(&__c,1);
00065 /** \endcond skip */
00066 
00067 ostream &operator<<(ostream &out, const simple_string x) {
00068     out << x._s;
00069     return out;
00070 }
00071 
00072 /* A buffer large enough for any result that can fit on a page. */
00073 #if SM_PAGESIZE < 8192
00074 #define    ERRLOG_BUF_SIZE    8192
00075 #else
00076 #define    ERRLOG_BUF_SIZE    SM_PAGESIZE
00077 #endif
00078 static char buffer[ERRLOG_BUF_SIZE];
00079 
00080 
00081 /** \cond skip */
00082 ErrLogInfo::ErrLogInfo(ErrLog *e)
00083     : _ident(e->ident()), _e(e)
00084 { 
00085 }
00086 /** \endcond skip */
00087 
00088 // grot- have to wrap w_keyed_list_t to get its destructor
00089 static w_keyed_list_t<ErrLogInfo,unsafe_list_dummy_lock_t,simple_string> 
00090         _tab(W_KEYED_ARG(ErrLogInfo, _ident, hash_link), unsafe_nolock);
00091 
00092 
00093 /**\cond skip */
00094 class errlog_dummy {
00095     // class exists *JUST* to get rid of all the logs
00096     // so that the hash_t code doesn't choke on exit().
00097     // 
00098     // ... and for debugging purposes
00099 
00100     friend class ErrLog;
00101 
00102 protected:
00103     bool table_cleared;
00104 
00105 public:
00106     errlog_dummy(){ 
00107         table_cleared = false;
00108 #ifdef ZERO_INIT
00109         memset(buffer, '\0', sizeof(buffer));
00110 #endif
00111     }
00112     ~errlog_dummy();
00113     void dump();
00114 }_d;
00115 
00116 errlog_dummy::~errlog_dummy() {
00117     ErrLogInfo *ei;
00118 
00119     while((ei = _tab.pop())) {
00120         delete ei;
00121     }
00122     table_cleared = true;
00123 }
00124 
00125 void
00126 errlog_dummy::dump() {
00127     ErrLogInfo *ei;
00128     w_list_i <ErrLogInfo,unsafe_list_dummy_lock_t> iter(_tab);
00129     while((ei=iter.next())) {
00130         ei->dump();
00131     }
00132 }
00133 /**\endcond skip */
00134 
00135 LogPriority
00136 ErrLog::parse(const char *arg, bool *ok)
00137     //doesn't change *ok if no errors
00138 {
00139     LogPriority level = log_none;
00140 
00141     if(strcmp(arg, "off")==0) {
00142         level = log_none;
00143     } else
00144     if(strcmp(arg, "trace")==0 || strcmp(arg,"debug")==0) {
00145         level = log_debug;
00146     } else
00147     if(strcmp(arg, "info")==0) {
00148         level = log_info;
00149     } else
00150     if(strcmp(arg, "warning")==0) {
00151         level = log_warning;
00152     } else
00153     if(strcmp(arg, "error")==0) {
00154         level = log_error;
00155     } else
00156     if(strcmp(arg, "internal")==0 || strcmp(arg,"critical")==0) {
00157         level = log_internal;
00158     } else
00159     if(strcmp(arg, "fatal")==0 || strcmp(arg,"alert")==0) {
00160         level = log_fatal;
00161     } else
00162     if(strcmp(arg, "emerg")==0) {
00163         level = log_emerg;
00164     } else {
00165         if (ok) *ok = false;
00166     }
00167     return level;
00168 }
00169 
00170 void 
00171 ErrLog::_closelogfile() 
00172 { 
00173     assert(_file != NULL);
00174     fclose(_file);
00175 }
00176 
00177 void
00178 ErrLog::_openlogfile(
00179     const char *fn      
00180 ) 
00181 {
00182     const char *filename=fn;
00183     if(strcmp(filename, "-")==0) {
00184         // cerr << "log to stderr" << endl;
00185         _destination = log_to_stderr;
00186         _file = stderr;
00187         return;
00188     }
00189     if(filename) {
00190         _destination = log_to_unix_file;
00191         if(strncmp(filename, "unix:", 5) == 0) {
00192             filename += 5;
00193         } else if (strncmp(filename, "shore:", 6) == 0) {
00194             filename += 6;
00195         }
00196         _file = fopen(filename, "a+");
00197         if(_file == NULL) {
00198             w_rc_t e = RC(fcOS);
00199             cerr << "Cannot fopen Unix file " << filename << endl;
00200             cerr << e << endl;
00201             W_COERCE(e);
00202         }
00203     } else {
00204         cerr << "Unknown logging destination." << endl;
00205         W_FATAL(fcINTERNAL);
00206     }
00207 
00208 }
00209 
00210 void
00211 ErrLog::_init1()
00212 {
00213     clog.init_errlog(this);
00214 #if defined(_WIN32) && defined(FC_ERRLOG_WIN32_LOCK)
00215     InitializeCriticalSection(&_crit);
00216 #endif
00217     w_reset_strstream(this->clog);
00218 }
00219 
00220 void
00221 ErrLog::_init2()
00222 {
00223     ErrLogInfo *ei;
00224     if((ei = _tab.search(this->_ident)) == 0) {
00225         ei = new ErrLogInfo(this);
00226         _tab.put_in_order(ei); // not really ordered
00227     } else {
00228         cerr <<  "An ErrLog called " << _ident << " already exists." << endl;
00229         W_FATAL(fcINTERNAL);
00230     }
00231 }
00232 
00233 ErrLog::ErrLog(
00234     const char *ident,        // required
00235     LoggingDestination dest,     // required
00236     const char *filename,
00237     LogPriority level,         //  = log_error
00238     char *ownbuf,         //  = 0
00239     int  ownbufsz         //  = 0
00240 
00241 ) :
00242     _destination(dest),
00243     _level(level), 
00244     _file(0), 
00245     _ident(ident), 
00246     _buffer(ownbuf?ownbuf:buffer),
00247     _bufsize(ownbuf?ownbufsz:sizeof(buffer)),
00248     clog(ownbuf?ownbuf:buffer, ownbuf?ownbufsz:sizeof(buffer)),
00249     _magic(ERRORLOG__MAGIC)
00250 {
00251     _init1();
00252 
00253     switch( dest ) {
00254     case log_to_unix_file: 
00255         {     
00256             if(!filename) {
00257                 filename = "-"; // stderr
00258             }
00259             _openlogfile(filename);
00260         }
00261         break;
00262 
00263     case log_to_stderr:
00264         _file = stderr;
00265         break;
00266 
00267     case log_to_ether:
00268         _file = 0;
00269         break;
00270 
00271     default:
00272         // fatal error
00273         cerr << "Bad argument 2 to ErrLog constructor" <<endl;
00274         W_FATAL_MSG(fcINTERNAL, << "Bad argument 2 to ErrLog constructor");
00275         break;
00276     }
00277     _init2();
00278 }
00279 
00280 ErrLog::ErrLog(
00281     const char *ident,        // required
00282     LoggingDestination dest,     // required
00283     FILE *file,             
00284     LogPriority level,         //  = log_error
00285     char *ownbuf,         //  = 0
00286     int  ownbufsz         //  = 0
00287 
00288 ) :
00289     _destination(dest),
00290     _level(level), 
00291     _file(file), 
00292     _ident(ident), 
00293     _buffer(ownbuf?ownbuf:buffer),
00294     _bufsize(ownbuf?ownbufsz:sizeof(buffer)),
00295     clog(ownbuf?ownbuf:buffer, ownbuf?ownbufsz:sizeof(buffer)),
00296     _magic(ERRORLOG__MAGIC)
00297 {
00298     _init1();
00299     w_assert9( dest == log_to_open_file );
00300     _init2();
00301 }
00302 
00303 ErrLog::~ErrLog() 
00304 {
00305     switch(_destination) {
00306         case log_to_unix_file:
00307         case log_to_open_file:
00308             _closelogfile();
00309             break;
00310 
00311         case log_to_stderr: 
00312             // let global destructors 
00313             // do the close - we didn't open
00314             // it, we shouldn't close it!
00315             break;
00316 
00317         case log_to_ether:
00318             break;
00319     }
00320     if( !_d.table_cleared ) {
00321         ErrLogInfo *ei = _tab.search(this->_ident);
00322         assert(ei!=NULL);
00323         // remove from the list
00324         (void) ei->hash_link.detach();
00325         delete ei;
00326     }
00327 #if defined(_WIN32) && defined(FC_ERRLOG_WIN32_LOCK)
00328     DeleteCriticalSection(&_crit);
00329 #endif
00330 }
00331 
00332 void 
00333 ErrLog::log(enum LogPriority prio, const char *format, ...) 
00334 {
00335     if(_magic != ERRORLOG__MAGIC) {
00336         cerr << "Trying to use uninitialized ErrLog." <<endl;
00337         ::exit(1);
00338     }
00339     va_list ap;
00340     va_start(ap, format);
00341 
00342 #if defined(_WIN32) && defined(FC_ERRLOG_WIN32_LOCK)
00343     EnterCriticalSection(&_crit);
00344 #endif
00345     _flush(true); 
00346 
00347     if (prio > _level) {
00348 #if defined(_WIN32) && defined(FC_ERRLOG_WIN32_LOCK)
00349         LeaveCriticalSection(&_crit);
00350 #endif
00351         return;
00352     }
00353 
00354     switch(_destination) {
00355 
00356         case log_to_unix_file:
00357         case log_to_open_file:
00358         case log_to_stderr:
00359 
00360 #if HAVE_VPRINTF
00361             (void) vfprintf(_file,format, ap);
00362 #else
00363 #error need vfprintf
00364 #endif
00365             fputc('\n', _file);
00366             fflush(_file);
00367             break;
00368             
00369         case log_to_ether:
00370             break;
00371     }
00372     va_end(ap);
00373 
00374     // clear the slate for the next use of operator<<
00375     w_reset_strstream(this->clog);
00376 
00377 #if defined(_WIN32) && defined(FC_ERRLOG_WIN32_LOCK)
00378     LeaveCriticalSection(&_crit);
00379 #endif
00380 
00381 }
00382 
00383 void 
00384 ErrLog::_flush(bool 
00385 #if defined(_WIN32) && defined(FC_ERRLOG_WIN32_LOCK)
00386     already_in_crit
00387 #endif
00388 ) 
00389 { 
00390 #if defined(_WIN32) && defined(FC_ERRLOG_WIN32_LOCK)
00391     if(!already_in_crit) EnterCriticalSection(&_crit);
00392 #endif
00393 
00394     if(_magic != ERRORLOG__MAGIC) {
00395         cerr << "Fatal error: Trying to use uninitialized ErrLog." <<endl;
00396         ::exit(1);
00397     }
00398     this->clog << ends ;
00399 
00400     if (this->clog._prio <= _level) {
00401         switch(_destination) {
00402 
00403             case log_to_unix_file:
00404             case log_to_open_file:
00405             case log_to_stderr:
00406                 fprintf(_file, "%s", this->clog.c_str());
00407                 // fprintf(_file, "%s\n", this->clog.c_str());
00408                 fflush(_file);
00409                 break;
00410                 
00411             case log_to_ether:
00412                 break;
00413         }
00414     } 
00415     this->clog.flush();
00416 
00417     // reset to beginning of buffer
00418     w_reset_strstream(this->clog);
00419 #if defined(_WIN32) && defined(FC_ERRLOG_WIN32_LOCK)
00420     if(!already_in_crit) LeaveCriticalSection(&_crit);
00421 #endif
00422 }
00423 
00424 logstream *
00425 is_logstream(ostream &o) 
00426 {
00427     logstream *l=0;
00428     const ostream *tied = o.tie();
00429     // cerr << "tied " << ::hex((unsigned int)tied) << endl;
00430     if(tied == &logstream::static_stream) {
00431         l = (logstream *)&o;
00432     }
00433     if(l) {
00434         // cerr << "magic1 " << (unsigned int)l->__magic1 << endl;
00435         // cerr << "magic2 " << (unsigned int)l->__magic1 << endl;
00436         // cerr << "_prio" << l->_prio << endl;
00437     }
00438     if(l && 
00439         (l->__magic1 == logstream::LOGSTREAM__MAGIC) &&
00440         (l->__magic2 == logstream::LOGSTREAM__MAGIC) &&
00441         (l->_prio >= log_none) &&
00442         (l->_prio <= log_all) &&
00443         (l->_log->_magic == ErrLog::ERRORLOG__MAGIC)
00444        ) {
00445         // cerr << " IS log stream" << endl;
00446         return l;
00447     } else {
00448         // cerr << " NOT log stream" << endl;
00449         return (logstream *)0;
00450     }
00451 }
00452 
00453 ostream & 
00454 flush_and_setprio(ostream& o, LogPriority p)
00455 {
00456     // cerr << "flush_and_setprio o=" << &o << endl;
00457     logstream *l = is_logstream(o);
00458     if(l) {
00459         l->_log->_flush(false); 
00460     if(p != log_none) {
00461         l->_prio =  p;
00462     }
00463     } else {
00464     o << flush;
00465     }
00466     return o;
00467 }
00468 
00469 ostream& flushl(ostream& out)
00470 {
00471     out << endl;
00472     return flush_and_setprio(out, log_none); 
00473 }
00474 ostream& emerg_prio(ostream& o){return flush_and_setprio(o, log_emerg); }
00475 ostream& fatal_prio(ostream& o){return flush_and_setprio(o, log_fatal); }
00476 ostream& internal_prio(ostream& o){ return flush_and_setprio(o, log_internal); }
00477 ostream& error_prio(ostream& o){return flush_and_setprio(o, log_error); }
00478 ostream& warning_prio(ostream& o){ return flush_and_setprio(o, log_warning); }
00479 ostream& info_prio(ostream& o){ return flush_and_setprio(o, log_info); }
00480 ostream& debug_prio(ostream& o){ return flush_and_setprio(o, log_debug); }
00481 
00482 #ifdef USE_REGEX
00483 #include "regex_posix.h"
00484 #endif
00485 #include "w_debug.cpp"
00486 
00487 #if W_DEBUG_LEVEL > 3
00488 void dummy() { DBG(<<""); } // to keep gcc quiet about _fname_debug_
00489 #endif
00490 

Generated on Wed Jul 7 17:22:32 2010 for Shore Storage Manager by  doxygen 1.4.7