diff --git a/db/db.vcxproj b/db/db.vcxproj index 12d21893ac5..b8347280a49 100644 --- a/db/db.vcxproj +++ b/db/db.vcxproj @@ -549,12 +549,16 @@ + + + + diff --git a/db/dbwebserver.cpp b/db/dbwebserver.cpp index b67cd9ab52d..c2037d09699 100644 --- a/db/dbwebserver.cpp +++ b/db/dbwebserver.cpp @@ -21,7 +21,7 @@ #include "pch.h" #include "../util/miniwebserver.h" -#include "../util/web/html.h" +#include "../util/mongoutils/html.h" #include "../util/md5.hpp" #include "db.h" #include "repl.h" @@ -41,6 +41,7 @@ namespace mongo { using namespace mongoutils::html; using namespace bson; + extern void fillRsLog(stringstream&); extern string bind_ip; extern const char *replInfo; @@ -270,8 +271,9 @@ namespace mongo { try { theReplSet->summarizeAsHtml(s); } - catch(...) { s << "error summarizing replset status"; } + catch(...) { s << "error summarizing replset status\n"; } } + fillRsLog(s); s << _end(); return s.str(); } diff --git a/db/repl/consensus.cpp b/db/repl/consensus.cpp index f78bb103e3c..a598045d74e 100644 --- a/db/repl/consensus.cpp +++ b/db/repl/consensus.cpp @@ -44,7 +44,7 @@ namespace mongo { class E : public BackgroundJob { void run() { ok = 0; - log() << "not done" << endl; + log() << "not done" << rsLog; try { ScopedConn c(m->fullName()); if( c->runCommand("admin", electCmd, result) ) diff --git a/db/repl/health.cpp b/db/repl/health.cpp index 6acc204e114..8677075f667 100644 --- a/db/repl/health.cpp +++ b/db/repl/health.cpp @@ -21,8 +21,9 @@ #include "../../client/dbclient.h" #include "../commands.h" #include "../../util/concurrency/value.h" -#include "../../util/web/html.h" +#include "../../util/mongoutils/html.h" #include "../../util/goodies.h" +#include "../../util/ramlog.h" #include "../helpers/dblogger.h" #include "connections.h" @@ -36,6 +37,9 @@ namespace mongo { using namespace mongoutils::html; + static RamLog _rsLog; + Tee *rsLog = &_rsLog; + /* { replSetHeartbeat : } */ class CmdReplSetHeartbeat : public Command { public: @@ -74,7 +78,7 @@ namespace mongo { m->_health = 0.0; if( m->_upSince ) { m->_upSince = 0; - log() << "replSet " << m->fullName() << " is now down" << endl; + log() << "replSet " << m->fullName() << " is now down" << rsLog; } } @@ -94,7 +98,7 @@ namespace mongo { m->_lastHeartbeat = time(0); if( ok ) { if( m->_upSince == 0 ) { - log() << "replSet " << m->fullName() << " is now up" << endl; + log() << "replSet " << m->fullName() << " is now up" << rsLog; m->_upSince = m->_lastHeartbeat; } m->_health = 1.0; @@ -184,6 +188,14 @@ namespace mongo { s << _table(); } + void fillRsLog(stringstream& s) { + s << "
\n";
+        vector v = _rsLog.get();
+        for( unsigned i = 0; i < v.size(); i++ )
+            s << v[i];
+        s << "
\n"; + } + void ReplSet::summarizeStatus(BSONObjBuilder& b) const { Member *m =_members.head(); vector v; diff --git a/db/repl/replset.cpp b/db/repl/replset.cpp index a1fd81af14f..a4d202317cc 100644 --- a/db/repl/replset.cpp +++ b/db/repl/replset.cpp @@ -25,6 +25,7 @@ namespace mongo { ReplSet *theReplSet = 0; void ReplSet::fillIsMaster(BSONObjBuilder& b) { + log() << "hellO" << rsLog; b.append("ismaster", 0); b.append("ok", false); b.append("msg", "not yet implemented"); @@ -44,7 +45,7 @@ namespace mongo { const char *slash = strchr(p, '/'); uassert(13093, "bad --replSet config string format is: /,[,...]", slash != 0 && p != slash); _name = string(p, slash-p); - log() << "replSet " << cfgString << endl; + log() << "replSet " << cfgString << rsLog; set temp; vector *seeds = new vector; @@ -65,7 +66,7 @@ namespace mongo { temp.insert(m); uassert(13101, "can't use localhost in replset host list", !m.isLocalHost()); if( m.isSelf() ) - log() << "replSet ignoring seed " << m.toString() << " (=self)" << endl; + log() << "replSet ignoring seed " << m.toString() << " (=self)" << rsLog; else seeds->push_back(m); if( *comma == 0 ) @@ -146,13 +147,13 @@ namespace mongo { startupStatusMsg = "can't get admin.system.replset config from self or any seed (uninitialized?)"; log() << "replSet can't get admin.system.replset config from self or any seed (EMPTYCONFIG)\n"; log() << "replSet have you ran replSetInitiate yet?\n"; - log() << "replSet sleeping 1 minute and will try again." << endl; + log() << "replSet sleeping 1 minute and will try again." << rsLog; } else { startupStatus = EMPTYUNREACHABLE; startupStatusMsg = "can't currently get admin.system.replset config from self or any seed (EMPTYUNREACHABLE)"; log() << "replSet can't get admin.system.replset config from self or any seed.\n"; - log() << "replSet sleeping 1 minute and will try again." << endl; + log() << "replSet sleeping 1 minute and will try again." << rsLog; } sleepsecs(60); @@ -164,7 +165,7 @@ namespace mongo { startupStatus = BADCONFIG; startupStatusMsg = "replSet error loading set config (BADCONFIG)"; log() << "replSet error loading configurations\n"; - log() << "replSet replication will not start" << endl; + log() << "replSet replication will not start" << rsLog; fatal(); throw; } @@ -186,7 +187,7 @@ namespace mongo { (theReplSet = new ReplSet(cmdLine.replSet))->go(); } catch(std::exception& e) { - log() << "replSet Caught exception in management thread: " << e.what() << endl; + log() << "replSet Caught exception in management thread: " << e.what() << rsLog; if( theReplSet ) theReplSet->fatal(); } diff --git a/db/repl/replset.h b/db/repl/replset.h index 1b1f0972e40..d119ab1e950 100644 --- a/db/repl/replset.h +++ b/db/repl/replset.h @@ -28,6 +28,8 @@ namespace mongo { extern bool replSet; // true if using repl sets extern class ReplSet *theReplSet; // null until initialized + extern Tee *rsLog; + /* information about the entire repl set, such as the various servers in the set, and their state */ /* note: We currently do not free mem when the set goes away - it is assumed the replset is a singleton and long lived. @@ -142,7 +144,7 @@ namespace mongo { friend class FeedbackThread; public: - void fatal() { _myState = FATAL; log() << "replSet fatal error, stopping replication" << endl; } + void fatal() { _myState = FATAL; log() << "replSet fatal error, stopping replication" << rsLog; } }; diff --git a/db/repl/replset_commands.cpp b/db/repl/replset_commands.cpp index 034cb42e221..a0c653df525 100644 --- a/db/repl/replset_commands.cpp +++ b/db/repl/replset_commands.cpp @@ -63,7 +63,7 @@ namespace mongo { ReplSetConfig newConfig(cmdObj["replSetInitiate"].Obj()); - log() << newConfig.toString() << endl; + log() << newConfig.toString() << rsLog; newConfig.save(); diff --git a/db/repl/rs_config.cpp b/db/repl/rs_config.cpp index 2a598118c36..9e2faf7a69b 100644 --- a/db/repl/rs_config.cpp +++ b/db/repl/rs_config.cpp @@ -138,13 +138,13 @@ namespace mongo { m.check(); } catch( const char * p ) { - log() << "replSet cfg parsing exception for members[" << i << "] " << p << endl; + log() << "replSet cfg parsing exception for members[" << i << "] " << p << rsLog; stringstream ss; ss << "replSet members[" << i << "] " << p; uassert(13107, ss.str(), false); } catch(DBException& e) { - log() << "replSet cfg parsing exception for members[" << i << "] " << e.what() << endl; + log() << "replSet cfg parsing exception for members[" << i << "] " << e.what() << rsLog; stringstream ss; ss << "replSet members[" << i << "] bad config object"; uassert(13135, ss.str(), false); @@ -173,7 +173,7 @@ namespace mongo { clear(); int level = 2; DEV level = 0; - log(0) << "replSet load config from: " << h.toString() << endl; + log(0) << "replSet load config from: " << h.toString() << rsLog; auto_ptr c; try { @@ -207,7 +207,7 @@ namespace mongo { version = -1; } catch( UserException& e) { - log(level) << "replSet couldn't load config " << h.toString() << ' ' << e.what() << endl; + log(level) << "replSet couldn't load config " << h.toString() << ' ' << e.what() << rsLog; return; } @@ -215,7 +215,7 @@ namespace mongo { uassert(13109, "multiple rows in local.system.replset not supported", !c->more()); from(o); _ok = true; - log(level) << "replSet load ok" << endl; + log(level) << "replSet load ok" << rsLog; } } diff --git a/util/log.h b/util/log.h index c50e4bacc93..e2965e80aa4 100644 --- a/util/log.h +++ b/util/log.h @@ -41,8 +41,16 @@ namespace mongo { const T& t_; }; + class Tee { + public: + virtual void write(const string& str) = 0; + }; + class Nullstream { public: + virtual Nullstream& operator<< (Tee* tee) { + return *this; + } virtual ~Nullstream() {} virtual Nullstream& operator<<(const char *) { return *this; @@ -111,15 +119,10 @@ namespace mongo { virtual Nullstream& operator<< (ios_base& (*hex)(ios_base&)) { return *this; } - virtual void flush(){} + virtual void flush(Tee *t = 0) {} }; extern Nullstream nullstream; - class Tee { - public: - virtual void write(const string& str) = 0; - }; - class Logstream : public Nullstream { static mongo::mutex mutex; static int doneSetup; @@ -160,9 +163,9 @@ namespace mongo { ss << x.val(); return *this; } - Logstream& operator<< (Tee& tee) { + Nullstream& operator<< (Tee* tee) { ss << '\n'; - flush(&tee); + flush(tee); return *this; } Logstream& operator<< (ostream& ( *_endl )(ostream&)) { diff --git a/util/mongoutils/README b/util/mongoutils/README new file mode 100755 index 00000000000..d3d874bfb12 --- /dev/null +++ b/util/mongoutils/README @@ -0,0 +1,7 @@ +mongoutils namespace requirements: + +(1) code is not database specific, rather, true utilities +(2) are cross platform +(3) may require boost headers, but not libs +(4) are clean and easy to use in any c++ project without pulling in lots of other stuff +(5) apache license diff --git a/util/web/html.h b/util/mongoutils/html.h similarity index 82% rename from util/web/html.h rename to util/mongoutils/html.h index 2e9cd0597fe..e4e95e76875 100644 --- a/util/web/html.h +++ b/util/mongoutils/html.h @@ -9,6 +9,21 @@ (4) are clean and easy to use in any c++ project without pulling in lots of other stuff */ +/* Copyright 2010 10gen Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #include namespace mongoutils { diff --git a/util/ramlog.h b/util/ramlog.h new file mode 100644 index 00000000000..3f2a5ce76b4 --- /dev/null +++ b/util/ramlog.h @@ -0,0 +1,59 @@ +// log.h + +/* Copyright 2009 10gen Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "log.h" + +namespace mongo { + + class RamLog : public Tee { + enum { + N = 128, + C = 256 + }; + char lines[N][C]; + unsigned h, t; + + public: + RamLog() { + h = 0; t = 1; + for( int i = 0; i < N; i++ ) + lines[i][C-1] = 0; + } + virtual void write(const string& str) { + char *p = lines[t]; + if( str.size() < C ) + strcpy(p, str.c_str()); + else + memcpy(p, str.c_str(), C-1); + t = (t+1) % N; + if( h == t ) + h = (h+1) % N; + } + vector get() const { + vector v; + unsigned x = h; + while( x != t ) { + v.push_back(lines[x]); + x = (x+1) % N; + } + return v; + } + }; + +}