summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
authorBenety Goh <benety@mongodb.com>2014-06-10 18:50:40 -0400
committerBenety Goh <benety@mongodb.com>2014-06-26 19:41:32 -0400
commit4d00dd9723f84f197afffd901101276916d1ee6c (patch)
tree1d57039912b23cf3132a10faca60934dbdb463cb /src/mongo
parente1dca2cdeed7cf5549a85d487def752d600af244 (diff)
downloadmongo-4d00dd9723f84f197afffd901101276916d1ee6c.tar.gz
SERVER-5092 support log tags for LOG() messages
Diffstat (limited to 'src/mongo')
-rw-r--r--src/mongo/logger/SConscript3
-rw-r--r--src/mongo/logger/log_domain-impl.h2
-rw-r--r--src/mongo/logger/log_domain.h19
-rw-r--r--src/mongo/logger/log_manager.h6
-rw-r--r--src/mongo/logger/log_tag.cpp57
-rw-r--r--src/mongo/logger/log_tag.h72
-rw-r--r--src/mongo/logger/log_tag_settings.cpp105
-rw-r--r--src/mongo/logger/log_tag_settings.h97
-rw-r--r--src/mongo/logger/log_test.cpp281
-rw-r--r--src/mongo/logger/logger.h2
-rw-r--r--src/mongo/logger/tag_message_log_domain.cpp82
-rw-r--r--src/mongo/logger/tag_message_log_domain.h84
-rw-r--r--src/mongo/util/log.h37
13 files changed, 821 insertions, 26 deletions
diff --git a/src/mongo/logger/SConscript b/src/mongo/logger/SConscript
index 624c2d7a923..926d3c68350 100644
--- a/src/mongo/logger/SConscript
+++ b/src/mongo/logger/SConscript
@@ -7,10 +7,13 @@ env.Library('logger',
'console.cpp',
'log_manager.cpp',
'log_severity.cpp',
+ 'log_tag.cpp',
+ 'log_tag_settings.cpp',
'logger.cpp',
'logstream_builder.cpp',
'message_event_utf8_encoder.cpp',
'message_log_domain.cpp',
+ 'tag_message_log_domain.cpp',
'ramlog.cpp',
'rotatable_file_manager.cpp',
'rotatable_file_writer.cpp',
diff --git a/src/mongo/logger/log_domain-impl.h b/src/mongo/logger/log_domain-impl.h
index cc5df19afd1..67ff6bb2f1a 100644
--- a/src/mongo/logger/log_domain-impl.h
+++ b/src/mongo/logger/log_domain-impl.h
@@ -43,7 +43,7 @@ namespace logger {
template <typename E>
LogDomain<E>::LogDomain()
- : _minimumLoggedSeverity(LogSeverity::Log()), _abortOnFailure(false)
+ : _abortOnFailure(false)
{}
template <typename E>
diff --git a/src/mongo/logger/log_domain.h b/src/mongo/logger/log_domain.h
index 0d788c462e7..f55f04dd6f4 100644
--- a/src/mongo/logger/log_domain.h
+++ b/src/mongo/logger/log_domain.h
@@ -42,7 +42,7 @@ namespace logger {
/**
* Logging domain for events of type E.
*
- * A logging domain consists of a set of Appenders and a minimum severity.
+ * A logging domain consists of a set of Appenders.
*
* 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
@@ -96,22 +96,6 @@ namespace logger {
Status 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; }
-
- /**
* Gets the state of the abortOnFailure flag.
*/
bool getAbortOnFailure() const { return _abortOnFailure; }
@@ -147,7 +131,6 @@ namespace logger {
private:
typedef std::vector<EventAppender*> AppenderVector;
- LogSeverity _minimumLoggedSeverity;
AppenderVector _appenders;
bool _abortOnFailure;
};
diff --git a/src/mongo/logger/log_manager.h b/src/mongo/logger/log_manager.h
index 7b60d2feaed..bdef7870b9b 100644
--- a/src/mongo/logger/log_manager.h
+++ b/src/mongo/logger/log_manager.h
@@ -30,7 +30,7 @@
#include <string>
#include "mongo/base/disallow_copying.h"
-#include "mongo/logger/message_log_domain.h"
+#include "mongo/logger/tag_message_log_domain.h"
#include "mongo/logger/rotatable_file_writer.h"
#include "mongo/platform/unordered_map.h"
@@ -51,7 +51,7 @@ namespace logger {
/**
* Gets the global domain for this manager. It has no name.
*/
- MessageLogDomain* getGlobalDomain() { return &_globalDomain; }
+ TagMessageLogDomain* getGlobalDomain() { return &_globalDomain; }
/**
* Get the log domain with the given name, creating if needed.
@@ -62,7 +62,7 @@ namespace logger {
typedef unordered_map<std::string, MessageLogDomain*> DomainsByNameMap;
DomainsByNameMap _domains;
- MessageLogDomain _globalDomain;
+ TagMessageLogDomain _globalDomain;
};
} // namespace logger
diff --git a/src/mongo/logger/log_tag.cpp b/src/mongo/logger/log_tag.cpp
new file mode 100644
index 00000000000..f2df1d7585e
--- /dev/null
+++ b/src/mongo/logger/log_tag.cpp
@@ -0,0 +1,57 @@
+/* Copyright 2014 MongoDB 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_tag.h"
+
+#include "mongo/util/assert_util.h"
+
+namespace mongo {
+namespace logger {
+
+ std::string LogTag::getShortName() const {
+ switch (_value) {
+ case kDefault: return "Default";
+ case kAccessControl: return "AccessControl";
+ case kCommands: return "Commands";
+ case kIndexing: return "Indexing";
+ case kJournalling: return "Journalling";
+ case kNetworking: return "Networking";
+ case kQuery: return "Query";
+ case kReplication: return "Replication";
+ case kSharding: return "Sharding";
+ case kStorage: return "Storage";
+ case kWrites: return "Writes";
+ case kNumLogTags: return "Total";
+ // No default. Compiler should complain if there's a tag that's not handled.
+ }
+ invariant(0);
+ }
+
+} // logger
+} // mongo
diff --git a/src/mongo/logger/log_tag.h b/src/mongo/logger/log_tag.h
new file mode 100644
index 00000000000..06e39613833
--- /dev/null
+++ b/src/mongo/logger/log_tag.h
@@ -0,0 +1,72 @@
+/* Copyright 2014 MongoDB 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 <string>
+
+namespace mongo {
+namespace logger {
+
+ /**
+ * Log tags.
+ * Debug messages logged using the LOG() or MONGO_LOG_TAG()
+ * macros may be associated with one or more log tags.
+ */
+ class LogTag {
+ public:
+ enum Value {
+ kDefault = 0,
+ kAccessControl,
+ kCommands,
+ kIndexing,
+ kJournalling,
+ kNetworking,
+ kQuery,
+ kReplication,
+ kSharding,
+ kStorage,
+ kWrites,
+ kNumLogTags
+ };
+
+ /* implicit */ LogTag(Value value) : _value(value) {}
+
+ operator Value() const { return _value; }
+
+ /**
+ * Returns short name of log tag.
+ * Used to generate server parameter names in the format "logLevel_<tag short name>".
+ */
+ std::string getShortName() const;
+
+ private:
+ Value _value;
+ };
+
+} // namespace logger
+} // namespace mongo
diff --git a/src/mongo/logger/log_tag_settings.cpp b/src/mongo/logger/log_tag_settings.cpp
new file mode 100644
index 00000000000..82ff1f48357
--- /dev/null
+++ b/src/mongo/logger/log_tag_settings.cpp
@@ -0,0 +1,105 @@
+/* Copyright 2014 MongoDB 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_tag_settings.h"
+
+#include "mongo/util/assert_util.h"
+
+namespace mongo {
+namespace logger {
+
+ LogTagSettings::LogTagSettings() {
+ _minimumLoggedSeverity[LogTag::kDefault] = char(LogSeverity::Log().toInt());
+
+ for (int i = 0; i < int(LogTag::kNumLogTags); ++i) {
+ _minimumLoggedSeverity[i] = _minimumLoggedSeverity[LogTag::kDefault];
+ _hasMinimumLoggedSeverity[i] = false;
+ }
+
+ _hasMinimumLoggedSeverity[LogTag::kDefault] = true;
+ }
+
+ LogTagSettings::~LogTagSettings() { }
+
+ bool LogTagSettings::hasMinimumLogSeverity(LogTag tag) const {
+ dassert(int(tag) >= 0 && int(tag) < LogTag::kNumLogTags);
+ return _hasMinimumLoggedSeverity[tag];
+ }
+
+ LogSeverity LogTagSettings::getMinimumLogSeverity(LogTag tag) const {
+ dassert(int(tag) >= 0 && int(tag) < LogTag::kNumLogTags);
+ return LogSeverity::cast(_minimumLoggedSeverity[tag]);
+ }
+
+ void LogTagSettings::setMinimumLoggedSeverity(LogTag tag, LogSeverity severity) {
+ dassert(int(tag) >= 0 && int(tag) < LogTag::kNumLogTags);
+ _minimumLoggedSeverity[tag] = char(severity.toInt());
+ _hasMinimumLoggedSeverity[tag] = true;
+
+ // Set severities for unconfigured tags to be the same as LogTag::kDefault.
+ if (tag == LogTag::kDefault) {
+ for (int i = 0; i < int(LogTag::kNumLogTags); ++i) {
+ if (!_hasMinimumLoggedSeverity[i]) {
+ _minimumLoggedSeverity[i] = char(severity.toInt());
+ }
+ }
+ }
+ }
+
+ void LogTagSettings::clearMinimumLoggedSeverity(LogTag tag) {
+ dassert(int(tag) >= 0 && int(tag) < LogTag::kNumLogTags);
+
+ // LogTag::kDefault must always be configured.
+ if (tag == LogTag::kDefault) {
+ setMinimumLoggedSeverity(tag, LogSeverity::Log());
+ return;
+ }
+
+ // Set unconfigured severity level to match LogTag::kDefault.
+ _minimumLoggedSeverity[tag] = _minimumLoggedSeverity[LogTag::kDefault];
+ _hasMinimumLoggedSeverity[tag] = false;
+ }
+
+ bool LogTagSettings::shouldLog(LogSeverity severity) const {
+ return severity >= LogSeverity::cast(_minimumLoggedSeverity[LogTag::kDefault]);
+ }
+
+ bool LogTagSettings::shouldLog(LogTag tag, LogSeverity severity) const {
+ dassert(int(tag) >= 0 && int(tag) < LogTag::kNumLogTags);
+
+ // Should match LogTag::kDefault if minimum severity level is not configured for tag.
+ dassert(_hasMinimumLoggedSeverity[tag] ||
+ _minimumLoggedSeverity[tag] ==
+ _minimumLoggedSeverity[LogTag::kDefault]);
+
+ return severity >= LogSeverity::cast(_minimumLoggedSeverity[tag]);
+ }
+
+} // logger
+} // mongo
diff --git a/src/mongo/logger/log_tag_settings.h b/src/mongo/logger/log_tag_settings.h
new file mode 100644
index 00000000000..abed408c42f
--- /dev/null
+++ b/src/mongo/logger/log_tag_settings.h
@@ -0,0 +1,97 @@
+/* Copyright 2014 MongoDB 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 "mongo/base/disallow_copying.h"
+#include "mongo/logger/log_tag.h"
+#include "mongo/logger/log_severity.h"
+
+namespace mongo {
+namespace logger {
+
+ /**
+ * Contains log severities for a list of log tags.
+ * kDefault always has a log severity defined but it is not necessary to
+ * provide log severities for the other tags (up to but not including kNumLogTags).
+ */
+ class LogTagSettings {
+ MONGO_DISALLOW_COPYING(LogTagSettings);
+ public:
+ LogTagSettings();
+ ~LogTagSettings();
+
+ /**
+ * Returns true if a minimum log severity has been set for this tag.
+ * Used by log level commands to query tag severity configuration.
+ */
+ bool hasMinimumLogSeverity(LogTag tag) const;
+
+ /**
+ * Gets the minimum log severity for tag.
+ * Result is defined only if hasMinimumLogSeverity() returns true for tag.
+ */
+ LogSeverity getMinimumLogSeverity(LogTag tag) const;
+
+ /**
+ * Sets the minimum log severity for tag.
+ */
+ void setMinimumLoggedSeverity(LogTag tag, LogSeverity severity);
+
+ /**
+ * Clears the minimum log severity for tag.
+ * For kDefault, severity level is initialized to default value.
+ */
+ void clearMinimumLoggedSeverity(LogTag tag);
+
+ /**
+ * Predicate that answers the question, "Should I, the caller, append to you, the log
+ * domain, tagged messages of the given severity?" True means yes.
+ *
+ * No tags provided means to check against kDefault only.
+ *
+ * If a tag is specified but minimum severity levels are not configured,
+ * compare 'severity' against the configured level for kDefault.
+ */
+ bool shouldLog(LogSeverity severity) const;
+ bool shouldLog(LogTag tag, LogSeverity severity) const;
+
+ private:
+ // True if a log severity is explicitly set for a tag.
+ // This differentiates between unconfigured tags and tags that happen to have the same
+ // severity as kDefault.
+ // This is also used to update the severities of unconfigured tags when the severity for
+ // kDefault is modified.
+ bool _hasMinimumLoggedSeverity[LogTag::kNumLogTags];
+
+ // Log severities for tags.
+ // Store numerical values of severities to be cache-line friendly.
+ // Set to kDefault minimum logged severity if _hasMinimumLoggedSeverity[i] is false.
+ char _minimumLoggedSeverity[LogTag::kNumLogTags];
+ };
+} // namespace logger
+} // namespace mongo
diff --git a/src/mongo/logger/log_test.cpp b/src/mongo/logger/log_test.cpp
index abc2e1abd4c..26d6bce05d0 100644
--- a/src/mongo/logger/log_test.cpp
+++ b/src/mongo/logger/log_test.cpp
@@ -33,6 +33,8 @@
#include "mongo/logger/appender.h"
#include "mongo/logger/encoder.h"
+#include "mongo/logger/log_tag.h"
+#include "mongo/logger/log_tag_settings.h"
#include "mongo/logger/message_event_utf8_encoder.h"
#include "mongo/logger/message_log_domain.h"
#include "mongo/logger/rotatable_file_appender.h"
@@ -52,16 +54,20 @@ namespace {
class LogTest : public unittest::Test {
friend class LogTestAppender;
public:
- LogTest() {
+ LogTest() : _severityOld(globalLogDomain()->getMinimumLogSeverity()) {
globalLogDomain()->clearAppenders();
_appenderHandle = globalLogDomain()->attachAppender(
MessageLogDomain::AppenderAutoPtr(new LogTestAppender(this)));
}
- virtual ~LogTest() { globalLogDomain()->detachAppender(_appenderHandle); }
+ virtual ~LogTest() {
+ globalLogDomain()->detachAppender(_appenderHandle);
+ globalLogDomain()->setMinimumLoggedSeverity(_severityOld);
+ }
protected:
std::vector<std::string> _logLines;
+ LogSeverity _severityOld;
private:
class LogTestAppender : public MessageLogDomain::EventAppender {
@@ -155,5 +161,276 @@ namespace {
B() { log() << "Exercising initializer time logging."; }
} b;
+ // Constants for log tag test cases.
+ const LogTag tagA = LogTag::kCommands;
+ const LogTag tagB = LogTag::kAccessControl;
+ const LogTag tagC = LogTag::kNetworking;
+
+ // No log tag declared at file scope.
+ // Tag severity configuration:
+ // LogTag::kDefault: 2
+ TEST_F(LogTest, MongoLogMacroNoFileScopeLogTag) {
+ globalLogDomain()->setMinimumLoggedSeverity(LogSeverity::Debug(2));
+
+ LOG(2) << "This is logged";
+ LOG(3) << "This is not logged";
+ ASSERT_EQUALS(1U, _logLines.size());
+ ASSERT_EQUALS(std::string("This is logged\n"), _logLines[0]);
+
+ // MONGO_LOG_TAG
+ _logLines.clear();
+ MONGO_LOG_TAG(2, tagA) << "This is logged";
+ MONGO_LOG_TAG(3, tagA) << "This is not logged";
+ ASSERT_EQUALS(1U, _logLines.size());
+ ASSERT_EQUALS(std::string("This is logged\n"), _logLines[0]);
+
+ // MONGO_LOG_TAG2
+ _logLines.clear();
+ MONGO_LOG_TAG2(2, tagA, tagB) << "This is logged";
+ MONGO_LOG_TAG2(3, tagA, tagB) << "This is not logged";
+ ASSERT_EQUALS(1U, _logLines.size());
+ ASSERT_EQUALS(std::string("This is logged\n"), _logLines[0]);
+
+ // MONGO_LOG_TAG3
+ _logLines.clear();
+ MONGO_LOG_TAG3(2, tagA, tagB, tagC) << "This is logged";
+ MONGO_LOG_TAG3(3, tagA, tagB, tagC) << "This is not logged";
+ ASSERT_EQUALS(1U, _logLines.size());
+ ASSERT_EQUALS(std::string("This is logged\n"), _logLines[0]);
+ }
+
+ // Default log tag declared at inner namespace scope (tagB).
+ // Tag severity configuration:
+ // LogTag::kDefault: 1
+ // tagB: 2
+ namespace scoped_default_log_tag_test {
+
+ // Set MONGO_LOG's default tag to tagB.
+ MONGO_LOG_DEFAULT_TAG_FILE(tagB);
+
+ TEST_F(LogTest, MongoLogMacroNamespaceScopeLogTagDeclared) {
+ globalLogDomain()->setMinimumLoggedSeverity(LogSeverity::Debug(1));
+ globalLogDomain()->setMinimumLoggedSeverity(tagB,
+ LogSeverity::Debug(2));
+
+ // LOG - uses log tag (tagB) declared in MONGO_LOG_DEFAULT_TAG_FILE.
+ LOG(2) << "This is logged";
+ LOG(3) << "This is not logged";
+ ASSERT_EQUALS(1U, _logLines.size());
+ ASSERT_EQUALS(std::string("This is logged\n"), _logLines[0]);
+
+ globalLogDomain()->clearMinimumLoggedSeverity(tagB);
+ }
+
+ } // namespace scoped_default_log_tag_test
+
+ // Default log tag declared at function scope (tagA).
+ // Tag severity configuration:
+ // LogTag::kDefault: 1
+ // tagA: 2
+ TEST_F(LogTest, MongoLogMacroFunctionScopeLogTagDeclared) {
+ globalLogDomain()->setMinimumLoggedSeverity(LogSeverity::Debug(1));
+ globalLogDomain()->setMinimumLoggedSeverity(tagA, LogSeverity::Debug(2));
+
+ // Set MONGO_LOG's default tag to tagA.
+ MONGO_LOG_DEFAULT_TAG_LOCAL(tagA);
+
+ // LOG - uses log tag (tagA) declared in MONGO_LOG_DEFAULT_TAG.
+ LOG(2) << "This is logged";
+ LOG(3) << "This is not logged";
+ ASSERT_EQUALS(1U, _logLines.size());
+ ASSERT_EQUALS(std::string("This is logged\n"), _logLines[0]);
+
+ // MONGO_LOG_TAG - log message tag matches function scope tag.
+ _logLines.clear();
+ MONGO_LOG_TAG(2, tagA) << "This is logged";
+ MONGO_LOG_TAG(3, tagA) << "This is not logged";
+ ASSERT_EQUALS(1U, _logLines.size());
+ ASSERT_EQUALS(std::string("This is logged\n"), _logLines[0]);
+
+ // MONGO_LOG_TAG - log message tag not configured - fall back on LogTag::kDefault severity.
+ _logLines.clear();
+ MONGO_LOG_TAG(1, tagB) << "This is logged";
+ MONGO_LOG_TAG(2, tagB) << "This is not logged";
+ ASSERT_EQUALS(1U, _logLines.size());
+ ASSERT_EQUALS(std::string("This is logged\n"), _logLines[0]);
+
+ // MONGO_LOG_TAG2
+ _logLines.clear();
+ MONGO_LOG_TAG2(2, tagA, tagB) << "This is logged";
+ MONGO_LOG_TAG2(3, tagA, tagB) << "This is not logged";
+ ASSERT_EQUALS(1U, _logLines.size());
+ ASSERT_EQUALS(std::string("This is logged\n"), _logLines[0]);
+
+ // MONGO_LOG_TAG2 - reverse order.
+ _logLines.clear();
+ MONGO_LOG_TAG2(2, tagB, tagA) << "This is logged";
+ MONGO_LOG_TAG2(3, tagB, tagA) << "This is not logged";
+ ASSERT_EQUALS(1U, _logLines.size());
+ ASSERT_EQUALS(std::string("This is logged\n"), _logLines[0]);
+
+ // MONGO_LOG_TAG2 - none of the log message tags configured - fall back on LogTag::kDefault.
+ _logLines.clear();
+ MONGO_LOG_TAG2(1, tagB, tagC) << "This is logged";
+ MONGO_LOG_TAG2(2, tagB, tagC) << "This is not logged";
+ ASSERT_EQUALS(1U, _logLines.size());
+ ASSERT_EQUALS(std::string("This is logged\n"), _logLines[0]);
+
+ // MONGO_LOG_TAG3
+ _logLines.clear();
+ MONGO_LOG_TAG3(2, tagA, tagB, tagC) << "This is logged";
+ MONGO_LOG_TAG3(3, tagA, tagB, tagC) << "This is not logged";
+ ASSERT_EQUALS(1U, _logLines.size());
+ ASSERT_EQUALS(std::string("This is logged\n"), _logLines[0]);
+
+ // MONGO_LOG_TAG3 - configured tag as 2nd tag.
+ _logLines.clear();
+ MONGO_LOG_TAG3(2, tagB, tagA, tagC) << "This is logged";
+ MONGO_LOG_TAG3(3, tagB, tagA, tagC) << "This is not logged";
+ ASSERT_EQUALS(1U, _logLines.size());
+ ASSERT_EQUALS(std::string("This is logged\n"), _logLines[0]);
+
+ // MONGO_LOG_TAG3 - configured tag as 3rd tag.
+ _logLines.clear();
+ MONGO_LOG_TAG3(2, tagB, tagC, tagA) << "This is logged";
+ MONGO_LOG_TAG3(3, tagB, tagC, tagA) << "This is not logged";
+ ASSERT_EQUALS(1U, _logLines.size());
+ ASSERT_EQUALS(std::string("This is logged\n"), _logLines[0]);
+
+ // MONGO_LOG_TAG3 - none of the log message tags configured - fall back on LogTag::kDefault.
+ _logLines.clear();
+ MONGO_LOG_TAG3(1, tagB, tagC, LogTag::kIndexing) << "This is logged";
+ MONGO_LOG_TAG3(2, tagB, tagC, LogTag::kIndexing) << "This is not logged";
+ ASSERT_EQUALS(1U, _logLines.size());
+ ASSERT_EQUALS(std::string("This is logged\n"), _logLines[0]);
+
+ globalLogDomain()->clearMinimumLoggedSeverity(tagA);
+ }
+
+ //
+ // Tag log level tests.
+ // The global log manager holds the tag log level configuration for the global log domain.
+ // LOG() and MONGO_LOG_TAG() macros in util/log.h determine at runtime if a log message
+ // should be written to the log domain.
+ //
+
+ TEST_F(LogTest, LogTagSettingsMinimumLogSeverity) {
+ LogTagSettings settings;
+ ASSERT_TRUE(settings.hasMinimumLogSeverity(LogTag::kDefault));
+ ASSERT_TRUE(settings.getMinimumLogSeverity(LogTag::kDefault) == LogSeverity::Log());
+ for (int i = 0; i < int(LogTag::kNumLogTags); ++i) {
+ LogTag tag = static_cast<LogTag::Value>(i);
+ if (tag == LogTag::kDefault) { continue; }
+ ASSERT_FALSE(settings.hasMinimumLogSeverity(tag));
+ }
+
+ // Override and clear minimum severity level.
+ for (int i = 0; i < int(LogTag::kNumLogTags); ++i) {
+ LogTag tag = static_cast<LogTag::Value>(i);
+ LogSeverity severity = LogSeverity::Debug(2);
+
+ // Override severity level.
+ settings.setMinimumLoggedSeverity(tag, severity);
+ ASSERT_TRUE(settings.hasMinimumLogSeverity(tag));
+ ASSERT_TRUE(settings.getMinimumLogSeverity(tag) == severity);
+
+ // Clear severity level.
+ // Special case: when clearing LogTag::kDefault, the corresponding
+ // severity level is set to default values (ie. Log()).
+ settings.clearMinimumLoggedSeverity(tag);
+ if (tag == LogTag::kDefault) {
+ ASSERT_TRUE(settings.hasMinimumLogSeverity(tag));
+ ASSERT_TRUE(settings.getMinimumLogSeverity(LogTag::kDefault) == LogSeverity::Log());
+ }
+ else {
+ ASSERT_FALSE(settings.hasMinimumLogSeverity(tag));
+ }
+ }
+ }
+
+ // Test for shouldLog() when the minimum logged severity is set only for LogTag::kDefault.
+ TEST_F(LogTest, LogTagSettingsShouldLogDefaultLogTagOnly) {
+ LogTagSettings settings;
+
+ // Initial log severity for LogTag::kDefault is Log().
+ ASSERT_TRUE(settings.shouldLog(LogSeverity::Info()));
+ ASSERT_TRUE(settings.shouldLog(LogSeverity::Log()));
+ ASSERT_FALSE(settings.shouldLog(LogSeverity::Debug(1)));
+ ASSERT_FALSE(settings.shouldLog(LogSeverity::Debug(2)));
+
+ // If any tags are provided to shouldLog(), we should get the same outcome
+ // because we have not configured any non-LogTag::kDefault tags.
+ ASSERT_TRUE(settings.shouldLog(tagA, LogSeverity::Log()));
+ ASSERT_FALSE(settings.shouldLog(tagA, LogSeverity::Debug(1)));
+
+ // Set minimum logged severity so that Debug(1) messages are written to log domain.
+ settings.setMinimumLoggedSeverity(LogTag::kDefault, LogSeverity::Debug(1));
+ ASSERT_TRUE(settings.shouldLog(LogSeverity::Info()));
+ ASSERT_TRUE(settings.shouldLog(LogSeverity::Log()));
+ ASSERT_TRUE(settings.shouldLog(LogSeverity::Debug(1)));
+ ASSERT_FALSE(settings.shouldLog(LogSeverity::Debug(2)));
+
+ // Same results when tags are supplied to shouldLog().
+ ASSERT_TRUE(settings.shouldLog(tagA, LogSeverity::Debug(1)));
+ ASSERT_FALSE(settings.shouldLog(tagA, LogSeverity::Debug(2)));
+ }
+
+ // Test for shouldLog() when we have configured a single tag.
+ // Also checks that severity level has been reverted to match LogTag::kDefault
+ // after clearing level.
+ // Minimum severity levels:
+ // LogTag::kDefault: 1
+ // tagA: 2
+ TEST_F(LogTest, LogTagSettingsShouldLogSingleTag) {
+ LogTagSettings settings;
+
+ settings.setMinimumLoggedSeverity(LogTag::kDefault, LogSeverity::Debug(1));
+ settings.setMinimumLoggedSeverity(tagA, LogSeverity::Debug(2));
+
+ // Tags for log message: LogTag::kDefault only.
+ ASSERT_TRUE(settings.shouldLog(LogSeverity::Debug(1)));
+ ASSERT_FALSE(settings.shouldLog(LogSeverity::Debug(2)));
+
+ // Tags for log message: tagA only.
+ ASSERT_TRUE(settings.shouldLog(tagA, LogSeverity::Debug(2)));
+ ASSERT_FALSE(settings.shouldLog(tagA, LogSeverity::Debug(3)));
+
+ // Clear severity level for tagA and check shouldLog() again.
+ settings.clearMinimumLoggedSeverity(tagA);
+ ASSERT_TRUE(settings.shouldLog(tagA, LogSeverity::Debug(1)));
+ ASSERT_FALSE(settings.shouldLog(tagA, LogSeverity::Debug(2)));
+ }
+
+ // Test for shouldLog() when we have configured multiple tags.
+ // Minimum severity levels:
+ // LogTag::kDefault: 1
+ // tagA: 2
+ // tagB: 0
+ TEST_F(LogTest, LogTagSettingsShouldLogMultipleTagsConfigured) {
+ LogTagSettings settings;
+
+ settings.setMinimumLoggedSeverity(LogTag::kDefault, LogSeverity::Debug(1));
+ settings.setMinimumLoggedSeverity(tagA, LogSeverity::Debug(2));
+ settings.setMinimumLoggedSeverity(tagB, LogSeverity::Log());
+
+ // Tags for log message: LogTag::kDefault only.
+ ASSERT_TRUE(settings.shouldLog(LogSeverity::Debug(1)));
+ ASSERT_FALSE(settings.shouldLog(LogSeverity::Debug(2)));
+
+ // Tags for log message: tagA only.
+ ASSERT_TRUE(settings.shouldLog(tagA, LogSeverity::Debug(2)));
+ ASSERT_FALSE(settings.shouldLog(tagA, LogSeverity::Debug(3)));
+
+ // Tags for log message: tagB only.
+ ASSERT_TRUE(settings.shouldLog(tagB, LogSeverity::Log()));
+ ASSERT_FALSE(settings.shouldLog(tagB, LogSeverity::Debug(1)));
+
+ // Tags for log message: tagC only.
+ // Since a tag-specific minimum severity is not configured for tagC,
+ // shouldLog() falls back on LogTag::kDefault.
+ ASSERT_TRUE(settings.shouldLog(tagC, LogSeverity::Debug(1)));
+ ASSERT_FALSE(settings.shouldLog(tagC, LogSeverity::Debug(2)));
+ }
+
} // namespace
} // namespace mongo
diff --git a/src/mongo/logger/logger.h b/src/mongo/logger/logger.h
index e6125e4e99b..c3077a14102 100644
--- a/src/mongo/logger/logger.h
+++ b/src/mongo/logger/logger.h
@@ -48,7 +48,7 @@ namespace logger {
/**
* Gets the global MessageLogDomain associated for the global log manager.
*/
- inline MessageLogDomain* globalLogDomain() { return globalLogManager()->getGlobalDomain(); }
+ inline TagMessageLogDomain* globalLogDomain() { return globalLogManager()->getGlobalDomain(); }
} // namespace logger
} // namespace mongo
diff --git a/src/mongo/logger/tag_message_log_domain.cpp b/src/mongo/logger/tag_message_log_domain.cpp
new file mode 100644
index 00000000000..00ca1c32b00
--- /dev/null
+++ b/src/mongo/logger/tag_message_log_domain.cpp
@@ -0,0 +1,82 @@
+/* Copyright 2014 MongoDB 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/tag_message_log_domain.h"
+
+namespace mongo {
+namespace logger {
+
+ TagMessageLogDomain::TagMessageLogDomain() {}
+
+ TagMessageLogDomain::~TagMessageLogDomain() {}
+
+ bool TagMessageLogDomain::hasMinimumLogSeverity(LogTag tag) const {
+ return _settings.hasMinimumLogSeverity(tag);
+ }
+
+ bool TagMessageLogDomain::shouldLog(LogSeverity severity) const {
+ return _settings.shouldLog(severity);
+ }
+
+ bool TagMessageLogDomain::shouldLog(LogTag tag, LogSeverity severity) const {
+ return _settings.shouldLog(tag, severity);
+ }
+
+ bool TagMessageLogDomain::shouldLog(LogTag tag1, LogTag tag2, LogSeverity severity) const {
+ return _settings.shouldLog(tag1, severity) || _settings.shouldLog(tag2, severity);
+ }
+
+ bool TagMessageLogDomain::shouldLog(LogTag tag1, LogTag tag2, LogTag tag3,
+ LogSeverity severity) const {
+ return _settings.shouldLog(tag1, severity) || _settings.shouldLog(tag2, severity) ||
+ _settings.shouldLog(tag3, severity);
+ }
+
+ LogSeverity TagMessageLogDomain::getMinimumLogSeverity() const {
+ return _settings.getMinimumLogSeverity(LogTag::kDefault);
+ }
+
+ LogSeverity TagMessageLogDomain::getMinimumLogSeverity(LogTag tag) const {
+ return _settings.getMinimumLogSeverity(tag);
+ }
+
+ void TagMessageLogDomain::setMinimumLoggedSeverity(LogSeverity severity) {
+ _settings.setMinimumLoggedSeverity(LogTag::kDefault, severity);
+ }
+
+ void TagMessageLogDomain::setMinimumLoggedSeverity(LogTag tag, LogSeverity severity) {
+ _settings.setMinimumLoggedSeverity(tag, severity);
+ }
+
+ void TagMessageLogDomain::clearMinimumLoggedSeverity(LogTag tag) {
+ _settings.clearMinimumLoggedSeverity(tag);
+ }
+
+} // namespace logger
+} // namespace mongo
diff --git a/src/mongo/logger/tag_message_log_domain.h b/src/mongo/logger/tag_message_log_domain.h
new file mode 100644
index 00000000000..59e419d4700
--- /dev/null
+++ b/src/mongo/logger/tag_message_log_domain.h
@@ -0,0 +1,84 @@
+/* Copyright 2014 MongoDB 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 "mongo/logger/log_tag_settings.h"
+#include "mongo/logger/message_log_domain.h"
+
+namespace mongo {
+namespace logger {
+
+ /**
+ * Logging domain for ephemeral messages with minimum severity.
+ */
+ class TagMessageLogDomain : public MessageLogDomain {
+ MONGO_DISALLOW_COPYING(TagMessageLogDomain);
+ public:
+ TagMessageLogDomain();
+
+ ~TagMessageLogDomain();
+
+ /**
+ * 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) const;
+ bool shouldLog(LogTag tag, LogSeverity severity) const;
+ bool shouldLog(LogTag tag1, LogTag tag2, LogSeverity severity) const;
+ bool shouldLog(LogTag tag1, LogTag tag2, LogTag tag3, LogSeverity severity) const;
+
+ /**
+ * Returns true if a minimum log severity has been set for this tag.
+ * Called by log level commands to query tag severity configuration.
+ */
+ bool hasMinimumLogSeverity(LogTag tag) const;
+
+ /**
+ * Gets the minimum severity of messages that should be sent to this LogDomain.
+ */
+ LogSeverity getMinimumLogSeverity() const;
+ LogSeverity getMinimumLogSeverity(LogTag tag) const;
+
+ /**
+ * Sets the minimum severity of messages that should be sent to this LogDomain.
+ */
+ void setMinimumLoggedSeverity(LogSeverity severity);
+ void setMinimumLoggedSeverity(LogTag, LogSeverity severity);
+
+ /**
+ * Clears the minimum log severity for tag.
+ * For kDefault, severity level is initialized to default value.
+ */
+ void clearMinimumLoggedSeverity(LogTag tag);
+
+ private:
+ LogTagSettings _settings;
+ };
+
+} // namespace logger
+} // namespace mongo
diff --git a/src/mongo/util/log.h b/src/mongo/util/log.h
index ab221bd01da..a98b9b161f5 100644
--- a/src/mongo/util/log.h
+++ b/src/mongo/util/log.h
@@ -31,6 +31,7 @@
#include "mongo/base/status.h"
#include "mongo/bson/util/builder.h"
+#include "mongo/logger/log_tag.h"
#include "mongo/logger/logger.h"
#include "mongo/logger/logstream_builder.h"
#include "mongo/logger/tee.h"
@@ -85,12 +86,25 @@ namespace logger {
}
+// MONGO_LOG uses log tag from MongoLogDefaultTag from current or global namespace.
#define MONGO_LOG(DLEVEL) \
- if (!(::mongo::logger::globalLogDomain())->shouldLog(::mongo::LogstreamBuilder::severityCast(DLEVEL))) {} \
+ if (!(::mongo::logger::globalLogDomain())->shouldLog(MongoLogDefaultTag_tag, ::mongo::LogstreamBuilder::severityCast(DLEVEL))) {} \
else LogstreamBuilder(::mongo::logger::globalLogDomain(), getThreadName(), ::mongo::LogstreamBuilder::severityCast(DLEVEL))
#define LOG MONGO_LOG
+#define MONGO_LOG_TAG(DLEVEL, TAG1) \
+ if (!(::mongo::logger::globalLogDomain())->shouldLog((TAG1), ::mongo::LogstreamBuilder::severityCast(DLEVEL))) {} \
+ else LogstreamBuilder(::mongo::logger::globalLogDomain(), getThreadName(), ::mongo::LogstreamBuilder::severityCast(DLEVEL))
+
+#define MONGO_LOG_TAG2(DLEVEL, TAG1, TAG2) \
+ if (!(::mongo::logger::globalLogDomain())->shouldLog((TAG1), (TAG2), ::mongo::LogstreamBuilder::severityCast(DLEVEL))) {} \
+ else LogstreamBuilder(::mongo::logger::globalLogDomain(), getThreadName(), ::mongo::LogstreamBuilder::severityCast(DLEVEL))
+
+#define MONGO_LOG_TAG3(DLEVEL, TAG1, TAG2, TAG3) \
+ if (!(::mongo::logger::globalLogDomain())->shouldLog((TAG1), (TAG2), (TAG3), ::mongo::LogstreamBuilder::severityCast(DLEVEL))) {} \
+ else LogstreamBuilder(::mongo::logger::globalLogDomain(), getThreadName(), ::mongo::LogstreamBuilder::severityCast(DLEVEL))
+
/**
* Rotates the log files. Returns true if all logs rotate successfully.
*
@@ -127,3 +141,24 @@ namespace logger {
void logContext(const char *msg = NULL);
} // namespace mongo
+
+/**
+ * Defines default log tag 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_TAG_FILE(TAG) \
+ static const ::mongo::logger::LogTag MongoLogDefaultTag_tag = (TAG);
+
+/**
+ * MONGO_LOG_DEFAULT_TAG for local code block.
+ */
+#define MONGO_LOG_DEFAULT_TAG_LOCAL(TAG) \
+ const ::mongo::logger::LogTag MongoLogDefaultTag_tag = (TAG);
+
+// Provide log tag in global scope so that MONGO_LOG will always have
+// a valid tag.
+const ::mongo::logger::LogTag MongoLogDefaultTag_tag = ::mongo::logger::LogTag::kDefault;