提问人:CaTo 提问时间:11/18/2023 更新时间:11/18/2023 访问量:20
提升日志:使用设置文件筛选命名范围
Boost Log: Filtering named scopes using a settings file
问:
我正在我的项目中使用 Boost Log,我希望能够在设置文件中筛选我当前对控制台接收器感兴趣的范围。
我使用以下方法添加了名称范围属性:
BOOST_LOG_ATTRIBUTE_KEYWORD(scope_attr, "Scope", boost::log::attributes::named_scope::value_type)
boost::log::core::get()->add_global_attribute("Scope", boost::log::attributes::named_scope());
在代码中,我使用 BOOST_LOG_NAMED_SCOPE 宏,并使用 boost::log::init_from_stream 传递以下设置:
[Core]
DisableLogging = false
Filter = "%Severity% >= DEBUG"
[Sinks.1]
Destination = Console
Format = "[%Severity%] [%TimeStamp%] [%Scope%] [%Tag%]: %Message%"
Filter = "%Scope% = \"TargetScope\" & %Severity% >= DEBUG"
[Sinks.2]
Destination = TextFile
FileName = textfile.log
AutoFlush = true
Format = "[%Severity%] [%TimeStamp%] [%Scope%] [%Tag%]: %Message%"
在未激活过滤器的情况下,“Scope”属性工作正常,并正确打印,在范围之间添加“->”,并且有些日志中只有目标范围被打印为“...[目标范围] ...”。但是,如果我激活过滤器,则不会打印任何内容。
默认情况下是否支持筛选命名范围?还是应该为过滤器解析系统编写一个扩展?
答:
1赞
sehe
11/18/2023
#1
必须注意的是,默认情况下,库仅支持在库构建时已知的属性值类型。在库中注册之前,用户定义的类型将无法在解析的过滤器和格式化程序中正常工作。还可以覆盖已知类型的格式规则,包括支持字符串模板中的其他格式参数。有关此内容的更多信息,请参阅扩展库部分。
从 Boost 日志记录中,按命名范围过滤,您可以获得一个过滤函数(由我简化):
bool my_filter(bl::value_ref<attr::named_scope_list> const& scopes, std::string const& target_scope) {
if (!scopes.empty())
for (auto& scope : scopes.get())
if (scope.scope_name == target_scope)
return true;
return false;
}
解析过滤器
在这里,我们必须扩展库设置支持。
向筛选器分析器添加对用户定义类型的支持可提供一些步骤。
我选择了自定义(非简单)过滤器工厂,并将其与广义匹配函数相结合,如刚才所示、命名和:my_filter
all
any
struct scope_filter_factory : bl::filter_factory<char> {
bl::filter on_equality_relation(bl::attribute_name const& name, string_type const& arg) override {
return px::bind(any<std::equal_to<>>, //
expr::attr<attr::named_scope_list>(name).or_none(), //
arg);
}
bl::filter on_inequality_relation(bl::attribute_name const& name, string_type const& arg) override {
return px::bind(all<std::not_equal_to<>>, //
expr::attr<attr::named_scope_list>(name).or_none(), //
arg);
}
private:
using list = attr::named_scope_list;
template <typename Rel>
static bool any(bl::value_ref<list> const& attr, std::string const& target_scope) {
if (attr.empty())
return false;
return std::any_of(begin(attr.get()), end(attr.get()), [&, cmp = Rel{}](auto const& scope) {
return cmp(scope.scope_name, target_scope);
});
}
template <typename Rel>
static bool all(bl::value_ref<list> const& attr, std::string const& target_scope) {
if (attr.empty())
return true;
return std::all_of(begin(attr.get()), end(attr.get()), [&, cmp = Rel{}](auto const& scope) {
return cmp(scope.scope_name, target_scope);
});
}
};
您用 注册它,例如:register_filter_factory
void init_logging() {
bl::core::get()->add_global_attribute("Scope", attr::named_scope());
bl::register_filter_factory("Scope", boost::make_shared<scope_filter_factory>());
std::ifstream ifs("logging.cfg");
bl::init_from_stream(ifs);
}
然后,我们可以使用一些函数进行测试,例如
void bar(log_level level) {
BOOST_LOG_NAMED_SCOPE(__FUNCTION__);
BOOST_LOG_SEV(glg, level) << __FUNCTION__ << ":" << 222;
BOOST_LOG_SEV(glg, level) << __FUNCTION__ << ":" << 333;
}
void foo(log_level level) {
BOOST_LOG_NAMED_SCOPE(__FUNCTION__);
BOOST_LOG_SEV(glg, level) << __FUNCTION__ << ":" << 333;
bar(level);
BOOST_LOG_SEV(glg, level) << __FUNCTION__ << ":" << 444;
}
int main() {
init_logging();
for (auto level : {log_level::trace, log_level::debug, log_level::info, //
log_level::warning, log_level::error, log_level::fatal})
foo(level);
}
完整清单
#include <boost/log/attributes/named_scope.hpp>
#include <boost/log/attributes/scoped_attribute.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/utility/setup.hpp>
#include <boost/phoenix.hpp>
#include <fstream>
namespace bl = boost::log;
namespace attr = bl::attributes;
namespace expr = bl::expressions;
namespace px = boost::phoenix;
using log_level = bl::trivial::severity_level;
bl::sources::severity_logger<log_level> glg;
BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", bl::trivial::severity_level)
BOOST_LOG_ATTRIBUTE_KEYWORD(scope_attr, "Scope", attr::named_scope::value_type)
// ============================================================================
// Custom filter factory
struct scope_filter_factory : bl::filter_factory<char> {
bl::filter on_equality_relation(bl::attribute_name const& name, string_type const& arg) override {
return px::bind(any<std::equal_to<>>, //
expr::attr<attr::named_scope_list>(name).or_none(), //
arg);
}
bl::filter on_inequality_relation(bl::attribute_name const& name, string_type const& arg) override {
return px::bind(all<std::not_equal_to<>>, //
expr::attr<attr::named_scope_list>(name).or_none(), //
arg);
}
private:
using list = attr::named_scope_list;
template <typename Rel>
static bool any(bl::value_ref<list> const& attr, std::string const& target_scope) {
if (attr.empty())
return false;
return std::any_of(begin(attr.get()), end(attr.get()), [&, cmp = Rel{}](auto const& scope) {
return cmp(scope.scope_name, target_scope);
});
}
template <typename Rel>
static bool all(bl::value_ref<list> const& attr, std::string const& target_scope) {
if (attr.empty())
return true;
return std::all_of(begin(attr.get()), end(attr.get()), [&, cmp = Rel{}](auto const& scope) {
return cmp(scope.scope_name, target_scope);
});
}
};
void init_logging() {
bl::core::get()->add_global_attribute("Scope", attr::named_scope());
bl::register_filter_factory("Scope", boost::make_shared<scope_filter_factory>());
std::ifstream ifs("logging.cfg");
bl::init_from_stream(ifs);
}
// ============================================================================
void bar(log_level level) {
BOOST_LOG_NAMED_SCOPE(__FUNCTION__);
BOOST_LOG_SEV(glg, level) << __FUNCTION__ << ":" << 222;
BOOST_LOG_SEV(glg, level) << __FUNCTION__ << ":" << 333;
}
void foo(log_level level) {
BOOST_LOG_NAMED_SCOPE(__FUNCTION__);
BOOST_LOG_SEV(glg, level) << __FUNCTION__ << ":" << 333;
bar(level);
BOOST_LOG_SEV(glg, level) << __FUNCTION__ << ":" << 444;
}
int main() {
init_logging();
for (auto level : {log_level::trace, log_level::debug, log_level::info, //
log_level::warning, log_level::error, log_level::fatal})
foo(level);
}
评论