summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
authorBenety Goh <benety@mongodb.com>2014-08-07 17:13:30 -0400
committerBenety Goh <benety@mongodb.com>2014-08-12 18:56:41 -0400
commit850d2d0912e519e544f0c896583a6fbd5cceabce (patch)
tree30e780d2fc9253fd2db178641fa8b32e42a1446e /src/mongo
parenta3845092f26955e6cbfca868fd136b7d5eefed9b (diff)
downloadmongo-850d2d0912e519e544f0c896583a6fbd5cceabce.tar.gz
SERVER-14729 support overriding of default log component in unconditional log functions severe(), error(), warning() and log()
Diffstat (limited to 'src/mongo')
-rw-r--r--src/mongo/logger/SConscript3
-rw-r--r--src/mongo/logger/log_function_test.cpp119
-rw-r--r--src/mongo/logger/log_test.cpp108
-rw-r--r--src/mongo/logger/log_test.h88
-rw-r--r--src/mongo/util/log.h96
5 files changed, 348 insertions, 66 deletions
diff --git a/src/mongo/logger/SConscript b/src/mongo/logger/SConscript
index 482d753595e..4febd815244 100644
--- a/src/mongo/logger/SConscript
+++ b/src/mongo/logger/SConscript
@@ -32,6 +32,9 @@ env.Program('console_test', 'console_test.cpp',
env.CppUnitTest('log_test', 'log_test.cpp',
LIBDEPS=['logger', '$BUILD_DIR/mongo/foundation'])
+env.CppUnitTest('log_function_test', 'log_function_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/log_function_test.cpp b/src/mongo/logger/log_function_test.cpp
new file mode 100644
index 00000000000..112ac9892bd
--- /dev/null
+++ b/src/mongo/logger/log_function_test.cpp
@@ -0,0 +1,119 @@
+/* Copyright 2013 10gen Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/logger/log_test.h"
+
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "mongo/logger/appender.h"
+#include "mongo/logger/encoder.h"
+#include "mongo/logger/log_component.h"
+#include "mongo/logger/message_event_utf8_encoder.h"
+#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kReplication
+#include "mongo/util/log.h"
+#include "mongo/util/mongoutils/str.h"
+
+using namespace mongo::logger;
+
+namespace mongo {
+namespace {
+
+ typedef LogTest<MessageEventDetailsEncoder> LogTestDetailsEncoder;
+
+ // Constants for log component test cases.
+ const LogComponent componentA = LogComponent::kCommands;
+ const LogComponent componentB = MONGO_LOG_DEFAULT_COMPONENT;
+
+ // Tests pass through of log component:
+ // unconditional log functions -> LogStreamBuilder -> MessageEventEphemeral
+ // -> MessageEventDetailsEncoder
+ // MONGO_DEFAULT_LOG_COMPONENT is set to kReplication before including util/log.h
+ // so non-debug logging without explicit component will log with kReplication instead
+ // of kDefault.
+ TEST_F(LogTestDetailsEncoder, LogFunctionsOverrideGlobalComponent) {
+ // severe() - no component specified.
+ severe() << "This is logged";
+ ASSERT_EQUALS(1U, _logLines.size());
+ ASSERT_NOT_EQUALS(_logLines[0].find(str::stream() << " F " << componentB.getNameForLog()),
+ std::string::npos);
+
+ // severe() - with component.
+ _logLines.clear();
+ severe(componentA) << "This is logged";
+ ASSERT_EQUALS(1U, _logLines.size());
+ ASSERT_NOT_EQUALS(_logLines[0].find(str::stream() << " F " << componentA.getNameForLog()),
+ std::string::npos);
+
+ // error() - no component specified.
+ _logLines.clear();
+ error() << "This is logged";
+ ASSERT_EQUALS(1U, _logLines.size());
+ ASSERT_NOT_EQUALS(_logLines[0].find(str::stream() << " E " << componentB.getNameForLog()),
+ std::string::npos);
+
+ // error() - with component.
+ _logLines.clear();
+ error(componentA) << "This is logged";
+ ASSERT_EQUALS(1U, _logLines.size());
+ ASSERT_NOT_EQUALS(_logLines[0].find(str::stream() << " E " << componentA.getNameForLog()),
+ std::string::npos);
+
+ // warning() - no component specified.
+ _logLines.clear();
+ warning() << "This is logged";
+ ASSERT_EQUALS(1U, _logLines.size());
+ ASSERT_NOT_EQUALS(_logLines[0].find(str::stream() << " W " << componentB.getNameForLog()),
+ std::string::npos);
+
+ // warning() - with component.
+ _logLines.clear();
+ warning(componentA) << "This is logged";
+ ASSERT_EQUALS(1U, _logLines.size());
+ ASSERT_NOT_EQUALS(_logLines[0].find(str::stream() << " W " << componentA.getNameForLog()),
+ std::string::npos);
+
+ // log() - no component specified.
+ _logLines.clear();
+ log() << "This is logged";
+ ASSERT_EQUALS(1U, _logLines.size());
+ ASSERT_NOT_EQUALS(_logLines[0].find(str::stream() << " I " << componentB.getNameForLog()),
+ std::string::npos);
+
+ // log() - with component.
+ _logLines.clear();
+ log(componentA) << "This is logged";
+ ASSERT_EQUALS(1U, _logLines.size());
+ ASSERT_NOT_EQUALS(_logLines[0].find(str::stream() << " I " << componentA.getNameForLog()),
+ std::string::npos);
+ }
+
+} // namespace
+} // namespace mongo
diff --git a/src/mongo/logger/log_test.cpp b/src/mongo/logger/log_test.cpp
index 0837b51b753..777e8d19b39 100644
--- a/src/mongo/logger/log_test.cpp
+++ b/src/mongo/logger/log_test.cpp
@@ -27,6 +27,8 @@
#include "mongo/platform/basic.h"
+#include "mongo/logger/log_test.h"
+
#include <sstream>
#include <string>
#include <vector>
@@ -50,48 +52,6 @@ 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.
- template <typename MessageEventEncoder>
- class LogTest : public unittest::Test {
- friend class LogTestAppender;
- public:
- LogTest() : _severityOld(globalLogDomain()->getMinimumLogSeverity()) {
- globalLogDomain()->clearAppenders();
- _appenderHandle = globalLogDomain()->attachAppender(
- MessageLogDomain::AppenderAutoPtr(new LogTestAppender(this)));
- }
-
- virtual ~LogTest() {
- globalLogDomain()->detachAppender(_appenderHandle);
- globalLogDomain()->setMinimumLoggedSeverity(_severityOld);
- }
-
- protected:
- std::vector<std::string> _logLines;
- LogSeverity _severityOld;
-
- 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;
- MessageEventEncoder _encoder;
- };
-
- MessageLogDomain::AppenderHandle _appenderHandle;
- };
-
typedef LogTest<MessageEventDetailsEncoder> LogTestDetailsEncoder;
typedef LogTest<MessageEventUnadornedEncoder> LogTestUnadornedEncoder;
@@ -590,5 +550,69 @@ namespace {
ASSERT_EQUALS(_logLines[0].find(componentC.getNameForLog().toString()), std::string::npos);
}
+ // Tests pass through of log component:
+ // unconditional log functions -> LogStreamBuilder -> MessageEventEphemeral
+ // -> MessageEventDetailsEncoder
+ TEST_F(LogTestDetailsEncoder, LogFunctions) {
+ // severe() - no component specified.
+ severe() << "This is logged";
+ ASSERT_EQUALS(1U, _logLines.size());
+ ASSERT_NOT_EQUALS(_logLines[0].find(
+ str::stream() << " F " << componentDefault.getNameForLog()),
+ std::string::npos);
+
+ // severe() - with component.
+ _logLines.clear();
+ severe(componentA) << "This is logged";
+ ASSERT_EQUALS(1U, _logLines.size());
+ ASSERT_NOT_EQUALS(_logLines[0].find(str::stream() << " F " << componentA.getNameForLog()),
+ std::string::npos);
+
+ // error() - no component specified.
+ _logLines.clear();
+ error() << "This is logged";
+ ASSERT_EQUALS(1U, _logLines.size());
+ ASSERT_NOT_EQUALS(_logLines[0].find(
+ str::stream() << " E " << componentDefault.getNameForLog()),
+ std::string::npos);
+
+ // error() - with component.
+ _logLines.clear();
+ error(componentA) << "This is logged";
+ ASSERT_EQUALS(1U, _logLines.size());
+ ASSERT_NOT_EQUALS(_logLines[0].find(str::stream() << " E " << componentA.getNameForLog()),
+ std::string::npos);
+
+ // warning() - no component specified.
+ _logLines.clear();
+ warning() << "This is logged";
+ ASSERT_EQUALS(1U, _logLines.size());
+ ASSERT_NOT_EQUALS(_logLines[0].find(
+ str::stream() << " W " << componentDefault.getNameForLog()),
+ std::string::npos);
+
+ // warning() - with component.
+ _logLines.clear();
+ warning(componentA) << "This is logged";
+ ASSERT_EQUALS(1U, _logLines.size());
+ ASSERT_NOT_EQUALS(_logLines[0].find(str::stream() << " W " << componentA.getNameForLog()),
+ std::string::npos);
+
+ // log() - no component specified.
+ _logLines.clear();
+ log() << "This is logged";
+ ASSERT_EQUALS(1U, _logLines.size());
+ ASSERT_NOT_EQUALS(_logLines[0].find(
+ str::stream() << " I " << componentDefault.getNameForLog()),
+ std::string::npos);
+
+ // log() - with component.
+ _logLines.clear();
+ log(componentA) << "This is logged";
+ ASSERT_EQUALS(1U, _logLines.size());
+ ASSERT_NOT_EQUALS(_logLines[0].find(str::stream() << " I " << componentA.getNameForLog()),
+ std::string::npos);
+ }
+
} // namespace
} // namespace mongo
diff --git a/src/mongo/logger/log_test.h b/src/mongo/logger/log_test.h
new file mode 100644
index 00000000000..f0b2f8c7efd
--- /dev/null
+++ b/src/mongo/logger/log_test.h
@@ -0,0 +1,88 @@
+/* Copyright 2013 10gen Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#pragma once
+
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "mongo/base/status.h"
+#include "mongo/logger/appender.h"
+#include "mongo/logger/log_severity.h"
+#include "mongo/logger/logger.h"
+#include "mongo/logger/message_log_domain.h"
+#include "mongo/unittest/unittest.h"
+
+namespace mongo {
+namespace logger {
+
+ // Used for testing logging framework only.
+ // TODO(schwerin): Have logger write to a different log from the global log, so that tests can
+ // redirect their global log output for examination.
+ template <typename MessageEventEncoder>
+ class LogTest : public unittest::Test {
+ friend class LogTestAppender;
+ public:
+ LogTest() : _severityOld(globalLogDomain()->getMinimumLogSeverity()) {
+ globalLogDomain()->clearAppenders();
+ _appenderHandle = globalLogDomain()->attachAppender(
+ MessageLogDomain::AppenderAutoPtr(new LogTestAppender(this)));
+ }
+
+ virtual ~LogTest() {
+ globalLogDomain()->detachAppender(_appenderHandle);
+ globalLogDomain()->setMinimumLoggedSeverity(_severityOld);
+ }
+
+ protected:
+ std::vector<std::string> _logLines;
+ LogSeverity _severityOld;
+
+ 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;
+ MessageEventEncoder _encoder;
+ };
+
+ MessageLogDomain::AppenderHandle _appenderHandle;
+ };
+
+} // namespace logger
+} // namespace mongo
diff --git a/src/mongo/util/log.h b/src/mongo/util/log.h
index f63f858ada4..b8043e0dda1 100644
--- a/src/mongo/util/log.h
+++ b/src/mongo/util/log.h
@@ -37,6 +37,32 @@
#include "mongo/logger/tee.h"
#include "mongo/util/concurrency/thread_name.h"
+/**
+ * Defines default log component for MONGO_LOG.
+ * Use this macro inside an implementation namespace or code block where debug messages
+ * are logged using MONGO_LOG().
+ *
+ * Note: Do not use more than once inside any namespace/code block.
+ */
+#define MONGO_LOG_DEFAULT_COMPONENT_FILE(COMPONENT) \
+ static const ::mongo::logger::LogComponent MongoLogDefaultComponent_component = (COMPONENT);
+
+/**
+ * MONGO_LOG_DEFAULT_COMPONENT for local code block.
+ */
+#define MONGO_LOG_DEFAULT_COMPONENT_LOCAL(COMPONENT) \
+ const ::mongo::logger::LogComponent MongoLogDefaultComponent_component = (COMPONENT);
+
+// Provide log component in global scope so that MONGO_LOG will always have a valid component.
+// Global log component will be kDefault unless overridden by MONGO_LOG_DEFAULT_COMPONENT.
+#if defined(MONGO_LOG_DEFAULT_COMPONENT)
+const ::mongo::logger::LogComponent MongoLogDefaultComponent_component =
+ MONGO_LOG_DEFAULT_COMPONENT;
+#else
+const ::mongo::logger::LogComponent MongoLogDefaultComponent_component =
+ ::mongo::logger::LogComponent::kDefault;
+#endif // MONGO_LOG_DEFAULT_COMPONENT
+
namespace mongo {
namespace logger {
@@ -45,6 +71,8 @@ namespace logger {
} // namespace logger
+namespace {
+
using logger::LogstreamBuilder;
using logger::LabeledLevel;
using logger::Tee;
@@ -55,7 +83,15 @@ namespace logger {
inline LogstreamBuilder severe() {
return LogstreamBuilder(logger::globalLogDomain(),
getThreadName(),
- logger::LogSeverity::Severe());
+ logger::LogSeverity::Severe(),
+ ::MongoLogDefaultComponent_component);
+ }
+
+ inline LogstreamBuilder severe(logger::LogComponent component) {
+ return LogstreamBuilder(logger::globalLogDomain(),
+ getThreadName(),
+ logger::LogSeverity::Severe(),
+ component);
}
/**
@@ -64,7 +100,15 @@ namespace logger {
inline LogstreamBuilder error() {
return LogstreamBuilder(logger::globalLogDomain(),
getThreadName(),
- logger::LogSeverity::Error());
+ logger::LogSeverity::Error(),
+ ::MongoLogDefaultComponent_component);
+ }
+
+ inline LogstreamBuilder error(logger::LogComponent component) {
+ return LogstreamBuilder(logger::globalLogDomain(),
+ getThreadName(),
+ logger::LogSeverity::Error(),
+ component);
}
/**
@@ -73,7 +117,15 @@ namespace logger {
inline LogstreamBuilder warning() {
return LogstreamBuilder(logger::globalLogDomain(),
getThreadName(),
- logger::LogSeverity::Warning());
+ logger::LogSeverity::Warning(),
+ ::MongoLogDefaultComponent_component);
+ }
+
+ inline LogstreamBuilder warning(logger::LogComponent component) {
+ return LogstreamBuilder(logger::globalLogDomain(),
+ getThreadName(),
+ logger::LogSeverity::Warning(),
+ component);
}
/**
@@ -82,9 +134,25 @@ namespace logger {
inline LogstreamBuilder log() {
return LogstreamBuilder(logger::globalLogDomain(),
getThreadName(),
- logger::LogSeverity::Log());
+ logger::LogSeverity::Log(),
+ ::MongoLogDefaultComponent_component);
}
+ inline LogstreamBuilder log(logger::LogComponent component) {
+ return LogstreamBuilder(logger::globalLogDomain(),
+ getThreadName(),
+ logger::LogSeverity::Log(),
+ component);
+ }
+
+ inline LogstreamBuilder log(logger::LogComponent::Value componentValue) {
+ return LogstreamBuilder(logger::globalLogDomain(),
+ getThreadName(),
+ logger::LogSeverity::Log(),
+ componentValue);
+ }
+
+} // namespace
// MONGO_LOG uses log component from MongoLogDefaultComponent from current or global namespace.
#define MONGO_LOG(DLEVEL) \
@@ -142,23 +210,3 @@ namespace logger {
} // namespace mongo
-/**
- * Defines default log component for MONGO_LOG.
- * Use this macro inside an implementation namespace or code block where debug messages
- * are logged using MONGO_LOG().
- *
- * Note: Do not use more than once inside any namespace/code block.
- * Using static function instead of enum to support use inside function code block.
- */
-#define MONGO_LOG_DEFAULT_COMPONENT_FILE(COMPONENT) \
- static const ::mongo::logger::LogComponent MongoLogDefaultComponent_component = (COMPONENT);
-
-/**
- * MONGO_LOG_DEFAULT_COMPONENT for local code block.
- */
-#define MONGO_LOG_DEFAULT_COMPONENT_LOCAL(COMPONENT) \
- const ::mongo::logger::LogComponent MongoLogDefaultComponent_component = (COMPONENT);
-
-// Provide log component in global scope so that MONGO_LOG will always have a valid component.
-const ::mongo::logger::LogComponent MongoLogDefaultComponent_component =
- ::mongo::logger::LogComponent::kDefault;