MongoDB  2.0.3
log.h
00001 // @file log.h
00002 
00003 /*    Copyright 2009 10gen Inc.
00004  *
00005  *    Licensed under the Apache License, Version 2.0 (the "License");
00006  *    you may not use this file except in compliance with the License.
00007  *    You may obtain a copy of the License at
00008  *
00009  *    http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  *    Unless required by applicable law or agreed to in writing, software
00012  *    distributed under the License is distributed on an "AS IS" BASIS,
00013  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  *    See the License for the specific language governing permissions and
00015  *    limitations under the License.
00016  */
00017 
00018 #pragma once
00019 
00020 #include <string.h>
00021 #include <errno.h>
00022 #include "../bson/util/builder.h"
00023 
00024 #ifndef _WIN32
00025 //#include <syslog.h>
00026 #endif
00027 
00028 namespace mongo {
00029 
00030     enum LogLevel {  LL_DEBUG , LL_INFO , LL_NOTICE , LL_WARNING , LL_ERROR , LL_SEVERE };
00031 
00032     inline const char * logLevelToString( LogLevel l ) {
00033         switch ( l ) {
00034         case LL_DEBUG:
00035         case LL_INFO:
00036         case LL_NOTICE:
00037             return "";
00038         case LL_WARNING:
00039             return "warning" ;
00040         case LL_ERROR:
00041             return "ERROR";
00042         case LL_SEVERE:
00043             return "SEVERE";
00044         default:
00045             return "UNKNOWN";
00046         }
00047     }
00048 
00049     class LabeledLevel {
00050     public:
00051 
00052         LabeledLevel( int level ) : _level( level ) {}
00053         LabeledLevel( const char* label, int level ) : _label( label ), _level( level ) {}
00054         LabeledLevel( const string& label, int level ) : _label( label ), _level( level ) {}
00055 
00056         LabeledLevel operator+( int i ) const {
00057             return LabeledLevel( _label, _level + i );
00058         }
00059 
00060         LabeledLevel operator+( const char* label ) const {
00061             if( _label == "" )
00062                 return LabeledLevel( label, _level );
00063             return LabeledLevel( _label + string("::") + label, _level );
00064         }
00065 
00066         LabeledLevel operator+( string& label ) const {
00067             return LabeledLevel( _label + string("::") + label, _level );
00068         }
00069 
00070         LabeledLevel operator-( int i ) const {
00071             return LabeledLevel( _label, _level - i );
00072         }
00073 
00074         const string& getLabel() const { return _label; }
00075         int getLevel() const { return _level; }
00076 
00077     private:
00078         string _label;
00079         int _level;
00080     };
00081 
00082     class LazyString {
00083     public:
00084         virtual ~LazyString() {}
00085         virtual string val() const = 0;
00086     };
00087 
00088     // Utility class for stringifying object only when val() called.
00089     template< class T >
00090     class LazyStringImpl : public LazyString {
00091     public:
00092         LazyStringImpl( const T &t ) : t_( t ) {}
00093         virtual string val() const { return t_.toString(); }
00094     private:
00095         const T& t_;
00096     };
00097 
00098     class Tee {
00099     public:
00100         virtual ~Tee() {}
00101         virtual void write(LogLevel level , const string& str) = 0;
00102     };
00103 
00104     class Nullstream {
00105     public:
00106         virtual Nullstream& operator<< (Tee* tee) {
00107             return *this;
00108         }
00109         virtual ~Nullstream() {}
00110         virtual Nullstream& operator<<(const char *) {
00111             return *this;
00112         }
00113         virtual Nullstream& operator<<(const string& ) {
00114             return *this;
00115         }
00116         virtual Nullstream& operator<<(const StringData& ) {
00117             return *this;
00118         }
00119         virtual Nullstream& operator<<(char *) {
00120             return *this;
00121         }
00122         virtual Nullstream& operator<<(char) {
00123             return *this;
00124         }
00125         virtual Nullstream& operator<<(int) {
00126             return *this;
00127         }
00128         virtual Nullstream& operator<<(ExitCode) {
00129             return *this;
00130         }
00131         virtual Nullstream& operator<<(unsigned long) {
00132             return *this;
00133         }
00134         virtual Nullstream& operator<<(long) {
00135             return *this;
00136         }
00137         virtual Nullstream& operator<<(unsigned) {
00138             return *this;
00139         }
00140         virtual Nullstream& operator<<(unsigned short) {
00141             return *this;
00142         }
00143         virtual Nullstream& operator<<(double) {
00144             return *this;
00145         }
00146         virtual Nullstream& operator<<(void *) {
00147             return *this;
00148         }
00149         virtual Nullstream& operator<<(const void *) {
00150             return *this;
00151         }
00152         virtual Nullstream& operator<<(long long) {
00153             return *this;
00154         }
00155         virtual Nullstream& operator<<(unsigned long long) {
00156             return *this;
00157         }
00158         virtual Nullstream& operator<<(bool) {
00159             return *this;
00160         }
00161         virtual Nullstream& operator<<(const LazyString&) {
00162             return *this;
00163         }
00164         template< class T >
00165         Nullstream& operator<<(T *t) {
00166             return operator<<( static_cast<void*>( t ) );
00167         }
00168         template< class T >
00169         Nullstream& operator<<(const T *t) {
00170             return operator<<( static_cast<const void*>( t ) );
00171         }
00172         template< class T >
00173         Nullstream& operator<<(const shared_ptr<T> p ) {
00174             T * t = p.get();
00175             if ( ! t )
00176                 *this << "null";
00177             else
00178                 *this << *t;
00179             return *this;
00180         }
00181         template< class T >
00182         Nullstream& operator<<(const T &t) {
00183             return operator<<( static_cast<const LazyString&>( LazyStringImpl< T >( t ) ) );
00184         }
00185 
00186         virtual Nullstream& operator<< (ostream& ( *endl )(ostream&)) {
00187             return *this;
00188         }
00189         virtual Nullstream& operator<< (ios_base& (*hex)(ios_base&)) {
00190             return *this;
00191         }
00192 
00193         virtual void flush(Tee *t = 0) {}
00194     };
00195     extern Nullstream nullstream;
00196 
00197     class Logstream : public Nullstream {
00198         static mongo::mutex mutex;
00199         static int doneSetup;
00200         stringstream ss;
00201         int indent;
00202         LogLevel logLevel;
00203         static FILE* logfile;
00204         static boost::scoped_ptr<ostream> stream;
00205         static vector<Tee*> * globalTees;
00206     public:
00207         inline static void logLockless( const StringData& s );
00208 
00209         static void setLogFile(FILE* f) {
00210             scoped_lock lk(mutex);
00211             logfile = f;
00212         }
00213 
00214         static int magicNumber() {
00215             return 1717;
00216         }
00217 
00218         static int getLogDesc() {
00219             int fd = -1;
00220             if (logfile != NULL)
00221 #if defined(_WIN32)
00222                 // the ISO C++ conformant name is _fileno
00223                 fd = _fileno( logfile );
00224 #else
00225                 fd = fileno( logfile );
00226 #endif
00227             return fd;
00228         }
00229 
00230         inline void flush(Tee *t = 0);
00231 
00232         inline Nullstream& setLogLevel(LogLevel l) {
00233             logLevel = l;
00234             return *this;
00235         }
00236 
00238         Logstream& operator<<(const char *x) { ss << x; return *this; }
00239         Logstream& operator<<(const string& x) { ss << x; return *this; }
00240         Logstream& operator<<(const StringData& x) { ss << x.data(); return *this; }
00241         Logstream& operator<<(char *x)       { ss << x; return *this; }
00242         Logstream& operator<<(char x)        { ss << x; return *this; }
00243         Logstream& operator<<(int x)         { ss << x; return *this; }
00244         Logstream& operator<<(ExitCode x)    { ss << x; return *this; }
00245         Logstream& operator<<(long x)          { ss << x; return *this; }
00246         Logstream& operator<<(unsigned long x) { ss << x; return *this; }
00247         Logstream& operator<<(unsigned x)      { ss << x; return *this; }
00248         Logstream& operator<<(unsigned short x){ ss << x; return *this; }
00249         Logstream& operator<<(double x)        { ss << x; return *this; }
00250         Logstream& operator<<(void *x)         { ss << x; return *this; }
00251         Logstream& operator<<(const void *x)   { ss << x; return *this; }
00252         Logstream& operator<<(long long x)     { ss << x; return *this; }
00253         Logstream& operator<<(unsigned long long x) { ss << x; return *this; }
00254         Logstream& operator<<(bool x)               { ss << x; return *this; }
00255 
00256         Logstream& operator<<(const LazyString& x) {
00257             ss << x.val();
00258             return *this;
00259         }
00260         Nullstream& operator<< (Tee* tee) {
00261             ss << '\n';
00262             flush(tee);
00263             return *this;
00264         }
00265         Logstream& operator<< (ostream& ( *_endl )(ostream&)) {
00266             ss << '\n';
00267             flush(0);
00268             return *this;
00269         }
00270         Logstream& operator<< (ios_base& (*_hex)(ios_base&)) {
00271             ss << _hex;
00272             return *this;
00273         }
00274 
00275         Logstream& prolog() {
00276             return *this;
00277         }
00278 
00279         void addGlobalTee( Tee * t ) {
00280             if ( ! globalTees )
00281                 globalTees = new vector<Tee*>();
00282             globalTees->push_back( t );
00283         }
00284         
00285         void indentInc(){ indent++; }
00286         void indentDec(){ indent--; }
00287         int getIndent() const { return indent; }
00288 
00289     private:
00290         static thread_specific_ptr<Logstream> tsp;
00291         Logstream() {
00292             indent = 0;
00293             _init();
00294         }
00295         void _init() {
00296             ss.str("");
00297             logLevel = LL_INFO;
00298         }
00299     public:
00300         static Logstream& get() {
00301             if ( StaticObserver::_destroyingStatics ) {
00302                 cout << "Logstream::get called in uninitialized state" << endl;
00303             }
00304             Logstream *p = tsp.get();
00305             if( p == 0 )
00306                 tsp.reset( p = new Logstream() );
00307             return *p;
00308         }
00309     };
00310 
00311     extern int logLevel;
00312     extern int tlogLevel;
00313 
00314     inline Nullstream& out( int level = 0 ) {
00315         if ( level > logLevel )
00316             return nullstream;
00317         return Logstream::get();
00318     }
00319 
00320     /* flush the log stream if the log level is
00321        at the specified level or higher. */
00322     inline void logflush(int level = 0) {
00323         if( level > logLevel )
00324             Logstream::get().flush(0);
00325     }
00326 
00327     /* without prolog */
00328     inline Nullstream& _log( int level = 0 ) {
00329         if ( level > logLevel )
00330             return nullstream;
00331         return Logstream::get();
00332     }
00333 
00336     inline Nullstream& tlog( int level = 0 ) {
00337         if ( level > tlogLevel || level > logLevel )
00338             return nullstream;
00339         return Logstream::get().prolog();
00340     }
00341 
00342     inline Nullstream& log( int level ) {
00343         if ( level > logLevel )
00344             return nullstream;
00345         return Logstream::get().prolog();
00346     }
00347 
00348 #define MONGO_LOG(level) if ( MONGO_unlikely(logLevel >= (level)) ) log( level )
00349 #define LOG MONGO_LOG
00350 
00351     inline Nullstream& log( LogLevel l ) {
00352         return Logstream::get().prolog().setLogLevel( l );
00353     }
00354 
00355     inline Nullstream& log( const LabeledLevel& ll ) {
00356         Nullstream& stream = log( ll.getLevel() );
00357         if( ll.getLabel() != "" )
00358             stream << "[" << ll.getLabel() << "] ";
00359         return stream;
00360     }
00361 
00362     inline Nullstream& log() {
00363         return Logstream::get().prolog();
00364     }
00365 
00366     inline Nullstream& error() {
00367         return log( LL_ERROR );
00368     }
00369 
00370     inline Nullstream& warning() {
00371         return log( LL_WARNING );
00372     }
00373 
00374     /* default impl returns "" -- mongod overrides */
00375     extern const char * (*getcurns)();
00376 
00377     inline Nullstream& problem( int level = 0 ) {
00378         if ( level > logLevel )
00379             return nullstream;
00380         Logstream& l = Logstream::get().prolog();
00381         l << ' ' << getcurns() << ' ';
00382         return l;
00383     }
00384 
00389     void initLogging( const string& logpath , bool append );
00390     void rotateLogs( int signal = 0 );
00391 
00392     std::string toUtf8String(const std::wstring& wide);
00393 
00394     inline string errnoWithDescription(int x = errno) {
00395         stringstream s;
00396         s << "errno:" << x << ' ';
00397 
00398 #if defined(_WIN32)
00399         LPTSTR errorText = NULL;
00400         FormatMessage(
00401             FORMAT_MESSAGE_FROM_SYSTEM
00402             |FORMAT_MESSAGE_ALLOCATE_BUFFER
00403             |FORMAT_MESSAGE_IGNORE_INSERTS,
00404             NULL,
00405             x, 0,
00406             (LPTSTR) &errorText,  // output
00407             0, // minimum size for output buffer
00408             NULL);
00409         if( errorText ) {
00410             string x = toUtf8String(errorText);
00411             for( string::iterator i = x.begin(); i != x.end(); i++ ) {
00412                 if( *i == '\n' || *i == '\r' )
00413                     break;
00414                 s << *i;
00415             }
00416             LocalFree(errorText);
00417         }
00418         else
00419             s << strerror(x);
00420         /*
00421         DWORD n = FormatMessage(
00422             FORMAT_MESSAGE_ALLOCATE_BUFFER |
00423             FORMAT_MESSAGE_FROM_SYSTEM |
00424             FORMAT_MESSAGE_IGNORE_INSERTS,
00425             NULL, x,
00426             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
00427             (LPTSTR) &lpMsgBuf, 0, NULL);
00428         */
00429 #else
00430         s << strerror(x);
00431 #endif
00432         return s.str();
00433     }
00434 
00438     string errnoWithPrefix( const char * prefix );
00439 
00440     void Logstream::logLockless( const StringData& s ) {
00441         if ( s.size() == 0 )
00442             return;
00443 
00444         if ( doneSetup == 1717 ) {
00445             if (fwrite(s.data(), s.size(), 1, logfile)) {
00446                 fflush(logfile);
00447             }
00448             else {
00449                 int x = errno;
00450                 cout << "Failed to write to logfile: " << errnoWithDescription(x) << endl;
00451             }
00452         }
00453         else {
00454             cout << s.data();
00455             cout.flush();
00456         }
00457     }
00458 
00459     void Logstream::flush(Tee *t) {
00460         // this ensures things are sane
00461         if ( doneSetup == 1717 ) {
00462             string msg = ss.str();
00463             string threadName = getThreadName();
00464             const char * type = logLevelToString(logLevel);
00465 
00466             int spaceNeeded = (int)(msg.size() + 64 + threadName.size());
00467             int bufSize = 128;
00468             while ( bufSize < spaceNeeded )
00469                 bufSize += 128;
00470 
00471             BufBuilder b(bufSize);
00472             time_t_to_String( time(0) , b.grow(20) );
00473             if (!threadName.empty()) {
00474                 b.appendChar( '[' );
00475                 b.appendStr( threadName , false );
00476                 b.appendChar( ']' );
00477                 b.appendChar( ' ' );
00478             }
00479 
00480             for ( int i=0; i<indent; i++ )
00481                 b.appendChar( '\t' );
00482 
00483             if ( type[0] ) {
00484                 b.appendStr( type , false );
00485                 b.appendStr( ": " , false );
00486             }
00487 
00488             b.appendStr( msg );
00489 
00490             string out( b.buf() , b.len() - 1);
00491 
00492             scoped_lock lk(mutex);
00493 
00494             if( t ) t->write(logLevel,out);
00495             if ( globalTees ) {
00496                 for ( unsigned i=0; i<globalTees->size(); i++ )
00497                     (*globalTees)[i]->write(logLevel,out);
00498             }
00499 
00500 #ifndef _WIN32
00501             //syslog( LOG_INFO , "%s" , cc );
00502 #endif
00503             if(fwrite(out.data(), out.size(), 1, logfile)) {
00504                 fflush(logfile);
00505             }
00506             else {
00507                 int x = errno;
00508                 cout << "Failed to write to logfile: " << errnoWithDescription(x) << ": " << out << endl;
00509             }
00510 
00511 #ifdef POSIX_FADV_DONTNEED
00512             // This only applies to pages that have already been flushed
00513             RARELY posix_fadvise(fileno(logfile), 0, 0, POSIX_FADV_DONTNEED);
00514 #endif
00515 
00516         }
00517         _init();
00518     }
00519 
00520     struct LogIndentLevel {
00521         LogIndentLevel(){
00522             Logstream::get().indentInc();
00523         }
00524         ~LogIndentLevel(){
00525             Logstream::get().indentDec();
00526         }
00527     };
00528 
00529     extern Tee* const warnings; // Things put here go in serverStatus
00530 
00531 } // namespace mongo