blob: a517cb34f47af8de06a12f027546e74a551541db [file] [log] [blame]
/*
*
* Copyright (c) 2006 The Apache Software Foundation
*
* 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 "qpid/log/Selector.h"
#include "qpid/log/Options.h"
#include <boost/bind.hpp>
#include <algorithm>
#include <string.h>
namespace qpid {
namespace log {
using namespace std;
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) {
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);
}
}
level = LevelTraits::level(levelStr); // throws if bad level name
isCategory = CategoryTraits::isCategory(patternStr);
if (isCategory) {
category = CategoryTraits::category(patternStr);
}
}
// 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(lvl), se.patternStr);
}
}
} else {
if (se.isCategory) {
enableFlags[se.level][se.category] = true;
} else {
enable(se.level, se.patternStr);
}
}
}
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 {
disable(se.level, se.patternStr);
}
}
}
/**
* 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);
}
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=table[level].begin();
i != table[level].end();
++i)
{
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 (level==critical)
return true; // critical cannot be disabled
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