00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
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
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 LazyString {
00050 public:
00051 virtual ~LazyString() {}
00052 virtual string val() const = 0;
00053 };
00054
00055
00056 template< class T >
00057 class LazyStringImpl : public LazyString {
00058 public:
00059 LazyStringImpl( const T &t ) : t_( t ) {}
00060 virtual string val() const { return t_.toString(); }
00061 private:
00062 const T& t_;
00063 };
00064
00065 class Tee {
00066 public:
00067 virtual ~Tee() {}
00068 virtual void write(LogLevel level , const string& str) = 0;
00069 };
00070
00071 class Nullstream {
00072 public:
00073 virtual Nullstream& operator<< (Tee* tee) {
00074 return *this;
00075 }
00076 virtual ~Nullstream() {}
00077 virtual Nullstream& operator<<(const char *) {
00078 return *this;
00079 }
00080 virtual Nullstream& operator<<(const string& ) {
00081 return *this;
00082 }
00083 virtual Nullstream& operator<<(const StringData& ) {
00084 return *this;
00085 }
00086 virtual Nullstream& operator<<(char *) {
00087 return *this;
00088 }
00089 virtual Nullstream& operator<<(char) {
00090 return *this;
00091 }
00092 virtual Nullstream& operator<<(int) {
00093 return *this;
00094 }
00095 virtual Nullstream& operator<<(ExitCode) {
00096 return *this;
00097 }
00098 virtual Nullstream& operator<<(unsigned long) {
00099 return *this;
00100 }
00101 virtual Nullstream& operator<<(long) {
00102 return *this;
00103 }
00104 virtual Nullstream& operator<<(unsigned) {
00105 return *this;
00106 }
00107 virtual Nullstream& operator<<(double) {
00108 return *this;
00109 }
00110 virtual Nullstream& operator<<(void *) {
00111 return *this;
00112 }
00113 virtual Nullstream& operator<<(const void *) {
00114 return *this;
00115 }
00116 virtual Nullstream& operator<<(long long) {
00117 return *this;
00118 }
00119 virtual Nullstream& operator<<(unsigned long long) {
00120 return *this;
00121 }
00122 virtual Nullstream& operator<<(bool) {
00123 return *this;
00124 }
00125 virtual Nullstream& operator<<(const LazyString&) {
00126 return *this;
00127 }
00128 template< class T >
00129 Nullstream& operator<<(T *t) {
00130 return operator<<( static_cast<void*>( t ) );
00131 }
00132 template< class T >
00133 Nullstream& operator<<(const T *t) {
00134 return operator<<( static_cast<const void*>( t ) );
00135 }
00136 template< class T >
00137 Nullstream& operator<<(const shared_ptr<T> p ) {
00138 T * t = p.get();
00139 if ( ! t )
00140 *this << "null";
00141 else
00142 *this << *t;
00143 return *this;
00144 }
00145 template< class T >
00146 Nullstream& operator<<(const T &t) {
00147 return operator<<( static_cast<const LazyString&>( LazyStringImpl< T >( t ) ) );
00148 }
00149
00150 virtual Nullstream& operator<< (ostream& ( *endl )(ostream&)) {
00151 return *this;
00152 }
00153 virtual Nullstream& operator<< (ios_base& (*hex)(ios_base&)) {
00154 return *this;
00155 }
00156
00157 virtual void flush(Tee *t = 0) {}
00158 };
00159 extern Nullstream nullstream;
00160
00161 class Logstream : public Nullstream {
00162 static mongo::mutex mutex;
00163 static int doneSetup;
00164 stringstream ss;
00165 int indent;
00166 LogLevel logLevel;
00167 static FILE* logfile;
00168 static boost::scoped_ptr<ostream> stream;
00169 static vector<Tee*> * globalTees;
00170 public:
00171 inline static void logLockless( const StringData& s );
00172
00173 static void setLogFile(FILE* f) {
00174 scoped_lock lk(mutex);
00175 logfile = f;
00176 }
00177
00178 static int magicNumber() {
00179 return 1717;
00180 }
00181
00182 static int getLogDesc() {
00183 int fd = -1;
00184 if (logfile != NULL)
00185 #if defined(_WIN32)
00186
00187 fd = _fileno( logfile );
00188 #else
00189 fd = fileno( logfile );
00190 #endif
00191 return fd;
00192 }
00193
00194 inline void flush(Tee *t = 0);
00195
00196 inline Nullstream& setLogLevel(LogLevel l) {
00197 logLevel = l;
00198 return *this;
00199 }
00200
00202 Logstream& operator<<(const char *x) { ss << x; return *this; }
00203 Logstream& operator<<(const string& x) { ss << x; return *this; }
00204 Logstream& operator<<(const StringData& x) { ss << x.data(); return *this; }
00205 Logstream& operator<<(char *x) { ss << x; return *this; }
00206 Logstream& operator<<(char x) { ss << x; return *this; }
00207 Logstream& operator<<(int x) { ss << x; return *this; }
00208 Logstream& operator<<(ExitCode x) { ss << x; return *this; }
00209 Logstream& operator<<(long x) { ss << x; return *this; }
00210 Logstream& operator<<(unsigned long x) { ss << x; return *this; }
00211 Logstream& operator<<(unsigned x) { ss << x; return *this; }
00212 Logstream& operator<<(double x) { ss << x; return *this; }
00213 Logstream& operator<<(void *x) { ss << x; return *this; }
00214 Logstream& operator<<(const void *x) { ss << x; return *this; }
00215 Logstream& operator<<(long long x) { ss << x; return *this; }
00216 Logstream& operator<<(unsigned long long x) { ss << x; return *this; }
00217 Logstream& operator<<(bool x) { ss << x; return *this; }
00218
00219 Logstream& operator<<(const LazyString& x) {
00220 ss << x.val();
00221 return *this;
00222 }
00223 Nullstream& operator<< (Tee* tee) {
00224 ss << '\n';
00225 flush(tee);
00226 return *this;
00227 }
00228 Logstream& operator<< (ostream& ( *_endl )(ostream&)) {
00229 ss << '\n';
00230 flush(0);
00231 return *this;
00232 }
00233 Logstream& operator<< (ios_base& (*_hex)(ios_base&)) {
00234 ss << _hex;
00235 return *this;
00236 }
00237
00238 Logstream& prolog() {
00239 return *this;
00240 }
00241
00242 void addGlobalTee( Tee * t ) {
00243 if ( ! globalTees )
00244 globalTees = new vector<Tee*>();
00245 globalTees->push_back( t );
00246 }
00247
00248 void indentInc(){ indent++; }
00249 void indentDec(){ indent--; }
00250 int getIndent() const { return indent; }
00251
00252 private:
00253 static thread_specific_ptr<Logstream> tsp;
00254 Logstream() {
00255 indent = 0;
00256 _init();
00257 }
00258 void _init() {
00259 ss.str("");
00260 logLevel = LL_INFO;
00261 }
00262 public:
00263 static Logstream& get() {
00264 Logstream *p = tsp.get();
00265 if( p == 0 )
00266 tsp.reset( p = new Logstream() );
00267 return *p;
00268 }
00269 };
00270
00271 extern int logLevel;
00272 extern int tlogLevel;
00273
00274 inline Nullstream& out( int level = 0 ) {
00275 if ( level > logLevel )
00276 return nullstream;
00277 return Logstream::get();
00278 }
00279
00280
00281
00282 inline void logflush(int level = 0) {
00283 if( level > logLevel )
00284 Logstream::get().flush(0);
00285 }
00286
00287
00288 inline Nullstream& _log( int level = 0 ) {
00289 if ( level > logLevel )
00290 return nullstream;
00291 return Logstream::get();
00292 }
00293
00296 inline Nullstream& tlog( int level = 0 ) {
00297 if ( level > tlogLevel || level > logLevel )
00298 return nullstream;
00299 return Logstream::get().prolog();
00300 }
00301
00302 inline Nullstream& log( int level ) {
00303 if ( level > logLevel )
00304 return nullstream;
00305 return Logstream::get().prolog();
00306 }
00307
00308 #define MONGO_LOG(level) if ( logLevel >= (level) ) log( level )
00309 #define LOG MONGO_LOG
00310
00311 inline Nullstream& log( LogLevel l ) {
00312 return Logstream::get().prolog().setLogLevel( l );
00313 }
00314
00315
00316 inline Nullstream& log() {
00317 return Logstream::get().prolog();
00318 }
00319
00320 inline Nullstream& error() {
00321 return log( LL_ERROR );
00322 }
00323
00324 inline Nullstream& warning() {
00325 return log( LL_WARNING );
00326 }
00327
00328
00329 extern const char * (*getcurns)();
00330
00331 inline Nullstream& problem( int level = 0 ) {
00332 if ( level > logLevel )
00333 return nullstream;
00334 Logstream& l = Logstream::get().prolog();
00335 l << ' ' << getcurns() << ' ';
00336 return l;
00337 }
00338
00343 void initLogging( const string& logpath , bool append );
00344 void rotateLogs( int signal = 0 );
00345
00346 std::string toUtf8String(const std::wstring& wide);
00347
00348 inline string errnoWithDescription(int x = errno) {
00349 stringstream s;
00350 s << "errno:" << x << ' ';
00351
00352 #if defined(_WIN32)
00353 LPTSTR errorText = NULL;
00354 FormatMessage(
00355 FORMAT_MESSAGE_FROM_SYSTEM
00356 |FORMAT_MESSAGE_ALLOCATE_BUFFER
00357 |FORMAT_MESSAGE_IGNORE_INSERTS,
00358 NULL,
00359 x, 0,
00360 (LPTSTR) &errorText,
00361 0,
00362 NULL);
00363 if( errorText ) {
00364 string x = toUtf8String(errorText);
00365 for( string::iterator i = x.begin(); i != x.end(); i++ ) {
00366 if( *i == '\n' || *i == '\r' )
00367 break;
00368 s << *i;
00369 }
00370 LocalFree(errorText);
00371 }
00372 else
00373 s << strerror(x);
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383 #else
00384 s << strerror(x);
00385 #endif
00386 return s.str();
00387 }
00388
00392 string errnoWithPrefix( const char * prefix );
00393
00394 void Logstream::logLockless( const StringData& s ) {
00395
00396 if ( s.size() == 0 )
00397 return;
00398
00399 if ( doneSetup == 1717 ) {
00400 if (fwrite(s.data(), s.size(), 1, logfile)) {
00401 fflush(logfile);
00402 }
00403 else {
00404 int x = errno;
00405 cout << "Failed to write to logfile: " << errnoWithDescription(x) << endl;
00406 }
00407 }
00408 else {
00409 cout << s.data();
00410 cout.flush();
00411 }
00412 }
00413
00414 void Logstream::flush(Tee *t) {
00415
00416 if ( doneSetup == 1717 ) {
00417 string msg = ss.str();
00418 string threadName = getThreadName();
00419 const char * type = logLevelToString(logLevel);
00420
00421 int spaceNeeded = (int)(msg.size() + 64 + threadName.size());
00422 int bufSize = 128;
00423 while ( bufSize < spaceNeeded )
00424 bufSize += 128;
00425
00426 BufBuilder b(bufSize);
00427 time_t_to_String( time(0) , b.grow(20) );
00428 if (!threadName.empty()) {
00429 b.appendChar( '[' );
00430 b.appendStr( threadName , false );
00431 b.appendChar( ']' );
00432 b.appendChar( ' ' );
00433 }
00434
00435 for ( int i=0; i<indent; i++ )
00436 b.appendChar( '\t' );
00437
00438 if ( type[0] ) {
00439 b.appendStr( type , false );
00440 b.appendStr( ": " , false );
00441 }
00442
00443 b.appendStr( msg );
00444
00445 string out( b.buf() , b.len() - 1);
00446
00447 scoped_lock lk(mutex);
00448
00449 if( t ) t->write(logLevel,out);
00450 if ( globalTees ) {
00451 for ( unsigned i=0; i<globalTees->size(); i++ )
00452 (*globalTees)[i]->write(logLevel,out);
00453 }
00454
00455 #ifndef _WIN32
00456
00457 #endif
00458 if(fwrite(out.data(), out.size(), 1, logfile)) {
00459 fflush(logfile);
00460 }
00461 else {
00462 int x = errno;
00463 cout << "Failed to write to logfile: " << errnoWithDescription(x) << ": " << out << endl;
00464 }
00465 }
00466 _init();
00467 }
00468
00469 struct LogIndentLevel {
00470 LogIndentLevel(){
00471 Logstream::get().indentInc();
00472 }
00473 ~LogIndentLevel(){
00474 Logstream::get().indentDec();
00475 }
00476 };
00477
00478 }