summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
authorAndy Schwerin <schwerin@10gen.com>2013-07-01 14:35:03 -0400
committerAndy Schwerin <schwerin@10gen.com>2013-07-09 16:43:33 -0400
commitea22c3173541606519ddcb6da578b837a092b1c1 (patch)
treed3736e74ee67126f00466eec1686578ba8797749 /src/mongo
parent4bab9b0ee8dbffa00c4c86ea20195524a90f81f4 (diff)
downloadmongo-ea22c3173541606519ddcb6da578b837a092b1c1.tar.gz
SERVER-10084 New logging implementation.
This change-set: * Introduces a new top-level directory, mongo/logger, containing most of the implementation of logging functionality formerly found in log.cpp/log.h. * Cleans up existing, unusual uses of the logging system that were not trivially compatible with the new implementation. * Replaces Logstream/Nulstream with a LogstreamBuilder object, whose destructor writes log messages. This new LogstreamBuilder is reentrant, unlike the old logging code, which was thread-safe but not reentrant. Additionally, std::endl is no longer required to terminate a log line. When a LogstreamBuilder goes out of scope, the log message gets committed. * Separates the log system into several components: a global LogManager, several LogDomains, various kinds of Appenders (e.g., SyslogAppender) and Encoders (for formatting messages). * Allows unit tests to capture and examine log output. This patch does _not_ introduce support for hierarchical log domains, or for enabling and disabling specific log domains when the server is running in a multi-threaded mode. This is future work.
Diffstat (limited to 'src/mongo')
-rw-r--r--src/mongo/SConscript7
-rw-r--r--src/mongo/base/error_codes.err2
-rw-r--r--src/mongo/client/dbclient_rs.cpp2
-rw-r--r--src/mongo/client/dbclientcursor.h3
-rw-r--r--src/mongo/client/distlock.cpp29
-rw-r--r--src/mongo/client/distlock_test.cpp1
-rw-r--r--src/mongo/client/parallel.cpp6
-rw-r--r--src/mongo/db/btree.cpp17
-rw-r--r--src/mongo/db/btreebuilder.cpp3
-rw-r--r--src/mongo/db/client.cpp1
-rw-r--r--src/mongo/db/cmdline.cpp5
-rw-r--r--src/mongo/db/commands/index_stats.cpp2
-rw-r--r--src/mongo/db/commands/isself.cpp22
-rw-r--r--src/mongo/db/commands/mr.cpp2
-rw-r--r--src/mongo/db/commands/parameters.cpp41
-rw-r--r--src/mongo/db/commands/pipeline_command.cpp4
-rw-r--r--src/mongo/db/commands/storage_details.cpp2
-rw-r--r--src/mongo/db/commands/write_commands/batch_executor.cpp5
-rw-r--r--src/mongo/db/database.cpp4
-rw-r--r--src/mongo/db/db.cpp18
-rw-r--r--src/mongo/db/dbcommands.cpp23
-rw-r--r--src/mongo/db/dbcommands_admin.cpp5
-rw-r--r--src/mongo/db/dbwebserver.cpp11
-rw-r--r--src/mongo/db/index.cpp2
-rw-r--r--src/mongo/db/index/btree_based_builder.cpp13
-rw-r--r--src/mongo/db/index_update.cpp4
-rw-r--r--src/mongo/db/initialize_server_global_state.cpp87
-rw-r--r--src/mongo/db/instance.cpp14
-rw-r--r--src/mongo/db/jsobj.cpp9
-rw-r--r--src/mongo/db/ops/query.cpp10
-rw-r--r--src/mongo/db/pagefault.cpp4
-rw-r--r--src/mongo/db/pdfile.cpp14
-rw-r--r--src/mongo/db/pipeline/pipeline_d.cpp6
-rw-r--r--src/mongo/db/query_optimizer_internal.cpp3
-rw-r--r--src/mongo/db/record.cpp2
-rw-r--r--src/mongo/db/repl/master_slave.cpp27
-rw-r--r--src/mongo/db/repl/oplog.cpp4
-rw-r--r--src/mongo/db/repl/rs.cpp4
-rw-r--r--src/mongo/db/server_extra_log_context.cpp2
-rw-r--r--src/mongo/db/storage/namespace_index.cpp2
-rw-r--r--src/mongo/dbtests/basictests.cpp51
-rw-r--r--src/mongo/dbtests/documenttests.cpp3
-rw-r--r--src/mongo/dbtests/extsorttests.cpp3
-rw-r--r--src/mongo/dbtests/framework.cpp4
-rw-r--r--src/mongo/dbtests/jstests.cpp32
-rw-r--r--src/mongo/dbtests/mmaptests.cpp3
-rw-r--r--src/mongo/dbtests/perf/perftest.cpp2
-rw-r--r--src/mongo/dbtests/perftests.cpp8
-rw-r--r--src/mongo/dbtests/queryoptimizertests2.cpp4
-rw-r--r--src/mongo/dbtests/queryutiltests.cpp4
-rw-r--r--src/mongo/dbtests/replsettests.cpp2
-rw-r--r--src/mongo/dbtests/repltests.cpp2
-rw-r--r--src/mongo/dbtests/spin_lock_test.cpp2
-rw-r--r--src/mongo/dbtests/threadedtests.cpp11
-rw-r--r--src/mongo/logger/SConscript16
-rw-r--r--src/mongo/logger/appender.h44
-rw-r--r--src/mongo/logger/console.cpp50
-rw-r--r--src/mongo/logger/console.h48
-rw-r--r--src/mongo/logger/console_appender.h54
-rw-r--r--src/mongo/logger/encoder.h37
-rw-r--r--src/mongo/logger/labeled_level.h64
-rw-r--r--src/mongo/logger/log_domain-impl.h90
-rw-r--r--src/mongo/logger/log_domain.h133
-rw-r--r--src/mongo/logger/log_manager.cpp47
-rw-r--r--src/mongo/logger/log_manager.h57
-rw-r--r--src/mongo/logger/log_severity-inl.h42
-rw-r--r--src/mongo/logger/log_severity.cpp55
-rw-r--r--src/mongo/logger/log_severity.h123
-rw-r--r--src/mongo/logger/log_test.cpp147
-rw-r--r--src/mongo/logger/logger.cpp54
-rw-r--r--src/mongo/logger/logger.h42
-rw-r--r--src/mongo/logger/logstream_builder.cpp110
-rw-r--r--src/mongo/logger/logstream_builder.h140
-rw-r--r--src/mongo/logger/message_event.h46
-rw-r--r--src/mongo/logger/message_event_utf8_encoder.cpp87
-rw-r--r--src/mongo/logger/message_event_utf8_encoder.h53
-rw-r--r--src/mongo/logger/message_log_domain.cpp28
-rw-r--r--src/mongo/logger/message_log_domain.h32
-rw-r--r--src/mongo/logger/ramlog.cpp (renamed from src/mongo/util/ramlog.cpp)66
-rw-r--r--src/mongo/logger/ramlog.h90
-rw-r--r--src/mongo/logger/rotatable_file_appender.h61
-rw-r--r--src/mongo/logger/rotatable_file_manager.cpp70
-rw-r--r--src/mongo/logger/rotatable_file_manager.h77
-rw-r--r--src/mongo/logger/rotatable_file_writer.h3
-rw-r--r--src/mongo/logger/rotatable_file_writer_test.cpp3
-rw-r--r--src/mongo/logger/syslog_appender.h71
-rw-r--r--src/mongo/logger/tee.h35
-rw-r--r--src/mongo/s/chunk.cpp9
-rw-r--r--src/mongo/s/commands_admin.cpp16
-rw-r--r--src/mongo/s/config.cpp6
-rw-r--r--src/mongo/s/cursors.cpp16
-rw-r--r--src/mongo/s/d_split.cpp12
-rw-r--r--src/mongo/s/grid.cpp11
-rw-r--r--src/mongo/s/s_only.cpp15
-rw-r--r--src/mongo/s/server.cpp6
-rw-r--r--src/mongo/s/strategy_shard.cpp2
-rw-r--r--src/mongo/s/strategy_single.cpp2
-rw-r--r--src/mongo/s/version_manager.cpp9
-rw-r--r--src/mongo/scripting/engine_v8.cpp168
-rw-r--r--src/mongo/scripting/engine_v8.h3
-rw-r--r--src/mongo/shell/dbshell.cpp10
-rw-r--r--src/mongo/tools/bsondump.cpp2
-rw-r--r--src/mongo/tools/tool.cpp10
-rw-r--r--src/mongo/unittest/crutch.cpp1
-rw-r--r--src/mongo/unittest/unittest.cpp21
-rw-r--r--src/mongo/unittest/unittest.h7
-rw-r--r--src/mongo/util/background.cpp5
-rw-r--r--src/mongo/util/concurrency/SConscript8
-rw-r--r--src/mongo/util/concurrency/mutexdebugger.cpp11
-rw-r--r--src/mongo/util/concurrency/thread_name.cpp77
-rw-r--r--src/mongo/util/concurrency/thread_name.h35
-rw-r--r--src/mongo/util/exception_filter_win32.cpp1
-rw-r--r--src/mongo/util/file_allocator.cpp1
-rw-r--r--src/mongo/util/goodies.h3
-rw-r--r--src/mongo/util/log.cpp390
-rw-r--r--src/mongo/util/log.h479
-rw-r--r--src/mongo/util/net/message_port.cpp5
-rw-r--r--src/mongo/util/net/message_server_port.cpp3
-rw-r--r--src/mongo/util/net/sock.cpp13
-rw-r--r--src/mongo/util/net/sock.h9
-rw-r--r--src/mongo/util/progress_meter.cpp6
-rw-r--r--src/mongo/util/ramlog.h52
-rw-r--r--src/mongo/util/signal_handlers.cpp12
-rw-r--r--src/mongo/util/stacktrace.cpp4
-rw-r--r--src/mongo/util/stacktrace.h10
-rw-r--r--src/mongo/util/time_support.h4
-rw-r--r--src/mongo/util/util.cpp51
-rw-r--r--src/mongo/util/version.cpp3
128 files changed, 2831 insertions, 1305 deletions
diff --git a/src/mongo/SConscript b/src/mongo/SConscript
index b74f20f2d3e..adf013719fa 100644
--- a/src/mongo/SConscript
+++ b/src/mongo/SConscript
@@ -24,7 +24,8 @@ env.SConscript(['base/SConscript',
'logger/SConscript',
'platform/SConscript',
's/SConscript',
- 'unittest/SConscript'])
+ 'unittest/SConscript',
+ 'util/concurrency/SConscript'])
def add_exe( v ):
return "${PROGPREFIX}%s${PROGSUFFIX}" % v
@@ -46,7 +47,9 @@ env.StaticLibrary('foundation',
],
LIBDEPS=['stacktrace',
'$BUILD_DIR/mongo/base/base',
+ '$BUILD_DIR/mongo/logger/logger',
'$BUILD_DIR/mongo/platform/platform',
+ '$BUILD_DIR/mongo/util/concurrency/thread_name',
'$BUILD_DIR/third_party/shim_allocator',
'$BUILD_DIR/third_party/shim_boost'])
@@ -196,7 +199,6 @@ commonFiles = [ "pch.cpp",
"util/util.cpp",
"util/file_allocator.cpp",
"util/trace.cpp",
- "util/ramlog.cpp",
"util/progress_meter.cpp",
"util/concurrency/task.cpp",
"util/concurrency/thread_pool.cpp",
@@ -278,6 +280,7 @@ env.StaticLibrary('mongocommon', commonFiles,
'stacktrace',
'stringutils',
'fail_point',
+ 'util/concurrency/thread_name',
'$BUILD_DIR/third_party/shim_pcrecpp',
'$BUILD_DIR/third_party/murmurhash3/murmurhash3',
'$BUILD_DIR/third_party/shim_boost'] +
diff --git a/src/mongo/base/error_codes.err b/src/mongo/base/error_codes.err
index c16a63767b1..bbcdd6ae25e 100644
--- a/src/mongo/base/error_codes.err
+++ b/src/mongo/base/error_codes.err
@@ -41,5 +41,7 @@ error_code("FileRenameFailed", 37)
error_code("FileNotOpen", 38)
error_code("FileStreamFailed", 39)
error_code("ConflictingUpdateOperators", 40)
+error_code("FileAlreadyOpen", 41)
+error_code("LogWriteFailed", 42)
error_class("NetworkError", ["HostUnreachable", "HostNotFound"])
diff --git a/src/mongo/client/dbclient_rs.cpp b/src/mongo/client/dbclient_rs.cpp
index 773f2d6fdf3..360101b70e0 100644
--- a/src/mongo/client/dbclient_rs.cpp
+++ b/src/mongo/client/dbclient_rs.cpp
@@ -1823,7 +1823,7 @@ namespace mongo {
return _lazyState._lastClient->recv( m );
}
catch( DBException& e ){
- log() << "could not receive data from " << _lazyState._lastClient << causedBy( e ) << endl;
+ log() << "could not receive data from " << _lazyState._lastClient->toString() << causedBy( e ) << endl;
return false;
}
}
diff --git a/src/mongo/client/dbclientcursor.h b/src/mongo/client/dbclientcursor.h
index 20c28df0a0d..46ae49c46b1 100644
--- a/src/mongo/client/dbclientcursor.h
+++ b/src/mongo/client/dbclientcursor.h
@@ -78,8 +78,7 @@ namespace mongo {
BSONObj o = next();
if( strcmp(o.firstElementFieldName(), "$err") == 0 ) {
string s = "nextSafe(): " + o.toString();
- if( logLevel >= 5 )
- log() << s << endl;
+ LOG(5) << s;
uasserted(13106, s);
}
return o;
diff --git a/src/mongo/client/distlock.cpp b/src/mongo/client/distlock.cpp
index 31f0e0c18d0..3e091a55352 100644
--- a/src/mongo/client/distlock.cpp
+++ b/src/mongo/client/distlock.cpp
@@ -24,6 +24,7 @@
#include "mongo/client/dbclientcursor.h"
#include "mongo/s/type_locks.h"
#include "mongo/s/type_lockpings.h"
+#include "mongo/util/concurrency/thread_name.h"
#include "mongo/util/timer.h"
namespace mongo {
@@ -173,8 +174,9 @@ namespace mongo {
scoped_lock lk( _mutex );
int numOldLocks = _oldLockOIDs.size();
- if( numOldLocks > 0 )
+ if( numOldLocks > 0 ) {
LOG( DistributedLock::logLvl - 1 ) << "trying to delete " << _oldLockOIDs.size() << " old lock entries for process " << process << endl;
+ }
bool removed = false;
for( list<OID>::iterator i = _oldLockOIDs.begin(); i != _oldLockOIDs.end();
@@ -532,6 +534,20 @@ namespace mongo {
return true;
}
+ static void logErrMsgOrWarn(const StringData& messagePrefix,
+ const StringData& lockName,
+ const StringData& errMsg,
+ const StringData& altErrMsg) {
+
+ if (errMsg.empty()) {
+ LOG(DistributedLock::logLvl - 1) << messagePrefix << " '" << lockName << "' " <<
+ altErrMsg << std::endl;
+ }
+ else {
+ warning() << messagePrefix << " '" << lockName << "' " << causedBy(errMsg.toString());
+ }
+ }
+
// Semantics of this method are basically that if the lock cannot be acquired, returns false, can be retried.
// If the lock should not be tried again (some unexpected error) a LockException is thrown.
// If we are only trying to re-enter a currently held lock, reenter should be true.
@@ -704,8 +720,7 @@ namespace mongo {
// TODO: Clean up all the extra code to exit this method, probably with a refactor
if ( !errMsg.empty() || !err["n"].type() || err["n"].numberInt() < 1 ) {
- ( errMsg.empty() ? LOG( logLvl - 1 ) : warning() ) << "Could not force lock '" << lockName << "' "
- << ( !errMsg.empty() ? causedBy(errMsg) : string("(another force won)") ) << endl;
+ logErrMsgOrWarn("Could not force lock", lockName, errMsg, "(another force won");
*other = o; other->getOwned(); conn.done();
return false;
}
@@ -749,10 +764,7 @@ namespace mongo {
// TODO: Clean up all the extra code to exit this method, probably with a refactor
if ( ! errMsg.empty() || ! err["n"].type() || err["n"].numberInt() < 1 ) {
- ( errMsg.empty() ? LOG( logLvl - 1 ) : warning() ) << "Could not re-enter lock '" << lockName << "' "
- << ( !errMsg.empty() ? causedBy(errMsg) : string("(not sure lock is held)") )
- << " gle: " << err
- << endl;
+ logErrMsgOrWarn("Could not re-enter lock", lockName, errMsg, "(not sure lock is held");
*other = o; other->getOwned(); conn.done();
return false;
}
@@ -822,8 +834,7 @@ namespace mongo {
currLock = conn->findOne( LocksType::ConfigNS , BSON( LocksType::name(_name) ) );
if ( !errMsg.empty() || !err["n"].type() || err["n"].numberInt() < 1 ) {
- ( errMsg.empty() ? LOG( logLvl - 1 ) : warning() ) << "could not acquire lock '" << lockName << "' "
- << ( !errMsg.empty() ? causedBy( errMsg ) : string("(another update won)") ) << endl;
+ logErrMsgOrWarn("could not acquire lock", lockName, errMsg, "(another update won");
*other = currLock;
other->getOwned();
gotLock = false;
diff --git a/src/mongo/client/distlock_test.cpp b/src/mongo/client/distlock_test.cpp
index 60c3e5fcc79..aa5ba21069a 100644
--- a/src/mongo/client/distlock_test.cpp
+++ b/src/mongo/client/distlock_test.cpp
@@ -29,6 +29,7 @@
#include "mongo/db/auth/privilege.h"
#include "mongo/db/commands.h"
#include "mongo/util/bson_util.h"
+#include "mongo/util/concurrency/thread_name.h"
#include "mongo/util/timer.h"
// Modify some config options for the RNG, since they cause MSVC to fail
diff --git a/src/mongo/client/parallel.cpp b/src/mongo/client/parallel.cpp
index 8afbfdbbe95..a55eb9785a2 100644
--- a/src/mongo/client/parallel.cpp
+++ b/src/mongo/client/parallel.cpp
@@ -776,7 +776,7 @@ namespace mongo {
ShardPtr primary;
string prefix;
- if (MONGO_unlikely(logLevel >= pc)) {
+ if (MONGO_unlikely(logger::globalLogDomain()->shouldLog(pc))) {
if( _totalTries > 0 ) {
prefix = str::stream() << "retrying (" << _totalTries << " tries)";
}
@@ -798,7 +798,7 @@ namespace mongo {
// Try to get either the chunk manager or the primary shard
config->getChunkManagerOrPrimary( ns, manager, primary );
- if (MONGO_unlikely(logLevel >= pc)) {
+ if (MONGO_unlikely(logger::globalLogDomain()->shouldLog(pc))) {
if (manager) {
vinfo = str::stream() << "[" << manager->getns() << " @ "
<< manager->getVersion().toString() << "]";
@@ -826,7 +826,7 @@ namespace mongo {
// Don't use version to get shards here
todo = _qShards;
- if (MONGO_unlikely(logLevel >= pc)) {
+ if (MONGO_unlikely(logger::globalLogDomain()->shouldLog(pc))) {
vinfo = str::stream() << "[" << _qShards.size() << " shards specified]";
}
}
diff --git a/src/mongo/db/btree.cpp b/src/mongo/db/btree.cpp
index 0a5e8d905d4..c74d71a6884 100644
--- a/src/mongo/db/btree.cpp
+++ b/src/mongo/db/btree.cpp
@@ -146,7 +146,7 @@ namespace mongo {
this->assertValid(order, true);
if ( bt_dmp ) {
- _log() << thisLoc.toString() << ' ';
+ log() << thisLoc.toString() << ' ';
((BtreeBucket *) this)->dump(depth);
}
@@ -1761,18 +1761,19 @@ namespace mongo {
template< class V >
void BtreeBucket<V>::dump(unsigned depth) const {
string indent = string(depth, ' ');
- _log() << "BUCKET n:" << this->n;
- _log() << " parent:" << hex << this->parent.getOfs() << dec;
+ LogstreamBuilder l = log();
+ l << "BUCKET n:" << this->n;
+ l << " parent:" << hex << this->parent.getOfs() << dec;
for ( int i = 0; i < this->n; i++ ) {
- _log() << '\n' << indent;
+ l << '\n' << indent;
KeyNode k = keyNode(i);
string ks = k.key.toString();
- _log() << " " << hex << k.prevChildBucket.getOfs() << '\n';
- _log() << indent << " " << i << ' ' << ks.substr(0, 30) << " Loc:" << k.recordLoc.toString() << dec;
+ l << " " << hex << k.prevChildBucket.getOfs() << '\n';
+ l << indent << " " << i << ' ' << ks.substr(0, 30) << " Loc:" << k.recordLoc.toString() << dec;
if ( this->k(i).isUnused() )
- _log() << " UNUSED";
+ l << " UNUSED";
}
- _log() << "\n" << indent << " " << hex << this->nextChild.getOfs() << dec << endl;
+ l << "\n" << indent << " " << hex << this->nextChild.getOfs() << dec << endl;
}
/** todo: meaning of return code unclear clean up */
diff --git a/src/mongo/db/btreebuilder.cpp b/src/mongo/db/btreebuilder.cpp
index 26c8e27c4b4..a97882b510a 100644
--- a/src/mongo/db/btreebuilder.cpp
+++ b/src/mongo/db/btreebuilder.cpp
@@ -151,8 +151,9 @@ namespace mongo {
mayCommitProgressDurably();
}
- if( levels > 1 )
+ if( levels > 1 ) {
LOG(2) << "btree levels: " << levels << endl;
+ }
}
/** when all addKeys are done, we then build the higher levels of the tree */
diff --git a/src/mongo/db/client.cpp b/src/mongo/db/client.cpp
index 6e098264367..974d072fe93 100644
--- a/src/mongo/db/client.cpp
+++ b/src/mongo/db/client.cpp
@@ -48,6 +48,7 @@
#include "mongo/s/d_logic.h"
#include "mongo/s/stale_exception.h" // for SendStaleConfigException
#include "mongo/scripting/engine.h"
+#include "mongo/util/concurrency/thread_name.h"
#include "mongo/util/file_allocator.h"
#include "mongo/util/mongoutils/checksum.h"
#include "mongo/util/mongoutils/str.h"
diff --git a/src/mongo/db/cmdline.cpp b/src/mongo/db/cmdline.cpp
index f1c6d8661de..5b271439f15 100644
--- a/src/mongo/db/cmdline.cpp
+++ b/src/mongo/db/cmdline.cpp
@@ -296,12 +296,13 @@ namespace {
}
if (params.count("verbose")) {
- logLevel = 1;
+ logger::globalLogDomain()->setMinimumLoggedSeverity(logger::LogSeverity::Debug(1));
}
for (string s = "vv"; s.length() <= 12; s.append("v")) {
if (params.count(s)) {
- logLevel = s.length();
+ logger::globalLogDomain()->setMinimumLoggedSeverity(
+ logger::LogSeverity::Debug(s.length()));
}
}
diff --git a/src/mongo/db/commands/index_stats.cpp b/src/mongo/db/commands/index_stats.cpp
index 1309e078ee9..6a5a6f0cf6a 100644
--- a/src/mongo/db/commands/index_stats.cpp
+++ b/src/mongo/db/commands/index_stats.cpp
@@ -501,7 +501,7 @@ namespace mongo {
string ns = dbname + "." + cmdObj.firstElement().valuestrsafe();
const NamespaceDetails* nsd = nsdetails(ns);
if (!cmdLine.quiet) {
- tlog() << "CMD: indexStats " << ns << endl;
+ MONGO_TLOG(0) << "CMD: indexStats " << ns << endl;
}
if (!nsd) {
errmsg = "ns not found";
diff --git a/src/mongo/db/commands/isself.cpp b/src/mongo/db/commands/isself.cpp
index 055f966c3fe..b6f7e8d6d85 100644
--- a/src/mongo/db/commands/isself.cpp
+++ b/src/mongo/db/commands/isself.cpp
@@ -97,12 +97,15 @@ namespace mongo {
freeifaddrs( addrs );
addrs = NULL;
- if (logLevel >= 1) {
- LOG(1) << "getMyAddrs():";
+ if (logger::globalLogDomain()->shouldLog(logger::LogSeverity::Debug(1))) {
+ LogstreamBuilder builder(logger::globalLogDomain(),
+ getThreadName(),
+ logger::LogSeverity::Debug(1));
+ builder << "getMyAddrs():";
for (vector<string>::const_iterator it=out.begin(), end=out.end(); it!=end; ++it) {
- LOG(1) << " [" << *it << ']';
+ builder << " [" << *it << ']';
}
- LOG(1) << endl;
+ builder << endl;
}
return out;
@@ -141,12 +144,15 @@ namespace mongo {
freeaddrinfo(addrs);
- if (logLevel >= 1) {
- LOG(1) << "getallIPs(\"" << iporhost << "\"):";
+ if (logger::globalLogDomain()->shouldLog(logger::LogSeverity::Debug(1))) {
+ LogstreamBuilder builder(logger::globalLogDomain(),
+ getThreadName(),
+ logger::LogSeverity::Debug(1));
+ builder << "getallIPs(\"" << iporhost << "\"):";
for (vector<string>::const_iterator it=out.begin(), end=out.end(); it!=end; ++it) {
- LOG(1) << " [" << *it << ']';
+ builder << " [" << *it << ']';
}
- LOG(1) << endl;
+ builder << endl;
}
return out;
diff --git a/src/mongo/db/commands/mr.cpp b/src/mongo/db/commands/mr.cpp
index be11a40b995..05cbdb1dd31 100644
--- a/src/mongo/db/commands/mr.cpp
+++ b/src/mongo/db/commands/mr.cpp
@@ -910,7 +910,7 @@ namespace mongo {
{
dbtempreleasecond tl;
if ( ! tl.unlocked() )
- LOG( LL_WARNING ) << "map/reduce can't temp release" << endl;
+ warning() << "map/reduce can't temp release" << endl;
// reduce and finalize last array
finalReduce( all );
}
diff --git a/src/mongo/db/commands/parameters.cpp b/src/mongo/db/commands/parameters.cpp
index b23f6c49665..ddb6bb4a217 100644
--- a/src/mongo/db/commands/parameters.cpp
+++ b/src/mongo/db/commands/parameters.cpp
@@ -23,6 +23,7 @@
#include "mongo/db/commands.h"
#include "mongo/db/cmdline.h"
#include "mongo/db/server_parameters.h"
+#include "mongo/util/mongoutils/str.h"
namespace mongo {
@@ -162,11 +163,41 @@ namespace mongo {
} cmdSet;
namespace {
- ExportedServerParameter<int> LogLevelSetting( ServerParameterSet::getGlobal(),
- "logLevel",
- &logLevel,
- true,
- true );
+ class LogLevelSetting : public ServerParameter {
+ public:
+ LogLevelSetting() : ServerParameter(ServerParameterSet::getGlobal(), "logLevel") {}
+
+ virtual void append(BSONObjBuilder& b, const std::string& name) {
+ b << name << logger::globalLogDomain()->getMinimumLogSeverity().toInt();
+ }
+
+ virtual Status set(const BSONElement& newValueElement) {
+ typedef logger::LogSeverity LogSeverity;
+ int newValue;
+ if (!newValueElement.coerce(&newValue) || newValue < 0)
+ return Status(ErrorCodes::BadValue, mongoutils::str::stream() <<
+ "Invalid value for logLevel: " << newValueElement);
+ LogSeverity newSeverity = (newValue > 0) ? LogSeverity::Debug(newValue) :
+ LogSeverity::Log();
+ logger::globalLogDomain()->setMinimumLoggedSeverity(newSeverity);
+ return Status::OK();
+ }
+
+ virtual Status setFromString(const std::string& str) {
+ typedef logger::LogSeverity LogSeverity;
+ int newValue;
+ Status status = parseNumberFromString(str, &newValue);
+ if (!status.isOK())
+ return status;
+ if (newValue < 0)
+ return Status(ErrorCodes::BadValue, mongoutils::str::stream() <<
+ "Invalid value for logLevel: " << newValue);
+ LogSeverity newSeverity = (newValue > 0) ? LogSeverity::Debug(newValue) :
+ LogSeverity::Log();
+ logger::globalLogDomain()->setMinimumLoggedSeverity(newSeverity);
+ return Status::OK();
+ }
+ } logLevelSetting;
ExportedServerParameter<bool> NoTableScanSetting( ServerParameterSet::getGlobal(),
"notablescan",
diff --git a/src/mongo/db/commands/pipeline_command.cpp b/src/mongo/db/commands/pipeline_command.cpp
index d5905325bd2..56df3369d24 100644
--- a/src/mongo/db/commands/pipeline_command.cpp
+++ b/src/mongo/db/commands/pipeline_command.cpp
@@ -127,7 +127,7 @@ namespace mongo {
BSONObj shardBson(shardBuilder.done());
DEV (log() << "\n---- shardBson\n" <<
- shardBson.jsonString(Strict, 1) << "\n----\n").flush();
+ shardBson.jsonString(Strict, 1) << "\n----\n");
/* for debugging purposes, show what the pipeline now looks like */
DEV {
@@ -135,7 +135,7 @@ namespace mongo {
pPipeline->toBson(&pipelineBuilder);
BSONObj pipelineBson(pipelineBuilder.done());
(log() << "\n---- pipelineBson\n" <<
- pipelineBson.jsonString(Strict, 1) << "\n----\n").flush();
+ pipelineBson.jsonString(Strict, 1) << "\n----\n");
}
/* on the shard servers, create the local pipeline */
diff --git a/src/mongo/db/commands/storage_details.cpp b/src/mongo/db/commands/storage_details.cpp
index b86ec1dff5e..4ea51f0ebd9 100644
--- a/src/mongo/db/commands/storage_details.cpp
+++ b/src/mongo/db/commands/storage_details.cpp
@@ -777,7 +777,7 @@ namespace {
const string ns = dbname + "." + cmdObj.firstElement().valuestrsafe();
const NamespaceDetails* nsd = nsdetails(ns);
if (!cmdLine.quiet) {
- tlog() << "CMD: storageDetails " << ns << ", analyze " << subCommandStr << endl;
+ MONGO_TLOG(0) << "CMD: storageDetails " << ns << ", analyze " << subCommandStr << endl;
}
if (!nsd) {
errmsg = "ns not found";
diff --git a/src/mongo/db/commands/write_commands/batch_executor.cpp b/src/mongo/db/commands/write_commands/batch_executor.cpp
index 23aca5cc1c6..89096429f91 100644
--- a/src/mongo/db/commands/write_commands/batch_executor.cpp
+++ b/src/mongo/db/commands/write_commands/batch_executor.cpp
@@ -157,9 +157,10 @@ namespace mongo {
opDebug.recordStats();
// Log operation if running with at least "-v", or if exceeds slow threshold.
- if (logLevel >= 1
+ if (logger::globalLogDomain()->shouldLog(logger::LogSeverity::Debug(1))
|| opDebug.executionTime > cmdLine.slowMS + childOp.getExpectedLatencyMs()) {
- tlog() << opDebug.report(childOp) << endl;
+
+ MONGO_TLOG(1) << opDebug.report(childOp) << endl;
}
// TODO Log operation if logLevel >= 3 and assertion thrown (as assembleResponse()
diff --git a/src/mongo/db/database.cpp b/src/mongo/db/database.cpp
index 1d151241830..2f69f217e24 100644
--- a/src/mongo/db/database.cpp
+++ b/src/mongo/db/database.cpp
@@ -194,7 +194,7 @@ namespace mongo {
{
if( n < (int) _files.size() && _files[n] ) {
- dlog(2) << "openExistingFile " << n << " is already open" << endl;
+ MONGO_DLOG(2) << "openExistingFile " << n << " is already open" << endl;
return true;
}
}
@@ -474,7 +474,7 @@ namespace mongo {
// that would make the DBs map very large. not clear what to do to handle though,
// perhaps just log it, which is what we do here with the "> 40" :
bool cant = !Lock::isWriteLocked(ns);
- if( logLevel >= 1 || m.size() > 40 || cant || DEBUG_BUILD ) {
+ if( logger::globalLogDomain()->shouldLog(logger::LogSeverity::Debug(1)) || m.size() > 40 || cant || DEBUG_BUILD ) {
log() << "opening db: " << (path==dbpath?"":path) << ' ' << dbname << endl;
}
massert(15927, "can't open database in a read lock. if db was just closed, consider retrying the query. might otherwise indicate an internal error", !cant);
diff --git a/src/mongo/db/db.cpp b/src/mongo/db/db.cpp
index 8ac02271f06..51a1c61fb4b 100644
--- a/src/mongo/db/db.cpp
+++ b/src/mongo/db/db.cpp
@@ -60,6 +60,7 @@
#include "mongo/scripting/engine.h"
#include "mongo/util/background.h"
#include "mongo/util/concurrency/task.h"
+#include "mongo/util/concurrency/thread_name.h"
#include "mongo/util/exception_filter_win32.h"
#include "mongo/util/file_allocator.h"
#include "mongo/util/net/message_server.h"
@@ -446,12 +447,15 @@ namespace mongo {
void run() {
Client::initThread( name().c_str() );
- if( cmdLine.syncdelay == 0 )
+ if( cmdLine.syncdelay == 0 ) {
log() << "warning: --syncdelay 0 is not recommended and can have strange performance" << endl;
- else if( cmdLine.syncdelay == 1 )
+ }
+ else if( cmdLine.syncdelay == 1 ) {
log() << "--syncdelay 1" << endl;
- else if( cmdLine.syncdelay != 60 )
+ }
+ else if( cmdLine.syncdelay != 60 ) {
LOG(1) << "--syncdelay " << cmdLine.syncdelay << endl;
+ }
int time_flushing = 0;
while ( ! inShutdown() ) {
_diaglog.flush();
@@ -474,7 +478,7 @@ namespace mongo {
_flushed(time_flushing);
- if( logLevel >= 1 || time_flushing >= 10000 ) {
+ if( logger::globalLogDomain()->shouldLog(logger::LogSeverity::Debug(1)) || time_flushing >= 10000 ) {
log() << "flushing mmaps took " << time_flushing << "ms " << " for " << numFiles << " files" << endl;
}
}
@@ -577,13 +581,15 @@ namespace mongo {
Client::initThread("initandlisten");
- Logstream::get().addGlobalTee( new RamLog("global") );
+ logger::globalLogDomain()->attachAppender(
+ logger::MessageLogDomain::AppenderAutoPtr(
+ new RamLogAppender(new RamLog("global"))));
bool is32bit = sizeof(int*) == 4;
{
ProcessId pid = ProcessId::getCurrent();
- Nullstream& l = log();
+ LogstreamBuilder l = log();
l << "MongoDB starting : pid=" << pid << " port=" << cmdLine.port << " dbpath=" << dbpath;
if( replSettings.master ) l << " master=" << replSettings.master;
if( replSettings.slave ) l << " slave=" << (int) replSettings.slave;
diff --git a/src/mongo/db/dbcommands.cpp b/src/mongo/db/dbcommands.cpp
index 8ab4b4a0d14..3a2a9036f62 100644
--- a/src/mongo/db/dbcommands.cpp
+++ b/src/mongo/db/dbcommands.cpp
@@ -599,8 +599,9 @@ namespace mongo {
bool run(const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
int was = _diaglog.setLevel( cmdObj.firstElement().numberInt() );
_diaglog.flush();
- if ( !cmdLine.quiet )
- tlog() << "CMD: diagLogging set to " << _diaglog.getLevel() << " from: " << was << endl;
+ if ( !cmdLine.quiet ) {
+ MONGO_TLOG(0) << "CMD: diagLogging set to " << _diaglog.getLevel() << " from: " << was << endl;
+ }
result.append( "was" , was );
return true;
}
@@ -643,8 +644,9 @@ namespace mongo {
virtual bool run(const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) {
string nsToDrop = dbname + '.' + cmdObj.firstElement().valuestr();
NamespaceDetails *d = nsdetails(nsToDrop);
- if ( !cmdLine.quiet )
- tlog() << "CMD: drop " << nsToDrop << endl;
+ if ( !cmdLine.quiet ) {
+ MONGO_TLOG(0) << "CMD: drop " << nsToDrop << endl;
+ }
if ( d == 0 ) {
errmsg = "ns not found";
return false;
@@ -817,8 +819,9 @@ namespace mongo {
BSONElement e = jsobj.firstElement();
string toDeleteNs = dbname + '.' + e.valuestr();
NamespaceDetails *d = nsdetails(toDeleteNs);
- if ( !cmdLine.quiet )
- tlog() << "CMD: dropIndexes " << toDeleteNs << endl;
+ if ( !cmdLine.quiet ) {
+ MONGO_TLOG(0) << "CMD: dropIndexes " << toDeleteNs << endl;
+ }
if ( d ) {
stopIndexBuilds(dbname, jsobj);
@@ -883,7 +886,7 @@ namespace mongo {
BSONElement e = jsobj.firstElement();
string toDeleteNs = dbname + '.' + e.valuestr();
NamespaceDetails *d = nsdetails(toDeleteNs);
- tlog() << "CMD: reIndex " << toDeleteNs << endl;
+ MONGO_TLOG(0) << "CMD: reIndex " << toDeleteNs << endl;
BackgroundOperation::assertNoBgOpInProgForNs(toDeleteNs.c_str());
if ( ! d ) {
@@ -2165,8 +2168,9 @@ namespace mongo {
return;
}
- if ( c->adminOnly() )
+ if ( c->adminOnly() ) {
LOG( 2 ) << "command: " << cmdObj << endl;
+ }
if (c->maintenanceMode() && theReplSet) {
mmSetter.reset(new MaintenanceModeSetter());
@@ -2241,8 +2245,7 @@ namespace mongo {
bool _runCommands(const char *ns, BSONObj& _cmdobj, BufBuilder &b, BSONObjBuilder& anObjBuilder, bool fromRepl, int queryOptions) {
string dbname = nsToDatabase( ns );
- if( logLevel >= 1 )
- log() << "run command " << ns << ' ' << _cmdobj << endl;
+ LOG(1) << "run command " << ns << ' ' << _cmdobj << endl;
const char *p = strchr(ns, '.');
if ( !p ) return false;
diff --git a/src/mongo/db/dbcommands_admin.cpp b/src/mongo/db/dbcommands_admin.cpp
index d2d68df8011..48bf66cd477 100644
--- a/src/mongo/db/dbcommands_admin.cpp
+++ b/src/mongo/db/dbcommands_admin.cpp
@@ -162,8 +162,9 @@ namespace mongo {
bool run(const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl ) {
string ns = dbname + "." + cmdObj.firstElement().valuestrsafe();
NamespaceDetails * d = nsdetails( ns );
- if ( !cmdLine.quiet )
- tlog() << "CMD: validate " << ns << endl;
+ if ( !cmdLine.quiet ) {
+ MONGO_TLOG(0) << "CMD: validate " << ns << endl;
+ }
if ( ! d ) {
errmsg = "ns not found";
diff --git a/src/mongo/db/dbwebserver.cpp b/src/mongo/db/dbwebserver.cpp
index bab3fa99f3f..54d4c323a42 100644
--- a/src/mongo/db/dbwebserver.cpp
+++ b/src/mongo/db/dbwebserver.cpp
@@ -26,6 +26,7 @@
#include <boost/date_time/posix_time/posix_time.hpp>
#include <pcrecpp.h>
+#include "mongo/base/init.h"
#include "mongo/db/auth/authorization_manager.h"
#include "mongo/db/auth/authorization_manager_global.h"
#include "mongo/db/auth/authorization_session.h"
@@ -334,7 +335,8 @@ namespace mongo {
_log = RamLog::get( "global" );
if ( ! _log ) {
_log = new RamLog("global");
- Logstream::get().addGlobalTee( _log );
+ logger::globalLogDomain()->attachAppender(logger::MessageLogDomain::AppenderAutoPtr(
+ new RamLogAppender(_log)));
}
}
@@ -344,7 +346,12 @@ namespace mongo {
RamLog * _log;
};
- LogPlugin * logPlugin = new LogPlugin();
+ MONGO_INITIALIZER_GENERAL(WebStatusLogPlugin, ("ServerLogRedirection"), ("default"))(
+ InitializerContext*) {
+
+ new LogPlugin;
+ return Status::OK();
+ }
// -- handler framework ---
diff --git a/src/mongo/db/index.cpp b/src/mongo/db/index.cpp
index 8d3a46c0f2b..9f6da5803be 100644
--- a/src/mongo/db/index.cpp
+++ b/src/mongo/db/index.cpp
@@ -243,7 +243,7 @@ namespace mongo {
return false;
}
sourceCollection = nsdetails(sourceNS);
- tlog() << "info: creating collection " << sourceNS << " on add index" << endl;
+ MONGO_TLOG(0) << "info: creating collection " << sourceNS << " on add index" << endl;
verify( sourceCollection );
}
diff --git a/src/mongo/db/index/btree_based_builder.cpp b/src/mongo/db/index/btree_based_builder.cpp
index 42618de14e9..735cb292b9b 100644
--- a/src/mongo/db/index/btree_based_builder.cpp
+++ b/src/mongo/db/index/btree_based_builder.cpp
@@ -162,7 +162,7 @@ namespace mongo {
phaseOne->addKeys(keys, loc, mayInterrupt);
cursor->advance();
progressMeter->hit();
- if ( logLevel > 1 && phaseOne->n % 10000 == 0 ) {
+ if ( logger::globalLogDomain()->shouldLog(logger::LogSeverity::Debug(2) ) && phaseOne->n % 10000 == 0 ) {
printMemInfo( "\t iterating objects" );
}
}
@@ -175,7 +175,7 @@ namespace mongo {
Timer t;
- tlog(1) << "fastBuildIndex " << ns << ' ' << idx.info.obj().toString() << endl;
+ MONGO_TLOG(1) << "fastBuildIndex " << ns << ' ' << idx.info.obj().toString() << endl;
bool dupsAllowed = !idx.unique() || ignoreUniqueIndex(idx);
bool dropDups = idx.dropDups() || inDBRepair;
@@ -183,7 +183,8 @@ namespace mongo {
getDur().writingDiskLoc(idx.head).Null();
- if ( logLevel > 1 ) printMemInfo( "before index start" );
+ if ( logger::globalLogDomain()->shouldLog(logger::LogSeverity::Debug(2) ) )
+ printMemInfo( "before index start" );
/* get and sort all the keys ----- */
ProgressMeterHolder pm(op->setMessage("index: (1/3) external sort",
@@ -201,9 +202,11 @@ namespace mongo {
d->setIndexIsMultikey(ns, idxNo);
}
- if ( logLevel > 1 ) printMemInfo( "before final sort" );
+ if ( logger::globalLogDomain()->shouldLog(logger::LogSeverity::Debug(2) ) )
+ printMemInfo( "before final sort" );
phase1.sorter->sort( mayInterrupt );
- if ( logLevel > 1 ) printMemInfo( "after final sort" );
+ if ( logger::globalLogDomain()->shouldLog(logger::LogSeverity::Debug(2) ) )
+ printMemInfo( "after final sort" );
LOG(t.seconds() > 5 ? 0 : 1) << "\t external sort used : " << sorter.numFiles()
<< " files " << " in " << t.seconds() << " secs" << endl;
diff --git a/src/mongo/db/index_update.cpp b/src/mongo/db/index_update.cpp
index daaa955f84f..390f1794de5 100644
--- a/src/mongo/db/index_update.cpp
+++ b/src/mongo/db/index_update.cpp
@@ -269,7 +269,7 @@ namespace mongo {
bool background = idx.info.obj()["background"].trueValue();
- tlog() << "build index " << ns << ' ' << idx.keyPattern() << ( background ? " background" : "" ) << endl;
+ MONGO_TLOG(0) << "build index " << ns << ' ' << idx.keyPattern() << ( background ? " background" : "" ) << endl;
Timer t;
unsigned long long n;
@@ -284,7 +284,7 @@ namespace mongo {
BackgroundIndexBuildJob j(ns.c_str());
n = j.go(ns, d, idx);
}
- tlog() << "build index done. scanned " << n << " total records. " << t.millis() / 1000.0 << " secs" << endl;
+ MONGO_TLOG(0) << "build index done. scanned " << n << " total records. " << t.millis() / 1000.0 << " secs" << endl;
}
extern BSONObj id_obj; // { _id : 1 }
diff --git a/src/mongo/db/initialize_server_global_state.cpp b/src/mongo/db/initialize_server_global_state.cpp
index 9d20834d5b2..125ab6fccf1 100644
--- a/src/mongo/db/initialize_server_global_state.cpp
+++ b/src/mongo/db/initialize_server_global_state.cpp
@@ -19,15 +19,25 @@
#include "mongo/db/initialize_server_global_state.h"
#include <boost/filesystem/operations.hpp>
+#include <memory>
#ifndef _WIN32
+#include <syslog.h>
#include <sys/types.h>
#include <sys/wait.h>
#endif
+#include "mongo/base/init.h"
#include "mongo/db/auth/authorization_manager.h"
#include "mongo/db/auth/security_key.h"
#include "mongo/db/cmdline.h"
+#include "mongo/logger/logger.h"
+#include "mongo/logger/message_event.h"
+#include "mongo/logger/message_event_utf8_encoder.h"
+#include "mongo/logger/rotatable_file_appender.h"
+#include "mongo/logger/rotatable_file_manager.h"
+#include "mongo/logger/rotatable_file_writer.h"
+#include "mongo/logger/syslog_appender.h"
#include "mongo/platform/process_id.h"
#include "mongo/util/log.h"
#include "mongo/util/net/listen.h"
@@ -132,14 +142,13 @@ namespace mongo {
// this is run in the final child process (the server)
- // stdout handled in initLogging
- //fclose(stdout);
- //freopen("/dev/null", "w", stdout);
-
- fclose(stderr);
- fclose(stdin);
+ FILE* f = freopen("/dev/null", "w", stdout);
+ if ( f == NULL ) {
+ cout << "Cant reassign stdout while forking server process: " << strerror(errno) << endl;
+ return false;
+ }
- FILE* f = freopen("/dev/null", "w", stderr);
+ f = freopen("/dev/null", "w", stderr);
if ( f == NULL ) {
cout << "Cant reassign stderr while forking server process: " << strerror(errno) << endl;
return false;
@@ -160,32 +169,74 @@ namespace mongo {
_exit(EXIT_FAILURE);
}
- bool initializeServerGlobalState() {
+ MONGO_INITIALIZER_GENERAL(ServerLogRedirection,
+ ("GlobalLogManager", "globalVariablesConfigured"),
+ ("default"))(
+ InitializerContext*) {
- Listener::globalTicketHolder.resize( cmdLine.maxConns );
+ using logger::LogManager;
+ using logger::MessageEventEphemeral;
+ using logger::MessageEventDetailsEncoder;
+ using logger::MessageEventWithContextEncoder;
+ using logger::MessageLogDomain;
+ using logger::RotatableFileAppender;
+ using logger::StatusWithRotatableFileWriter;
#ifndef _WIN32
- if (!fs::is_directory(cmdLine.socket)) {
- cout << cmdLine.socket << " must be a directory" << endl;
- return false;
- }
+ using logger::SyslogAppender;
if (cmdLine.logWithSyslog) {
StringBuilder sb;
sb << cmdLine.binaryName << "." << cmdLine.port;
- Logstream::useSyslog( sb.str().c_str() );
+ openlog(strdup(sb.str().c_str()), LOG_PID | LOG_CONS, LOG_USER);
+ LogManager* manager = logger::globalLogManager();
+ manager->getGlobalDomain()->clearAppenders();
+ manager->getGlobalDomain()->attachAppender(
+ MessageLogDomain::AppenderAutoPtr(
+ new SyslogAppender<MessageEventEphemeral>(
+ new logger::MessageEventWithContextEncoder)));
+ manager->getNamedDomain("javascriptOutput")->attachAppender(
+ MessageLogDomain::AppenderAutoPtr(
+ new SyslogAppender<MessageEventEphemeral>(
+ new logger::MessageEventWithContextEncoder)));
}
-#endif
+#endif // defined(_WIN32)
+
if (!cmdLine.logpath.empty()) {
fassert(16448, !cmdLine.logWithSyslog);
string absoluteLogpath = boost::filesystem::absolute(
cmdLine.logpath, cmdLine.cwd).string();
- if (!initLogging(absoluteLogpath, cmdLine.logAppend)) {
- cout << "Bad logpath value: \"" << absoluteLogpath << "\"; terminating." << endl;
- return false;
+ StatusWithRotatableFileWriter writer =
+ logger::globalRotatableFileManager()->openFile(absoluteLogpath, cmdLine.logAppend);
+ if (!writer.isOK()) {
+ return writer.getStatus();
}
+ LogManager* manager = logger::globalLogManager();
+ manager->getGlobalDomain()->clearAppenders();
+ manager->getGlobalDomain()->attachAppender(
+ MessageLogDomain::AppenderAutoPtr(
+ new RotatableFileAppender<MessageEventEphemeral>(
+ new MessageEventDetailsEncoder, writer.getValue())));
+ manager->getNamedDomain("javascriptOutput")->attachAppender(
+ MessageLogDomain::AppenderAutoPtr(
+ new RotatableFileAppender<MessageEventEphemeral>(
+ new MessageEventDetailsEncoder, writer.getValue())));
}
+ return Status::OK();
+ }
+
+ bool initializeServerGlobalState() {
+
+ Listener::globalTicketHolder.resize( cmdLine.maxConns );
+
+#ifndef _WIN32
+ if (!fs::is_directory(cmdLine.socket)) {
+ cout << cmdLine.socket << " must be a directory" << endl;
+ return false;
+ }
+#endif
+
if (!cmdLine.pidFile.empty()) {
writePidFile(cmdLine.pidFile);
}
diff --git a/src/mongo/db/instance.cpp b/src/mongo/db/instance.cpp
index cfcbb0480c4..9b260663b93 100644
--- a/src/mongo/db/instance.cpp
+++ b/src/mongo/db/instance.cpp
@@ -318,7 +318,7 @@ namespace mongo {
void mongoAbort(const char *msg) {
if( reportEventToSystem )
reportEventToSystem(msg);
- rawOut(msg);
+ severe() << msg;
::abort();
}
@@ -406,7 +406,7 @@ namespace mongo {
debug.op = op;
long long logThreshold = cmdLine.slowMS;
- bool shouldLog = logLevel >= 1;
+ bool shouldLog = logger::globalLogDomain()->shouldLog(logger::LogSeverity::Debug(1));
if ( op == dbQuery ) {
if ( handlePossibleShardedMessage( m , &dbresponse ) )
@@ -466,12 +466,12 @@ namespace mongo {
}
}
catch ( UserException& ue ) {
- tlog(3) << " Caught Assertion in " << opToString(op) << ", continuing "
+ MONGO_TLOG(3) << " Caught Assertion in " << opToString(op) << ", continuing "
<< ue.toString() << endl;
debug.exceptionInfo = ue.getInfo();
}
catch ( AssertionException& e ) {
- tlog(3) << " Caught Assertion in " << opToString(op) << ", continuing "
+ MONGO_TLOG(3) << " Caught Assertion in " << opToString(op) << ", continuing "
<< e.toString() << endl;
debug.exceptionInfo = e.getInfo();
shouldLog = true;
@@ -484,7 +484,7 @@ namespace mongo {
logThreshold += currentOp.getExpectedLatencyMs();
if ( shouldLog || debug.executionTime > logThreshold ) {
- mongo::tlog() << debug.report( currentOp ) << endl;
+ MONGO_TLOG(0) << debug.report( currentOp ) << endl;
}
if ( currentOp.shouldDBProfile( debug.executionTime ) ) {
@@ -514,13 +514,13 @@ namespace mongo {
uassert( 13004 , str::stream() << "sent negative cursors to kill: " << n , n >= 1 );
if ( n > 2000 ) {
- LOG( n < 30000 ? LL_WARNING : LL_ERROR ) << "receivedKillCursors, n=" << n << endl;
+ ( n < 30000 ? warning() : error() ) << "receivedKillCursors, n=" << n << endl;
verify( n < 30000 );
}
int found = ClientCursor::eraseIfAuthorized(n, (long long *) x);
- if ( logLevel > 0 || found != n ) {
+ if ( logger::globalLogDomain()->shouldLog(logger::LogSeverity::Debug(1)) || found != n ) {
LOG( found == n ? 1 : 0 ) << "killcursors: found " << found << " of " << n << endl;
}
diff --git a/src/mongo/db/jsobj.cpp b/src/mongo/db/jsobj.cpp
index 55c484720ed..bc488d07aea 100644
--- a/src/mongo/db/jsobj.cpp
+++ b/src/mongo/db/jsobj.cpp
@@ -922,13 +922,14 @@ namespace mongo {
}
void BSONObj::dump() const {
- out() << hex;
+ LogstreamBuilder builder = out();
+ builder << hex;
const char *p = objdata();
for ( int i = 0; i < objsize(); i++ ) {
- out() << i << '\t' << ( 0xff & ( (unsigned) *p ) );
+ builder << i << '\t' << ( 0xff & ( (unsigned) *p ) );
if ( *p >= 'A' && *p <= 'z' )
- out() << '\t' << *p;
- out() << endl;
+ builder << '\t' << *p;
+ builder << endl;
p++;
}
}
diff --git a/src/mongo/db/ops/query.cpp b/src/mongo/db/ops/query.cpp
index b7156d305ae..9f6822fd51a 100644
--- a/src/mongo/db/ops/query.cpp
+++ b/src/mongo/db/ops/query.cpp
@@ -800,7 +800,7 @@ namespace mongo {
ccPointer.reset( new ClientCursor( queryOptions, cursor, ns,
jsobj.getOwned() ) );
cursorid = ccPointer->cursorid();
- DEV tlog(2) << "query has more, cursorid: " << cursorid << endl;
+ DEV { MONGO_TLOG(2) << "query has more, cursorid: " << cursorid << endl; }
if ( cursor->supportYields() ) {
ClientCursor::YieldData data;
ccPointer->prepareToYield( data );
@@ -815,7 +815,10 @@ namespace mongo {
}
if ( !ccPointer->ok() && ccPointer->c()->tailable() ) {
- DEV tlog() << "query has no more but tailable, cursorid: " << cursorid << endl;
+ DEV {
+ MONGO_TLOG(0) << "query has no more but tailable, cursorid: " << cursorid <<
+ endl;
+ }
}
if( queryOptions & QueryOption_Exhaust ) {
@@ -941,8 +944,7 @@ namespace mongo {
uassert( 16332 , "can't have an empty ns" , ns[0] );
- if( logLevel >= 2 )
- log() << "runQuery called " << ns << " " << jsobj << endl;
+ LOG(2) << "runQuery called " << ns << " " << jsobj << endl;
curop.debug().ns = ns;
curop.debug().ntoreturn = pq.getNumToReturn();
diff --git a/src/mongo/db/pagefault.cpp b/src/mongo/db/pagefault.cpp
index 74d4e486d53..3a738e55ecc 100644
--- a/src/mongo/db/pagefault.cpp
+++ b/src/mongo/db/pagefault.cpp
@@ -45,7 +45,7 @@ namespace mongo {
if( LockMongoFilesShared::getEra() != era ) {
// files opened and closed. we don't try to handle but just bail out; this is much simpler
// and less error prone and saves us from taking a dbmutex readlock.
- dlog(2) << "era changed" << endl;
+ MONGO_DLOG(2) << "era changed" << endl;
return;
}
r->touch();
@@ -59,7 +59,7 @@ namespace mongo {
verify( cc()._pageFaultRetryableSection == 0 );
if( Lock::isLocked() ) {
cc()._pageFaultRetryableSection = 0;
- if( debug || logLevel > 2 ) {
+ if( debug || logger::globalLogDomain()->shouldLog(logger::LogSeverity::Debug(3)) ) {
LOGSOME << "info PageFaultRetryableSection will not yield, already locked upon reaching" << endl;
}
}
diff --git a/src/mongo/db/pdfile.cpp b/src/mongo/db/pdfile.cpp
index db6d1351308..e6ba5e9d104 100644
--- a/src/mongo/db/pdfile.cpp
+++ b/src/mongo/db/pdfile.cpp
@@ -399,7 +399,7 @@ namespace mongo {
if( !boost::filesystem::exists(filename) )
return false;
if( !mmf.open(filename,false) ) {
- dlog(2) << "info couldn't open " << filename << " probably end of datafile list" << endl;
+ MONGO_DLOG(2) << "info couldn't open " << filename << " probably end of datafile list" << endl;
return false;
}
_mb = mmf.getView(); verify(_mb);
@@ -518,8 +518,11 @@ namespace mongo {
addNewExtentToNamespace(ns, e, loc, emptyLoc, newCapped);
- DEV tlog(1) << "new extent " << ns << " size: 0x" << hex << ExtentSize << " loc: 0x" << hex << offset
- << " emptyLoc:" << hex << emptyLoc.getOfs() << dec << endl;
+ DEV {
+ MONGO_TLOG(1) << "new extent " << ns << " size: 0x" << hex << ExtentSize << " loc: 0x"
+ << hex << offset << " emptyLoc:" << hex << emptyLoc.getOfs() << dec
+ << endl;
+ }
return e;
}
@@ -586,7 +589,7 @@ namespace mongo {
}
}
- if( n > 128 ) LOG( n < 512 ? 1 : 0 ) << "warning: newExtent " << n << " scanned\n";
+ if( n > 128 ) { LOG( n < 512 ? 1 : 0 ) << "warning: newExtent " << n << " scanned\n"; }
if( best ) {
Extent *e = best;
@@ -1953,8 +1956,9 @@ namespace mongo {
q = p / (c+"ns");
bool ok = false;
MONGO_ASSERT_ON_EXCEPTION( ok = fo.apply( q ) );
- if ( ok )
+ if ( ok ) {
LOG(2) << fo.op() << " file " << q.string() << endl;
+ }
int i = 0;
int extra = 10; // should not be necessary, this is defensive in case there are missing files
while ( 1 ) {
diff --git a/src/mongo/db/pipeline/pipeline_d.cpp b/src/mongo/db/pipeline/pipeline_d.cpp
index 5cfb53d148b..d6dcb22732e 100644
--- a/src/mongo/db/pipeline/pipeline_d.cpp
+++ b/src/mongo/db/pipeline/pipeline_d.cpp
@@ -120,11 +120,11 @@ namespace mongo {
/* for debugging purposes, show what the query and sort are */
DEV {
(log() << "\n---- query BSON\n" <<
- queryObj.jsonString(Strict, 1) << "\n----\n").flush();
+ queryObj.jsonString(Strict, 1) << "\n----\n");
(log() << "\n---- sort BSON\n" <<
- sortObj.jsonString(Strict, 1) << "\n----\n").flush();
+ sortObj.jsonString(Strict, 1) << "\n----\n");
(log() << "\n---- fullName\n" <<
- fullName << "\n----\n").flush();
+ fullName << "\n----\n");
}
// Create the necessary context to use a Cursor, including taking a namespace read lock,
diff --git a/src/mongo/db/query_optimizer_internal.cpp b/src/mongo/db/query_optimizer_internal.cpp
index 3191772ec51..6d21d03bec6 100644
--- a/src/mongo/db/query_optimizer_internal.cpp
+++ b/src/mongo/db/query_optimizer_internal.cpp
@@ -946,8 +946,9 @@ namespace mongo {
shared_ptr<QueryPlanRunner> QueryPlanRunnerQueue::init() {
massert( 10369, "no plans", _plans.plans().size() > 0 );
- if ( _plans.plans().size() > 1 )
+ if ( _plans.plans().size() > 1 ) {
LOG(1) << " running multiple plans" << endl;
+ }
for( QueryPlanSet::PlanVector::const_iterator i = _plans.plans().begin();
i != _plans.plans().end(); ++i ) {
shared_ptr<QueryPlanRunner> runner( _prototypeRunner.createChild() );
diff --git a/src/mongo/db/record.cpp b/src/mongo/db/record.cpp
index d55d6d40f68..46c36537e42 100644
--- a/src/mongo/db/record.cpp
+++ b/src/mongo/db/record.cpp
@@ -190,7 +190,7 @@ namespace mongo {
if ( rarely_count++ % ( 2048 / BigHashSize ) == 0 ) {
long long now = Listener::getElapsedTimeMillis();
RARELY if ( now == 0 ) {
- tlog() << "warning Listener::getElapsedTimeMillis returning 0ms" << endl;
+ MONGO_TLOG(0) << "warning Listener::getElapsedTimeMillis returning 0ms" << endl;
}
if ( now - _lastRotate > ( 1000 * RotateTimeSecs ) ) {
diff --git a/src/mongo/db/repl/master_slave.cpp b/src/mongo/db/repl/master_slave.cpp
index cb4a4ce3388..9fd6cb721f8 100644
--- a/src/mongo/db/repl/master_slave.cpp
+++ b/src/mongo/db/repl/master_slave.cpp
@@ -527,8 +527,7 @@ namespace mongo {
@param alreadyLocked caller already put us in write lock if true
*/
void ReplSource::sync_pullOpLog_applyOperation(BSONObj& op, bool alreadyLocked) {
- if( logLevel >= 6 ) // op.tostring is expensive so doing this check explicitly
- LOG(6) << "processing op: " << op << endl;
+ LOG(6) << "processing op: " << op << endl;
if( op.getStringField("op")[0] == 'n' )
return;
@@ -609,8 +608,7 @@ namespace mongo {
bool empty = ctx.db()->isEmpty();
bool incompleteClone = incompleteCloneDbs.count( clientName ) != 0;
- if( logLevel >= 6 )
- LOG(6) << "ns: " << ns << ", justCreated: " << ctx.justCreated() << ", empty: " << empty << ", incompleteClone: " << incompleteClone << endl;
+ LOG(6) << "ns: " << ns << ", justCreated: " << ctx.justCreated() << ", empty: " << empty << ", incompleteClone: " << incompleteClone << endl;
// always apply admin command command
// this is a bit hacky -- the semantics of replication/commands aren't well specified
@@ -844,17 +842,14 @@ namespace mongo {
nextOpTime = OpTime(); // will reread the op below
}
else if ( nextOpTime != syncedTo ) { // didn't get what we queried for - error
- Nullstream& l = log();
- l << "repl: nextOpTime " << nextOpTime.toStringLong() << ' ';
- if ( nextOpTime < syncedTo )
- l << "<??";
- else
- l << ">";
-
- l << " syncedTo " << syncedTo.toStringLong() << '\n';
- log() << "repl: time diff: " << (nextOpTime.getSecs() - syncedTo.getSecs()) << "sec\n";
- log() << "repl: tailing: " << tailing << '\n';
- log() << "repl: data too stale, halting replication" << endl;
+ log()
+ << "repl: nextOpTime " << nextOpTime.toStringLong() << ' '
+ << ((nextOpTime < syncedTo) ? "<??" : ">")
+ << " syncedTo " << syncedTo.toStringLong() << '\n'
+ << "repl: time diff: " << (nextOpTime.getSecs() - syncedTo.getSecs())
+ << "sec\n"
+ << "repl: tailing: " << tailing << '\n'
+ << "repl: data too stale, halting replication" << endl;
replInfo = replAllDead = "data too stale halted replication";
verify( syncedTo < nextOpTime );
throw SyncException();
@@ -977,7 +972,7 @@ namespace mongo {
_sleepAdviceTime = 0;
ReplInfo r("sync");
if ( !cmdLine.quiet ) {
- Nullstream& l = log();
+ LogstreamBuilder l = log();
l << "repl: syncing from ";
if( sourceName() != "main" ) {
l << "source:" << sourceName() << ' ';
diff --git a/src/mongo/db/repl/oplog.cpp b/src/mongo/db/repl/oplog.cpp
index 9917f10b982..1697641ace7 100644
--- a/src/mongo/db/repl/oplog.cpp
+++ b/src/mongo/db/repl/oplog.cpp
@@ -229,9 +229,7 @@ namespace mongo {
append_O_Obj(r->data(), partial, obj);
- if ( logLevel >= 6 ) {
- LOG( 6 ) << "logOp:" << BSONObj::make(r) << endl;
- }
+ LOG( 6 ) << "logOp:" << BSONObj::make(r) << endl;
}
static void _logOpOld(const char *opstr, const char *ns, const char *logNS, const BSONObj& obj, BSONObj *o2, bool *bb, bool fromMigrate ) {
diff --git a/src/mongo/db/repl/rs.cpp b/src/mongo/db/repl/rs.cpp
index 7290e24e7d6..e0c58423611 100644
--- a/src/mongo/db/repl/rs.cpp
+++ b/src/mongo/db/repl/rs.cpp
@@ -62,7 +62,7 @@ namespace mongo {
void replset::sethbmsg(const string& s, const int level) {
if (theReplSet) {
- theReplSet->sethbmsg(s, logLevel);
+ theReplSet->sethbmsg(s, level);
}
}
@@ -686,7 +686,7 @@ namespace mongo {
int n = 0;
for( vector<ReplSetConfig*>::iterator i = cfgs.begin(); i != cfgs.end(); i++ ) {
ReplSetConfig* cfg = *i;
- DEV LOG(1) << n+1 << " config shows version " << cfg->version << rsLog;
+ DEV { LOG(1) << n+1 << " config shows version " << cfg->version << rsLog; }
if( ++n == 1 ) myVersion = cfg->version;
if( cfg->ok() && cfg->version > v ) {
highest = cfg;
diff --git a/src/mongo/db/server_extra_log_context.cpp b/src/mongo/db/server_extra_log_context.cpp
index b183c202751..86c446505ca 100644
--- a/src/mongo/db/server_extra_log_context.cpp
+++ b/src/mongo/db/server_extra_log_context.cpp
@@ -61,7 +61,7 @@ namespace {
if (!logUserIds)
return Status::OK();
- return Logstream::registerExtraLogContextFn(appendServerExtraLogContext);
+ return logger::registerExtraLogContextFn(appendServerExtraLogContext);
}
} // namespace
diff --git a/src/mongo/db/storage/namespace_index.cpp b/src/mongo/db/storage/namespace_index.cpp
index 715300d6ef1..07cb3767161 100644
--- a/src/mongo/db/storage/namespace_index.cpp
+++ b/src/mongo/db/storage/namespace_index.cpp
@@ -70,7 +70,7 @@ namespace mongo {
_ht->kill(extra);
}
catch(DBException&) {
- dlog(3) << "caught exception in kill_ns" << endl;
+ MONGO_DLOG(3) << "caught exception in kill_ns" << endl;
}
}
}
diff --git a/src/mongo/dbtests/basictests.cpp b/src/mongo/dbtests/basictests.cpp
index ad3e5db00b8..ccc81202170 100644
--- a/src/mongo/dbtests/basictests.cpp
+++ b/src/mongo/dbtests/basictests.cpp
@@ -203,12 +203,12 @@ namespace BasicTests {
if( sec == 1 )
matches++;
else
- log() << "temp millis: " << t.millis() << endl;
+ mongo::unittest::log() << "temp millis: " << t.millis() << endl;
ASSERT( sec >= 0 && sec <= 2 );
t.reset();
}
if ( matches < 2 )
- log() << "matches:" << matches << endl;
+ mongo::unittest::log() << "matches:" << matches << endl;
ASSERT( matches >= 2 );
sleepmicros( 1527123 );
@@ -283,7 +283,7 @@ namespace BasicTests {
int elapsedMillis = t.millis();
- log() << "Slept for " << elapsedMillis << endl;
+ mongo::unittest::log() << "Slept for " << elapsedMillis << endl;
ASSERT( almostGTE( elapsedMillis, lastSleepTimeMillis, epsMillis ) );
lastSleepTimeMillis = elapsedMillis;
@@ -601,50 +601,6 @@ namespace BasicTests {
}
} ctest1;
- /** Simple tests for log tees. */
- class LogTee {
- public:
- ~LogTee() {
- // Clean global tees on test failure.
- Logstream::get().removeGlobalTee( &_tee );
- }
- void run() {
- // Attempting to remove a tee before any tees are added is safe.
- Logstream::get().removeGlobalTee( &_tee );
-
- // A log is not written to a non global tee.
- log() << "LogTee test" << endl;
- assertNumLogs( 0 );
-
- // A log is written to a global tee.
- Logstream::get().addGlobalTee( &_tee );
- log() << "LogTee test" << endl;
- assertNumLogs( 1 );
-
- // A log is not written to a tee removed from the global tee list.
- Logstream::get().removeGlobalTee( &_tee );
- log() << "LogTee test" << endl;
- assertNumLogs( 1 );
- }
- private:
- void assertNumLogs( int expected ) const {
- ASSERT_EQUALS( expected, _tee.numLogs() );
- }
- class Tee : public mongo::Tee {
- public:
- Tee() :
- _numLogs() {
- }
- virtual void write( LogLevel level, const string &str ) {
- ++_numLogs;
- }
- int numLogs() const { return _numLogs; }
- private:
- int _numLogs;
- };
- Tee _tee;
- };
-
class All : public Suite {
public:
All() : Suite( "basic" ) {
@@ -684,7 +640,6 @@ namespace BasicTests {
add< CompressionTest1 >();
- add< LogTee >();
}
} myall;
diff --git a/src/mongo/dbtests/documenttests.cpp b/src/mongo/dbtests/documenttests.cpp
index 073127550bd..73075d039a3 100644
--- a/src/mongo/dbtests/documenttests.cpp
+++ b/src/mongo/dbtests/documenttests.cpp
@@ -1285,7 +1285,8 @@ namespace DocumentTests {
assertComparison(expectedResult, fromBson(a), fromBson(b));
}
void assertComparison(int expectedResult, const Value& a, const Value& b) {
- log() << "testing " << a.toString() << " and " << b.toString() << endl;
+ mongo::unittest::log() <<
+ "testing " << a.toString() << " and " << b.toString() << endl;
// reflexivity
ASSERT_EQUALS(0, cmp(a, a));
ASSERT_EQUALS(0, cmp(b, b));
diff --git a/src/mongo/dbtests/extsorttests.cpp b/src/mongo/dbtests/extsorttests.cpp
index 072bce89c5e..27c71517068 100644
--- a/src/mongo/dbtests/extsorttests.cpp
+++ b/src/mongo/dbtests/extsorttests.cpp
@@ -488,7 +488,8 @@ namespace ExtSortTests {
}
} catch (...) {
- log() << "Failure from line " << line << " on iteration " << iteration << endl;
+ mongo::unittest::log() <<
+ "Failure from line " << line << " on iteration " << iteration << endl;
throw;
}
}
diff --git a/src/mongo/dbtests/framework.cpp b/src/mongo/dbtests/framework.cpp
index 826579da552..665cfe7a002 100644
--- a/src/mongo/dbtests/framework.cpp
+++ b/src/mongo/dbtests/framework.cpp
@@ -167,7 +167,7 @@ namespace mongo {
}
if (params.count("debug") || params.count("verbose") ) {
- logLevel = 1;
+ logger::globalLogDomain()->setMinimumLoggedSeverity(logger::LogSeverity::Debug(1));
}
if (params.count("list")) {
@@ -254,7 +254,7 @@ namespace mongo {
TestWatchDog twd;
twd.go();
- // set tlogLevel to -1 to suppress tlog() output in a test program
+ // set tlogLevel to -1 to suppress MONGO_TLOG(0) output in a test program
tlogLevel = -1;
int ret = ::mongo::unittest::Suite::run(suites,filter,runsPerTest);
diff --git a/src/mongo/dbtests/jstests.cpp b/src/mongo/dbtests/jstests.cpp
index 1542ecf0b20..fb201d3aba7 100644
--- a/src/mongo/dbtests/jstests.cpp
+++ b/src/mongo/dbtests/jstests.cpp
@@ -132,35 +132,39 @@ namespace JSTests {
}
};
- /** Installs a tee for auditing log messages, including those logged with tlog(). */
+ /** Installs a tee for auditing log messages, including those logged with MONGO_TLOG(0)(). */
class LogRecordingScope {
public:
LogRecordingScope() :
- _oldTLogLevel( tlogLevel ) {
+ _oldTLogLevel(tlogLevel),
+ _logged(false),
+ _handle(mongo::logger::globalLogDomain()->attachAppender(
+ mongo::logger::MessageLogDomain::AppenderAutoPtr(new Tee(this)))) {
tlogLevel = 0;
- Logstream::get().addGlobalTee( &_tee );
}
~LogRecordingScope() {
- Logstream::get().removeGlobalTee( &_tee );
+ mongo::logger::globalLogDomain()->detachAppender(_handle);
tlogLevel = _oldTLogLevel;
}
/** @return most recent log entry. */
- bool logged() const { return _tee.logged(); }
+ bool logged() const { return _logged; }
private:
- class Tee : public mongo::Tee {
+ class Tee : public mongo::logger::MessageLogDomain::EventAppender {
public:
- Tee() :
- _logged() {
+ Tee(LogRecordingScope* scope) : _scope(scope) {}
+ virtual ~Tee() {}
+ virtual Status append(const logger::MessageEventEphemeral& event) {
+ _scope->_logged = true;
+ return Status::OK();
}
- virtual void write( LogLevel level, const string &str ) { _logged = true; }
- bool logged() const { return _logged; }
private:
- bool _logged;
+ LogRecordingScope* _scope;
};
int _oldTLogLevel;
- Tee _tee;
+ bool _logged;
+ mongo::logger::MessageLogDomain::AppenderHandle _handle;
};
-
+
/** Error logging in Scope::exec(). */
class ExecLogError {
public:
@@ -870,7 +874,7 @@ namespace JSTests {
~Utf8Check() { reset(); }
void run() {
if( !globalScriptEngine->utf8Ok() ) {
- log() << "warning: utf8 not supported" << endl;
+ mongo::unittest::log() << "warning: utf8 not supported" << endl;
return;
}
string utf8ObjSpec = "{'_id':'\\u0001\\u007f\\u07ff\\uffff'}";
diff --git a/src/mongo/dbtests/mmaptests.cpp b/src/mongo/dbtests/mmaptests.cpp
index 9f710b89b36..cb69f6b6bbf 100644
--- a/src/mongo/dbtests/mmaptests.cpp
+++ b/src/mongo/dbtests/mmaptests.cpp
@@ -97,7 +97,8 @@ namespace MMapTests {
}
}
if( t.millis() > 10000 ) {
- log() << "warning: MMap LeakTest is unusually slow N:" << N << ' ' << t.millis() << "ms" << endl;
+ mongo::unittest::log() << "warning: MMap LeakTest is unusually slow N:" << N <<
+ ' ' << t.millis() << "ms" << endl;
}
}
diff --git a/src/mongo/dbtests/perf/perftest.cpp b/src/mongo/dbtests/perf/perftest.cpp
index d0a04a39ef9..290b371150d 100644
--- a/src/mongo/dbtests/perf/perftest.cpp
+++ b/src/mongo/dbtests/perf/perftest.cpp
@@ -762,7 +762,7 @@ namespace Misc {
int main( int argc, char **argv, char** envp ) {
mongo::runGlobalInitializersOrDie(argc, argv, envp);
- logLevel = -1;
+ mongo::logger::globalLogDomain()->setMinimumLoggedSeverity(mongo::logger::LogSeverity::Log());
client_ = new DBDirectClient();
return mongo::dbtests::runDbTests(argc, argv, "/data/db/perftest");
diff --git a/src/mongo/dbtests/perftests.cpp b/src/mongo/dbtests/perftests.cpp
index b0302ac2878..e1f82bfe496 100644
--- a/src/mongo/dbtests/perftests.cpp
+++ b/src/mongo/dbtests/perftests.cpp
@@ -825,14 +825,14 @@ namespace PerfTests {
if( dontOptimizeOutHopefully ) {
throw TestException();
}
- log() << "hmmm" << endl;
+ mongo::unittest::log() << "hmmm" << endl;
}
void thr2(int n) {
if( --n <= 0 ) {
if( dontOptimizeOutHopefully ) {
throw TestException();
}
- log() << "hmmm" << endl;
+ mongo::unittest::log() << "hmmm" << endl;
}
Z z;
try {
@@ -846,7 +846,7 @@ namespace PerfTests {
if( dontOptimizeOutHopefully ) {
throw TestException();
}
- log() << "hmmm" << endl;
+ mongo::unittest::log() << "hmmm" << endl;
}
try {
Z z;
@@ -860,7 +860,7 @@ namespace PerfTests {
if( dontOptimizeOutHopefully ) {
throw TestException();
}
- log() << "hmmm" << endl;
+ mongo::unittest::log() << "hmmm" << endl;
}
Z z;
thr4(n-1);
diff --git a/src/mongo/dbtests/queryoptimizertests2.cpp b/src/mongo/dbtests/queryoptimizertests2.cpp
index f671063d972..a82e46f8038 100644
--- a/src/mongo/dbtests/queryoptimizertests2.cpp
+++ b/src/mongo/dbtests/queryoptimizertests2.cpp
@@ -226,9 +226,9 @@ namespace {
class QueryMissingNs : public Base {
public:
- QueryMissingNs() { log() << "querymissingns starts" << endl; }
+ QueryMissingNs() { mongo::unittest::log() << "querymissingns starts" << endl; }
~QueryMissingNs() {
- log() << "end QueryMissingNs" << endl;
+ mongo::unittest::log() << "end QueryMissingNs" << endl;
}
void run() {
Message m;
diff --git a/src/mongo/dbtests/queryutiltests.cpp b/src/mongo/dbtests/queryutiltests.cpp
index ad7b0f8f569..949f49e099c 100644
--- a/src/mongo/dbtests/queryutiltests.cpp
+++ b/src/mongo/dbtests/queryutiltests.cpp
@@ -75,7 +75,7 @@ namespace QueryUtilTests {
virtual bool isPointIntervalSet() { return false; }
static void checkElt( BSONElement expected, BSONElement actual ) {
if ( expected.woCompare( actual, false ) ) {
- log() << "expected: " << expected << ", got: " << actual;
+ mongo::unittest::log() << "expected: " << expected << ", got: " << actual;
ASSERT( false );
}
}
@@ -2123,7 +2123,7 @@ namespace QueryUtilTests {
}
static void assertEqualWithoutFieldNames( const BSONObj &one, const BSONObj &two ) {
if ( !equalWithoutFieldNames( one, two ) ) {
- log() << one << " != " << two << endl;
+ mongo::unittest::log() << one << " != " << two << endl;
ASSERT( equalWithoutFieldNames( one, two ) );
}
}
diff --git a/src/mongo/dbtests/replsettests.cpp b/src/mongo/dbtests/replsettests.cpp
index d25ca4315dd..82fe74b322e 100644
--- a/src/mongo/dbtests/replsettests.cpp
+++ b/src/mongo/dbtests/replsettests.cpp
@@ -209,7 +209,7 @@ namespace ReplSetTests {
}
}
}
- log() << "index build ending" << endl;
+ mongo::unittest::log() << "index build ending" << endl;
killCurrentOp.notifyAllWaiters();
cc().shutdown();
diff --git a/src/mongo/dbtests/repltests.cpp b/src/mongo/dbtests/repltests.cpp
index da1b6557e4c..7291ad6bde6 100644
--- a/src/mongo/dbtests/repltests.cpp
+++ b/src/mongo/dbtests/repltests.cpp
@@ -126,7 +126,7 @@ namespace ReplTests {
ReplSource a(b.obj());
for( vector< BSONObj >::iterator i = ops.begin(); i != ops.end(); ++i ) {
if ( 0 ) {
- log() << "op: " << *i << endl;
+ mongo::unittest::log() << "op: " << *i << endl;
}
a.applyOperation( *i );
}
diff --git a/src/mongo/dbtests/spin_lock_test.cpp b/src/mongo/dbtests/spin_lock_test.cpp
index cd789c9fe09..408c51eb408 100644
--- a/src/mongo/dbtests/spin_lock_test.cpp
+++ b/src/mongo/dbtests/spin_lock_test.cpp
@@ -92,7 +92,7 @@ namespace {
}
int ms = timer.millis();
- log() << "spinlock ConcurrentIncs time: " << ms << endl;
+ mongo::unittest::log() << "spinlock ConcurrentIncs time: " << ms << endl;
ASSERT_EQUALS( counter, threads*incs );
#if defined(__linux__)
diff --git a/src/mongo/dbtests/threadedtests.cpp b/src/mongo/dbtests/threadedtests.cpp
index 7005c1e2165..dbb000b4def 100644
--- a/src/mongo/dbtests/threadedtests.cpp
+++ b/src/mongo/dbtests/threadedtests.cpp
@@ -253,7 +253,7 @@ namespace ThreadedTests {
cc().shutdown();
}
virtual void validate() {
- log() << "mongomutextest validate" << endl;
+ mongo::unittest::log() << "mongomutextest validate" << endl;
ASSERT( ! Lock::isReadLocked() );
ASSERT( wToXSuccessfulUpgradeCount >= 39 * N / 2000 );
{
@@ -645,10 +645,13 @@ namespace ThreadedTests {
#endif
DEV {
// a _DEBUG buildbot might be slow, try to avoid false positives
- log() << "warning lock upgrade was slow " << t.millis() << endl;
+ mongo::unittest::log() <<
+ "warning lock upgrade was slow " << t.millis() << endl;
}
else {
- log() << "assertion failure: lock upgrade was too slow: " << t.millis() << endl;
+ mongo::unittest::log() <<
+ "assertion failure: lock upgrade was too slow: " <<
+ t.millis() << endl;
ASSERT( false );
}
}
@@ -946,7 +949,7 @@ namespace ThreadedTests {
_hotel.checkOut();
if( ( i % ( checkIns / 10 ) ) == 0 )
- log() << "checked in " << i << " times..." << endl;
+ mongo::unittest::log() << "checked in " << i << " times..." << endl;
}
diff --git a/src/mongo/logger/SConscript b/src/mongo/logger/SConscript
index 369486f3b43..e4d3163b203 100644
--- a/src/mongo/logger/SConscript
+++ b/src/mongo/logger/SConscript
@@ -4,11 +4,23 @@ Import("env")
env.StaticLibrary('logger',
[
+ 'console.cpp',
+ 'log_manager.cpp',
+ 'log_severity.cpp',
+ 'logger.cpp',
+ 'logstream_builder.cpp',
+ 'message_event_utf8_encoder.cpp',
+ 'message_log_domain.cpp',
+ 'ramlog.cpp',
+ 'rotatable_file_manager.cpp',
'rotatable_file_writer.cpp',
],
- LIBDEPS=['$BUILD_DIR/mongo/base/base'])
+ LIBDEPS=['$BUILD_DIR/mongo/base/base',
+ '$BUILD_DIR/mongo/util/concurrency/thread_name'])
+
+env.CppUnitTest('log_test', 'log_test.cpp',
+ LIBDEPS=['logger', '$BUILD_DIR/mongo/foundation'])
env.CppUnitTest('rotatable_file_writer_test',
'rotatable_file_writer_test.cpp',
LIBDEPS=['logger'])
-
diff --git a/src/mongo/logger/appender.h b/src/mongo/logger/appender.h
new file mode 100644
index 00000000000..4248cf68a07
--- /dev/null
+++ b/src/mongo/logger/appender.h
@@ -0,0 +1,44 @@
+/* Copyright 2013 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 "mongo/base/status.h"
+
+namespace mongo {
+namespace logger {
+
+ /**
+ * Interface for sinks in a logging system. The core of logging is when events of type E are
+ * appended to instances of Appender<E>.
+ *
+ * Example concrete instances are ConsoleAppender<E>, SyslogAppender<E> and
+ * RotatableFileAppender<E>.
+ */
+ template <typename E>
+ class Appender {
+ public:
+ typedef E Event;
+
+ virtual ~Appender() {}
+
+ /**
+ * Appends "event", returns Status::OK() on success.
+ */
+ virtual Status append(const Event& event) = 0;
+ };
+
+} // namespace logger
+} // namespace mongo
diff --git a/src/mongo/logger/console.cpp b/src/mongo/logger/console.cpp
new file mode 100644
index 00000000000..cbff1c09b25
--- /dev/null
+++ b/src/mongo/logger/console.cpp
@@ -0,0 +1,50 @@
+/* Copyright 2013 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 "mongo/platform/basic.h"
+
+#include "mongo/logger/console.h"
+
+#include <iostream>
+
+namespace mongo {
+namespace {
+
+ /*
+ * Theory of operation:
+ *
+ * At process start, the loader initializes "consoleMutex" to NULL. At some point during static
+ * initialization, the static initialization process, running in the one and only extant thread,
+ * allocates a new boost::mutex on the heap and assigns consoleMutex to point to it. While
+ * consoleMutex is still NULL, we know that there is only one thread extant, so it is safe to
+ * skip locking the consoleMutex in the Console constructor. Once the mutex is initialized,
+ * users of Console can start acquiring it.
+ */
+
+ boost::mutex *consoleMutex = new boost::mutex;
+
+} // namespace
+
+ Console::Console() : _consoleLock() {
+ if (consoleMutex) {
+ boost::unique_lock<boost::mutex> lk(*consoleMutex);
+ lk.swap(_consoleLock);
+ }
+ }
+
+ std::ostream& Console::out() { return std::cout; }
+ std::istream& Console::in() { return std::cin; }
+
+} // namespace mongo
diff --git a/src/mongo/logger/console.h b/src/mongo/logger/console.h
new file mode 100644
index 00000000000..b27799a6223
--- /dev/null
+++ b/src/mongo/logger/console.h
@@ -0,0 +1,48 @@
+/* Copyright 2013 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 <boost/thread/mutex.hpp>
+#include <iosfwd>
+
+namespace mongo {
+
+ /**
+ * Representation of the console. Use this in place of cout/cin, in applications that write to
+ * the console from multiple threads (such as those that use the logging subsystem).
+ *
+ * The Console type is synchronized such that only one instance may be in the fully constructed
+ * state at a time. Correct usage is to instantiate one, write or read from it as desired, and
+ * then destroy it.
+ *
+ * The console streams accept UTF-8 encoded data, and attempt to write it to the attached
+ * console faithfully.
+ *
+ * TODO(schwerin): If no console is attached on Windows (services), should writes here go to the
+ * event logger?
+ */
+ class Console {
+ public:
+ Console();
+
+ std::ostream& out();
+ std::istream& in();
+
+ private:
+ boost::unique_lock<boost::mutex> _consoleLock;
+ };
+
+} // namespace mongo
diff --git a/src/mongo/logger/console_appender.h b/src/mongo/logger/console_appender.h
new file mode 100644
index 00000000000..214fc921148
--- /dev/null
+++ b/src/mongo/logger/console_appender.h
@@ -0,0 +1,54 @@
+/* Copyright 2013 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 <boost/scoped_ptr.hpp>
+#include <iostream>
+
+#include "mongo/base/disallow_copying.h"
+#include "mongo/base/status.h"
+#include "mongo/logger/appender.h"
+#include "mongo/logger/console.h"
+#include "mongo/logger/encoder.h"
+
+namespace mongo {
+namespace logger {
+
+ /**
+ * Appender for writing to the console (stdout).
+ */
+ template <typename Event>
+ class ConsoleAppender : public Appender<Event> {
+ MONGO_DISALLOW_COPYING(ConsoleAppender);
+
+ public:
+ typedef Encoder<Event> EventEncoder;
+
+ explicit ConsoleAppender(EventEncoder* encoder) : _encoder(encoder) {}
+ virtual Status append(const Event& event) {
+ Console console;
+ _encoder->encode(event, console.out()).flush();
+ if (!console.out())
+ return Status(ErrorCodes::LogWriteFailed, "Error writing log message to console.");
+ return Status::OK();
+ }
+
+ private:
+ boost::scoped_ptr<EventEncoder> _encoder;
+ };
+
+} // namespace logger
+} // namespace mongo
diff --git a/src/mongo/logger/encoder.h b/src/mongo/logger/encoder.h
new file mode 100644
index 00000000000..f79e0d3a74e
--- /dev/null
+++ b/src/mongo/logger/encoder.h
@@ -0,0 +1,37 @@
+/* Copyright 2013 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 <iosfwd>
+
+namespace mongo {
+namespace logger {
+
+ /**
+ * Interface for objects that encode Events to std::ostreams.
+ *
+ * Most appender implementations write to streams, and Encoders represent the process of
+ * encoding events into streams.
+ */
+ template <typename Event>
+ class Encoder {
+ public:
+ virtual ~Encoder() {}
+ virtual std::ostream& encode(const Event& event, std::ostream& os) = 0;
+ };
+
+} // namespace logger
+} // nnamspace mongo
diff --git a/src/mongo/logger/labeled_level.h b/src/mongo/logger/labeled_level.h
new file mode 100644
index 00000000000..03a90b6bab5
--- /dev/null
+++ b/src/mongo/logger/labeled_level.h
@@ -0,0 +1,64 @@
+/* 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 <string>
+
+#include "mongo/logger/log_severity.h"
+
+namespace mongo {
+namespace logger {
+
+ /**
+ * Deprecated utility for associating a string and log level together.
+ */
+ class LabeledLevel {
+ public:
+ LabeledLevel( int level ) : _level( level ) {}
+ LabeledLevel( const char* label, int level ) : _label( label ), _level( level ) {}
+ LabeledLevel( const std::string& label, int level ) : _label( label ), _level( level ) {}
+
+ LabeledLevel operator+( int i ) const {
+ return LabeledLevel( _label, _level + i );
+ }
+
+ LabeledLevel operator-( int i ) const {
+ return LabeledLevel( _label, _level - i );
+ }
+
+ const std::string& getLabel() const { return _label; }
+ int getLevel() const { return _level; }
+
+ operator LogSeverity () const { return logger::LogSeverity::cast(_level); }
+
+ private:
+ std::string _label;
+ int _level;
+ };
+
+ inline bool operator<( const LabeledLevel& ll, const int i ) { return ll.getLevel() < i; }
+ inline bool operator<( const int i, const LabeledLevel& ll ) { return i < ll.getLevel(); }
+ inline bool operator>( const LabeledLevel& ll, const int i ) { return ll.getLevel() > i; }
+ inline bool operator>( const int i, const LabeledLevel& ll ) { return i > ll.getLevel(); }
+ inline bool operator<=( const LabeledLevel& ll, const int i ) { return ll.getLevel() <= i; }
+ inline bool operator<=( const int i, const LabeledLevel& ll ) { return i <= ll.getLevel(); }
+ inline bool operator>=( const LabeledLevel& ll, const int i ) { return ll.getLevel() >= i; }
+ inline bool operator>=( const int i, const LabeledLevel& ll ) { return i >= ll.getLevel(); }
+ inline bool operator==( const LabeledLevel& ll, const int i ) { return ll.getLevel() == i; }
+ inline bool operator==( const int i, const LabeledLevel& ll ) { return i == ll.getLevel(); }
+
+} // namespace logger
+} // namespace mongo
diff --git a/src/mongo/logger/log_domain-impl.h b/src/mongo/logger/log_domain-impl.h
new file mode 100644
index 00000000000..cb9e0605f8d
--- /dev/null
+++ b/src/mongo/logger/log_domain-impl.h
@@ -0,0 +1,90 @@
+/* Copyright 2013 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 "mongo/logger/message_log_domain.h"
+
+#include <algorithm>
+
+/*
+ * Implementation of LogDomain<E>. Include this in cpp files to instantiate new LogDomain types.
+ * See message_log_domain.h, e.g.
+ */
+
+namespace mongo {
+namespace logger {
+
+ template <typename E>
+ LogDomain<E>::LogDomain() : _minimumLoggedSeverity(LogSeverity::Log()) {}
+
+ template <typename E>
+ LogDomain<E>::~LogDomain() {
+ clearAppenders();
+ }
+
+ template <typename E>
+ void LogDomain<E>::append(const E& event) {
+ for (typename AppenderVector::const_iterator iter = _appenders.begin();
+ iter != _appenders.end(); ++iter) {
+
+ if (*iter) {
+ (*iter)->append(event);
+ }
+ }
+ }
+
+ template <typename E>
+ typename LogDomain<E>::AppenderHandle LogDomain<E>::attachAppender(
+ typename LogDomain<E>::AppenderAutoPtr appender) {
+
+ typename AppenderVector::iterator iter = std::find(
+ _appenders.begin(),
+ _appenders.end(),
+ static_cast<EventAppender*>(NULL));
+
+ if (iter == _appenders.end()) {
+ _appenders.push_back(appender.release());
+ return AppenderHandle(_appenders.size() - 1);
+ }
+ else {
+ *iter = appender.release();
+ return AppenderHandle(iter - _appenders.begin());
+ }
+ }
+
+ template <typename E>
+ typename LogDomain<E>::AppenderAutoPtr LogDomain<E>::detachAppender(
+ typename LogDomain<E>::AppenderHandle handle) {
+
+ EventAppender*& appender = _appenders.at(handle._index);
+ AppenderAutoPtr result(appender);
+ appender = NULL;
+ return result;
+ }
+
+ template <typename E>
+ void LogDomain<E>::clearAppenders() {
+ for(typename AppenderVector::const_iterator iter = _appenders.begin();
+ iter != _appenders.end(); ++iter) {
+
+ delete *iter;
+ }
+
+ _appenders.clear();
+ }
+
+} // namespace logger
+} // namespace mongo
diff --git a/src/mongo/logger/log_domain.h b/src/mongo/logger/log_domain.h
new file mode 100644
index 00000000000..b1f6dcb81f3
--- /dev/null
+++ b/src/mongo/logger/log_domain.h
@@ -0,0 +1,133 @@
+/* Copyright 2013 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 <boost/scoped_ptr.hpp>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "mongo/base/disallow_copying.h"
+#include "mongo/logger/appender.h"
+#include "mongo/logger/log_severity.h"
+
+namespace mongo {
+namespace logger {
+
+ /**
+ * Logging domain for events of type E.
+ *
+ * A logging domain consists of a set of Appenders and a minimum severity.
+ *
+ * TODO: The severity doesn't seem to apply for auditing, maybe it only belongs on the
+ * MessageLogManager? We don't really have multiple tunable logging domains, right now. Other
+ * than the global domain, shouldLog doesn't matter.
+ *
+ * Usage: Configure the log domain in a single threaded context, using attachAppender,
+ * detachAppender and clearAppenders(). The domain takes ownership of any attached appender,
+ * returning an AppenderHandle for each attached appender. That handle may be used later to
+ * detach the appender, causing the domain to release ownership of it. Mostly, this
+ * attach/detach behavior is useful in testing, since you do not want to change the appenders of
+ * a domain that is currently receiving append() calls.
+ *
+ * Once you've configured the domain, call append() from potentially many threads, to add log
+ * messages.
+ */
+ template <typename E>
+ class LogDomain {
+ MONGO_DISALLOW_COPYING(LogDomain);
+ public:
+ typedef E Event;
+ typedef Appender<Event> EventAppender;
+
+ /**
+ * Opaque handle returned by attachAppender(), which can be subsequently passed to
+ * detachAppender() to detach an appender from an instance of LogDomain.
+ */
+ class AppenderHandle {
+ friend class LogDomain;
+ public:
+ AppenderHandle() {}
+
+ private:
+ explicit AppenderHandle(size_t index) : _index(index) {}
+
+ size_t _index;
+ };
+
+ // TODO(schwerin): Replace with unique_ptr in C++11.
+ typedef std::auto_ptr<EventAppender> AppenderAutoPtr;
+
+ LogDomain();
+ ~LogDomain();
+
+ /**
+ * Receives an event for logging, calling append(event) on all attached appenders.
+ *
+ * TODO(schwerin): Should we return failed statuses somehow? vector<AppenderHandle, Status>
+ * for failed appends, e.g.?
+ */
+ void append(const Event& event);
+
+ /**
+ * Predicate that answers the question, "Should I, the caller, append to you, the log
+ * domain, messages of the given severity?" True means yes.
+ */
+ bool shouldLog(LogSeverity severity) { return severity >= _minimumLoggedSeverity; }
+
+ /**
+ * Gets the minimum severity of messages that should be sent to this LogDomain.
+ */
+ LogSeverity getMinimumLogSeverity() { return _minimumLoggedSeverity; }
+
+ /**
+ * Sets the minimum severity of messages that should be sent to this LogDomain.
+ */
+ void setMinimumLoggedSeverity(LogSeverity severity) { _minimumLoggedSeverity = severity; }
+
+
+ //
+ // Configuration methods. Must be synchronized with each other and calls to "append" by the
+ // caller.
+ //
+
+ /**
+ * Attaches "appender" to this domain, taking ownership of it. Returns a handle that may be
+ * used later to detach this appender.
+ */
+ AppenderHandle attachAppender(AppenderAutoPtr appender);
+
+ /**
+ * Detaches the appender referenced by "handle" from this domain, releasing ownership of it.
+ * Returns an auto_ptr to the handler to the caller, who is now responsible for its
+ * deletion. Caller should consider "handle" is invalid after this call.
+ */
+ AppenderAutoPtr detachAppender(AppenderHandle handle);
+
+ /**
+ * Destroy all attached appenders, invalidating all handles.
+ */
+ void clearAppenders();
+
+ private:
+ typedef std::vector<EventAppender*> AppenderVector;
+
+ LogSeverity _minimumLoggedSeverity;
+ AppenderVector _appenders;
+ };
+
+} // namespace logger
+} // namespace mongo
diff --git a/src/mongo/logger/log_manager.cpp b/src/mongo/logger/log_manager.cpp
new file mode 100644
index 00000000000..7340ad1bc8b
--- /dev/null
+++ b/src/mongo/logger/log_manager.cpp
@@ -0,0 +1,47 @@
+/* Copyright 2013 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 "mongo/platform/basic.h"
+
+#include "mongo/logger/log_manager.h"
+
+#include "mongo/logger/console_appender.h"
+#include "mongo/logger/message_event_utf8_encoder.h"
+
+namespace mongo {
+namespace logger {
+
+ LogManager::LogManager() {
+ // Should really fassert that the following status .isOK(), but it never fails.
+ _globalDomain.attachAppender(MessageLogDomain::AppenderAutoPtr(
+ new ConsoleAppender<MessageEventEphemeral>(new MessageEventDetailsEncoder)));
+ }
+
+ LogManager::~LogManager() {
+ for (DomainsByNameMap::iterator iter = _domains.begin(); iter != _domains.end(); ++iter) {
+ delete iter->second;
+ }
+ }
+
+ MessageLogDomain* LogManager::getNamedDomain(const std::string& name) {
+ MessageLogDomain*& domain = _domains[name];
+ if (!domain) {
+ domain = new MessageLogDomain;
+ }
+ return domain;
+ }
+
+} // logger
+} // mongo
diff --git a/src/mongo/logger/log_manager.h b/src/mongo/logger/log_manager.h
new file mode 100644
index 00000000000..626f1062781
--- /dev/null
+++ b/src/mongo/logger/log_manager.h
@@ -0,0 +1,57 @@
+/* Copyright 2013 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 <string>
+
+#include "mongo/base/disallow_copying.h"
+#include "mongo/logger/message_log_domain.h"
+#include "mongo/logger/rotatable_file_writer.h"
+#include "mongo/platform/unordered_map.h"
+
+namespace mongo {
+namespace logger {
+
+ /**
+ * Container for managing log domains.
+ *
+ * Use this while setting up the logging system, before launching any threads.
+ */
+ class LogManager {
+ MONGO_DISALLOW_COPYING(LogManager);
+ public:
+ LogManager();
+ ~LogManager();
+
+ /**
+ * Gets the global domain for this manager. It has no name.
+ */
+ MessageLogDomain* getGlobalDomain() { return &_globalDomain; }
+
+ /**
+ * Get the log domain with the given name, creating if needed.
+ */
+ MessageLogDomain* getNamedDomain(const std::string& name);
+
+ private:
+ typedef unordered_map<std::string, MessageLogDomain*> DomainsByNameMap;
+
+ DomainsByNameMap _domains;
+ MessageLogDomain _globalDomain;
+ };
+
+} // namespace logger
+} // namespace mongo
diff --git a/src/mongo/logger/log_severity-inl.h b/src/mongo/logger/log_severity-inl.h
new file mode 100644
index 00000000000..26a1e92f417
--- /dev/null
+++ b/src/mongo/logger/log_severity-inl.h
@@ -0,0 +1,42 @@
+/* Copyright 2013 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
+
+namespace mongo {
+namespace logger {
+
+ LogSeverity LogSeverity::Severe() { return LogSeverity(-4); }
+ LogSeverity LogSeverity::Error() { return LogSeverity(-3); }
+ LogSeverity LogSeverity::Warning() { return LogSeverity(-2); }
+ LogSeverity LogSeverity::Info() { return LogSeverity(-1); }
+ LogSeverity LogSeverity::Log() { return LogSeverity(0); }
+ LogSeverity LogSeverity::Debug(int debugLevel) { return LogSeverity(debugLevel); }
+
+ LogSeverity LogSeverity::cast(int ll) { return LogSeverity(ll); }
+
+ int LogSeverity::toInt() const { return _severity; }
+ LogSeverity LogSeverity::moreSevere() const { return LogSeverity(_severity - 1); }
+ LogSeverity LogSeverity::lessSevere() const { return LogSeverity(_severity + 1); }
+
+ bool LogSeverity::operator==(LogSeverity other) const { return _severity == other._severity; }
+ bool LogSeverity::operator!=(LogSeverity other) const { return _severity != other._severity; }
+ bool LogSeverity::operator<(LogSeverity other) const { return _severity > other._severity; }
+ bool LogSeverity::operator<=(LogSeverity other) const { return _severity >= other._severity; }
+ bool LogSeverity::operator>(LogSeverity other) const { return _severity < other._severity; }
+ bool LogSeverity::operator>=(LogSeverity other) const { return _severity <= other._severity; }
+
+} // namespace logger
+} // namespace mongo
diff --git a/src/mongo/logger/log_severity.cpp b/src/mongo/logger/log_severity.cpp
new file mode 100644
index 00000000000..62f92c47c20
--- /dev/null
+++ b/src/mongo/logger/log_severity.cpp
@@ -0,0 +1,55 @@
+/* Copyright 2013 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 "mongo/platform/basic.h"
+
+#include "mongo/logger/log_severity.h"
+
+#include <iostream>
+
+namespace mongo {
+namespace logger {
+
+namespace {
+ const char unknownSeverityString[] = "UNKNOWN";
+ const char severeSeverityString[] = "SEVERE";
+ const char errorSeverityString[] = "ERROR";
+ const char warningSeverityString[] = "warning";
+ const char infoSeverityString[] = "info";
+ const char debugSeverityString[] = "debug";
+} // namespace
+
+ StringData LogSeverity::toStringData() const {
+ if (_severity > 0)
+ return StringData(debugSeverityString, StringData::LiteralTag());
+ if (*this == LogSeverity::Severe())
+ return StringData(severeSeverityString, StringData::LiteralTag());
+ if (*this == LogSeverity::Error())
+ return StringData(errorSeverityString, StringData::LiteralTag());
+ if (*this == LogSeverity::Warning())
+ return StringData(warningSeverityString, StringData::LiteralTag());
+ if (*this == LogSeverity::Info())
+ return StringData(infoSeverityString, StringData::LiteralTag());
+ if (*this == LogSeverity::Log())
+ return StringData(infoSeverityString, StringData::LiteralTag());
+ return StringData(unknownSeverityString, StringData::LiteralTag());
+ }
+
+ std::ostream& operator<<(std::ostream& os, LogSeverity severity) {
+ return os << severity.toStringData();
+ }
+
+} // namespace logger
+} // namespace mongo
diff --git a/src/mongo/logger/log_severity.h b/src/mongo/logger/log_severity.h
new file mode 100644
index 00000000000..e1e872bd6c0
--- /dev/null
+++ b/src/mongo/logger/log_severity.h
@@ -0,0 +1,123 @@
+/* Copyright 2013 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 <iosfwd>
+#include <string>
+
+#include "mongo/base/string_data.h"
+
+namespace mongo {
+namespace logger {
+
+ /**
+ * Representation of the severity / priority of a log message.
+ *
+ * Severities are totally ordered, from most severe to least severe as follows:
+ * Severe, Error, Warning, Info, Log, Debug(1), Debug(2), ...
+ */
+ class LogSeverity {
+ public:
+ //
+ // Static factory methods for getting LogSeverity objects of the various severity levels.
+ //
+
+ static inline LogSeverity Severe();
+ static inline LogSeverity Error();
+ static inline LogSeverity Warning();
+ static inline LogSeverity Info();
+ static inline LogSeverity Log(); // === Debug(0)
+ static inline LogSeverity Debug(int debugLevel);
+
+ /**
+ * Casts an integer to a severity.
+ *
+ * Do not use this. It exists to enable a handful of leftover uses of LOG(0) and the
+ * deprecated LabeledLevel.
+ */
+ static inline LogSeverity cast(int);
+
+ inline int toInt() const;
+
+ /**
+ * Returns a LogSeverity object that is one unit "more severe" than this one.
+ */
+ inline LogSeverity moreSevere() const;
+
+ /**
+ * Returns a LogSeverity object that is one unit "less severe" than this one.
+ */
+ inline LogSeverity lessSevere() const;
+
+ /**
+ * Returns a string naming this severity level.
+ *
+ * See toStringData(), below.
+ */
+ inline std::string toString() const;
+
+ /**
+ * Returns a StringData naming this security level.
+ *
+ * Not all levels are uniquely named. Debug(N) is named "debug", regardless of "N",
+ * e.g.
+ */
+ StringData toStringData() const;
+
+ //
+ // Comparison operations.
+ //
+
+ /// Returns true if this is exactly as severe as other.
+ inline bool operator==(const LogSeverity other) const;
+
+ /// Returns true if this is not exactly as severe as other.
+ inline bool operator!=(const LogSeverity other) const;
+
+ /// Returns true if this is less severe than other.
+ inline bool operator<(const LogSeverity other) const;
+
+ /// Returns true if this is no more severe than other.
+ inline bool operator<=(const LogSeverity other) const;
+
+ /// Returns true if this is more severe than other.
+ inline bool operator>(const LogSeverity other) const;
+
+ /// Returns true if this is no less severe than other.
+ inline bool operator>=(const LogSeverity other) const;
+
+ private:
+ explicit LogSeverity(int severity) : _severity(severity) {}
+
+ /// The stored severity. More negative is more severe. NOTE: This means that the >, <, >=
+ /// and <= operators on LogSeverity have opposite sense of the same operators on the
+ /// underlying integer. That is, given severities S1 and S2, S1 > S2 means that S1.toInt()
+ /// < S2.toInt().
+ ///
+ /// TODO(schwerin): Decide if we should change this so more positive is more severe. The
+ /// logLevel parameter in the database is more compatible with this sense, but it's not
+ /// totally intuitive. One could also remove the operator overloads in favor of named
+ /// methods, isNoMoreSevereThan, isLessSevereThan, isMoreSevereThan, isNoLessSevereThan,
+ /// isSameSeverity and isDifferentSeverity.
+ int _severity;
+ };
+
+ std::ostream& operator<<(std::ostream& os, LogSeverity severity);
+
+} // namespace logger
+} // namespace mongo
+
+#include "mongo/logger/log_severity-inl.h"
diff --git a/src/mongo/logger/log_test.cpp b/src/mongo/logger/log_test.cpp
new file mode 100644
index 00000000000..e816c4c382a
--- /dev/null
+++ b/src/mongo/logger/log_test.cpp
@@ -0,0 +1,147 @@
+/* Copyright 2013 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 "mongo/platform/basic.h"
+
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "mongo/logger/appender.h"
+#include "mongo/logger/encoder.h"
+#include "mongo/logger/message_event_utf8_encoder.h"
+#include "mongo/logger/message_log_domain.h"
+#include "mongo/logger/rotatable_file_appender.h"
+#include "mongo/logger/rotatable_file_writer.h"
+#include "mongo/platform/compiler.h"
+#include "mongo/unittest/unittest.h"
+#include "mongo/util/concurrency/thread_name.h"
+#include "mongo/util/log.h"
+
+using namespace mongo::logger;
+
+namespace mongo {
+namespace {
+
+ // TODO(schwerin): Have logger write to a different log from the global log, so that tests can
+ // redirect their global log output for examination.
+ class LogTest : public unittest::Test {
+ friend class LogTestAppender;
+ public:
+ LogTest() {
+ globalLogDomain()->clearAppenders();
+ _appenderHandle = globalLogDomain()->attachAppender(
+ MessageLogDomain::AppenderAutoPtr(new LogTestAppender(this)));
+ }
+
+ virtual ~LogTest() { globalLogDomain()->detachAppender(_appenderHandle); }
+
+ protected:
+ std::vector<std::string> _logLines;
+
+ private:
+ class LogTestAppender : public MessageLogDomain::EventAppender {
+ public:
+ explicit LogTestAppender(LogTest* ltest) : _ltest(ltest) {}
+ virtual ~LogTestAppender() {}
+ virtual Status append(const MessageLogDomain::Event& event) {
+ std::ostringstream _os;
+ if (!_encoder.encode(event, _os))
+ return Status(ErrorCodes::LogWriteFailed, "Failed to append to LogTestAppender.");
+ _ltest->_logLines.push_back(_os.str());
+ return Status::OK();
+ }
+
+ private:
+ LogTest *_ltest;
+ MessageEventUnadornedEncoder _encoder;
+ };
+
+ MessageLogDomain::AppenderHandle _appenderHandle;
+ };
+
+ TEST_F(LogTest, logContext) {
+ logContext("WHA!");
+ ASSERT_GREATER_THAN(_logLines.size(), 1U);
+ ASSERT_NOT_EQUALS(_logLines[0].find("WHA!"), std::string::npos);
+
+ // TODO(schwerin): Ensure that logContext rights a proper context to the log stream,
+ // including the address of the logContext() function.
+ //void const* logContextFn = reinterpret_cast<void const*>(logContext);
+ }
+
+ class CountAppender : public Appender<MessageEventEphemeral> {
+ public:
+ CountAppender() : _count(0) {}
+ virtual ~CountAppender() {}
+
+ virtual Status append(const MessageEventEphemeral& event) {
+ ++_count;
+ return Status::OK();
+ }
+
+ int getCount() { return _count; }
+
+ private:
+ int _count;
+ };
+
+ /** Simple tests for detaching appenders. */
+ TEST_F(LogTest, DetachAppender) {
+ MessageLogDomain::AppenderAutoPtr countAppender(new CountAppender);
+ MessageLogDomain domain;
+
+ // Appending to the domain before attaching the appender does not affect the appender.
+ domain.append(MessageEventEphemeral(LogSeverity::Log(), "", "1"));
+ ASSERT_EQUALS(0, dynamic_cast<CountAppender*>(countAppender.get())->getCount());
+
+ // Appending to the domain after attaching the appender does affect the appender.
+ MessageLogDomain::AppenderHandle handle = domain.attachAppender(countAppender);
+ domain.append(MessageEventEphemeral(LogSeverity::Log(), "", "2"));
+ countAppender = domain.detachAppender(handle);
+ ASSERT_EQUALS(1, dynamic_cast<CountAppender*>(countAppender.get())->getCount());
+
+ // Appending to the domain after detaching the appender does not affect the appender.
+ domain.append(MessageEventEphemeral(LogSeverity::Log(), "", "3"));
+ ASSERT_EQUALS(1, dynamic_cast<CountAppender*>(countAppender.get())->getCount());
+ }
+
+ class A {
+ public:
+ std::string toString() const {
+ log() << "Golly!\n";
+ return "Golly!";
+ }
+ };
+
+ // Tests that logging while in the midst of logging produces two distinct log messages, with the
+ // inner log message appearing before the outer.
+ TEST_F(LogTest, LogstreamBuilderReentrance) {
+ log() << "Logging A() -- " << A() << " -- done!" << std::endl;
+ ASSERT_EQUALS(2U, _logLines.size());
+ ASSERT_EQUALS(std::string("Golly!\n"), _logLines[0]);
+ ASSERT_EQUALS(std::string("Logging A() -- Golly! -- done!\n"), _logLines[1]);
+ }
+
+ //
+ // Instantiating this object is a basic test of static-initializer-time logging.
+ //
+ class B {
+ public:
+ B() { log() << "Exercising initializer time logging."; }
+ } b;
+
+} // namespace
+} // namespace mongo
diff --git a/src/mongo/logger/logger.cpp b/src/mongo/logger/logger.cpp
new file mode 100644
index 00000000000..27d28509b56
--- /dev/null
+++ b/src/mongo/logger/logger.cpp
@@ -0,0 +1,54 @@
+/* Copyright 2013 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 "mongo/logger/logger.h"
+
+#include "mongo/base/init.h"
+#include "mongo/base/status.h"
+#include "mongo/bson/inline_decls.h" // For MONGO_unlikely, which should really be in
+ // mongo/platform/compiler.h
+
+namespace mongo {
+namespace logger {
+
+ static LogManager* theGlobalLogManager; // NULL at program start, before even static
+ // initialization.
+
+ static RotatableFileManager theGlobalRotatableFileManager;
+
+ LogManager* globalLogManager() {
+ if (MONGO_unlikely(!theGlobalLogManager)) {
+ theGlobalLogManager = new LogManager;
+ }
+ return theGlobalLogManager;
+ }
+
+ RotatableFileManager* globalRotatableFileManager() {
+ return &theGlobalRotatableFileManager;
+ }
+
+ /**
+ * Just in case no static initializer called globalLogManager, make sure that the global log
+ * manager is instantiated while we're still in a single-threaded context.
+ */
+ MONGO_INITIALIZER_GENERAL(GlobalLogManager, MONGO_NO_PREREQUISITES, ("default"))(
+ InitializerContext*) {
+
+ globalLogManager();
+ return Status::OK();
+ }
+
+} // namespace logger
+} // namespace mongo
diff --git a/src/mongo/logger/logger.h b/src/mongo/logger/logger.h
new file mode 100644
index 00000000000..11a739d7721
--- /dev/null
+++ b/src/mongo/logger/logger.h
@@ -0,0 +1,42 @@
+/* Copyright 2013 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 "mongo/logger/message_log_domain.h"
+#include "mongo/logger/log_manager.h"
+#include "mongo/logger/rotatable_file_manager.h"
+
+namespace mongo {
+namespace logger {
+
+ /**
+ * Gets a global singleton instance of RotatableFileManager.
+ */
+ RotatableFileManager* globalRotatableFileManager();
+
+ /**
+ * Gets a global singleton instance of LogManager.
+ */
+ LogManager* globalLogManager();
+
+ /**
+ * Gets the global MessageLogDomain associated for the global log manager.
+ */
+ inline MessageLogDomain* globalLogDomain() { return globalLogManager()->getGlobalDomain(); }
+
+} // namespace logger
+} // namespace mongo
+
diff --git a/src/mongo/logger/logstream_builder.cpp b/src/mongo/logger/logstream_builder.cpp
new file mode 100644
index 00000000000..3083e693b92
--- /dev/null
+++ b/src/mongo/logger/logstream_builder.cpp
@@ -0,0 +1,110 @@
+/* Copyright 2013 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 "mongo/platform/basic.h"
+
+#include "mongo/logger/logstream_builder.h"
+
+#include "mongo/base/owned_pointer_vector.h"
+#include "mongo/logger/tee.h"
+#include "mongo/util/assert_util.h" // TODO: remove apple dep for this in threadlocal.h
+#include "mongo/util/concurrency/threadlocal.h"
+
+namespace mongo {
+
+namespace {
+
+ /// Type of per-thread cache for storing pre-constructed ostringstreams. While its type is
+ /// vector, it should only ever contain 0 or 1 item. It is a vector rather than just a
+ /// thread_specific_ptr<> because of the high cost of thread_specific_ptr<>::reset().
+ typedef OwnedPointerVector<std::ostringstream> OwnedOstreamVector;
+
+} // namespace
+
+ TSP_DECLARE(OwnedOstreamVector, threadOstreamCache);
+ TSP_DEFINE(OwnedOstreamVector, threadOstreamCache);
+
+namespace logger {
+
+ LogstreamBuilder::LogstreamBuilder(MessageLogDomain* domain,
+ const std::string& contextName,
+ LogSeverity severity)
+ : _domain(domain),
+ _contextName(contextName),
+ _severity(severity),
+ _os(NULL),
+ _tee(NULL) {
+ }
+
+ LogstreamBuilder::LogstreamBuilder(logger::MessageLogDomain* domain,
+ const std::string& contextName,
+ LabeledLevel labeledLevel)
+ : _domain(domain),
+ _contextName(contextName),
+ _severity(labeledLevel),
+ _os(NULL),
+ _tee(NULL) {
+
+ setBaseMessage(labeledLevel.getLabel());
+ }
+
+ LogstreamBuilder::LogstreamBuilder(const LogstreamBuilder& other)
+ : _domain(other._domain),
+ _contextName(other._contextName),
+ _severity(other._severity),
+ _baseMessage(other._baseMessage),
+ _os(NULL),
+ _tee(NULL) {
+
+ if (other._os || other._tee)
+ abort();
+ }
+
+
+ LogstreamBuilder::~LogstreamBuilder() {
+ if (_os) {
+ _baseMessage += _os->str();
+ _domain->append(MessageEventEphemeral(_severity, _contextName, _baseMessage));
+ if (_tee)
+ _tee->write(_baseMessage);
+ _os->str("");
+ std::vector<std::ostringstream*>& cache = threadOstreamCache.getMake()->mutableVector();
+ if (!cache.empty()) {
+ cache.push_back(_os);
+ }
+ }
+ }
+
+ void LogstreamBuilder::operator<<(Tee* tee) {
+ makeStream(); // Adding a Tee counts for purposes of deciding to make a log message.
+ // TODO: dassert(!_tee);
+ _tee = tee;
+ }
+
+ void LogstreamBuilder::makeStream() {
+ if (!_os) {
+ std::vector<std::ostringstream*>& oses = threadOstreamCache.getMake()->mutableVector();
+ if (oses.empty()) {
+ _os = new std::ostringstream;
+ }
+ else {
+ _os = oses.back();
+ oses.pop_back();
+ }
+ }
+ }
+
+} // namespace logger
+} // namespace mongo
diff --git a/src/mongo/logger/logstream_builder.h b/src/mongo/logger/logstream_builder.h
new file mode 100644
index 00000000000..befd7bd19b3
--- /dev/null
+++ b/src/mongo/logger/logstream_builder.h
@@ -0,0 +1,140 @@
+/* Copyright 2013 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 <boost/scoped_ptr.hpp>
+#include <iostream>
+#include <sstream>
+#include <string>
+
+#include "mongo/logger/labeled_level.h"
+#include "mongo/logger/log_severity.h"
+#include "mongo/logger/message_log_domain.h"
+#include "mongo/util/exit_code.h"
+
+namespace mongo {
+namespace logger {
+
+ class Tee;
+
+ /**
+ * Stream-ish object used to build and append log messages.
+ */
+ class LogstreamBuilder {
+ public:
+ static LogSeverity severityCast(int ll) { return LogSeverity::cast(ll); }
+ static LogSeverity severityCast(LogSeverity ls) { return ls; }
+ static LabeledLevel severityCast(const LabeledLevel &labeled) { return labeled; }
+
+ /**
+ * Construct a LogstreamBuilder that writes to "domain" on destruction.
+ *
+ * "contextName" is a short name of the thread or other context.
+ * "severity" is the logging priority/severity of the message.
+ */
+ LogstreamBuilder(MessageLogDomain* domain,
+ const std::string& contextName,
+ LogSeverity severity);
+
+ /**
+ * Deprecated.
+ */
+ LogstreamBuilder(MessageLogDomain* domain,
+ const std::string& contextName,
+ LabeledLevel labeledLevel);
+
+ /**
+ * Copies a LogstreamBuilder. LogstreamBuilder instances are copyable only until the first
+ * call to stream() or operator<<.
+ *
+ * TODO(schwerin): After C++11 transition, replace with a move-constructor, and make
+ * LogstreamBuilder movable.
+ */
+ LogstreamBuilder(const LogstreamBuilder& other);
+
+ /**
+ * Destroys a LogstreamBuilder(). If anything was written to it via stream() or operator<<,
+ * constructs a MessageLogDomain::Event and appends it to the associated domain.
+ */
+ ~LogstreamBuilder();
+
+
+ /**
+ * Sets an optional prefix for the message.
+ */
+ LogstreamBuilder& setBaseMessage(const std::string& baseMessage) {
+ _baseMessage = baseMessage;
+ return *this;
+ }
+
+ std::ostream& stream() { makeStream(); return *_os; }
+
+ LogstreamBuilder& operator<<(const char *x) { stream() << x; return *this; }
+ LogstreamBuilder& operator<<(const std::string& x) { stream() << x; return *this; }
+ LogstreamBuilder& operator<<(const StringData& x) { stream() << x; return *this; }
+ LogstreamBuilder& operator<<(char *x) { stream() << x; return *this; }
+ LogstreamBuilder& operator<<(char x) { stream() << x; return *this; }
+ LogstreamBuilder& operator<<(int x) { stream() << x; return *this; }
+ LogstreamBuilder& operator<<(ExitCode x) { stream() << x; return *this; }
+ LogstreamBuilder& operator<<(long x) { stream() << x; return *this; }
+ LogstreamBuilder& operator<<(unsigned long x) { stream() << x; return *this; }
+ LogstreamBuilder& operator<<(unsigned x) { stream() << x; return *this; }
+ LogstreamBuilder& operator<<(unsigned short x) { stream() << x; return *this; }
+ LogstreamBuilder& operator<<(double x) { stream() << x; return *this; }
+ LogstreamBuilder& operator<<(void *x) { stream() << x; return *this; }
+ LogstreamBuilder& operator<<(const void *x) { stream() << x; return *this; }
+ LogstreamBuilder& operator<<(long long x) { stream() << x; return *this; }
+ LogstreamBuilder& operator<<(unsigned long long x) { stream() << x; return *this; }
+ LogstreamBuilder& operator<<(bool x) { stream() << x; return *this; }
+
+ template <typename T>
+ LogstreamBuilder& operator<<(const T& x) {
+ stream() << x.toString();
+ return *this;
+ }
+
+ LogstreamBuilder& operator<< (std::ostream& ( *manip )(std::ostream&)) {
+ stream() << manip;
+ return *this;
+ }
+ LogstreamBuilder& operator<< (std::ios_base& (*manip)(std::ios_base&)) {
+ stream() << manip;
+ return *this;
+ }
+
+ /**
+ * In addition to appending the message to _domain, write it to the given tee. May only
+ * be called once per instance of LogstreamBuilder.
+ */
+ void operator<<(Tee* tee);
+
+ private:
+ LogstreamBuilder& operator=(const LogstreamBuilder& other);
+
+ void makeStream();
+
+ MessageLogDomain* _domain;
+ std::string _contextName;
+ LogSeverity _severity;
+ std::string _baseMessage;
+ std::ostringstream* _os;
+ Tee* _tee;
+
+ };
+
+
+} // namespace logger
+} // namespace mongo
diff --git a/src/mongo/logger/message_event.h b/src/mongo/logger/message_event.h
new file mode 100644
index 00000000000..35afc2b03e2
--- /dev/null
+++ b/src/mongo/logger/message_event.h
@@ -0,0 +1,46 @@
+/* Copyright 2013 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 "mongo/base/string_data.h"
+#include "mongo/logger/log_severity.h"
+
+namespace mongo {
+namespace logger {
+
+ /**
+ * Free form text log message object that does not own the storage behind its message and
+ * contextName.
+ *
+ * Used and owned by one thread. This is the message type used by MessageLogDomain.
+ */
+ class MessageEventEphemeral {
+ public:
+ MessageEventEphemeral(LogSeverity severity, StringData contextName, StringData message) :
+ _severity(severity), _contextName(contextName), _message(message) {}
+
+ LogSeverity getSeverity() const { return _severity; }
+ StringData getContextName() const { return _contextName; }
+ StringData getMessage() const { return _message; }
+
+ private:
+ LogSeverity _severity;
+ StringData _contextName;
+ StringData _message;
+ };
+
+} // namespace logger
+} // namespace mongo
diff --git a/src/mongo/logger/message_event_utf8_encoder.cpp b/src/mongo/logger/message_event_utf8_encoder.cpp
new file mode 100644
index 00000000000..b53c000e1e2
--- /dev/null
+++ b/src/mongo/logger/message_event_utf8_encoder.cpp
@@ -0,0 +1,87 @@
+/* Copyright 2013 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 "mongo/platform/basic.h"
+
+#include "mongo/logger/message_event_utf8_encoder.h"
+
+#include <iostream>
+
+#include "mongo/util/time_support.h"
+
+namespace mongo {
+namespace logger {
+
+ MessageEventDetailsEncoder::~MessageEventDetailsEncoder() {}
+ std::ostream& MessageEventDetailsEncoder::encode(const MessageEventEphemeral& event,
+ std::ostream &os) {
+
+ static const size_t maxLogLine = 10 * 1024;
+
+ char dateString[64];
+ curTimeString(dateString);
+ os << dateString << ' ';
+ StringData contextName = event.getContextName();
+ if (!contextName.empty()) {
+ os << '[' << contextName << "] ";
+ }
+
+ LogSeverity severity = event.getSeverity();
+ if (severity >= LogSeverity::Info()) {
+ os << severity << ": ";
+ }
+
+ StringData msg = event.getMessage();
+ if (msg.size() > maxLogLine) {
+ os << "warning: log line attempted (" << msg.size() / 1024 << "k) over max size (" <<
+ maxLogLine / 1024 << "k), printing beginning and end ... ";
+ os << msg.substr(0, maxLogLine / 3);
+ os << " .......... ";
+ os << msg.substr(msg.size() - (maxLogLine / 3));
+ }
+ else {
+ os << msg;
+ }
+ if (!msg.endsWith(StringData("\n", StringData::LiteralTag())))
+ os << '\n';
+ return os;
+ }
+
+ MessageEventWithContextEncoder::~MessageEventWithContextEncoder() {}
+ std::ostream& MessageEventWithContextEncoder::encode(const MessageEventEphemeral& event,
+ std::ostream& os) {
+ StringData contextName = event.getContextName();
+ if (!contextName.empty()) {
+ os << '[' << contextName << "] ";
+ }
+ StringData message = event.getMessage();
+ os << message;
+ if (!message.endsWith("\n"))
+ os << '\n';
+ return os;
+ }
+
+ MessageEventUnadornedEncoder::~MessageEventUnadornedEncoder() {}
+ std::ostream& MessageEventUnadornedEncoder::encode(const MessageEventEphemeral& event,
+ std::ostream& os) {
+ StringData message = event.getMessage();
+ os << message;
+ if (!message.endsWith("\n"))
+ os << '\n';
+ return os;
+ }
+
+} // namespace logger
+} // namespace mongo
diff --git a/src/mongo/logger/message_event_utf8_encoder.h b/src/mongo/logger/message_event_utf8_encoder.h
new file mode 100644
index 00000000000..948f39508bd
--- /dev/null
+++ b/src/mongo/logger/message_event_utf8_encoder.h
@@ -0,0 +1,53 @@
+/* Copyright 2013 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 "mongo/logger/encoder.h"
+#include "mongo/logger/message_event.h"
+
+namespace mongo {
+namespace logger {
+
+ /**
+ * Encoder that writes log messages of the style that MongoDB writes to console and files.
+ */
+ class MessageEventDetailsEncoder : public Encoder<MessageEventEphemeral> {
+ public:
+ virtual ~MessageEventDetailsEncoder();
+ virtual std::ostream& encode(const MessageEventEphemeral& event, std::ostream& os);
+ };
+
+ /**
+ * Encoder that generates log messages suitable for syslog.
+ */
+ class MessageEventWithContextEncoder : public Encoder<MessageEventEphemeral> {
+ public:
+ virtual ~MessageEventWithContextEncoder();
+ virtual std::ostream& encode(const MessageEventEphemeral& event, std::ostream& os);
+ };
+
+
+ /**
+ * Encoder that generates log messages containing only the raw text of the message.
+ */
+ class MessageEventUnadornedEncoder : public Encoder<MessageEventEphemeral> {
+ public:
+ virtual ~MessageEventUnadornedEncoder();
+ virtual std::ostream& encode(const MessageEventEphemeral& event, std::ostream& os);
+ };
+
+} // namespace logger
+} // namespace mongo
diff --git a/src/mongo/logger/message_log_domain.cpp b/src/mongo/logger/message_log_domain.cpp
new file mode 100644
index 00000000000..40d11c65f22
--- /dev/null
+++ b/src/mongo/logger/message_log_domain.cpp
@@ -0,0 +1,28 @@
+/* Copyright 2013 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 "mongo/platform/basic.h"
+
+#include "mongo/logger/message_log_domain.h"
+
+#include "mongo/logger/log_domain-impl.h"
+
+namespace mongo {
+namespace logger {
+
+ template class LogDomain<MessageEventEphemeral>;
+
+} // namespace logger
+} // namespace mongo
diff --git a/src/mongo/logger/message_log_domain.h b/src/mongo/logger/message_log_domain.h
new file mode 100644
index 00000000000..faf97d61342
--- /dev/null
+++ b/src/mongo/logger/message_log_domain.h
@@ -0,0 +1,32 @@
+/* Copyright 2013 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 <boost/scoped_ptr.hpp>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "mongo/logger/log_domain.h"
+#include "mongo/logger/message_event.h"
+
+namespace mongo {
+namespace logger {
+
+ typedef LogDomain<MessageEventEphemeral> MessageLogDomain;
+
+} // namespace logger
+} // namespace mongo
diff --git a/src/mongo/util/ramlog.cpp b/src/mongo/logger/ramlog.cpp
index 6501570bff3..6bb8e9df40d 100644
--- a/src/mongo/util/ramlog.cpp
+++ b/src/mongo/logger/ramlog.cpp
@@ -15,11 +15,13 @@
* limitations under the License.
*/
-#include "pch.h"
-#include "log.h"
-#include "ramlog.h"
-#include "mongoutils/html.h"
-#include "mongoutils/str.h"
+#include "mongo/platform/basic.h"
+
+#include "mongo/logger/ramlog.h"
+
+#include "mongo/logger/message_event_utf8_encoder.h"
+#include "mongo/util/mongoutils/html.h"
+#include "mongo/util/mongoutils/str.h"
namespace mongo {
@@ -47,15 +49,17 @@ namespace mongo {
}
- void RamLog::write(LogLevel ll, const std::string& str) {
+ void RamLog::write(const std::string& str) {
+ boost::unique_lock<boost::mutex> lk(_mutex);
_lastWrite = time(0);
_totalLinesWritten++;
char *p = lines[(h+n)%N];
unsigned sz = str.size();
+ if (0 == sz) return;
if( sz < C ) {
- if ( str.c_str()[sz-1] == '\n' ) {
+ if (str.c_str()[sz-1] == '\n' ) {
memcpy(p, str.c_str(), sz-1);
p[sz-1] = 0;
}
@@ -70,12 +74,23 @@ namespace mongo {
else h = (h+1) % N;
}
- void RamLog::get( vector<const char*>& v) const {
+ time_t RamLog::lastWrite() {
+ boost::unique_lock<boost::mutex> lk(_mutex);
+ return _lastWrite;
+ }
+
+ long long RamLog::getTotalLinesWritten() {
+ boost::unique_lock<boost::mutex> lk(_mutex);
+ return _totalLinesWritten;
+ }
+
+ void RamLog::get( std::vector<const char*>& v) {
+ boost::unique_lock<boost::mutex> lk(_mutex);
for( unsigned x=0, i=h; x++ < n; i=(i+1)%N )
v.push_back(lines[i]);
}
- int RamLog::repeats(const vector<const char *>& v, int i) {
+ int RamLog::repeats(const std::vector<const char *>& v, int i) {
for( int j = i-1; j >= 0 && j+8 > i; j-- ) {
if( strcmp(v[i]+20,v[j]+20) == 0 ) {
for( int x = 1; ; x++ ) {
@@ -90,7 +105,7 @@ namespace mongo {
}
- string RamLog::clean(const vector<const char *>& v, int i, string line ) {
+ string RamLog::clean(const std::vector<const char *>& v, int i, string line ) {
if( line.empty() ) line = v[i];
if( i > 0 && strncmp(v[i], v[i-1], 11) == 0 )
return string(" ") + line.substr(11);
@@ -98,8 +113,8 @@ namespace mongo {
}
string RamLog::color(const std::string& line) {
- string s = str::after(line, "replSet ");
- if( str::startsWith(s, "warning") || startsWith(s, "error") )
+ std::string s = str::after(line, "replSet ");
+ if( str::startsWith(s, "warning") || str::startsWith(s, "error") )
return html::red(line);
if( str::startsWith(s, "info") ) {
if( str::endsWith(s, " up\n") )
@@ -122,13 +137,13 @@ namespace mongo {
while( *sp && *sp != ' ' ) sp++;
string url(h, sp-h);
- stringstream ss;
+ std::stringstream ss;
ss << string(s, h-s) << "<a href=\"" << url << "\">" << url << "</a>" << sp;
return ss.str();
}
- void RamLog::toHTML(stringstream& s) {
- vector<const char*> v;
+ void RamLog::toHTML(std::stringstream& s) {
+ std::vector<const char*> v;
get( v );
s << "<pre>\n";
@@ -139,13 +154,13 @@ namespace mongo {
s << color( linkify( html::escape( clean(v, i) ).c_str() ) ) << '\n';
}
else {
- stringstream x;
+ std::stringstream x;
x << string(v[i], 0, 24);
int nr = (i-r);
int last = i+nr-1;
for( ; r < i ; r++ ) x << '.';
if( 1 ) {
- stringstream r;
+ std::stringstream r;
if( nr == 1 ) r << "repeat last line";
else r << "repeats last " << nr << " lines; ends " << string(v[last]+4,0,15);
s << html::a("", r.str(), html::escape( clean(v, i,x.str() ) ) );
@@ -158,6 +173,17 @@ namespace mongo {
s << "</pre>\n";
}
+ RamLogAppender::RamLogAppender(RamLog* ramlog) : _ramlog(ramlog) {}
+ RamLogAppender::~RamLogAppender() {}
+
+ Status RamLogAppender::append(const logger::MessageEventEphemeral& event) {
+ std::ostringstream ss;
+ logger::MessageEventDetailsEncoder encoder;
+ encoder.encode(event, ss);
+ _ramlog->write(ss.str());
+ return Status::OK();
+ }
+
// ---------------
// static things
// ---------------
@@ -172,8 +198,8 @@ namespace mongo {
return 0;
return i->second;
}
-
- void RamLog::getNames( vector<string>& names ) {
+
+ void RamLog::getNames( std::vector<string>& names ) {
if ( ! _named )
return;
@@ -186,6 +212,4 @@ namespace mongo {
mongo::mutex* RamLog::_namedLock;
RamLog::RM* RamLog::_named = 0;
-
- Tee* const warnings = new RamLog("warnings"); // Things put here go in serverStatus
}
diff --git a/src/mongo/logger/ramlog.h b/src/mongo/logger/ramlog.h
new file mode 100644
index 00000000000..2b78d91daaa
--- /dev/null
+++ b/src/mongo/logger/ramlog.h
@@ -0,0 +1,90 @@
+// ramlog.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 <map>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "mongo/base/disallow_copying.h"
+#include "mongo/base/string_data.h"
+#include "mongo/base/status.h"
+#include "mongo/util/concurrency/mutex.h"
+#include "mongo/logger/appender.h"
+#include "mongo/logger/message_event.h"
+#include "mongo/logger/tee.h"
+
+namespace mongo {
+
+ class RamLog : public logger::Tee {
+ MONGO_DISALLOW_COPYING(RamLog);
+ public:
+ RamLog( const std::string& name );
+
+ void write(const std::string& str);
+
+ void get( std::vector<const char*>& v);
+
+ void toHTML(std::stringstream& s);
+
+ static RamLog* get( const std::string& name );
+ static void getNames( std::vector<std::string>& names );
+
+ time_t lastWrite();
+ long long getTotalLinesWritten();
+
+ private:
+ static int repeats(const std::vector<const char *>& v, int i);
+ static string clean(const std::vector<const char *>& v, int i, string line="");
+ static string color(const std::string& line);
+
+ /* turn http:... into an anchor */
+ static string linkify(const char *s);
+
+ ~RamLog(); // want this private as we want to leak so we can use them till the very end
+
+ enum {
+ N = 1024, // number of lines
+ C = 512 // max size of line
+ };
+
+ boost::mutex _mutex; // Guards all non-static data.
+ char lines[N][C];
+ unsigned h; // current position
+ unsigned n; // number of lines stores 0 o N
+ string _name;
+ long long _totalLinesWritten;
+
+ typedef std::map<string,RamLog*> RM;
+ static mongo::mutex* _namedLock;
+ static RM* _named;
+ time_t _lastWrite;
+ };
+
+ class RamLogAppender : public logger::Appender<logger::MessageEventEphemeral> {
+ public:
+ explicit RamLogAppender(RamLog* ramlog);
+ virtual ~RamLogAppender();
+
+ virtual Status append(const logger::MessageEventEphemeral& event);
+
+ private:
+ RamLog* _ramlog;
+ };
+}
diff --git a/src/mongo/logger/rotatable_file_appender.h b/src/mongo/logger/rotatable_file_appender.h
new file mode 100644
index 00000000000..32384011280
--- /dev/null
+++ b/src/mongo/logger/rotatable_file_appender.h
@@ -0,0 +1,61 @@
+/* Copyright 2013 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 "mongo/base/disallow_copying.h"
+#include "mongo/base/status.h"
+#include "mongo/logger/appender.h"
+#include "mongo/logger/encoder.h"
+#include "mongo/logger/rotatable_file_writer.h"
+
+namespace mongo {
+namespace logger {
+
+ /**
+ * Appender for writing to instances of RotatableFileWriter.
+ */
+ template <typename Event>
+ class RotatableFileAppender : public Appender<Event> {
+ MONGO_DISALLOW_COPYING(RotatableFileAppender);
+
+ public:
+ typedef Encoder<Event> EventEncoder;
+
+ /**
+ * Constructs an appender, that owns "encoder", but not "writer." Caller must
+ * keep "writer" in scope at least as long as the constructed appender.
+ */
+ RotatableFileAppender(EventEncoder* encoder, RotatableFileWriter* writer) :
+ _encoder(encoder),
+ _writer(writer) {
+ }
+
+ virtual Status append(const Event& event) {
+ RotatableFileWriter::Use useWriter(_writer);
+ Status status = useWriter.status();
+ if (!status.isOK())
+ return status;
+ _encoder->encode(event, useWriter.stream()).flush();
+ return useWriter.status();
+ }
+
+ private:
+ boost::scoped_ptr<EventEncoder> _encoder;
+ RotatableFileWriter* _writer;
+ };
+
+} // namespace logger
+} // namespace mongo
diff --git a/src/mongo/logger/rotatable_file_manager.cpp b/src/mongo/logger/rotatable_file_manager.cpp
new file mode 100644
index 00000000000..acf31ed90ac
--- /dev/null
+++ b/src/mongo/logger/rotatable_file_manager.cpp
@@ -0,0 +1,70 @@
+/* Copyright 2013 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 "mongo/platform/basic.h"
+
+#include "mongo/logger/rotatable_file_manager.h"
+
+#include "mongo/logger/rotatable_file_writer.h"
+#include "mongo/util/map_util.h"
+
+namespace mongo {
+namespace logger {
+
+ RotatableFileManager::RotatableFileManager() {}
+
+ RotatableFileManager::~RotatableFileManager() {
+ for (WriterByNameMap::iterator iter = _writers.begin(); iter != _writers.end(); ++iter) {
+ delete iter->second;
+ }
+ }
+
+ StatusWithRotatableFileWriter RotatableFileManager::openFile(const std::string& fileName,
+ bool append) {
+ if (_writers.count(fileName) > 0) {
+ return StatusWithRotatableFileWriter(ErrorCodes::FileAlreadyOpen,
+ "File \"" + fileName + "\" already opened.");
+ }
+ std::auto_ptr<RotatableFileWriter> writer(new RotatableFileWriter);
+ RotatableFileWriter::Use writerUse(writer.get());
+ Status status = writerUse.setFileName(fileName, append);
+ if (!status.isOK())
+ return StatusWithRotatableFileWriter(status);
+ _writers.insert(std::make_pair(fileName, writer.get()));
+ return StatusWith<RotatableFileWriter*>(writer.release());
+ }
+
+ RotatableFileWriter* RotatableFileManager::getFile(const std::string& name) {
+ return mapFindWithDefault(_writers, name, static_cast<RotatableFileWriter*>(NULL));
+ }
+
+ RotatableFileManager::FileNameStatusPairVector RotatableFileManager::rotateAll(
+ const std::string& renameTargetSuffix) {
+
+ FileNameStatusPairVector badStatuses;
+ for (WriterByNameMap::const_iterator iter = _writers.begin();
+ iter != _writers.end(); ++iter) {
+
+ Status status = RotatableFileWriter::Use(iter->second).rotate(
+ iter->first + renameTargetSuffix);
+ if (!status.isOK()) {
+ badStatuses.push_back(std::make_pair(iter->first, status));
+ }
+ }
+ return badStatuses;
+ }
+
+} // namespace logger
+} // namespace mongo
diff --git a/src/mongo/logger/rotatable_file_manager.h b/src/mongo/logger/rotatable_file_manager.h
new file mode 100644
index 00000000000..5ab377a5e33
--- /dev/null
+++ b/src/mongo/logger/rotatable_file_manager.h
@@ -0,0 +1,77 @@
+/* Copyright 2013 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 <string>
+#include <utility>
+#include <vector>
+
+#include "mongo/base/disallow_copying.h"
+#include "mongo/base/status.h"
+#include "mongo/base/status_with.h"
+#include "mongo/logger/rotatable_file_writer.h"
+#include "mongo/platform/unordered_map.h"
+
+namespace mongo {
+namespace logger {
+
+ typedef StatusWith<RotatableFileWriter*> StatusWithRotatableFileWriter;
+
+ /**
+ * Utility object that owns and manages rotation for RotatableFileWriters.
+ *
+ * Unlike RotatableFileWriter, this type leaves synchronization to its consumers.
+ */
+ class RotatableFileManager {
+ MONGO_DISALLOW_COPYING(RotatableFileManager);
+ public:
+ typedef std::pair<std::string, Status> FileNameStatusPair;
+ typedef std::vector<FileNameStatusPair> FileNameStatusPairVector;
+
+ RotatableFileManager();
+ ~RotatableFileManager();
+
+ /**
+ * Opens "name" in mode "append" and returns a new RotatableFileWriter set to
+ * operate on the file.
+ *
+ * If the manager already has opened "name", returns ErrorCodes::FileAlreadyOpen.
+ * May also return failure codes issued by RotatableFileWriter::Use::setFileName().
+ */
+ StatusWithRotatableFileWriter openFile(const std::string& name, bool append);
+
+ /**
+ * Gets a RotatableFileWriter for writing to "name", if the manager owns one, or NULL if
+ * not.
+ */
+ RotatableFileWriter* getFile(const std::string& name);
+
+ /**
+ * Rotates all managed files, renaming each file by appending "renameTargetSuffix".
+ *
+ * Returns a vector of <filename, Status> pairs for filenames with non-OK rotate status.
+ * An empty vector indicates that all files were rotated successfully.
+ */
+ FileNameStatusPairVector rotateAll(const std::string& renameTargetSuffix);
+
+ private:
+ typedef unordered_map<std::string, RotatableFileWriter*> WriterByNameMap;
+
+ WriterByNameMap _writers;
+ };
+
+} // namespace logger
+} // namespace mongo
diff --git a/src/mongo/logger/rotatable_file_writer.h b/src/mongo/logger/rotatable_file_writer.h
index 7cc2b3df0c4..00cf8d65c24 100644
--- a/src/mongo/logger/rotatable_file_writer.h
+++ b/src/mongo/logger/rotatable_file_writer.h
@@ -34,6 +34,9 @@ namespace logger {
* manipulation methods for the stream. For any instance of RotatableFileWriter, at most one
* fully constructed instance of RotatableFileWriter::Use exists at a time, providing mutual
* exclusion.
+ *
+ * Behavior is undefined if two instances of RotatableFileWriter should simultaneously have the
+ * same value for their fileName.
*/
class RotatableFileWriter {
MONGO_DISALLOW_COPYING(RotatableFileWriter);
diff --git a/src/mongo/logger/rotatable_file_writer_test.cpp b/src/mongo/logger/rotatable_file_writer_test.cpp
index 767533498dc..bc690396443 100644
--- a/src/mongo/logger/rotatable_file_writer_test.cpp
+++ b/src/mongo/logger/rotatable_file_writer_test.cpp
@@ -45,9 +45,6 @@ namespace {
TEST_F(RotatableFileWriterTest, RotationTest) {
using namespace logger;
- const std::string logFileName("LogTest_RotatableFileAppender.txt");
- const std::string logFileNameRotated("LogTest_RotatableFileAppender_Rotated.txt");
-
{
RotatableFileWriter writer;
RotatableFileWriter::Use writerUse(&writer);
diff --git a/src/mongo/logger/syslog_appender.h b/src/mongo/logger/syslog_appender.h
new file mode 100644
index 00000000000..6ec5fcaf4e0
--- /dev/null
+++ b/src/mongo/logger/syslog_appender.h
@@ -0,0 +1,71 @@
+/* Copyright 2013 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
+
+#ifndef _WIN32 // TODO(schwerin): Should be #if MONGO_CONFIG_HAVE_SYSLOG_H?
+
+#include <boost/scoped_ptr.hpp>
+#include <sstream>
+#include <syslog.h>
+
+#include "mongo/base/disallow_copying.h"
+#include "mongo/base/status.h"
+#include "mongo/logger/appender.h"
+#include "mongo/logger/encoder.h"
+
+namespace mongo {
+namespace logger {
+
+ /**
+ * Appender for writing to syslog. Users must have separately called openlog().
+ */
+ template <typename Event>
+ class SyslogAppender : public Appender<Event> {
+ MONGO_DISALLOW_COPYING(SyslogAppender);
+
+ public:
+ typedef Encoder<Event> EventEncoder;
+
+ explicit SyslogAppender(EventEncoder* encoder) : _encoder(encoder) {}
+ virtual Status append(const Event& event) {
+ std::ostringstream os;
+ _encoder->encode(event, os);
+ if (!os)
+ return Status(ErrorCodes::LogWriteFailed, "Error writing log message to syslog.");
+ syslog(getSyslogPriority(event.getSeverity()), "%s", os.str().c_str());
+ return Status::OK();
+ }
+
+ private:
+ int getSyslogPriority(LogSeverity severity) {
+ if (severity <= LogSeverity::Debug(1))
+ return LOG_DEBUG;
+ if (severity == LogSeverity::Warning())
+ return LOG_WARNING;
+ if (severity == LogSeverity::Error())
+ return LOG_ERR;
+ if (severity >= LogSeverity::Severe())
+ return LOG_CRIT;
+ // Info() and Log().
+ return LOG_INFO;
+ }
+ boost::scoped_ptr<EventEncoder> _encoder;
+ };
+
+} // namespace logger
+} // namespace mongo
+
+#endif
diff --git a/src/mongo/logger/tee.h b/src/mongo/logger/tee.h
new file mode 100644
index 00000000000..d07addf931b
--- /dev/null
+++ b/src/mongo/logger/tee.h
@@ -0,0 +1,35 @@
+/* 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 <string>
+
+namespace mongo {
+namespace logger {
+
+ class Tee {
+ public:
+ virtual ~Tee() {}
+
+ /**
+ * Implementations of Tee::write must handle their own synchronization. Callers may assume
+ * it is safe to call this method at any time from any thread.
+ */
+ virtual void write(const std::string& str) = 0;
+ };
+
+} // namespace logger
+} // namespace mongo
diff --git a/src/mongo/s/chunk.cpp b/src/mongo/s/chunk.cpp
index e0e8e9510e5..513ab618bea 100644
--- a/src/mongo/s/chunk.cpp
+++ b/src/mongo/s/chunk.cpp
@@ -417,11 +417,11 @@ namespace mongo {
ChunkPtr toMove = cm->findIntersectingChunk(min);
if ( ! (toMove->getMin() == min && toMove->getMax() == max) ){
- LOG(1) << "recently split chunk: " << range << " modified before we could migrate " << toMove << endl;
+ LOG(1).stream() << "recently split chunk: " << range << " modified before we could migrate " << toMove << endl;
return true;
}
- log() << "moving chunk (auto): " << toMove << " to: " << newLocation.toString() << endl;
+ log().stream() << "moving chunk (auto): " << toMove << " to: " << newLocation.toString() << endl;
BSONObj res;
massert( 10412 ,
@@ -1346,7 +1346,7 @@ namespace mongo {
}
catch (...) {
- LOG( LL_ERROR ) << "\t invalid ChunkRangeMap! printing ranges:" << endl;
+ error() << "\t invalid ChunkRangeMap! printing ranges:" << endl;
for (ChunkRangeMap::const_iterator it=_ranges.begin(), end=_ranges.end(); it != end; ++it)
cout << it->first << ": " << *it->second << endl;
@@ -1456,7 +1456,8 @@ namespace mongo {
cmdBuilder.append( "shardHost" , s.getConnString() );
BSONObj cmd = cmdBuilder.obj();
- LOG(1) << " setShardVersion " << s.getName()
+ LOG(1).stream()
+ << " setShardVersion " << s.getName()
<< " " << conn.getServerAddress()
<< " " << ns
<< " " << cmd
diff --git a/src/mongo/s/commands_admin.cpp b/src/mongo/s/commands_admin.cpp
index cdc0431238c..1d91b12cd40 100644
--- a/src/mongo/s/commands_admin.cpp
+++ b/src/mongo/s/commands_admin.cpp
@@ -667,7 +667,7 @@ namespace mongo {
}
}
- tlog() << "CMD: shardcollection: " << cmdObj << endl;
+ MONGO_TLOG(0) << "CMD: shardcollection: " << cmdObj << endl;
config->shardCollection( ns , proposedKey , careAboutUnique , &initSplits );
@@ -693,7 +693,8 @@ namespace mongo {
BSONObj moveResult;
if (!chunk->moveAndCommit(to, Chunk::MaxChunkSize,
false, true, moveResult)) {
- warning() << "Couldn't move chunk " << chunk << " to shard " << to
+ warning().stream()
+ << "Couldn't move chunk " << chunk << " to shard " << to
<< " while sharding collection " << ns << ". Reason: "
<< moveResult << endl;
}
@@ -715,9 +716,10 @@ namespace mongo {
if ( ! subSplits.empty() ){
BSONObj splitResult;
if ( ! currentChunk->multiSplit( subSplits , splitResult ) ){
- warning() << "Couldn't split chunk " << currentChunk
- << " while sharding collection " << ns << ". Reason: "
- << splitResult << endl;
+ warning().stream()
+ << "Couldn't split chunk " << currentChunk
+ << " while sharding collection " << ns << ". Reason: "
+ << splitResult << endl;
}
subSplits.clear();
}
@@ -890,7 +892,7 @@ namespace mongo {
}
verify(chunk.get());
- log() << "splitting: " << ns << " shard: " << chunk << endl;
+ log().stream() << "splitting: " << ns << " shard: " << chunk << endl;
BSONObj res;
bool worked;
@@ -1005,7 +1007,7 @@ namespace mongo {
return false;
}
- tlog() << "CMD: movechunk: " << cmdObj << endl;
+ MONGO_TLOG(0) << "CMD: movechunk: " << cmdObj << endl;
BSONObj res;
if (!c->moveAndCommit(to,
diff --git a/src/mongo/s/config.cpp b/src/mongo/s/config.cpp
index 155bbc95c33..c811374233a 100644
--- a/src/mongo/s/config.cpp
+++ b/src/mongo/s/config.cpp
@@ -850,7 +850,7 @@ namespace mongo {
}
if ( up == 1 ) {
- LOG( LL_WARNING ) << "only 1 config server reachable, continuing" << endl;
+ warning() << "only 1 config server reachable, continuing" << endl;
return true;
}
@@ -870,7 +870,7 @@ namespace mongo {
stringstream ss;
ss << "config servers " << _config[firstGood] << " and " << _config[i] << " differ";
- LOG( LL_WARNING ) << ss.str() << endl;
+ warning() << ss.str() << endl;
if ( tries <= 1 ) {
ss << "\n" << c1 << "\t" << c2 << "\n" << d1 << "\t" << d2;
errmsg = ss.str();
@@ -890,7 +890,7 @@ namespace mongo {
if ( checkConsistency ) {
string errmsg;
if ( ! checkConfigServersConsistent( errmsg ) ) {
- LOG( LL_ERROR ) << "could not verify that config servers are in sync" << causedBy(errmsg) << warnings;
+ error() << "could not verify that config servers are in sync" << causedBy(errmsg) << warnings;
return false;
}
}
diff --git a/src/mongo/s/cursors.cpp b/src/mongo/s/cursors.cpp
index 446c8ae4f48..5bda5766fcc 100644
--- a/src/mongo/s/cursors.cpp
+++ b/src/mongo/s/cursors.cpp
@@ -167,16 +167,16 @@ namespace mongo {
CursorCache::~CursorCache() {
// TODO: delete old cursors?
- bool print = logLevel > 0;
+ bool print = logger::globalLogDomain()->shouldLog(logger::LogSeverity::Debug(1));
if ( _cursors.size() || _refs.size() )
print = true;
verify(_refs.size() == _refsNS.size());
if ( print )
- cout << " CursorCache at shutdown - "
- << " sharded: " << _cursors.size()
- << " passthrough: " << _refs.size()
- << endl;
+ log() << " CursorCache at shutdown - "
+ << " sharded: " << _cursors.size()
+ << " passthrough: " << _refs.size()
+ << endl;
}
ShardedClientCursorPtr CursorCache::get( long long id ) const {
@@ -276,7 +276,7 @@ namespace mongo {
int n = *x++;
if ( n > 2000 ) {
- LOG( n < 30000 ? LL_WARNING : LL_ERROR ) << "receivedKillCursors, n=" << n << endl;
+ ( n < 30000 ? warning() : error() ) << "receivedKillCursors, n=" << n << endl;
}
@@ -291,7 +291,7 @@ namespace mongo {
LOG(_myLogLevel) << "CursorCache::gotKillCursors id: " << id << endl;
if ( ! id ) {
- LOG( LL_WARNING ) << " got cursor id of 0 to kill" << endl;
+ warning() << " got cursor id of 0 to kill" << endl;
continue;
}
@@ -311,7 +311,7 @@ namespace mongo {
MapNormal::iterator refsIt = _refs.find(id);
MapNormal::iterator refsNSIt = _refsNS.find(id);
if (refsIt == _refs.end()) {
- LOG( LL_WARNING ) << "can't find cursor: " << id << endl;
+ warning() << "can't find cursor: " << id << endl;
continue;
}
verify(refsNSIt != _refsNS.end());
diff --git a/src/mongo/s/d_split.cpp b/src/mongo/s/d_split.cpp
index 464b870f107..65427fec359 100644
--- a/src/mongo/s/d_split.cpp
+++ b/src/mongo/s/d_split.cpp
@@ -624,8 +624,8 @@ namespace mongo {
result.append( "requestedMin" , min );
result.append( "requestedMax" , max );
- LOG( LL_WARNING ) << "aborted split because " << errmsg << ": " << min << "->" << max
- << " is now " << currMin << "->" << currMax << endl;
+ warning() << "aborted split because " << errmsg << ": " << min << "->" << max
+ << " is now " << currMin << "->" << currMax << endl;
return false;
}
@@ -634,8 +634,8 @@ namespace mongo {
result.append( "from" , myShard.getName() );
result.append( "official" , shard );
- LOG( LL_WARNING ) << "aborted split because " << errmsg << ": chunk is at " << shard
- << " and not at " << myShard.getName() << endl;
+ warning() << "aborted split because " << errmsg << ": chunk is at " << shard
+ << " and not at " << myShard.getName() << endl;
return false;
}
@@ -644,8 +644,8 @@ namespace mongo {
maxVersion.addToBSON( result, "officialVersion" );
shardingState.getVersion( ns ).addToBSON( result, "myVersion" );
- LOG( LL_WARNING ) << "aborted split because " << errmsg << ": official " << maxVersion
- << " mine: " << shardingState.getVersion(ns) << endl;
+ warning() << "aborted split because " << errmsg << ": official " << maxVersion
+ << " mine: " << shardingState.getVersion(ns) << endl;
return false;
}
diff --git a/src/mongo/s/grid.cpp b/src/mongo/s/grid.cpp
index fa1abb2d151..15dd930ad0a 100644
--- a/src/mongo/s/grid.cpp
+++ b/src/mongo/s/grid.cpp
@@ -549,13 +549,10 @@ namespace mongo {
return true;
}
- if ( logLevel ) {
- stringstream ss;
- ss << " now: " << now
- << " startTime: " << startTime
- << " stopTime: " << stopTime;
- log() << "_inBalancingWindow: " << ss.str() << endl;
- }
+ LOG(1).stream() << "_inBalancingWindow: "
+ << " now: " << now
+ << " startTime: " << startTime
+ << " stopTime: " << stopTime;
// allow balancing if during the activeWindow
// note that a window may be open during the night
diff --git a/src/mongo/s/s_only.cpp b/src/mongo/s/s_only.cpp
index 10b9eb43366..48824ab7da3 100644
--- a/src/mongo/s/s_only.cpp
+++ b/src/mongo/s/s_only.cpp
@@ -15,20 +15,21 @@
* limitations under the License.
*/
-#include "pch.h"
+#include "mongo/pch.h"
#include "mongo/client/connpool.h"
#include "mongo/db/auth/authorization_manager.h"
#include "mongo/db/auth/authorization_manager_global.h"
#include "mongo/db/auth/authorization_session.h"
#include "mongo/db/auth/authz_session_external_state_s.h"
-#include "mongo/s/shard.h"
+#include "mongo/db/commands.h"
+#include "mongo/db/dbhelpers.h"
+#include "mongo/db/matcher.h"
+#include "mongo/s/client_info.h"
#include "mongo/s/grid.h"
-#include "request.h"
-#include "client_info.h"
-#include "../db/dbhelpers.h"
-#include "../db/matcher.h"
-#include "../db/commands.h"
+#include "mongo/s/request.h"
+#include "mongo/s/shard.h"
+#include "mongo/util/concurrency/thread_name.h"
/*
most a pile of hacks to make linking nicer
diff --git a/src/mongo/s/server.cpp b/src/mongo/s/server.cpp
index e5fb69bbe00..5d6d18c7c8d 100644
--- a/src/mongo/s/server.cpp
+++ b/src/mongo/s/server.cpp
@@ -44,6 +44,7 @@
#include "mongo/scripting/engine.h"
#include "mongo/util/admin_access.h"
#include "mongo/util/concurrency/task.h"
+#include "mongo/util/concurrency/thread_name.h"
#include "mongo/util/exception_filter_win32.h"
#include "mongo/util/log.h"
#include "mongo/util/net/message.h"
@@ -228,7 +229,8 @@ namespace mongo {
void init() {
serverID.init();
- Logstream::get().addGlobalTee( new RamLog("global") );
+ logger::globalLogDomain()->attachAppender(
+ logger::MessageLogDomain::AppenderAutoPtr(new RamLogAppender(new RamLog("global"))));
}
void start( const MessageServer::Options& opts ) {
@@ -445,7 +447,7 @@ static void processCommandLineOptions(const std::vector<std::string>& argv) {
}
if ( params.count( "test" ) ) {
- logLevel = 5;
+ ::mongo::logger::globalLogDomain()->setMinimumLoggedSeverity(::mongo::logger::LogSeverity::Debug(5));
StartupTest::runTests();
cout << "tests passed" << endl;
::_exit(EXIT_SUCCESS);
diff --git a/src/mongo/s/strategy_shard.cpp b/src/mongo/s/strategy_shard.cpp
index 62af3cc7f4b..2cd4df22900 100644
--- a/src/mongo/s/strategy_shard.cpp
+++ b/src/mongo/s/strategy_shard.cpp
@@ -587,7 +587,7 @@ namespace mongo {
<< "inserting "
<< group.inserts.size()
<< " documents to shard "
- << group.shard
+ << group.shard->toString()
<< " at version "
<< (group.manager.get() ?
group.manager->getVersion().toString() :
diff --git a/src/mongo/s/strategy_single.cpp b/src/mongo/s/strategy_single.cpp
index cc95e9cf890..7a3590936b5 100644
--- a/src/mongo/s/strategy_single.cpp
+++ b/src/mongo/s/strategy_single.cpp
@@ -210,7 +210,7 @@ namespace mongo {
b.append( "err" , "can't do unlock through mongos" );
}
else {
- LOG( LL_WARNING ) << "unknown sys command [" << ns << "]" << endl;
+ warning() << "unknown sys command [" << ns << "]" << endl;
return false;
}
diff --git a/src/mongo/s/version_manager.cpp b/src/mongo/s/version_manager.cpp
index 1496ebc1407..bc146e49074 100644
--- a/src/mongo/s/version_manager.cpp
+++ b/src/mongo/s/version_manager.cpp
@@ -222,10 +222,11 @@ namespace mongo {
"version is zero" ) ) << endl;
}
- LOG(2) << " have to set shard version for conn: " << conn->getServerAddress() << " ns:" << ns
- << " my last seq: " << sequenceNumber << " current: " << officialSequenceNumber
- << " version: " << version << " manager: " << manager.get()
- << endl;
+ LOG(2).stream()
+ << " have to set shard version for conn: " << conn->getServerAddress() << " ns:" << ns
+ << " my last seq: " << sequenceNumber << " current: " << officialSequenceNumber
+ << " version: " << version << " manager: " << manager.get()
+ << endl;
const string versionableServerAddress(conn->getServerAddress());
diff --git a/src/mongo/scripting/engine_v8.cpp b/src/mongo/scripting/engine_v8.cpp
index 3e61236416a..527c9b0fd5c 100644
--- a/src/mongo/scripting/engine_v8.cpp
+++ b/src/mongo/scripting/engine_v8.cpp
@@ -17,6 +17,7 @@
#include "mongo/scripting/engine_v8.h"
+#include "mongo/base/init.h"
#include "mongo/platform/unordered_set.h"
#include "mongo/scripting/v8_db.h"
#include "mongo/scripting/v8_utils.h"
@@ -303,78 +304,77 @@ namespace mongo {
template <typename _GCState>
void gcCallback(v8::GCType type, v8::GCCallbackFlags flags) {
- const int verbosity = 1; // log level for stat collection
- if (logLevel < verbosity)
- // don't collect stats unless verbose
- return;
-
- v8::HeapStatistics stats;
- v8::V8::GetHeapStatistics(&stats);
- log() << "V8 GC " << _GCState::name
- << " heap stats - "
- << " total: " << stats.total_heap_size()
- << " exec: " << stats.total_heap_size_executable()
- << " used: " << stats.used_heap_size()<< " limit: "
- << stats.heap_size_limit()
- << endl;
- }
-
- V8ScriptEngine::V8ScriptEngine() :
- _globalInterruptLock("GlobalV8InterruptLock"),
- _opToScopeMap(),
- _deadlineMonitor() {
- }
-
- V8ScriptEngine::~V8ScriptEngine() {
- }
-
- void ScriptEngine::setup() {
- if (!globalScriptEngine) {
- globalScriptEngine = new V8ScriptEngine();
- }
- }
-
- std::string ScriptEngine::getInterpreterVersionString() {
- return "V8 3.12.19";
- }
-
- void V8ScriptEngine::interrupt(unsigned opId) {
- mongo::mutex::scoped_lock intLock(_globalInterruptLock);
- OpIdToScopeMap::iterator iScope = _opToScopeMap.find(opId);
- if (iScope == _opToScopeMap.end()) {
- // got interrupt request for a scope that no longer exists
- LOG(1) << "received interrupt request for unknown op: " << opId
- << printKnownOps_inlock() << endl;
- return;
- }
- LOG(1) << "interrupting op: " << opId << printKnownOps_inlock() << endl;
- iScope->second->kill();
- }
-
- void V8ScriptEngine::interruptAll() {
- mongo::mutex::scoped_lock interruptLock(_globalInterruptLock);
- for (OpIdToScopeMap::iterator iScope = _opToScopeMap.begin();
- iScope != _opToScopeMap.end(); ++iScope) {
- iScope->second->kill();
- }
- }
-
- void V8Scope::registerOpId() {
- scoped_lock giLock(_engine->_globalInterruptLock);
- if (_engine->haveGetCurrentOpIdCallback()) {
- // this scope has an associated operation
- _opId = _engine->getCurrentOpId();
- _engine->_opToScopeMap[_opId] = this;
- }
- else
- // no associated op id (e.g. running from shell)
- _opId = 0;
- LOG(2) << "V8Scope " << this << " registered for op " << _opId << endl;
- }
-
- void V8Scope::unregisterOpId() {
- scoped_lock giLock(_engine->_globalInterruptLock);
- LOG(2) << "V8Scope " << this << " unregistered for op " << _opId << endl;
+ if (!logger::globalLogDomain()->shouldLog(logger::LogSeverity::Debug(1)))
+ // don't collect stats unless verbose
+ return;
+
+ v8::HeapStatistics stats;
+ v8::V8::GetHeapStatistics(&stats);
+ log() << "V8 GC " << _GCState::name
+ << " heap stats - "
+ << " total: " << stats.total_heap_size()
+ << " exec: " << stats.total_heap_size_executable()
+ << " used: " << stats.used_heap_size()<< " limit: "
+ << stats.heap_size_limit()
+ << endl;
+ }
+
+ V8ScriptEngine::V8ScriptEngine() :
+ _globalInterruptLock("GlobalV8InterruptLock"),
+ _opToScopeMap(),
+ _deadlineMonitor() {
+ }
+
+ V8ScriptEngine::~V8ScriptEngine() {
+ }
+
+ void ScriptEngine::setup() {
+ if (!globalScriptEngine) {
+ globalScriptEngine = new V8ScriptEngine();
+ }
+ }
+
+ std::string ScriptEngine::getInterpreterVersionString() {
+ return "V8 3.12.19";
+ }
+
+ void V8ScriptEngine::interrupt(unsigned opId) {
+ mongo::mutex::scoped_lock intLock(_globalInterruptLock);
+ OpIdToScopeMap::iterator iScope = _opToScopeMap.find(opId);
+ if (iScope == _opToScopeMap.end()) {
+ // got interrupt request for a scope that no longer exists
+ LOG(1) << "received interrupt request for unknown op: " << opId
+ << printKnownOps_inlock() << endl;
+ return;
+ }
+ LOG(1) << "interrupting op: " << opId << printKnownOps_inlock() << endl;
+ iScope->second->kill();
+ }
+
+ void V8ScriptEngine::interruptAll() {
+ mongo::mutex::scoped_lock interruptLock(_globalInterruptLock);
+ for (OpIdToScopeMap::iterator iScope = _opToScopeMap.begin();
+ iScope != _opToScopeMap.end(); ++iScope) {
+ iScope->second->kill();
+ }
+ }
+
+ void V8Scope::registerOpId() {
+ scoped_lock giLock(_engine->_globalInterruptLock);
+ if (_engine->haveGetCurrentOpIdCallback()) {
+ // this scope has an associated operation
+ _opId = _engine->getCurrentOpId();
+ _engine->_opToScopeMap[_opId] = this;
+ }
+ else
+ // no associated op id (e.g. running from shell)
+ _opId = 0;
+ LOG(2) << "V8Scope " << static_cast<const void*>(this) << " registered for op " << _opId << endl;
+ }
+
+ void V8Scope::unregisterOpId() {
+ scoped_lock giLock(_engine->_globalInterruptLock);
+ LOG(2) << "V8Scope " << static_cast<const void*>(this) << " unregistered for op " << _opId << endl;
if (_engine->haveGetCurrentOpIdCallback() || _opId != 0) {
// scope is currently associated with an operation id
V8ScriptEngine::OpIdToScopeMap::iterator it = _engine->_opToScopeMap.find(_opId);
@@ -387,12 +387,12 @@ namespace mongo {
v8::Locker l(_isolate);
mongo::mutex::scoped_lock cbEnterLock(_interruptLock);
if (v8::V8::IsExecutionTerminating(_isolate)) {
- LOG(2) << "v8 execution interrupted. isolate: " << _isolate << endl;
+ LOG(2) << "v8 execution interrupted. isolate: " << static_cast<const void*>(_isolate) << endl;
return false;
}
if (_pendingKill || globalScriptEngine->interrupted()) {
// kill flag was set before entering our callback
- LOG(2) << "marked for death while leaving callback. isolate: " << _isolate << endl;
+ LOG(2) << "marked for death while leaving callback. isolate: " << static_cast<const void*>(_isolate) << endl;
v8::V8::TerminateExecution(_isolate);
return false;
}
@@ -405,11 +405,11 @@ namespace mongo {
mongo::mutex::scoped_lock cbLeaveLock(_interruptLock);
_inNativeExecution = false;
if (v8::V8::IsExecutionTerminating(_isolate)) {
- LOG(2) << "v8 execution interrupted. isolate: " << _isolate << endl;
+ LOG(2) << "v8 execution interrupted. isolate: " << static_cast<const void*>(_isolate) << endl;
return false;
}
if (_pendingKill || globalScriptEngine->interrupted()) {
- LOG(2) << "marked for death while leaving callback. isolate: " << _isolate << endl;
+ LOG(2) << "marked for death while leaving callback. isolate: " << static_cast<const void*>(_isolate) << endl;
v8::V8::TerminateExecution(_isolate);
return false;
}
@@ -422,9 +422,9 @@ namespace mongo {
// Set the TERMINATE flag on the stack guard for this isolate.
// This won't happen between calls to nativePrologue and nativeEpilogue().
v8::V8::TerminateExecution(_isolate);
- LOG(1) << "killing v8 scope. isolate: " << _isolate << endl;
+ LOG(1) << "killing v8 scope. isolate: " << static_cast<const void*>(_isolate) << endl;
}
- LOG(1) << "marking v8 scope for death. isolate: " << _isolate << endl;
+ LOG(1) << "marking v8 scope for death. isolate: " << static_cast<const void*>(_isolate) << endl;
_pendingKill = true;
}
@@ -438,7 +438,7 @@ namespace mongo {
*/
std::string V8ScriptEngine::printKnownOps_inlock() {
stringstream out;
- if (logLevel > 1) {
+ if (logger::globalLogDomain()->shouldLog(logger::LogSeverity::Debug(2))) {
out << " known ops: " << endl;
for(OpIdToScopeMap::iterator iSc = _opToScopeMap.begin();
iSc != _opToScopeMap.end(); ++iSc) {
@@ -1665,8 +1665,10 @@ namespace mongo {
// --- random utils ----
+ static logger::MessageLogDomain* jsPrintLogDomain;
v8::Handle<v8::Value> V8Scope::Print(V8Scope* scope, const v8::Arguments& args) {
- stringstream ss;
+ LogstreamBuilder builder(jsPrintLogDomain, getThreadName(), logger::LogSeverity::Log());
+ std::ostream& ss = builder.stream();
v8::HandleScope handle_scope;
bool first = true;
for (int i = 0; i < args.Length(); i++) {
@@ -1690,7 +1692,6 @@ namespace mongo {
ss << *str;
}
ss << "\n";
- Logstream::logLockless(ss.str());
return handle_scope.Close(v8::Undefined());
}
@@ -1730,4 +1731,9 @@ namespace mongo {
*v8::String::Utf8Value(args[0]->ToString())));
}
+ MONGO_INITIALIZER(JavascriptPrintDomain)(InitializerContext*) {
+ jsPrintLogDomain = logger::globalLogManager()->getNamedDomain("javascriptOutput");
+ return Status::OK();
+ }
+
} // namespace mongo
diff --git a/src/mongo/scripting/engine_v8.h b/src/mongo/scripting/engine_v8.h
index 7a005e7f05f..5b22c64df38 100644
--- a/src/mongo/scripting/engine_v8.h
+++ b/src/mongo/scripting/engine_v8.h
@@ -73,9 +73,10 @@ namespace mongo {
* V8Scope is destructed.
*/
~ObjTracker() {
- if (!_container.empty())
+ if (!_container.empty()) {
LOG(1) << "freeing " << _container.size() << " uncollected "
<< typeid(_ObjType).name() << " objects" << endl;
+ }
typename set<TrackedPtr*>::iterator it = _container.begin();
while (it != _container.end()) {
delete *it;
diff --git a/src/mongo/shell/dbshell.cpp b/src/mongo/shell/dbshell.cpp
index c77ebb463c2..f396b399a22 100644
--- a/src/mongo/shell/dbshell.cpp
+++ b/src/mongo/shell/dbshell.cpp
@@ -28,6 +28,9 @@
#include "mongo/client/sasl_client_authenticate.h"
#include "mongo/db/cmdline.h"
#include "mongo/db/repl/rs_member.h"
+#include "mongo/logger/console_appender.h"
+#include "mongo/logger/logger.h"
+#include "mongo/logger/message_event_utf8_encoder.h"
#include "mongo/scripting/engine.h"
#include "mongo/shell/linenoise.h"
#include "mongo/shell/shell_utils.h"
@@ -844,7 +847,7 @@ int _main( int argc, char* argv[], char **envp ) {
mongo::enableIPv6();
}
if ( params.count( "verbose" ) ) {
- logLevel = 1;
+ logger::globalLogDomain()->setMinimumLoggedSeverity(logger::LogSeverity::Debug(1));
}
if ( url == "*" ) {
@@ -859,6 +862,11 @@ int _main( int argc, char* argv[], char **envp ) {
mongo::runGlobalInitializersOrDie(argc, argv, envp);
mongo::StartupTest::runTests();
+ logger::globalLogManager()->getNamedDomain("javascriptOutput")->attachAppender(
+ logger::MessageLogDomain::AppenderAutoPtr(
+ new logger::ConsoleAppender<logger::MessageEventEphemeral>(
+ new logger::MessageEventUnadornedEncoder)));
+
if ( !nodb ) { // connect to db
//if ( ! mongo::cmdLine.quiet ) cout << "url: " << url << endl;
diff --git a/src/mongo/tools/bsondump.cpp b/src/mongo/tools/bsondump.cpp
index 31019f26d0c..4c87460b0b3 100644
--- a/src/mongo/tools/bsondump.cpp
+++ b/src/mongo/tools/bsondump.cpp
@@ -109,7 +109,7 @@ public:
else if ( e.type() == String && ! isValidUTF8( e.valuestr() ) ) {
cout << prefix << "\t\t\t" << "bad utf8 String!" << endl;
}
- else if ( logLevel > 0 ) {
+ else if ( logger::globalLogDomain()->shouldLog(logger::LogSeverity::Debug(1)) ) {
cout << prefix << "\t\t\t" << e << endl;
}
diff --git a/src/mongo/tools/tool.cpp b/src/mongo/tools/tool.cpp
index ed94e860cc9..8ca34f7d8d2 100644
--- a/src/mongo/tools/tool.cpp
+++ b/src/mongo/tools/tool.cpp
@@ -176,13 +176,13 @@ namespace mongo {
::_exit(0);
}
- if ( _params.count( "verbose" ) ) {
- logLevel = 1;
+ if (_params.count("verbose")) {
+ logger::globalLogDomain()->setMinimumLoggedSeverity(logger::LogSeverity::Debug(1));
}
- for (string s = "vv"; s.length() <= 10; s.append("v")) {
+ for (string s = "vv"; s.length() <= 12; s.append("v")) {
if (_params.count(s)) {
- logLevel = s.length();
+ logger::globalLogDomain()->setMinimumLoggedSeverity(logger::LogSeverity::Debug(s.length()));
}
}
@@ -498,7 +498,7 @@ namespace mongo {
posix_fadvise(fileno(file), 0, fileLength, POSIX_FADV_SEQUENTIAL);
#endif
- if (!_quiet && logLevel >= 1) {
+ if (!_quiet && logger::globalLogDomain()->shouldLog(logger::LogSeverity::Debug(1))) {
(_usesstdout ? cout : cerr ) << "\t file size: " << fileLength << endl;
}
diff --git a/src/mongo/unittest/crutch.cpp b/src/mongo/unittest/crutch.cpp
index bae6f6a30a9..232086527b2 100644
--- a/src/mongo/unittest/crutch.cpp
+++ b/src/mongo/unittest/crutch.cpp
@@ -32,7 +32,6 @@ namespace mongo {
StartupTest::StartupTest() {}
StartupTest::~StartupTest() {}
bool inShutdown() { return false; }
- std::string getThreadName() { return "UNKNOWN"; }
void setLastError(int code, const char* msg) {}
bool StaticObserver::_destroyingStatics = false;
} // namespace mongo
diff --git a/src/mongo/unittest/unittest.cpp b/src/mongo/unittest/unittest.cpp
index 0f51c016232..a891b7a10f7 100644
--- a/src/mongo/unittest/unittest.cpp
+++ b/src/mongo/unittest/unittest.cpp
@@ -21,6 +21,11 @@
#include <iostream>
#include <map>
+#include "mongo/base/init.h"
+#include "mongo/logger/console_appender.h"
+#include "mongo/logger/log_manager.h"
+#include "mongo/logger/message_event_utf8_encoder.h"
+#include "mongo/logger/message_log_domain.h"
#include "mongo/util/assert_util.h"
#include "mongo/util/log.h"
@@ -29,6 +34,8 @@ namespace mongo {
namespace unittest {
namespace {
+ logger::MessageLogDomain* unittestOutput =
+ logger::globalLogManager()->getNamedDomain("unittest");
typedef std::map<std::string, Suite*> SuiteMap;
inline SuiteMap& _allSuites() {
@@ -38,6 +45,20 @@ namespace mongo {
} // namespace
+ logger::LogstreamBuilder log() {
+ return LogstreamBuilder(unittestOutput, getThreadName(), logger::LogSeverity::Log());
+ }
+
+ MONGO_INITIALIZER_WITH_PREREQUISITES(UnitTestOutput, ("GlobalLogManager", "default"))(
+ InitializerContext*) {
+
+ unittestOutput->attachAppender(
+ logger::MessageLogDomain::AppenderAutoPtr(
+ new logger::ConsoleAppender<logger::MessageLogDomain::Event>(
+ new logger::MessageEventDetailsEncoder)));
+ return Status::OK();
+ }
+
class Result {
public:
Result( const std::string& name ) : _name( name ) , _rc(0) , _tests(0) , _fails(0) , _asserts(0) {}
diff --git a/src/mongo/unittest/unittest.h b/src/mongo/unittest/unittest.h
index ef5faee4e73..3f35e2aba73 100644
--- a/src/mongo/unittest/unittest.h
+++ b/src/mongo/unittest/unittest.h
@@ -33,6 +33,7 @@
#include <boost/scoped_ptr.hpp>
#include <boost/shared_ptr.hpp>
+#include "mongo/logger/logstream_builder.h"
#include "mongo/util/assert_util.h"
#include "mongo/util/mongoutils/str.h"
@@ -170,6 +171,12 @@ namespace mongo {
class Result;
/**
+ * Gets a LogstreamBuilder for logging to the unittest log domain, which may have
+ * different target from the global log domain.
+ */
+ mongo::logger::LogstreamBuilder log();
+
+ /**
* Type representing the function composing a test.
*/
typedef boost::function<void (void)> TestFunction;
diff --git a/src/mongo/util/background.cpp b/src/mongo/util/background.cpp
index 9c20829669d..347f8b1bdd5 100644
--- a/src/mongo/util/background.cpp
+++ b/src/mongo/util/background.cpp
@@ -24,6 +24,7 @@
#include "mongo/util/concurrency/mutex.h"
#include "mongo/util/concurrency/spin_lock.h"
+#include "mongo/util/concurrency/thread_name.h"
#include "mongo/util/mongoutils/str.h"
#include "mongo/util/net/ssl_manager.h"
#include "mongo/util/time_support.h"
@@ -65,10 +66,10 @@ namespace mongo {
run();
}
catch ( std::exception& e ) {
- LOG( LL_ERROR ) << "backgroundjob " << name() << " exception: " << e.what() << endl;
+ error() << "backgroundjob " << name() << " exception: " << e.what() << endl;
}
catch(...) {
- LOG( LL_ERROR ) << "uncaught exception in BackgroundJob " << name() << endl;
+ error() << "uncaught exception in BackgroundJob " << name() << endl;
}
{
diff --git a/src/mongo/util/concurrency/SConscript b/src/mongo/util/concurrency/SConscript
new file mode 100644
index 00000000000..60aaa5ef9e0
--- /dev/null
+++ b/src/mongo/util/concurrency/SConscript
@@ -0,0 +1,8 @@
+# -*- mode: python -*-
+
+Import("env")
+
+env.StaticLibrary('thread_name',
+ ['thread_name.cpp'],
+ LIBDEPS=['$BUILD_DIR/mongo/base/base',
+ '$BUILD_DIR/third_party/shim_boost'])
diff --git a/src/mongo/util/concurrency/mutexdebugger.cpp b/src/mongo/util/concurrency/mutexdebugger.cpp
index 873cedd3683..a9f0eb00d46 100644
--- a/src/mongo/util/concurrency/mutexdebugger.cpp
+++ b/src/mongo/util/concurrency/mutexdebugger.cpp
@@ -15,9 +15,11 @@
* limitations under the License.
*/
-#include "pch.h"
-#include "mutex.h"
-#include "value.h"
+#include "mongo/pch.h"
+
+#include "mongo/logger/logger.h"
+#include "mongo/util/concurrency/mutex.h"
+
namespace mongo {
@@ -43,7 +45,8 @@ namespace mongo {
}
void MutexDebugger::programEnding() {
- if( logLevel>=1 && followers.size() ) {
+ using logger::LogSeverity;
+ if(logger::globalLogDomain()->shouldLog(LogSeverity::Debug(1)) && followers.size()) {
std::cout << followers.size() << " mutexes in program" << endl;
for( map< mid, set<mid> >::iterator i = followers.begin(); i != followers.end(); i++ ) {
cout << i->first;
diff --git a/src/mongo/util/concurrency/thread_name.cpp b/src/mongo/util/concurrency/thread_name.cpp
new file mode 100644
index 00000000000..f25cccd9874
--- /dev/null
+++ b/src/mongo/util/concurrency/thread_name.cpp
@@ -0,0 +1,77 @@
+/* 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.
+ */
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/platform/compiler.h"
+#include "mongo/util/concurrency/thread_name.h"
+
+#include <boost/thread/tss.hpp>
+
+namespace mongo {
+
+namespace {
+ boost::thread_specific_ptr<std::string> _threadName;
+
+#if defined(_WIN32)
+
+#define MS_VC_EXCEPTION 0x406D1388
+#pragma pack(push,8)
+ typedef struct tagTHREADNAME_INFO {
+ DWORD dwType; // Must be 0x1000.
+ LPCSTR szName; // Pointer to name (in user addr space).
+ DWORD dwThreadID; // Thread ID (-1=caller thread).
+ DWORD dwFlags; // Reserved for future use, must be zero.
+ } THREADNAME_INFO;
+#pragma pack(pop)
+
+ void setWinThreadName(const char *name) {
+ /* is the sleep here necessary???
+ Sleep(10);
+ */
+ THREADNAME_INFO info;
+ info.dwType = 0x1000;
+ info.szName = name;
+ info.dwThreadID = -1;
+ info.dwFlags = 0;
+ __try {
+ RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info );
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER) {
+ }
+ }
+#endif
+
+} // namespace
+
+ void setThreadName(StringData name) {
+ _threadName.reset(new string(name.rawData(), name.size()));
+
+#if defined( DEBUG ) && defined( _WIN32 )
+ // naming might be expensive so don't do "conn*" over and over
+ setWinThreadName(_threadName.get()->c_str());
+#endif
+
+ }
+
+ const std::string& getThreadName() {
+ std::string* s;
+ while (!(s = _threadName.get())) {
+ setThreadName("");
+ }
+ return *s;
+ }
+
+} // namespace mongo
diff --git a/src/mongo/util/concurrency/thread_name.h b/src/mongo/util/concurrency/thread_name.h
new file mode 100644
index 00000000000..4a32789dfef
--- /dev/null
+++ b/src/mongo/util/concurrency/thread_name.h
@@ -0,0 +1,35 @@
+/* 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 <string>
+
+#include "mongo/base/string_data.h"
+
+namespace mongo {
+
+ /**
+ * Sets the name of the current thread to "name".
+ */
+ void setThreadName(StringData name);
+
+ /**
+ * Retrieves the name of the current thread, as previously set, or "" if no name was previously
+ * set.
+ */
+ const std::string& getThreadName();
+
+} // namespace mongo
diff --git a/src/mongo/util/exception_filter_win32.cpp b/src/mongo/util/exception_filter_win32.cpp
index 252f59bde96..9b11e1fb0aa 100644
--- a/src/mongo/util/exception_filter_win32.cpp
+++ b/src/mongo/util/exception_filter_win32.cpp
@@ -24,6 +24,7 @@
#include "mongo/util/exit_code.h"
#include "mongo/util/log.h"
#include "mongo/util/stacktrace.h"
+#include "mongo/util/text.h"
namespace mongo {
diff --git a/src/mongo/util/file_allocator.cpp b/src/mongo/util/file_allocator.cpp
index e59bce6934b..2e7091fc6fa 100644
--- a/src/mongo/util/file_allocator.cpp
+++ b/src/mongo/util/file_allocator.cpp
@@ -37,6 +37,7 @@
#endif
#include "mongo/platform/posix_fadvise.h"
+#include "mongo/util/concurrency/thread_name.h"
#include "mongo/util/mongoutils/str.h"
#include "mongo/util/paths.h"
#include "mongo/util/time_support.h"
diff --git a/src/mongo/util/goodies.h b/src/mongo/util/goodies.h
index 8b1c6c1dfe7..de449b2ccba 100644
--- a/src/mongo/util/goodies.h
+++ b/src/mongo/util/goodies.h
@@ -29,9 +29,6 @@ namespace mongo {
/* @return a dump of the buffer as hex byte ascii output */
string hexdump(const char *data, unsigned len);
- void setThreadName(const char * name);
- string getThreadName();
-
template<class T>
inline string ToString(const T& t) {
stringstream s;
diff --git a/src/mongo/util/log.cpp b/src/mongo/util/log.cpp
index 9ed7c224f6e..34421f3aecb 100644
--- a/src/mongo/util/log.cpp
+++ b/src/mongo/util/log.cpp
@@ -1,6 +1,3 @@
-/** @file log.cpp
- */
-
/* Copyright 2009 10gen Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,37 +13,32 @@
* limitations under the License.
*/
-#include "mongo/pch.h"
+#include "mongo/platform/basic.h"
-#include "mongo/platform/posix_fadvise.h"
+#include "mongo/util/log.h"
+
+#include "mongo/logger/ramlog.h"
+#include "mongo/logger/rotatable_file_manager.h"
#include "mongo/util/assert_util.h"
#include "mongo/util/concurrency/threadlocal.h"
+#include "mongo/util/concurrency/thread_name.h"
#include "mongo/util/stacktrace.h"
+#include "mongo/util/text.h"
#include "mongo/util/time_support.h"
using namespace std;
-#ifdef _WIN32
-# include <io.h>
-# include <fcntl.h>
-# include "mongo/util/text.h"
-#else
-# include <cxxabi.h>
-# include <sys/file.h>
-#endif
-
-#ifdef _WIN32
-# define dup2 _dup2 // Microsoft headers use ISO C names
-# define fileno _fileno
-#endif
-
-#include <boost/filesystem/operations.hpp>
+// TODO: Win32 unicode console writing (in logger/console_appender?).
+// TODO: Extra log context appending, and re-enable log_user_*.js
+// TODO: Eliminate cout/cerr.
+// TODO: LogIndent (for mongodump).
+// TODO: Eliminate rawOut.
namespace mongo {
- static Logstream::ExtraLogContextFn _appendExtraLogContext;
+ static logger::ExtraLogContextFn _appendExtraLogContext;
- Status Logstream::registerExtraLogContextFn(ExtraLogContextFn contextFn) {
+ Status logger::registerExtraLogContextFn(logger::ExtraLogContextFn contextFn) {
if (!contextFn)
return Status(ErrorCodes::BadValue, "Cannot register a NULL log context function.");
if (_appendExtraLogContext) {
@@ -57,183 +49,19 @@ namespace mongo {
return Status::OK();
}
- int logLevel = 0;
int tlogLevel = 0; // test log level. so we avoid overchattiness (somewhat) in the c++ unit tests
- mongo::mutex Logstream::mutex("Logstream");
- int Logstream::doneSetup = Logstream::magicNumber();
const char *default_getcurns() { return ""; }
const char * (*getcurns)() = default_getcurns;
- Nullstream nullstream;
- vector<Tee*>* Logstream::globalTees = 0;
-
- TSP_DECLARE(Logstream, Logstream_tsp);
- TSP_DEFINE(Logstream, Logstream_tsp);
-
- Nullstream& tlog( int level ) {
- if ( !debug && level > tlogLevel )
- return nullstream;
- if ( level > logLevel )
- return nullstream;
- return Logstream::get().prolog();
- }
-
- class LoggingManager {
- public:
- LoggingManager()
- : _enabled(0) , _file(0) {
- }
-
- bool start( const string& lp , bool append ) {
- uassert( 10268 , "LoggingManager already started" , ! _enabled );
- _append = append;
-
- bool exists = boost::filesystem::exists(lp);
- bool isdir = boost::filesystem::is_directory(lp);
- bool isreg = boost::filesystem::is_regular(lp);
-
- if ( exists ) {
- if ( isdir ) {
- cout << "logpath [" << lp << "] should be a filename, not a directory" << endl;
- return false;
- }
-
- if ( ! append ) {
- // only attempt rename if log is regular file
- if ( isreg ) {
- stringstream ss;
- ss << lp << "." << terseCurrentTime( false );
- string s = ss.str();
-
- if ( ! rename( lp.c_str() , s.c_str() ) ) {
- cout << "log file [" << lp
- << "] exists; copied to temporary file [" << s << "]" << endl;
- } else {
- cout << "log file [" << lp
- << "] exists and couldn't make backup [" << s
- << "]; run with --logappend or manually remove file: "
- << errnoWithDescription() << endl;
- return false;
- }
- }
- }
- }
- // test path
- FILE * test = fopen( lp.c_str() , _append ? "a" : "w" );
- if ( ! test ) {
- cout << "can't open [" << lp << "] for log file: " << errnoWithDescription() << endl;
- return false;
- }
-
- if (append && exists){
- // two blank lines before and after
- const string msg = "\n\n***** SERVER RESTARTED *****\n\n\n";
- massert(14036, errnoWithPrefix("couldn't write to log file"),
- fwrite(msg.data(), 1, msg.size(), test) == msg.size());
- }
-
- fclose( test );
-
- _path = lp;
- _enabled = 1;
- return rotate();
- }
-
- bool rotate() {
- if ( ! _enabled ) {
- cout << "logRotate is not possible: loggingManager not enabled" << endl;
- return true;
- }
-
- if ( _file ) {
-
-#ifdef POSIX_FADV_DONTNEED
- posix_fadvise(fileno(_file), 0, 0, POSIX_FADV_DONTNEED);
-#endif
-
- // Rename the (open) existing log file to a timestamped name
- stringstream ss;
- ss << _path << "." << terseCurrentTime( false );
- string s = ss.str();
- if (0 != rename(_path.c_str(), s.c_str())) {
- error() << "failed to rename '" << _path
- << "' to '" << s
- << "': " << errnoWithDescription() << endl;
- return false;
- }
- }
-
- FILE* tmp = 0; // The new file using the original logpath name
-
-#if _WIN32
- // We rename an open log file (above, on next rotation) and the trick to getting Windows to do that is
- // to open the file with FILE_SHARE_DELETE. So, we can't use the freopen() call that non-Windows
- // versions use because it would open the file without the FILE_SHARE_DELETE flag we need.
- //
- HANDLE newFileHandle = CreateFileA(
- _path.c_str(),
- GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- NULL,
- OPEN_ALWAYS,
- FILE_ATTRIBUTE_NORMAL,
- NULL
- );
- if ( INVALID_HANDLE_VALUE != newFileHandle ) {
- int newFileDescriptor = _open_osfhandle( reinterpret_cast<intptr_t>(newFileHandle), _O_APPEND );
- tmp = _fdopen( newFileDescriptor, _append ? "a" : "w" );
- }
-#else
- tmp = freopen(_path.c_str(), _append ? "a" : "w", stdout);
-#endif
- if ( !tmp ) {
- error() << "can't open: " << _path.c_str() << " for log file" << endl;
- return false;
- }
-
- // redirect stdout and stderr to log file
- dup2( fileno( tmp ), 1 ); // stdout
- dup2( fileno( tmp ), 2 ); // stderr
-
- Logstream::setLogFile(tmp); // after this point no thread will be using old file
-
-#if _WIN32
- if ( _file )
- fclose( _file ); // In Windows, we still have the old file open, close it now
-#endif
-
-#if 0 // enable to test redirection
- cout << "written to cout" << endl;
- cerr << "written to cerr" << endl;
- log() << "written to log()" << endl;
-#endif
-
- _file = tmp; // Save new file for next rotation
- return true;
- }
-
- private:
- bool _enabled;
- string _path;
- bool _append;
- FILE * _file;
-
- } loggingManager;
-
- bool initLogging( const string& lp , bool append ) {
- cout << "all output going to: " << lp << endl;
- return loggingManager.start( lp , append );
- }
-
bool rotateLogs() {
- return loggingManager.rotate();
+ using logger::RotatableFileManager;
+ RotatableFileManager* manager = logger::globalRotatableFileManager();
+ RotatableFileManager::FileNameStatusPairVector result(
+ manager->rotateAll("." + terseCurrentTime(false)));
+ return result.empty();
}
- // done *before* static initialization
- FILE* Logstream::logfile = stdout;
- bool Logstream::isSyslog = false;
-
string errnoWithDescription(int x) {
#if defined(_WIN32)
if( x < 0 )
@@ -282,178 +110,34 @@ namespace mongo {
return s.str();
}
- void Logstream::logLockless( const StringData& s ) {
-
- if ( s.size() == 0 )
- return;
-
- if ( doneSetup == 1717 ) {
-
-#if defined(_WIN32)
- int fd = fileno( logfile );
- if ( _isatty( fd ) ) {
- fflush( logfile );
- writeUtf8ToWindowsConsole( s.rawData(), s.size() );
- return;
- }
+ /*
+ * NOTE(schwerin): Called from signal handlers; should not be taking locks or allocating
+ * memory.
+ */
+ void rawOut(const StringData &s) {
+ for (size_t i = 0; i < s.size(); ++i) {
+#ifdef _WIN32
+ putc(s[i], stdout);
#else
- if ( isSyslog ) {
- syslog( LOG_INFO , "%s" , s.rawData() );
- return;
- }
+ putc_unlocked(s[i], stdout);
#endif
-
- if (fwrite(s.rawData(), s.size(), 1, logfile)) {
- fflush(logfile);
- }
- else {
- int x = errno;
- cout << "Failed to write to logfile: " << errnoWithDescription(x) << endl;
- }
- }
- else {
- cout << s;
- cout.flush();
}
}
- void Logstream::flush(Tee *t) {
- const size_t MAX_LOG_LINE = 1024 * 10;
-
- // this ensures things are sane
- if ( doneSetup == 1717 ) {
- string msg = ss.str();
-
- string threadName = getThreadName();
- const char * type = logLevelToString(logLevel);
-
- size_t msgLen = msg.size();
- if ( msgLen > MAX_LOG_LINE )
- msgLen = MAX_LOG_LINE;
-
- const int spaceNeeded = (int)( msgLen + 300 /* for extra info */ + threadName.size());
-
- BufBuilder b(spaceNeeded);
- char* dateStr = b.grow(24);
- curTimeString(dateStr);
- dateStr[23] = ' '; // change null char to space
-
- if (!threadName.empty()) {
- b.appendChar( '[' );
- b.appendStr( threadName , false );
- b.appendChar( ']' );
- b.appendChar( ' ' );
- }
-
- for ( int i=0; i<indent; i++ )
- b.appendChar( '\t' );
-
- if ( type[0] ) {
- b.appendStr( type , false );
- b.appendStr( ": " , false );
- }
-
- if (_appendExtraLogContext)
- _appendExtraLogContext(b);
-
- if ( msg.size() > MAX_LOG_LINE ) {
- stringstream sss;
- sss << "warning: log line attempted (" << msg.size() / 1024 << "k) over max size(" << MAX_LOG_LINE / 1024 << "k)";
- sss << ", printing beginning and end ... ";
- b.appendStr( sss.str(), false );
- const char * xx = msg.c_str();
- b.appendBuf( xx , MAX_LOG_LINE / 3 );
- b.appendStr( " .......... ", false );
- b.appendStr( xx + msg.size() - ( MAX_LOG_LINE / 3 ) );
- }
- else {
- b.appendStr( msg );
- }
-
- string out( b.buf() , b.len() - 1);
-
- scoped_lock lk(mutex);
-
- if( t ) t->write(logLevel,out);
- if ( globalTees ) {
- for ( unsigned i=0; i<globalTees->size(); i++ )
- (*globalTees)[i]->write(logLevel,out);
- }
-#if defined(_WIN32)
- int fd = fileno( logfile );
- if ( _isatty( fd ) ) {
- fflush( logfile );
- writeUtf8ToWindowsConsole( out.data(), out.size() );
- }
-#else
- if ( isSyslog ) {
- syslog( logLevelToSysLogLevel(logLevel) , "%s" , out.data() );
- }
-#endif
- else if ( fwrite( out.data(), out.size(), 1, logfile ) ) {
- fflush(logfile);
- }
- else {
- int x = errno;
- cout << "Failed to write to logfile: " << errnoWithDescription(x) << ": " << out << endl;
- }
-#ifdef POSIX_FADV_DONTNEED
- // This only applies to pages that have already been flushed
- RARELY posix_fadvise(fileno(logfile), 0, 0, POSIX_FADV_DONTNEED);
-#endif
- }
- _init();
- }
-
- void Logstream::removeGlobalTee( Tee * tee ) {
- if ( !globalTees ) {
- return;
- }
- for( std::vector<Tee*>::iterator i = globalTees->begin(); i != globalTees->end(); ++i ) {
- if ( *i == tee ) {
- globalTees->erase( i );
- return;
- }
+ void logContext(const char *errmsg) {
+ if ( errmsg ) {
+ problem() << errmsg << endl;
}
+ printStackTrace(problem().stream());
}
- void Logstream::setLogFile(FILE* f) {
- scoped_lock lk(mutex);
- logfile = f;
+ LogIndentLevel::LogIndentLevel() {
}
-
- Logstream& Logstream::get() {
- if ( StaticObserver::_destroyingStatics ) {
- cout << "Logstream::get called in uninitialized state" << endl;
- }
- Logstream *p = Logstream_tsp.get();
- if( p == 0 )
- Logstream_tsp.reset( p = new Logstream() );
- return *p;
- }
-
- /* note: can't use malloc herein - may be in signal handler.
- logLockless() likely does not comply and should still be fixed todo
- likewise class string?
- */
- void rawOut( const string &s ) {
- if( s.empty() ) return;
- char buf[64];
- curTimeString(buf);
- buf[23] = ' ';
- buf[24] = 0;
-
- Logstream::logLockless(buf);
- Logstream::logLockless(s);
- Logstream::logLockless("\n");
+ LogIndentLevel::~LogIndentLevel() {
}
- void logContext(const char *errmsg) {
- if ( errmsg ) {
- problem() << errmsg << endl;
- }
- printStackTrace();
- }
+ Tee* const warnings = new RamLog("warnings"); // Things put here go in serverStatus
+ Tee* const startupWarningsLog = new RamLog("startupWarnings"); // intentionally leaked
-}
+} // namespace mongo
diff --git a/src/mongo/util/log.h b/src/mongo/util/log.h
index eb31d317e25..942e9cbffe0 100644
--- a/src/mongo/util/log.h
+++ b/src/mongo/util/log.h
@@ -17,461 +17,118 @@
#pragma once
-#include <string.h>
-#include <sstream>
-#include <errno.h>
-#include <vector>
-#include <boost/shared_ptr.hpp>
-#include <boost/scoped_ptr.hpp>
-#include <boost/thread/tss.hpp>
-
#include "mongo/base/status.h"
#include "mongo/bson/util/builder.h"
-#include "mongo/util/concurrency/mutex.h"
-#include "mongo/util/debug_util.h"
-#include "mongo/util/exit_code.h"
-
-#ifndef _WIN32
-#include <syslog.h>
-#endif
+#include "mongo/logger/logger.h"
+#include "mongo/logger/logstream_builder.h"
+#include "mongo/logger/tee.h"
+#include "mongo/util/concurrency/thread_name.h"
namespace mongo {
- enum ExitCode;
-
- // using negative numbers so these are always less than ::mongo::loglevel (see MONGO_LOG)
- enum LogLevel { LL_DEBUG=-1000 , LL_INFO , LL_NOTICE , LL_WARNING , LL_ERROR , LL_SEVERE };
-
- inline const char * logLevelToString( LogLevel l ) {
- switch ( l ) {
- case LL_DEBUG:
- case LL_INFO:
- case LL_NOTICE:
- return "";
- case LL_WARNING:
- return "warning" ;
- case LL_ERROR:
- return "ERROR";
- case LL_SEVERE:
- return "SEVERE";
- default:
- return "UNKNOWN";
- }
- }
-
-#ifndef _WIN32
- inline const int logLevelToSysLogLevel( LogLevel l) {
- switch ( l ) {
- case LL_DEBUG:
- return LOG_DEBUG;
- case LL_INFO:
- return LOG_INFO;
- case LL_NOTICE:
- return LOG_NOTICE;
- case LL_WARNING:
- return LOG_WARNING;
- case LL_ERROR:
- return LOG_ERR;
- case LL_SEVERE:
- return LOG_EMERG;
- default:
- return LL_INFO;
- }
- }
-#endif
-
- class LabeledLevel {
- public:
- LabeledLevel( int level ) : _level( level ) {}
- LabeledLevel( const char* label, int level ) : _label( label ), _level( level ) {}
- LabeledLevel( const string& label, int level ) : _label( label ), _level( level ) {}
-
- LabeledLevel operator+( int i ) const {
- return LabeledLevel( _label, _level + i );
- }
-
- LabeledLevel operator+( const char* label ) const {
- if( _label == "" )
- return LabeledLevel( label, _level );
- return LabeledLevel( _label + string("::") + label, _level );
- }
-
- LabeledLevel operator+( const std::string& label ) const {
- return LabeledLevel( _label + string("::") + label, _level );
- }
-
- LabeledLevel operator-( int i ) const {
- return LabeledLevel( _label, _level - i );
- }
-
- const string& getLabel() const { return _label; }
- int getLevel() const { return _level; }
-
- private:
- string _label;
- int _level;
- };
-
- inline bool operator<( const LabeledLevel& ll, const int i ) { return ll.getLevel() < i; }
- inline bool operator<( const int i, const LabeledLevel& ll ) { return i < ll.getLevel(); }
- inline bool operator>( const LabeledLevel& ll, const int i ) { return ll.getLevel() > i; }
- inline bool operator>( const int i, const LabeledLevel& ll ) { return i > ll.getLevel(); }
- inline bool operator<=( const LabeledLevel& ll, const int i ) { return ll.getLevel() <= i; }
- inline bool operator<=( const int i, const LabeledLevel& ll ) { return i <= ll.getLevel(); }
- inline bool operator>=( const LabeledLevel& ll, const int i ) { return ll.getLevel() >= i; }
- inline bool operator>=( const int i, const LabeledLevel& ll ) { return i >= ll.getLevel(); }
- inline bool operator==( const LabeledLevel& ll, const int i ) { return ll.getLevel() == i; }
- inline bool operator==( const int i, const LabeledLevel& ll ) { return i == ll.getLevel(); }
-
- class LazyString {
- public:
- virtual ~LazyString() {}
- virtual string val() const = 0;
- };
-
- // Utility class for stringifying object only when val() called.
- template< class T >
- class LazyStringImpl : public LazyString {
- public:
- LazyStringImpl( const T &t ) : t_( t ) {}
- virtual string val() const { return t_.toString(); }
- private:
- const T& t_;
- };
-
- class Tee {
- public:
- virtual ~Tee() {}
- virtual void write(LogLevel level , const string& str) = 0;
- };
-
- class Nullstream {
- public:
- virtual Nullstream& operator<< (Tee* tee) {
- return *this;
- }
- virtual ~Nullstream() {}
- virtual Nullstream& operator<<(const char *) {
- return *this;
- }
- virtual Nullstream& operator<<(const string& ) {
- return *this;
- }
- virtual Nullstream& operator<<(const StringData& ) {
- return *this;
- }
- virtual Nullstream& operator<<(char *) {
- return *this;
- }
- virtual Nullstream& operator<<(char) {
- return *this;
- }
- virtual Nullstream& operator<<(int) {
- return *this;
- }
- virtual Nullstream& operator<<(ExitCode) {
- return *this;
- }
- virtual Nullstream& operator<<(unsigned long) {
- return *this;
- }
- virtual Nullstream& operator<<(long) {
- return *this;
- }
- virtual Nullstream& operator<<(unsigned) {
- return *this;
- }
- virtual Nullstream& operator<<(unsigned short) {
- return *this;
- }
- virtual Nullstream& operator<<(double) {
- return *this;
- }
- virtual Nullstream& operator<<(void *) {
- return *this;
- }
- virtual Nullstream& operator<<(const void *) {
- return *this;
- }
- virtual Nullstream& operator<<(long long) {
- return *this;
- }
- virtual Nullstream& operator<<(unsigned long long) {
- return *this;
- }
- virtual Nullstream& operator<<(bool) {
- return *this;
- }
- virtual Nullstream& operator<<(const LazyString&) {
- return *this;
- }
- template< class T >
- Nullstream& operator<<(T *t) {
- return operator<<( static_cast<void*>( t ) );
- }
- template< class T >
- Nullstream& operator<<(const T *t) {
- return operator<<( static_cast<const void*>( t ) );
- }
- template< class T >
- Nullstream& operator<<(const boost::shared_ptr<T> &p ) {
- T * t = p.get();
- if ( ! t )
- *this << "null";
- else
- *this << *t;
- return *this;
- }
- template< class T >
- Nullstream& operator<<(const T &t) {
- return operator<<( static_cast<const LazyString&>( LazyStringImpl< T >( t ) ) );
- }
-
- virtual Nullstream& operator<< (std::ostream& ( *endl )(std::ostream&)) {
- return *this;
- }
- virtual Nullstream& operator<< (std::ios_base& (*hex)(std::ios_base&)) {
- return *this;
- }
-
- virtual void flush(Tee *t = 0) {}
- };
- extern Nullstream nullstream;
-
- class Logstream : public Nullstream {
- static mongo::mutex mutex;
- static int doneSetup;
- std::stringstream ss;
- int indent;
- LogLevel logLevel;
- static FILE* logfile;
- static boost::scoped_ptr<std::ostream> stream;
- static std::vector<Tee*> * globalTees;
- static bool isSyslog;
- public:
- // Type for optional function for inserting context information in log messages. See
- // registerExtraLogContextFn, below.
- typedef void (*ExtraLogContextFn)(BufBuilder& builder);
-
- static void logLockless( const StringData& s );
-
- static void setLogFile(FILE* f);
-#ifndef _WIN32
- static void useSyslog(const char * name) {
- std::cout << "using syslog ident: " << name << std::endl;
-
- // openlog requires heap allocated non changing pointer
- // this should only be called once per pragram execution
-
- char * newName = (char *) malloc( strlen(name) + 1 );
- strcpy( newName , name);
- openlog( newName , LOG_PID | LOG_CONS | LOG_ODELAY , LOG_USER );
- isSyslog = true;
- }
-#endif
-
- static int magicNumber() { return 1717; }
-
- static int getLogDesc() {
- int fd = -1;
- if (logfile != NULL)
-#if defined(_WIN32)
- // the ISO C++ conformant name is _fileno
- fd = _fileno( logfile );
-#else
- fd = fileno( logfile );
-#endif
- return fd;
- }
-
- void flush(Tee *t = 0);
-
- inline Nullstream& setLogLevel(LogLevel l) {
- logLevel = l;
- return *this;
- }
+namespace logger {
+ typedef void (*ExtraLogContextFn)(BufBuilder& builder);
+ Status registerExtraLogContextFn(ExtraLogContextFn contextFn);
- /** note these are virtual */
- Logstream& operator<<(const char *x) { ss << x; return *this; }
- Logstream& operator<<(const string& x) { ss << x; return *this; }
- Logstream& operator<<(const StringData& x) { ss << x; return *this; }
- Logstream& operator<<(char *x) { ss << x; return *this; }
- Logstream& operator<<(char x) { ss << x; return *this; }
- Logstream& operator<<(int x) { ss << x; return *this; }
- Logstream& operator<<(ExitCode x) { ss << x; return *this; }
- Logstream& operator<<(long x) { ss << x; return *this; }
- Logstream& operator<<(unsigned long x) { ss << x; return *this; }
- Logstream& operator<<(unsigned x) { ss << x; return *this; }
- Logstream& operator<<(unsigned short x){ ss << x; return *this; }
- Logstream& operator<<(double x) { ss << x; return *this; }
- Logstream& operator<<(void *x) { ss << x; return *this; }
- Logstream& operator<<(const void *x) { ss << x; return *this; }
- Logstream& operator<<(long long x) { ss << x; return *this; }
- Logstream& operator<<(unsigned long long x) { ss << x; return *this; }
- Logstream& operator<<(bool x) { ss << x; return *this; }
+} // namespace logger
- Logstream& operator<<(const LazyString& x) {
- ss << x.val();
- return *this;
- }
- Nullstream& operator<< (Tee* tee) {
- ss << '\n';
- flush(tee);
- return *this;
- }
- Logstream& operator<< (std::ostream& ( *_endl )(std::ostream&)) {
- ss << '\n';
- flush(0);
- return *this;
- }
- Logstream& operator<< (std::ios_base& (*_hex)(std::ios_base&)) {
- ss << _hex;
- return *this;
- }
+ using logger::LogstreamBuilder;
+ using logger::LabeledLevel;
+ using logger::Tee;
- Logstream& prolog() {
- return *this;
- }
-
- void addGlobalTee( Tee * t ) {
- if ( ! globalTees )
- globalTees = new std::vector<Tee*>();
- globalTees->push_back( t );
- }
-
- void removeGlobalTee( Tee * tee );
-
- void indentInc(){ indent++; }
- void indentDec(){ indent--; }
- int getIndent() const { return indent; }
-
- // Replace any pre-existing function for appending context information to log lines with
- // "contextFn". Returns Status::OK on first call, and ErrorCodes::AlreadyInitialized if
- // called more than once. Returns ErrorCodes::BadValue if contextFn is NULL.
- static Status registerExtraLogContextFn(ExtraLogContextFn contextFn);
-
- private:
- Logstream() {
- indent = 0;
- _init();
- }
- void _init() {
- ss.str("");
- logLevel = LL_INFO;
- }
-
- public:
- static Logstream& get();
- };
-
- extern int logLevel;
- extern int tlogLevel;
-
- inline Nullstream& out( int level = 0 ) {
- if ( level > logLevel )
- return nullstream;
- return Logstream::get();
+ /**
+ * Returns a LogstreamBuilder for logging a message with LogSeverity::Severe().
+ */
+ inline LogstreamBuilder severe() {
+ return LogstreamBuilder(logger::globalLogDomain(),
+ getThreadName(),
+ logger::LogSeverity::Severe());
}
- /* flush the log stream if the log level is
- at the specified level or higher. */
- inline void logflush(int level = 0) {
- if( level > logLevel )
- Logstream::get().flush(0);
+ /**
+ * Returns a LogstreamBuilder for logging a message with LogSeverity::Error().
+ */
+ inline LogstreamBuilder error() {
+ return LogstreamBuilder(logger::globalLogDomain(),
+ getThreadName(),
+ logger::LogSeverity::Error());
}
- /* without prolog */
- inline Nullstream& _log( int level = 0 ) {
- if ( level > logLevel )
- return nullstream;
- return Logstream::get();
+ /**
+ * Returns a LogstreamBuilder for logging a message with LogSeverity::Warning().
+ */
+ inline LogstreamBuilder warning() {
+ return LogstreamBuilder(logger::globalLogDomain(),
+ getThreadName(),
+ logger::LogSeverity::Warning());
}
- /** logging which we may not want during unit tests (dbtests) runs.
- set tlogLevel to -1 to suppress tlog() output in a test program. */
- Nullstream& tlog( int level = 0 );
-
- // log if debug build or if at a certain level
- inline Nullstream& dlog( int level ) {
- if ( level <= logLevel || DEBUG_BUILD )
- return Logstream::get().prolog();
- return nullstream;
+ /**
+ * Returns a LogstreamBuilder for logging a message with LogSeverity::Log().
+ */
+ inline LogstreamBuilder log() {
+ return LogstreamBuilder(logger::globalLogDomain(),
+ getThreadName(),
+ logger::LogSeverity::Log());
}
-#define MONGO_LOG(level) \
- ( MONGO_likely( ::mongo::logLevel < (level) ) ) \
- ? ::mongo::nullstream : ::mongo::logWithLevel(level)
-#define LOG MONGO_LOG
- inline Nullstream& log() {
- return Logstream::get().prolog();
- }
+ /**
+ * Synonym for log().
+ */
+ inline LogstreamBuilder out() { return log(); }
- // Use MONGO_LOG() instead of this
- inline Nullstream& logWithLevel( int level ) {
- if ( level > logLevel )
- return nullstream;
- return Logstream::get().prolog();
- }
+ /**
+ * For logging which we may not want during unit tests (dbtests) runs. Set tlogLevel to -1 to
+ * suppress MONGO_TLOG() output in a test program.
+ */
+ extern int tlogLevel;
- inline Nullstream& logWithLevel( LogLevel l ) {
- return Logstream::get().prolog().setLogLevel( l );
- }
+#define MONGO_LOG(DLEVEL) \
+ if (!(::mongo::logger::globalLogDomain())->shouldLog(::mongo::LogstreamBuilder::severityCast(DLEVEL))) {} \
+ else LogstreamBuilder(::mongo::logger::globalLogDomain(), getThreadName(), ::mongo::LogstreamBuilder::severityCast(DLEVEL))
- inline Nullstream& logWithLevel( const LabeledLevel& ll ) {
- Nullstream& stream = logWithLevel( ll.getLevel() );
- if( ll.getLabel() != "" )
- stream << "[" << ll.getLabel() << "] ";
- return stream;
- }
+#define LOG MONGO_LOG
- inline Nullstream& error() {
- return logWithLevel( LL_ERROR );
- }
+#define MONGO_DLOG(DLEVEL) \
+ if (!(DEBUG_BUILD) && !::mongo::logger::globalLogDomain()->shouldLog(::mongo::LogstreamBuilder::severityCast(DLEVEL))) {} \
+ else LogstreamBuilder(::mongo::logger::globalLogDomain(), getThreadName(), ::mongo::LogstreamBuilder::severityCast(DLEVEL))
- inline Nullstream& warning() {
- return logWithLevel( LL_WARNING );
- }
+#define MONGO_TLOG(DLEVEL) \
+ if ((!::mongo::debug && ((DLEVEL) > tlogLevel)) || !::mongo::logger::globalLogDomain()->shouldLog(::mongo::LogstreamBuilder::severityCast(DLEVEL))) {} \
+ else LogstreamBuilder(::mongo::logger::globalLogDomain(), getThreadName(), ::mongo::LogstreamBuilder::severityCast(DLEVEL))
/* default impl returns "" -- mongod overrides */
extern const char * (*getcurns)();
- inline Nullstream& problem( int level = 0 ) {
- if ( level > logLevel )
- return nullstream;
- Logstream& l = Logstream::get().prolog();
- l << ' ' << getcurns() << ' ';
- return l;
+ inline LogstreamBuilder problem() {
+ std::string curns = getcurns();
+ curns.push_back(' ');
+ return log().setBaseMessage(curns);
}
/**
- log to a file rather than stdout
- defined in assert_util.cpp
+ * Rotates the log files. Returns true if all logs rotate successfully.
*/
- bool initLogging( const string& logpath , bool append );
bool rotateLogs();
- std::string toUtf8String(const std::wstring& wide);
-
/** output the error # and error message with prefix.
handy for use as parm in uassert/massert.
*/
string errnoWithPrefix( const char * prefix );
+ // Guard that alters the indentation level used by log messages on the current thread.
+ // Used only by mongodump (mongo/tools/dump.cpp). Do not introduce new uses.
struct LogIndentLevel {
- LogIndentLevel(){
- Logstream::get().indentInc();
- }
- ~LogIndentLevel(){
- Logstream::get().indentDec();
- }
+ LogIndentLevel();
+ ~LogIndentLevel();
};
extern Tee* const warnings; // Things put here go in serverStatus
extern Tee* const startupWarningsLog; // Things put here get reported in MMS
string errnoWithDescription(int errorcode = -1);
- void rawOut( const string &s );
+ void rawOut( const StringData &s );
/**
* Write the current context (backtrace), along with the optional "msg".
diff --git a/src/mongo/util/net/message_port.cpp b/src/mongo/util/net/message_port.cpp
index 42f8b9dbd92..fa87dccb0e7 100644
--- a/src/mongo/util/net/message_port.cpp
+++ b/src/mongo/util/net/message_port.cpp
@@ -205,7 +205,10 @@ again:
}
catch ( const SocketException & e ) {
- LOG(psock->getLogLevel() + (e.shouldPrint() ? 0 : 1) ) << "SocketException: remote: " << remote() << " error: " << e << endl;
+ logger::LogSeverity severity = psock->getLogLevel();
+ if (!e.shouldPrint())
+ severity = severity.lessSevere();
+ LOG(severity) << "SocketException: remote: " << remote() << " error: " << e << endl;
m.reset();
return false;
}
diff --git a/src/mongo/util/net/message_server_port.cpp b/src/mongo/util/net/message_server_port.cpp
index a972fa495be..eeec3cc3263 100644
--- a/src/mongo/util/net/message_server_port.cpp
+++ b/src/mongo/util/net/message_server_port.cpp
@@ -26,6 +26,7 @@
#include "mongo/db/lasterror.h"
#include "mongo/db/stats/counters.h"
#include "mongo/util/concurrency/ticketholder.h"
+#include "mongo/util/concurrency/thread_name.h"
#include "mongo/util/net/listen.h"
#include "mongo/util/net/message.h"
#include "mongo/util/net/message_port.h"
@@ -174,7 +175,7 @@ namespace mongo {
}
verify( inPort );
- inPort->psock->setLogLevel(1);
+ inPort->psock->setLogLevel(logger::LogSeverity::Debug(1));
scoped_ptr<MessagingPort> p( inPort );
string otherSide;
diff --git a/src/mongo/util/net/sock.cpp b/src/mongo/util/net/sock.cpp
index 1206e29f347..ab9a56703a6 100644
--- a/src/mongo/util/net/sock.cpp
+++ b/src/mongo/util/net/sock.cpp
@@ -56,7 +56,7 @@ namespace mongo {
struct timeval tv;
tv.tv_sec = (int)secs;
tv.tv_usec = (int)((long long)(secs*1000*1000) % (1000*1000));
- bool report = logLevel > 3; // solaris doesn't provide these
+ bool report = logger::globalLogDomain()->shouldLog(logger::LogSeverity::Debug(4));
DEV report = true;
#if defined(_WIN32)
tv.tv_sec *= 1000; // Windows timeout is a DWORD, in milliseconds.
@@ -194,7 +194,7 @@ namespace mongo {
if( target != "0.0.0.0" ) { // don't log if this as it is a
// CRT construction and log() may not work yet.
log() << "getaddrinfo(\"" << target << "\") failed: " <<
- gai_strerror(ret) << endl;
+ getAddrInfoStrError(ret) << endl;
}
*this = SockAddr(port);
}
@@ -392,13 +392,11 @@ namespace mongo {
// ------------ Socket -----------------
Socket::Socket(int fd , const SockAddr& remote) :
- _fd(fd), _remote(remote), _timeout(0), _lastValidityCheckAtSecs(time(0)) {
- _logLevel = 0;
+ _fd(fd), _remote(remote), _timeout(0), _lastValidityCheckAtSecs(time(0)), _logLevel(logger::LogSeverity::Log()) {
_init();
}
- Socket::Socket( double timeout, int ll ) {
- _logLevel = ll;
+ Socket::Socket( double timeout, logger::LogSeverity ll ) : _logLevel(ll) {
_fd = -1;
_timeout = timeout;
_lastValidityCheckAtSecs = time(0);
@@ -657,9 +655,10 @@ namespace mongo {
continue;
}
- if ( len <= 4 && ret != len )
+ if ( len <= 4 && ret != len ) {
LOG(_logLevel) << "Socket recv() got " << ret <<
" bytes wanted len=" << len << endl;
+ }
fassert(16508, ret <= len);
len -= ret;
buf += ret;
diff --git a/src/mongo/util/net/sock.h b/src/mongo/util/net/sock.h
index 6b59e03dc0f..b661c76ed0b 100644
--- a/src/mongo/util/net/sock.h
+++ b/src/mongo/util/net/sock.h
@@ -39,6 +39,7 @@
#include <openssl/ssl.h>
#endif
+#include "mongo/logger/log_severity.h"
#include "mongo/platform/compiler.h"
namespace mongo {
@@ -188,7 +189,7 @@ namespace mongo {
Generally you don't want a timeout, you should be very prepared for errors if you set one.
*/
- Socket(double so_timeout = 0, int logLevel = 0 );
+ Socket(double so_timeout = 0, logger::LogSeverity logLevel = logger::LogSeverity::Log() );
~Socket();
@@ -202,8 +203,8 @@ namespace mongo {
void recv( char * data , int len );
int unsafe_recv( char *buf, int max );
- int getLogLevel() const { return _logLevel; }
- void setLogLevel( int ll ) { _logLevel = ll; }
+ logger::LogSeverity getLogLevel() const { return _logLevel; }
+ void setLogLevel( logger::LogSeverity ll ) { _logLevel = ll; }
SockAddr remoteAddr() const { return _remote; }
string remoteString() const { return _remote.toString(); }
@@ -267,7 +268,7 @@ namespace mongo {
SSL* _ssl;
SSLManagerInterface* _sslManager;
#endif
- int _logLevel; // passed to log() when logging errors
+ logger::LogSeverity _logLevel; // passed to log() when logging errors
};
diff --git a/src/mongo/util/progress_meter.cpp b/src/mongo/util/progress_meter.cpp
index 57ea9f728ec..360657f4a8e 100644
--- a/src/mongo/util/progress_meter.cpp
+++ b/src/mongo/util/progress_meter.cpp
@@ -53,13 +53,11 @@ namespace mongo {
if ( _total > 0 ) {
int per = (int)( ( (double)_done * 100.0 ) / (double)_total );
- Nullstream& out = log() << "\t\t" << _name << ": " << _done
- << '/' << _total << '\t' << per << '%';
-
+ LogstreamBuilder out = log();
+ out << "\t\t" << _name << ": " << _done << '/' << _total << '\t' << per << '%';
if ( ! _units.empty() ) {
out << "\t(" << _units << ")";
}
-
out << endl;
}
_lastTime = t;
diff --git a/src/mongo/util/ramlog.h b/src/mongo/util/ramlog.h
index afa5e0390c1..fde33bb9b08 100644
--- a/src/mongo/util/ramlog.h
+++ b/src/mongo/util/ramlog.h
@@ -1,5 +1,3 @@
-// ramlog.h
-
/* Copyright 2009 10gen Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,52 +15,4 @@
#pragma once
-#include "mongo/util/concurrency/mutex.h"
-#include "mongo/util/log.h"
-
-namespace mongo {
-
- class RamLog : public Tee {
- public:
- RamLog( const std::string& name );
-
- virtual void write(LogLevel ll, const string& str);
-
- void get( vector<const char*>& v) const;
-
- void toHTML(stringstream& s);
-
- static RamLog* get( const std::string& name );
- static void getNames( vector<string>& names );
-
- time_t lastWrite() { return _lastWrite; } // 0 if no writes
- long long getTotalLinesWritten() const { return _totalLinesWritten; }
-
- protected:
- static int repeats(const vector<const char *>& v, int i);
- static string clean(const vector<const char *>& v, int i, string line="");
- static string color(const std::string& line);
-
- /* turn http:... into an anchor */
- static string linkify(const char *s);
-
- private:
- ~RamLog(); // want this private as we want to leak so we can use them till the very end
-
- enum {
- N = 1024, // number of lines
- C = 512 // max size of line
- };
- char lines[N][C];
- unsigned h; // current position
- unsigned n; // number of lines stores 0 o N
- string _name;
- long long _totalLinesWritten;
-
- typedef map<string,RamLog*> RM;
- static mongo::mutex* _namedLock;
- static RM* _named;
- time_t _lastWrite;
- };
-
-}
+#include "mongo/logger/ramlog.h"
diff --git a/src/mongo/util/signal_handlers.cpp b/src/mongo/util/signal_handlers.cpp
index 241d824b1a0..019fdb18935 100644
--- a/src/mongo/util/signal_handlers.cpp
+++ b/src/mongo/util/signal_handlers.cpp
@@ -104,14 +104,12 @@ namespace mongo {
}
void printStackAndExit( int signalNum ) {
- int fd = Logstream::getLogDesc();
+ const int fd = 0;
- if ( fd >= 0 ) {
- formattedWrite( fd , "Received signal %d\n" , signalNum );
- formattedWrite( fd , "Backtrace: " );
- formattedBacktrace( fd );
- formattedWrite( fd , "===\n" );
- }
+ formattedWrite( fd , "Received signal %d\n" , signalNum );
+ formattedWrite( fd , "Backtrace: " );
+ formattedBacktrace( fd );
+ formattedWrite( fd , "===\n" );
::_exit( EXIT_ABRUPT );
}
diff --git a/src/mongo/util/stacktrace.cpp b/src/mongo/util/stacktrace.cpp
index c1348a00240..eee96e52174 100644
--- a/src/mongo/util/stacktrace.cpp
+++ b/src/mongo/util/stacktrace.cpp
@@ -13,6 +13,8 @@
* limitations under the License.
*/
+#include "mongo/platform/basic.h"
+
#include "mongo/util/stacktrace.h"
#include <cstdlib>
@@ -22,13 +24,13 @@
#include <vector>
#include "mongo/util/log.h"
+#include "mongo/util/concurrency/mutex.h"
#ifdef _WIN32
#include <boost/filesystem/operations.hpp>
#include <boost/smart_ptr/scoped_array.hpp>
#include <sstream>
#include <stdio.h>
-#include "mongo/platform/windows_basic.h"
#include <DbgHelp.h>
#include "mongo/util/assert_util.h"
#else
diff --git a/src/mongo/util/stacktrace.h b/src/mongo/util/stacktrace.h
index f1cd6279107..289ab230c5e 100644
--- a/src/mongo/util/stacktrace.h
+++ b/src/mongo/util/stacktrace.h
@@ -21,16 +21,16 @@
#include <iostream>
-#include "mongo/platform/basic.h"
+#include "mongo/util/log.h"
namespace mongo {
- // Print stack trace information to "os", default to std::cout.
- void printStackTrace(std::ostream &os=std::cout);
+ // Print stack trace information to "os", default to the log stream.
+ void printStackTrace(std::ostream &os=log().stream());
#if defined(_WIN32)
- // Print stack trace (using a specified stack context) to "os", default to std::cout.
- void printWindowsStackTrace(CONTEXT &context, std::ostream &os=std::cout);
+ // Print stack trace (using a specified stack context) to "os", default to the log stream.
+ void printWindowsStackTrace(CONTEXT &context, std::ostream &os=log().stream());
// Print error message from C runtime followed by stack trace
int crtDebugCallback(int, char* originalMessage, int*);
diff --git a/src/mongo/util/time_support.h b/src/mongo/util/time_support.h
index b5e077412e8..f448628f0f0 100644
--- a/src/mongo/util/time_support.h
+++ b/src/mongo/util/time_support.h
@@ -32,8 +32,8 @@ namespace mongo {
*
* Wed Oct 31 13:34:47.996
*
- * @param timeStr pointer to the buffer to set the string - should at least be
- * 24 bytes big.
+ * @param timeStr pointer to the buffer to set the string - empirically, 64 bytes is enough for
+ * the buffer, 26 is not.
*/
void curTimeString(char* timeStr);
diff --git a/src/mongo/util/util.cpp b/src/mongo/util/util.cpp
index fbeedcc379c..da29c1f320f 100644
--- a/src/mongo/util/util.cpp
+++ b/src/mongo/util/util.cpp
@@ -43,57 +43,6 @@ namespace mongo {
return s;
}
- boost::thread_specific_ptr<string> _threadName;
-
-#if defined(_WIN32)
-
-#define MS_VC_EXCEPTION 0x406D1388
-#pragma pack(push,8)
- typedef struct tagTHREADNAME_INFO {
- DWORD dwType; // Must be 0x1000.
- LPCSTR szName; // Pointer to name (in user addr space).
- DWORD dwThreadID; // Thread ID (-1=caller thread).
- DWORD dwFlags; // Reserved for future use, must be zero.
- } THREADNAME_INFO;
-#pragma pack(pop)
-
- void setWinThreadName(const char *name) {
- /* is the sleep here necessary???
- Sleep(10);
- */
- THREADNAME_INFO info;
- info.dwType = 0x1000;
- info.szName = name;
- info.dwThreadID = -1;
- info.dwFlags = 0;
- __try {
- RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info );
- }
- __except(EXCEPTION_EXECUTE_HANDLER) {
- }
- }
-#endif
-
- void setThreadName(const char *name) {
- if ( ! name )
- name = "NONE";
-
- _threadName.reset( new string(name) );
-
-#if defined( DEBUG ) && defined( _WIN32 )
- // naming might be expensive so don't do "conn*" over and over
- setWinThreadName(name);
-#endif
-
- }
-
- string getThreadName() {
- string * s = _threadName.get();
- if ( s )
- return *s;
- return "";
- }
-
bool isPrime(int n) {
int z = 2;
while ( 1 ) {
diff --git a/src/mongo/util/version.cpp b/src/mongo/util/version.cpp
index 4c62a41a468..12b8f0208de 100644
--- a/src/mongo/util/version.cpp
+++ b/src/mongo/util/version.cpp
@@ -166,9 +166,6 @@ namespace mongo {
result.appendNumber("maxBsonObjectSize", BSONObjMaxUserSize);
}
-
- Tee* const startupWarningsLog = new RamLog("startupWarnings"); //intentionally leaked
-
//
// system warnings
//