errlog.cpp

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

Generated on Thu Dec 9 08:42:27 2010 for Shore Storage Manager by  doxygen 1.4.7