|
MongoDB
2.0.3
|
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
1.8.0