summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharles E. Rolke <chug@apache.org>2013-04-26 21:38:07 +0000
committerCharles E. Rolke <chug@apache.org>2013-04-26 21:38:07 +0000
commit81f5d2e11bc921902cab85bd1022d0bdf9d48e44 (patch)
treeecb119835dac7afd47056bcf79ffbf494947709a
parente7bd73ed567ede0f564a10e679a7c0ec402c9f67 (diff)
downloadqpid-python-81f5d2e11bc921902cab85bd1022d0bdf9d48e44.tar.gz
QPID-4651: C++ Broker add --log-disable option
Reviewed at https://reviews.apache.org/r/10799/ git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1476409 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--qpid/cpp/include/qpid/log/Options.h1
-rw-r--r--qpid/cpp/include/qpid/log/Selector.h75
-rw-r--r--qpid/cpp/src/qpid/broker/Broker.cpp10
-rw-r--r--qpid/cpp/src/qpid/log/Logger.cpp1
-rw-r--r--qpid/cpp/src/qpid/log/Options.cpp33
-rw-r--r--qpid/cpp/src/qpid/log/Selector.cpp216
-rw-r--r--qpid/cpp/src/tests/BrokerFixture.h1
-rwxr-xr-xqpid/cpp/src/tests/dynamic_log_level_test49
-rw-r--r--qpid/cpp/src/tests/logging.cpp122
9 files changed, 423 insertions, 85 deletions
diff --git a/qpid/cpp/include/qpid/log/Options.h b/qpid/cpp/include/qpid/log/Options.h
index 819f2c85f1..42a8fb40fe 100644
--- a/qpid/cpp/include/qpid/log/Options.h
+++ b/qpid/cpp/include/qpid/log/Options.h
@@ -39,6 +39,7 @@ struct Options : public qpid::Options {
std::string argv0;
std::string name;
std::vector<std::string> selectors;
+ std::vector<std::string> deselectors;
bool time, level, thread, source, function, hiresTs, category;
bool trace;
std::string prefix;
diff --git a/qpid/cpp/include/qpid/log/Selector.h b/qpid/cpp/include/qpid/log/Selector.h
index 498d4a7342..23b6818cf0 100644
--- a/qpid/cpp/include/qpid/log/Selector.h
+++ b/qpid/cpp/include/qpid/log/Selector.h
@@ -28,6 +28,22 @@ namespace log {
struct Options;
/**
+ * SelectorElement parses a cli/mgmt enable/disable entry into usable fields
+ * where cliEntry = [!]LEVEL[+-][:PATTERN]
+ */
+struct SelectorElement {
+ SelectorElement(const std::string cliEntry);
+ std::string levelStr;
+ std::string patternStr;
+ Level level;
+ Category category;
+ bool isDisable;
+ bool isCategory;
+ bool isLevelAndAbove;
+ bool isLevelAndBelow;
+};
+
+/**
* A selector identifies the set of log messages to enable.
*
* Thread object unsafe, pass-by-value type.
@@ -35,56 +51,45 @@ struct Options;
class Selector {
public:
/** Empty selector selects nothing */
- Selector() {
- reset();
- }
+ Selector();
/** Set selector from Options */
QPID_COMMON_EXTERN Selector(const Options&);
/** Equavlient to: Selector s; s.enable(l, s) */
- Selector(Level l, const std::string& s=std::string()) {
- reset();
- enable(l,s);
- }
+ Selector(Level l, const std::string& s=std::string());
- Selector(const std::string& enableStr) {
- reset();
- enable(enableStr);
- }
+ /** Selector from string */
+ Selector(const std::string& selector);
- /**
- * Enable messages with level in levels where the file
- * name contains substring. Empty string matches all.
- */
- void enable(Level level, const std::string& substring=std::string()) {
- substrings[level].push_back(substring);
- }
+ /** push option settings into runtime lookup structs */
+ QPID_COMMON_EXTERN void enable(const std::string& enableStr);
+ QPID_COMMON_EXTERN void disable(const std::string& disableStr);
/**
- * Enable messages at this level for this category
+ * Enable/disable messages with level in levels where the file
+ * name contains substring. Empty string matches all.
*/
- void enable(Level level, Category category) {
- catFlags[level][category] = true;
- }
-
- /** Enable based on a 'level[+]:file' string */
- QPID_COMMON_EXTERN void enable(const std::string& enableStr);
+ void enable(Level level, const std::string& substring=std::string());
+ void disable(Level level, const std::string& substring=std::string());
- /** True if level is enabled for file. */
+ /** Tests to determine if function names are in enable/disable tables */
QPID_COMMON_EXTERN bool isEnabled(Level level, const char* function);
- QPID_COMMON_EXTERN bool isEnabled(Level level, const char* function, Category category);
+ QPID_COMMON_EXTERN bool isDisabled(Level level, const char* function);
- /** Reset the category enable flags */
- QPID_COMMON_EXTERN void reset() {
- for (int lt = 0; lt < LevelTraits::COUNT; ++lt)
- for (int ct = 0; ct < CategoryTraits::COUNT; ++ct)
- catFlags[lt][ct] = false;
- }
+ /** Test to determine if log Statement is enabled */
+ QPID_COMMON_EXTERN bool isEnabled(Level level, const char* function, Category category);
private:
- std::vector<std::string> substrings[LevelTraits::COUNT];
- bool catFlags[LevelTraits::COUNT][CategoryTraits::COUNT];
+ typedef std::vector<std::string> FunctionNameTable [LevelTraits::COUNT];
+ FunctionNameTable enabledFunctions; // log function names explicitly enabled
+ FunctionNameTable disabledFunctions; // log function names explicitly disabled
+ bool enableFlags[LevelTraits::COUNT][CategoryTraits::COUNT];
+ bool disableFlags[LevelTraits::COUNT][CategoryTraits::COUNT];
+
+ bool lookupFuncName(Level level, const char* function, FunctionNameTable& table);
+ /** Reset the category enable flags */
+ QPID_COMMON_EXTERN void reset();
};
diff --git a/qpid/cpp/src/qpid/broker/Broker.cpp b/qpid/cpp/src/qpid/broker/Broker.cpp
index e059ffba2b..89dac01e19 100644
--- a/qpid/cpp/src/qpid/broker/Broker.cpp
+++ b/qpid/cpp/src/qpid/broker/Broker.cpp
@@ -1018,10 +1018,16 @@ void Broker::setLogLevel(const std::string& level)
std::string Broker::getLogLevel()
{
std::string level;
+ std::string sep("");
const std::vector<std::string>& selectors = qpid::log::Logger::instance().getOptions().selectors;
for (std::vector<std::string>::const_iterator i = selectors.begin(); i != selectors.end(); ++i) {
- if (i != selectors.begin()) level += std::string(",");
- level += *i;
+ level += sep + *i;
+ sep = ",";
+ }
+ const std::vector<std::string>& disselectors = qpid::log::Logger::instance().getOptions().deselectors;
+ for (std::vector<std::string>::const_iterator i = disselectors.begin(); i != disselectors.end(); ++i) {
+ level += sep + "!" + *i;
+ sep = ",";
}
return level;
}
diff --git a/qpid/cpp/src/qpid/log/Logger.cpp b/qpid/cpp/src/qpid/log/Logger.cpp
index 7e7e1e94c1..16b2f56049 100644
--- a/qpid/cpp/src/qpid/log/Logger.cpp
+++ b/qpid/cpp/src/qpid/log/Logger.cpp
@@ -172,6 +172,7 @@ void Logger::configure(const Options& opts) {
void Logger::reconfigure(const std::vector<std::string>& selectors) {
options.selectors = selectors;
+ options.deselectors.clear();
select(Selector(options));
}
diff --git a/qpid/cpp/src/qpid/log/Options.cpp b/qpid/cpp/src/qpid/log/Options.cpp
index 10422bbb1e..b310b7cfac 100644
--- a/qpid/cpp/src/qpid/log/Options.cpp
+++ b/qpid/cpp/src/qpid/log/Options.cpp
@@ -59,16 +59,33 @@ Options::Options(const std::string& argv0_, const std::string& name_) :
("trace,t", optValue(trace), "Enables all logging" )
("log-enable", optValue(selectors, "RULE"),
("Enables logging for selected levels and components. "
- "RULE is in the form 'LEVEL[+][:PATTERN]' "
+ "RULE is in the form 'LEVEL[+-][:PATTERN]'\n"
"LEVEL is one of: \n\t "+levels.str()+"\n"
- "PATTERN is a function name or a catogory: \n\t "+categories.str()+"\n"
+ "PATTERN is a logging category name, or a namespace-qualified "
+ "function name or name fragment. "
+ "Logging category names are: \n\t "+categories.str()+"\n"
"For example:\n"
- "\t'--log-enable warning+' "
+ "\t'--log-enable warning+'\n"
"logs all warning, error and critical messages.\n"
- "\t'--log-enable trace+:Broker' "
+ "\t'--log-enable trace+:Broker'\n"
"logs all category 'Broker' messages.\n"
- "\t'--log-enable debug:framing' "
- "logs debug messages from the framing namespace. "
+ "\t'--log-enable debug:framing'\n"
+ "logs debug messages from all functions with 'framing' in the namespace or function name.\n"
+ "This option can be used multiple times").c_str())
+ ("log-disable", optValue(deselectors, "RULE"),
+ ("Disables logging for selected levels and components. "
+ "RULE is in the form 'LEVEL[+-][:PATTERN]'\n"
+ "LEVEL is one of: \n\t "+levels.str()+"\n"
+ "PATTERN is a logging category name, or a namespace-qualified "
+ "function name or name fragment. "
+ "Logging category names are: \n\t "+categories.str()+"\n"
+ "For example:\n"
+ "\t'--log-disable warning-'\n"
+ "disables logging all warning, notice, info, debug, and trace messages.\n"
+ "\t'--log-disable trace:Broker'\n"
+ "disables all category 'Broker' trace messages.\n"
+ "\t'--log-disable debug-:qmf::'\n"
+ "disables logging debug and trace messages from all functions with 'qmf::' in the namespace.\n"
"This option can be used multiple times").c_str())
("log-time", optValue(time, "yes|no"), "Include time in log messages")
("log-level", optValue(level,"yes|no"), "Include severity level in log messages")
@@ -77,7 +94,7 @@ Options::Options(const std::string& argv0_, const std::string& name_) :
("log-function", optValue(function,"yes|no"), "Include function signature in log messages")
("log-hires-timestamp", optValue(hiresTs,"yes|no"), "Use hi-resolution timestamps in log messages")
("log-category", optValue(category,"yes|no"), "Include category in log messages")
- ("log-prefix", optValue(prefix,"STRING"), "Prefix to append to all log messages")
+ ("log-prefix", optValue(prefix,"STRING"), "Prefix to prepend to all log messages")
;
add(*sinkOptions);
}
@@ -87,6 +104,7 @@ Options::Options(const Options &o) :
argv0(o.argv0),
name(o.name),
selectors(o.selectors),
+ deselectors(o.deselectors),
time(o.time),
level(o.level),
thread(o.thread),
@@ -106,6 +124,7 @@ Options& Options::operator=(const Options& x) {
argv0 = x.argv0;
name = x.name;
selectors = x.selectors;
+ deselectors = x.deselectors;
time = x.time;
level= x.level;
thread = x.thread;
diff --git a/qpid/cpp/src/qpid/log/Selector.cpp b/qpid/cpp/src/qpid/log/Selector.cpp
index 8757486d88..9f52242694 100644
--- a/qpid/cpp/src/qpid/log/Selector.cpp
+++ b/qpid/cpp/src/qpid/log/Selector.cpp
@@ -27,59 +27,209 @@ namespace log {
using namespace std;
-void Selector::enable(const string& enableStr) {
- string level, pattern;
- size_t c=enableStr.find(':');
+const char LOG_SYMBOL_DISABLE ('!');
+const char LOG_SYMBOL_SEPERATOR(':');
+const char LOG_SYMBOL_AND_ABOVE('+');
+const char LOG_SYMBOL_AND_BELOW('-');
+
+//
+// Parse an enable or disable entry into usable fields.
+// Throws if 'level' field is not recognized.
+//
+SelectorElement::SelectorElement(const std::string cliEntry) :
+ level(qpid::log::debug),
+ category(qpid::log::unspecified),
+ isDisable(false),
+ isCategory(false),
+ isLevelAndAbove(false),
+ isLevelAndBelow(false)
+{
+ if (cliEntry.empty())
+ return;
+ std::string working(cliEntry);
+ if (LOG_SYMBOL_DISABLE == working[0]) {
+ isDisable = true;
+ working = working.substr(1);
+ }
+ size_t c=working.find(LOG_SYMBOL_SEPERATOR);
if (c==string::npos) {
- level=enableStr;
+ levelStr=working;
+ } else {
+ levelStr=working.substr(0,c);
+ patternStr=working.substr(c+1);
+ }
+ if (!levelStr.empty()) {
+ if (levelStr[levelStr.size()-1]==LOG_SYMBOL_AND_ABOVE) {
+ isLevelAndAbove = true;
+ levelStr = levelStr.substr(0, levelStr.size()-1);
+ } else if (levelStr[levelStr.size()-1]==LOG_SYMBOL_AND_BELOW) {
+ isLevelAndBelow = true;
+ levelStr = levelStr.substr(0, levelStr.size()-1);
+ }
}
- else {
- level=enableStr.substr(0,c);
- pattern=enableStr.substr(c+1);
+ level = LevelTraits::level(levelStr); // throws if bad level name
+ isCategory = CategoryTraits::isCategory(patternStr);
+ if (isCategory) {
+ category = CategoryTraits::category(patternStr);
}
- bool isCat = CategoryTraits::isCategory(pattern);
- if (!level.empty() && level[level.size()-1]=='+') {
- for (int i = LevelTraits::level(level.substr(0,level.size()-1));
- i < LevelTraits::COUNT;
- ++i) {
- if (isCat) {
- enable(Level(i), CategoryTraits::category(pattern));
+}
+
+// Empty selector
+Selector::Selector() {
+ reset();
+}
+
+
+// Selector from options
+Selector::Selector(const Options& opt){
+ reset();
+ for_each(opt.selectors.begin(), opt.selectors.end(),
+ boost::bind(&Selector::enable, this, _1));
+ for_each(opt.deselectors.begin(), opt.deselectors.end(),
+ boost::bind(&Selector::disable, this, _1));
+}
+
+
+// Selector from single level
+Selector::Selector(Level l, const std::string& s) {
+ reset();
+ enable(l, s);
+}
+
+
+// Selector from single enable
+Selector::Selector(const std::string& selector) {
+ reset();
+ enable(selector);
+}
+
+
+/**
+ * Process a single CLI --log-enable option
+ */
+void Selector::enable(const string& enableStr) {
+ if (enableStr.empty())
+ return;
+ SelectorElement se(enableStr);
+ if (se.isDisable) {
+ // Disable statements are allowed in an enable string as a convenient
+ // way to process management strings that have enable/disable mixed.
+ disable(enableStr);
+ } else if (se.isLevelAndAbove) {
+ for (int lvl = se.level; lvl < LevelTraits::COUNT; ++lvl) {
+ if (se.isCategory) {
+ enableFlags[lvl][se.category] = true;
+ } else {
+ enable(Level(lvl), se.patternStr);
+ }
+ }
+ } else if (se.isLevelAndBelow) {
+ for (int lvl = se.level; lvl >= 0; --lvl) {
+ if (se.isCategory) {
+ enableFlags[lvl][se.category] = true;
} else {
- enable(Level(i), pattern);
+ enable(Level(lvl), se.patternStr);
}
}
+ } else {
+ if (se.isCategory) {
+ enableFlags[se.level][se.category] = true;
+ } else {
+ enable(se.level, se.patternStr);
+ }
}
- else {
- if (isCat) {
- enable(LevelTraits::level(level), CategoryTraits::category(pattern));
+}
+
+void Selector::disable(const string& disableStr) {
+ if (disableStr.empty())
+ return;
+ SelectorElement se(disableStr);
+ if (se.isLevelAndAbove) {
+ for (int lvl = se.level; lvl < LevelTraits::COUNT; ++lvl) {
+ if (se.isCategory) {
+ disableFlags[lvl][se.category] = true;
+ } else {
+ disable(Level(lvl), se.patternStr);
+ }
+ }
+ } else if (se.isLevelAndBelow) {
+ for (int lvl = se.level; lvl >= 0; --lvl) {
+ if (se.isCategory) {
+ disableFlags[lvl][se.category] = true;
+ } else {
+ disable(Level(lvl), se.patternStr);
+ }
+ }
+ } else {
+ if (se.isCategory) {
+ disableFlags[se.level][se.category] = true;
} else {
- enable(LevelTraits::level(level), pattern);
+ disable(se.level, se.patternStr);
}
}
}
-Selector::Selector(const Options& opt){
- reset();
- for_each(opt.selectors.begin(), opt.selectors.end(),
- boost::bind(&Selector::enable, this, _1));
+
+/**
+* Enable/disable messages with level in levels where the file
+* name contains substring.
+*/
+void Selector::enable(Level level, const std::string& substring) {
+ enabledFunctions[level].push_back(substring);
}
-bool Selector::isEnabled(Level level, const char* function) {
+
+void Selector::disable(Level level, const std::string& substring) {
+ disabledFunctions[level].push_back(substring);
+}
+
+
+void Selector::reset() {
+ // Initialize fields in a Selector that are not automatically set
+ for (int lt = 0; lt < LevelTraits::COUNT; ++lt)
+ for (int ct = 0; ct < CategoryTraits::COUNT; ++ct)
+ enableFlags[lt][ct] = disableFlags[lt][ct] = false;
+}
+
+
+bool Selector::lookupFuncName(Level level, const char* function, FunctionNameTable& table) {
const char* functionEnd = function+::strlen(function);
- for (std::vector<std::string>::iterator i=substrings[level].begin();
- i != substrings[level].end();
+ for (std::vector<std::string>::iterator i=table[level].begin();
+ i != table[level].end();
++i)
- {
- if (std::search(function, functionEnd, i->begin(), i->end()) != functionEnd)
- return true;
- }
+ {
+ if (std::search(function, functionEnd, i->begin(), i->end()) != functionEnd)
+ return true;
+ }
return false;
}
+
+bool Selector::isEnabled(Level level, const char* function) {
+ return lookupFuncName(level, function, enabledFunctions);
+}
+
+bool Selector::isDisabled(Level level, const char* function) {
+ return lookupFuncName(level, function, disabledFunctions);
+}
+
+//
+// isEnabled
+//
+// Determines if all the fields in this Selector enable or disable a
+// level/function/category set from an actual QPID_LOG Statement.
+//
bool Selector::isEnabled(Level level, const char* function, Category category) {
- if (catFlags[level][category])
- return true;
- return isEnabled(level, function);
+ if (isDisabled(level, function))
+ return false; // Disabled by function name
+ if (disableFlags[level][category])
+ return false; // Disabled by category name
+ if (isEnabled(level, function))
+ return true; // Enabled by function name
+ if (enableFlags[level][category])
+ return true; // Enabled by category name
+ else
+ return false; // Unspecified defaults to disabled
}
}} // namespace qpid::log
diff --git a/qpid/cpp/src/tests/BrokerFixture.h b/qpid/cpp/src/tests/BrokerFixture.h
index 92c6d22b57..4ce8315c15 100644
--- a/qpid/cpp/src/tests/BrokerFixture.h
+++ b/qpid/cpp/src/tests/BrokerFixture.h
@@ -51,6 +51,7 @@ struct BrokerFixture : private boost::noncopyable {
if (!::getenv("QPID_LOG_ENABLE") && !::getenv("QPID_TRACE")) {
qpid::log::Options logOpts;
logOpts.selectors.clear();
+ logOpts.deselectors.clear();
logOpts.selectors.push_back("error+");
qpid::log::Logger::instance().configure(logOpts);
}
diff --git a/qpid/cpp/src/tests/dynamic_log_level_test b/qpid/cpp/src/tests/dynamic_log_level_test
index 534110e352..7548e40683 100755
--- a/qpid/cpp/src/tests/dynamic_log_level_test
+++ b/qpid/cpp/src/tests/dynamic_log_level_test
@@ -35,23 +35,56 @@ error() {
exit 1;
}
+checklog() {
+ if [[ $(grep echo $LOG_FILE | wc -l) -ne $1 ]]; then
+ cat $LOG_FILE
+ error "Log contents not as expected - " $2
+ fi
+}
+
rm -rf $LOG_FILE
PORT=$($QPIDD_EXEC --auth=no --no-module-dir --daemon --port=0 --log-to-file $LOG_FILE) || error "Could not start broker"
echo Broker for log level test started on $PORT, pid is $($QPIDD_EXEC --no-module-dir --check --port $PORT)
+# Set level to notice+ and send an echo request
+# The 'echo' in the log is hidden since it is at debug level.
$srcdir/qpid-ctrl -b localhost:$PORT setLogLevel level='notice+' > /dev/null
$srcdir/qpid-ctrl -b localhost:$PORT echo sequence=1 body=HIDDEN > /dev/null
+checklog 0 "Step 1 Expected no echo log entries"
+
+# Next, enable all Broker logs at debug and higher levels and send another echo
+# This 'echo' should be in the log.
$srcdir/qpid-ctrl -b localhost:$PORT setLogLevel level='debug+:Broker' > /dev/null
$srcdir/qpid-ctrl -b localhost:$PORT echo sequence=2 body=VISIBLE > /dev/null
-$srcdir/qpid-ctrl -b localhost:$PORT setLogLevel level='notice+' > /dev/null
+checklog 1 "Step 2 Expected one echo log entry"
-#check log includes debug statement for last echo, but not the first
-if [[ $(grep echo $LOG_FILE | wc -l) -ne 1 ]]; then
- cat $LOG_FILE
- error "Log contents not as expected"
-else
- rm -rf $LOG_FILE
- echo OK
+# Now turn on Broker debug messages but specifically disable ManagementMethod logs
+# The 'echo' should be hidden.
+$srcdir/qpid-ctrl -b localhost:$PORT setLogLevel level='debug+:Broker !debug+:broker::Broker::ManagementMethod' > /dev/null
+$srcdir/qpid-ctrl -b localhost:$PORT echo sequence=3 body=HIDDEN > /dev/null
+checklog 1 "Step 3 Expected one echo log entry"
+
+# Verify that the management get returns what was just set
+$srcdir/qpid-ctrl -b localhost:$PORT getLogLevel > dynamic_log_level.tmp
+if [[ $(grep 'level=debug+:Broker,!debug+:broker::Broker::ManagementMethod' dynamic_log_level.tmp | wc -l) -ne 1 ]]; then
+ error "Step 4 getLogLevel returned unexpected value: " `cat dynamic_log_level.tmp`
fi
+rm -rf dynamic_log_level.tmp
+
+cleanup
+
+# Start another broker with --log-disable settings and make sure the management string receives them
+rm -rf $LOG_FILE
+PORT=$($QPIDD_EXEC --auth=no --no-module-dir --daemon --port=0 --log-to-file $LOG_FILE --log-enable debug:foo --log-disable debug:bar) || error "Could not start broker"
+echo Broker for log level test started on $PORT, pid is $($QPIDD_EXEC --no-module-dir --check --port $PORT)
+
+$srcdir/qpid-ctrl -b localhost:$PORT getLogLevel > dynamic_log_level.tmp
+if [[ $(grep 'level=debug:foo,!debug:bar' dynamic_log_level.tmp | wc -l) -ne 1 ]]; then
+ error "Step 5 getLogLevel returned unexpected value: " `cat dynamic_log_level.tmp`
+fi
+rm -rf dynamic_log_level.tmp
+
+rm -rf $LOG_FILE
+echo OK
diff --git a/qpid/cpp/src/tests/logging.cpp b/qpid/cpp/src/tests/logging.cpp
index a29714c002..32cd09d73d 100644
--- a/qpid/cpp/src/tests/logging.cpp
+++ b/qpid/cpp/src/tests/logging.cpp
@@ -85,6 +85,17 @@ QPID_AUTO_TEST_CASE(testSelector_enable) {
BOOST_CHECK(s.isEnabled(critical, "oops"));
}
+QPID_AUTO_TEST_CASE(testSelector_disable) {
+ Selector s;
+ // Simple enable/disable
+ s.enable(trace,"foo");
+ BOOST_CHECK(s.isEnabled(trace,"foo"));
+ BOOST_CHECK(!s.isDisabled(trace,"foo"));
+ s.disable(trace,"foo");
+ BOOST_CHECK(s.isEnabled(trace,"foo"));
+ BOOST_CHECK(s.isDisabled(trace,"foo"));
+}
+
QPID_AUTO_TEST_CASE(testStatementEnabled) {
// Verify that the singleton enables and disables static
// log statements.
@@ -271,6 +282,9 @@ QPID_AUTO_TEST_CASE(testOptionsParse) {
"--log-enable", "error+:foo",
"--log-enable", "debug:bar",
"--log-enable", "info",
+ "--log-disable", "error+:foo",
+ "--log-disable", "debug:bar",
+ "--log-disable", "info",
"--log-to-stderr", "no",
"--log-to-file", "logout",
"--log-level", "yes",
@@ -288,6 +302,7 @@ QPID_AUTO_TEST_CASE(testOptionsParse) {
sinks = *opts.sinkOptions;
vector<string> expect=list_of("error+:foo")("debug:bar")("info");
BOOST_CHECK_EQUAL(expect, opts.selectors);
+ BOOST_CHECK_EQUAL(expect, opts.deselectors);
BOOST_CHECK(!sinks.logToStderr);
BOOST_CHECK(!sinks.logToStdout);
BOOST_CHECK(sinks.logFile == "logout");
@@ -333,6 +348,64 @@ QPID_AUTO_TEST_CASE(testSelectorFromOptions) {
BOOST_CHECK(s.isEnabled(critical, "foo"));
}
+QPID_AUTO_TEST_CASE(testDeselectorFromOptions) {
+ const char* argv[]={
+ 0,
+ "--log-disable", "error-:foo",
+ "--log-disable", "debug:bar",
+ "--log-disable", "info"
+ };
+ qpid::log::Options opts("");
+ opts.parse(ARGC(argv), const_cast<char**>(argv));
+ vector<string> expect=list_of("error-:foo")("debug:bar")("info");
+ BOOST_CHECK_EQUAL(expect, opts.deselectors);
+ Selector s(opts);
+ BOOST_CHECK(!s.isDisabled(warning, "x"));
+ BOOST_CHECK(!s.isDisabled(debug, "x"));
+ BOOST_CHECK(s.isDisabled(debug, "bar"));
+ BOOST_CHECK(s.isDisabled(trace, "foo"));
+ BOOST_CHECK(s.isDisabled(debug, "foo"));
+ BOOST_CHECK(s.isDisabled(info, "foo"));
+ BOOST_CHECK(s.isDisabled(notice, "foo"));
+ BOOST_CHECK(s.isDisabled(warning, "foo"));
+ BOOST_CHECK(s.isDisabled(error, "foo"));
+ BOOST_CHECK(!s.isDisabled(critical, "foo"));
+}
+
+QPID_AUTO_TEST_CASE(testMultiConflictingSelectorFromOptions) {
+ const char* argv[]={
+ 0,
+ "--log-enable", "trace+:foo",
+ "--log-disable", "error-:foo",
+ "--log-enable", "debug:bar",
+ "--log-disable", "debug:bar",
+ "--log-enable", "info",
+ "--log-disable", "info",
+ "--log-enable", "debug+:Model",
+ "--log-disable", "info-:Model"
+ };
+ qpid::log::Options opts("");
+ opts.parse(ARGC(argv), const_cast<char**>(argv));
+ Selector s(opts);
+ BOOST_CHECK(!s.isEnabled(warning, "x", log::broker));
+ BOOST_CHECK(!s.isEnabled(debug, "x", log::broker));
+ BOOST_CHECK(!s.isEnabled(trace, "foo", log::broker));
+ BOOST_CHECK(!s.isEnabled(debug, "foo", log::broker));
+ BOOST_CHECK(!s.isEnabled(info, "foo", log::broker));
+ BOOST_CHECK(!s.isEnabled(notice, "foo", log::broker));
+ BOOST_CHECK(!s.isEnabled(warning, "foo", log::broker));
+ BOOST_CHECK(!s.isEnabled(error, "foo", log::broker));
+ BOOST_CHECK(s.isEnabled(critical, "foo", log::broker));
+ BOOST_CHECK(!s.isEnabled(debug, "bar", log::model));
+ BOOST_CHECK(!s.isEnabled(trace, "zaz", log::model));
+ BOOST_CHECK(!s.isEnabled(debug, "zaz", log::model));
+ BOOST_CHECK(!s.isEnabled(info, "zaz", log::model));
+ BOOST_CHECK(s.isEnabled(notice, "zaz", log::model));
+ BOOST_CHECK(s.isEnabled(warning, "zaz", log::model));
+ BOOST_CHECK(s.isEnabled(error, "zaz", log::model));
+ BOOST_CHECK(s.isEnabled(critical, "zaz", log::model));
+}
+
QPID_AUTO_TEST_CASE(testLoggerStateure) {
Logger& l=Logger::instance();
ScopedSuppressLogging ls(l);
@@ -385,6 +458,55 @@ QPID_AUTO_TEST_CASE(testQuoteNonPrintable) {
unlink("logging.tmp");
}
+QPID_AUTO_TEST_CASE(testSelectorElements) {
+ SelectorElement s("debug");
+ BOOST_CHECK_EQUAL(s.levelStr, "debug");
+ BOOST_CHECK_EQUAL(s.patternStr, "");
+ BOOST_CHECK_EQUAL(s.level, debug);
+ BOOST_CHECK(!s.isDisable);
+ BOOST_CHECK(!s.isCategory);
+ BOOST_CHECK(!s.isLevelAndAbove);
+ BOOST_CHECK(!s.isLevelAndBelow);
+
+ SelectorElement t("debug:Broker");
+ BOOST_CHECK_EQUAL(t.levelStr, "debug");
+ BOOST_CHECK_EQUAL(t.patternStr, "Broker");
+ BOOST_CHECK_EQUAL(t.level, debug);
+ BOOST_CHECK_EQUAL(t.category, broker);
+ BOOST_CHECK(!t.isDisable);
+ BOOST_CHECK(t.isCategory);
+ BOOST_CHECK(!t.isLevelAndAbove);
+ BOOST_CHECK(!t.isLevelAndBelow);
+
+ SelectorElement u("info+:qmf::");
+ BOOST_CHECK_EQUAL(u.levelStr, "info");
+ BOOST_CHECK_EQUAL(u.patternStr, "qmf::");
+ BOOST_CHECK_EQUAL(u.level, info);
+ BOOST_CHECK(!u.isDisable);
+ BOOST_CHECK(!u.isCategory);
+ BOOST_CHECK(u.isLevelAndAbove);
+ BOOST_CHECK(!u.isLevelAndBelow);
+
+ SelectorElement v("critical-");
+ BOOST_CHECK_EQUAL(v.levelStr, "critical");
+ BOOST_CHECK_EQUAL(v.patternStr, "");
+ BOOST_CHECK_EQUAL(v.level, critical);
+ BOOST_CHECK(!v.isDisable);
+ BOOST_CHECK(!v.isCategory);
+ BOOST_CHECK(!v.isLevelAndAbove);
+ BOOST_CHECK(v.isLevelAndBelow);
+
+ SelectorElement w("!warning-:Management");
+ BOOST_CHECK_EQUAL(w.levelStr, "warning");
+ BOOST_CHECK_EQUAL(w.patternStr, "Management");
+ BOOST_CHECK_EQUAL(w.level, warning);
+ BOOST_CHECK_EQUAL(w.category, management);
+ BOOST_CHECK(w.isDisable);
+ BOOST_CHECK(w.isCategory);
+ BOOST_CHECK(!w.isLevelAndAbove);
+ BOOST_CHECK(w.isLevelAndBelow);
+}
+
QPID_AUTO_TEST_SUITE_END()
}} // namespace qpid::tests