diff options
author | Shaun Verch <shaun.verch@10gen.com> | 2013-10-02 17:47:24 -0400 |
---|---|---|
committer | Shaun Verch <shaun.verch@10gen.com> | 2013-10-11 15:09:26 -0400 |
commit | 8af35e1ed355a413782a45d13ce50b582ab91355 (patch) | |
tree | bd8251362396ee3c6050cf967abecbd4886d9a5f | |
parent | 39c6861e3a012cd6cc2148cd961be9cb7502ac3e (diff) | |
download | mongo-8af35e1ed355a413782a45d13ce50b582ab91355.tar.gz |
SERVER-10885 Create new Console class to redirect tool logging to stderr instead of stdout
-rw-r--r-- | src/mongo/SConscript | 5 | ||||
-rw-r--r-- | src/mongo/logger/console_appender.h | 4 | ||||
-rw-r--r-- | src/mongo/tools/bsondump_options.cpp | 3 | ||||
-rw-r--r-- | src/mongo/tools/dump.cpp | 10 | ||||
-rw-r--r-- | src/mongo/tools/export.cpp | 16 | ||||
-rw-r--r-- | src/mongo/tools/mongodump_options.cpp | 6 | ||||
-rw-r--r-- | src/mongo/tools/mongoexport_options.cpp | 9 | ||||
-rw-r--r-- | src/mongo/tools/stat.cpp | 4 | ||||
-rw-r--r-- | src/mongo/tools/tool.cpp | 21 | ||||
-rw-r--r-- | src/mongo/tools/tool.h | 10 | ||||
-rw-r--r-- | src/mongo/tools/tool_logger.cpp | 81 | ||||
-rw-r--r-- | src/mongo/tools/tool_logger.h | 39 | ||||
-rw-r--r-- | src/mongo/tools/tool_options.h | 3 |
13 files changed, 161 insertions, 50 deletions
diff --git a/src/mongo/SConscript b/src/mongo/SConscript index e885b7d9f43..49b4d96fabe 100644 --- a/src/mongo/SConscript +++ b/src/mongo/SConscript @@ -806,7 +806,10 @@ mongod = env.Install( Default( mongod ) # tools -allToolFiles = [ "tools/tool.cpp", "tools/stat_util.cpp", "tools/tool_options.cpp" ] +allToolFiles = ["tools/tool.cpp", + "tools/stat_util.cpp", + "tools/tool_options.cpp", + "tools/tool_logger.cpp"] env.StaticLibrary("alltools", allToolFiles, LIBDEPS=["serveronly", diff --git a/src/mongo/logger/console_appender.h b/src/mongo/logger/console_appender.h index 214fc921148..901b98dde6f 100644 --- a/src/mongo/logger/console_appender.h +++ b/src/mongo/logger/console_appender.h @@ -30,7 +30,7 @@ namespace logger { /** * Appender for writing to the console (stdout). */ - template <typename Event> + template <typename Event, typename ConsoleType = Console> class ConsoleAppender : public Appender<Event> { MONGO_DISALLOW_COPYING(ConsoleAppender); @@ -39,7 +39,7 @@ namespace logger { explicit ConsoleAppender(EventEncoder* encoder) : _encoder(encoder) {} virtual Status append(const Event& event) { - Console console; + ConsoleType console; _encoder->encode(event, console.out()).flush(); if (!console.out()) return Status(ErrorCodes::LogWriteFailed, "Error writing log message to console."); diff --git a/src/mongo/tools/bsondump_options.cpp b/src/mongo/tools/bsondump_options.cpp index f75d0dd96e2..dbeadc1d524 100644 --- a/src/mongo/tools/bsondump_options.cpp +++ b/src/mongo/tools/bsondump_options.cpp @@ -90,6 +90,9 @@ namespace mongo { toolGlobalParams.db = ""; } + // bsondump always outputs data to stdout, so we can't send messages there + toolGlobalParams.canUseStdout = false; + return Status::OK(); } diff --git a/src/mongo/tools/dump.cpp b/src/mongo/tools/dump.cpp index a58640a57c1..9d163d311d0 100644 --- a/src/mongo/tools/dump.cpp +++ b/src/mongo/tools/dump.cpp @@ -41,15 +41,7 @@ class Dump : public Tool { FILE* _f; }; public: - Dump() : Tool(true/*usesstdout*/) { } - - virtual void preSetup() { - if (mongoDumpGlobalParams.outputFile == "-") { - // write output to standard error to avoid mangling output - // must happen early to avoid sending junk to stdout - useStandardOutput(false); - } - } + Dump() : Tool() { } virtual void printHelp(ostream& out) { printMongoDumpHelp(&out); diff --git a/src/mongo/tools/export.cpp b/src/mongo/tools/export.cpp index f135d9853f3..1b1c38c5a0e 100644 --- a/src/mongo/tools/export.cpp +++ b/src/mongo/tools/export.cpp @@ -25,24 +25,14 @@ #include "mongo/db/json.h" #include "mongo/tools/mongoexport_options.h" #include "mongo/tools/tool.h" +#include "mongo/tools/tool_logger.h" #include "mongo/util/options_parser/option_section.h" using namespace mongo; class Export : public Tool { public: - Export() : Tool(false/*usesstdout*/) { } - - virtual void preSetup() { - if (mongoExportGlobalParams.outputFileSpecified) { - if (mongoExportGlobalParams.outputFile != "-") { - // we write output to standard error by default to avoid - // mangling output, but we don't need to do this if an output - // file was specified - useStandardOutput(true); - } - } - } + Export() : Tool() { } virtual void printHelp( ostream & out ) { printMongoExportHelp(&out); @@ -226,7 +216,7 @@ public: out << ']' << endl; if (!toolGlobalParams.quiet) { - (_usesstdout ? cout : cerr ) << "exported " << num << " records" << endl; + toolOutput() << "exported " << num << " records" << endl; } return 0; diff --git a/src/mongo/tools/mongodump_options.cpp b/src/mongo/tools/mongodump_options.cpp index c132079acb9..99fb70b8e1c 100644 --- a/src/mongo/tools/mongodump_options.cpp +++ b/src/mongo/tools/mongodump_options.cpp @@ -130,6 +130,12 @@ namespace mongo { toolGlobalParams.db = ""; } + if (mongoDumpGlobalParams.outputFile == "-") { + // write output to standard error to avoid mangling output + // must happen early to avoid sending junk to stdout + toolGlobalParams.canUseStdout = false; + } + return Status::OK(); } diff --git a/src/mongo/tools/mongoexport_options.cpp b/src/mongo/tools/mongoexport_options.cpp index 375e2ff624b..b6148046d80 100644 --- a/src/mongo/tools/mongoexport_options.cpp +++ b/src/mongo/tools/mongoexport_options.cpp @@ -138,6 +138,15 @@ namespace mongo { mongoExportGlobalParams.limit = getParam("limit", 0); mongoExportGlobalParams.skip = getParam("skip", 0); + // we write output to standard error by default to avoid mangling output, but we don't need + // to do this if an output file was specified + toolGlobalParams.canUseStdout = false; + if (mongoExportGlobalParams.outputFileSpecified) { + if (mongoExportGlobalParams.outputFile != "-") { + toolGlobalParams.canUseStdout = true; + } + } + return Status::OK(); } diff --git a/src/mongo/tools/stat.cpp b/src/mongo/tools/stat.cpp index 15baf05b831..0c9cb612fa6 100644 --- a/src/mongo/tools/stat.cpp +++ b/src/mongo/tools/stat.cpp @@ -81,10 +81,6 @@ namespace mongo { return out.getOwned(); } - - virtual void preSetup() { - } - int run() { _statUtil.setAll(mongoStatGlobalParams.allFields); _statUtil.setSeconds(mongoStatGlobalParams.sleep); diff --git a/src/mongo/tools/tool.cpp b/src/mongo/tools/tool.cpp index 8d9a396a29f..af40129f9da 100644 --- a/src/mongo/tools/tool.cpp +++ b/src/mongo/tools/tool.cpp @@ -44,8 +44,8 @@ using namespace mongo; namespace mongo { - Tool::Tool(bool usesstdout) : - _usesstdout(usesstdout), _autoreconnect(false), _conn(0), _slaveConn(0) { } + Tool::Tool() : + _autoreconnect(false), _conn(0), _slaveConn(0) { } Tool::~Tool() { if ( _conn ) @@ -69,8 +69,6 @@ namespace mongo { } } - preSetup(); - if (!toolGlobalParams.useDirectClient) { if (toolGlobalParams.noconnection) { // do nothing @@ -94,9 +92,8 @@ namespace mongo { } if (!toolGlobalParams.quiet) { - (_usesstdout ? std::cout : std::cerr ) << "connected to: " - << toolGlobalParams.connectionString - << std::endl; + toolOutput() << "connected to: " << toolGlobalParams.connectionString + << std::endl; } } @@ -243,7 +240,7 @@ namespace mongo { toolGlobalParams.authenticationMechanism)); } - BSONTool::BSONTool() : Tool(false/*usesstdout*/) { } + BSONTool::BSONTool() : Tool() { } int BSONTool::run() { @@ -261,7 +258,7 @@ namespace mongo { if ( fileLength == 0 ) { if (!toolGlobalParams.quiet) { - (_usesstdout ? cout : cerr ) << "file " << fileName << " empty, skipping" << endl; + toolOutput() << "file " << fileName << " empty, skipping" << endl; } return 0; } @@ -279,7 +276,7 @@ namespace mongo { if (!toolGlobalParams.quiet && logger::globalLogDomain()->shouldLog(logger::LogSeverity::Debug(1))) { - (_usesstdout ? cout : cerr ) << "\t file size: " << fileLength << endl; + toolOutput() << "\t file size: " << fileLength << endl; } unsigned long long read = 0; @@ -336,9 +333,9 @@ namespace mongo { uassert( 10265 , "counts don't match" , m.done() == fileLength ); if (!toolGlobalParams.quiet) { - (_usesstdout ? cout : cerr ) << m.hits() << " objects found" << endl; + toolOutput() << m.hits() << " objects found" << std::endl; if (bsonToolGlobalParams.hasFilter) - (_usesstdout ? cout : cerr ) << processed << " objects processed" << endl; + toolOutput() << processed << " objects processed" << std::endl; } return processed; } diff --git a/src/mongo/tools/tool.h b/src/mongo/tools/tool.h index d422e8507cb..8138aaeffa2 100644 --- a/src/mongo/tools/tool.h +++ b/src/mongo/tools/tool.h @@ -26,6 +26,7 @@ #include "mongo/db/instance.h" #include "mongo/db/matcher.h" +#include "mongo/tools/tool_logger.h" #include "mongo/tools/tool_options.h" #include "mongo/util/options_parser/environment.h" @@ -35,7 +36,7 @@ namespace mongo { class Tool { public: - Tool(bool usesstdout=true); + Tool(); virtual ~Tool(); static auto_ptr<Tool> (*createInstance)(); @@ -52,14 +53,8 @@ namespace mongo { string getAuthenticationDatabase(); - void useStandardOutput( bool mode ) { - _usesstdout = mode; - } - bool isMaster(); bool isMongos(); - - virtual void preSetup() {} virtual int run() = 0; @@ -69,7 +64,6 @@ namespace mongo { mongo::DBClientBase &conn( bool slaveIfPaired = false ); - bool _usesstdout; bool _autoreconnect; protected: diff --git a/src/mongo/tools/tool_logger.cpp b/src/mongo/tools/tool_logger.cpp new file mode 100644 index 00000000000..f719ba0b464 --- /dev/null +++ b/src/mongo/tools/tool_logger.cpp @@ -0,0 +1,81 @@ +/* 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/tools/tool_logger.h" + +#include <iostream> + +#include "mongo/base/init.h" +#include "mongo/logger/console_appender.h" +#include "mongo/logger/log_manager.h" +#include "mongo/logger/logger.h" +#include "mongo/logger/message_event.h" +#include "mongo/logger/message_event_utf8_encoder.h" +#include "mongo/tools/tool_options.h" + +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 ErrorConsole constructor. Once the mutex is initialized, + * users of ErrorConsole can start acquiring it. + */ + + boost::mutex *consoleMutex = new boost::mutex; + +} // namespace + + ErrorConsole::ErrorConsole() : _consoleLock() { + if (consoleMutex) { + boost::unique_lock<boost::mutex> lk(*consoleMutex); + lk.swap(_consoleLock); + } + } + + std::ostream& ErrorConsole::out() { return std::cerr; } + +MONGO_INITIALIZER_GENERAL(ToolLogRedirection, + ("GlobalLogManager", "EndStartupOptionHandling"), + ("default"))(InitializerContext*) { + + using logger::MessageEventEphemeral; + using logger::MessageEventDetailsEncoder; + using logger::MessageLogDomain; + using logger::ConsoleAppender; + + // If we are outputting data to stdout, we may need to redirect all logging to stderr + if (!toolGlobalParams.canUseStdout) { + logger::globalLogDomain()->clearAppenders(); + logger::globalLogDomain()->attachAppender(MessageLogDomain::AppenderAutoPtr( + new ConsoleAppender<MessageEventEphemeral, ErrorConsole>( + new MessageEventDetailsEncoder))); + } + + return Status::OK(); +} + + std::ostream& toolOutput() { + return toolGlobalParams.canUseStdout ? std::cout : std::cerr; + } + +} // namespace mongo diff --git a/src/mongo/tools/tool_logger.h b/src/mongo/tools/tool_logger.h new file mode 100644 index 00000000000..7d845bc28b4 --- /dev/null +++ b/src/mongo/tools/tool_logger.h @@ -0,0 +1,39 @@ +/* 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 { + + /** + * This is a version of the Console class that uses stderr for output instead of stdout. See + * the description of the Console class for other details about how this class should operate + */ + class ErrorConsole { + public: + ErrorConsole(); + + std::ostream& out(); + + private: + boost::unique_lock<boost::mutex> _consoleLock; + }; + + std::ostream& toolOutput(); + +} // namespace mongo diff --git a/src/mongo/tools/tool_options.h b/src/mongo/tools/tool_options.h index 470960c0b05..7e30e38a7c8 100644 --- a/src/mongo/tools/tool_options.h +++ b/src/mongo/tools/tool_options.h @@ -33,7 +33,7 @@ namespace mongo { struct ToolGlobalParams { - ToolGlobalParams() : hostSet(false), portSet(false) { } + ToolGlobalParams() : canUseStdout(true), hostSet(false), portSet(false) { } std::string name; std::string db; @@ -45,6 +45,7 @@ namespace mongo { std::string authenticationMechanism; bool quiet; + bool canUseStdout; bool noconnection; std::vector<std::string> fields; |