我有一个日志设置,其中有两种类型的日志消息:
这些属性定义如下:
BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", trivial::severity_level)
BOOST_LOG_ATTRIBUTE_KEYWORD(tag_attr, "Tag", std::string)
我想创建一个过滤器功能,该功能允许根据两个条件之一将消息添加到我的日志中(请注意,基于琐碎的记录器的严重性,基于自定义标签属性的日志消息始终会打印严重性级别信息级别)。
因此,我希望有一个过滤器,该过滤器根据邮件的严重性来确定邮件是否具有自定义标签,如果没有自定义标签,则允许该邮件。
我试图有一个相对简单的过滤器,它执行以下操作:
sink_->set_filter(
trivial::severity >= severityLevel
|| (expr::has_attr(tag_attr) && tag_attr == "JSON" && logJson_)
);
但是,由于严重性级别可能是Debug,Info,Warning,Error或Fatal,因此,如果将级别配置为Debug或Info,则过滤器会忽略自定义标签属性。
我尝试使用c ++ 11 lambda,如下所示:
sink_->set_filter([this, severityLevel](const auto& attr_set) {
if (<condition for custom tag first>) {
return true;
} else if (<condition for severity level second>) {
return true;
} else {
return false;
}
});
但是后来我对如何实际检查我的状况一无所知。我尝试了以下方法:
if (attr_set["Tag"].extract<std::string>() == "JSON" && logJson_) {
return true;
} else if (attr_set["Severity"].extract<trivial::severity_level>() >= severityLevel) {
return true;
} else {
return false;
}
但是编译器会对此抛出一些错误:
Core/Source/Log/Logger.cpp: In lambda function:
Core/Source/Log/Logger.cpp:127:48: error: expected primary-expression before '>' token
if (attr_set["Tag"].extract<std::string>() == "JSON" && logJson_) {
^
Core/Source/Log/Logger.cpp:127:50: error: expected primary-expression before ')' token
if (attr_set["Tag"].extract<std::string>() == "JSON" && logJson_) {
^
Core/Source/Log/Logger.cpp:129:72: error: expected primary-expression before '>' token
} else if (attr_set["Severity"].extract<trivial::severity_level>() >= severityLevel) {
^
Core/Source/Log/Logger.cpp:129:74: error: expected primary-expression before ')' token
} else if (attr_set["Severity"].extract<trivial::severity_level>() >= severityLevel) {
^
Core/Source/Log/Logger.cpp: In lambda function:
Core/Source/Log/Logger.cpp:134:5: error: control reaches end of non-void function [-Werror=return-type]
});
^
cc1plus: all warnings being treated as errors
scons: *** [obj/release/Core/Source/Log/Logger.os] Error 1
====5 errors, 0 warnings====
我一直在搜寻关于自己提取属性的增强日志文档,但是找不到所需的信息。
编辑:
为了后代,我将添加解决问题的方式(感谢Andrey给出的答案):
sink_->set_filter([this, severityLevel](const auto& attr_set) {
if (attr_set[tag_attr] == "JSON") {
return logJson_;
} else if (attr_set[severity] >= severityLevel) {
return true;
} else {
return false;
}
});
过滤器可以用多种方式编写,我将演示一些替代方法。
首先,使用表达式模板可以这样编写:
sink_->set_filter(
(expr::has_attr(tag_attr) && tag_attr == "JSON" && logJson_) ||
trivial::severity >= severityLevel
);
遵循C ++的常规短路规则,将首先测试tag属性,如果该条件成功,将不测试严重性。如果标签不存在或不是JSON或logJson_
不是true,则将测试严重性级别。
请注意,上面的过滤器将在构造时保存其参数的副本(包括logJson_
和severityLevel
),因此,如果您logJson_
稍后进行更改,则过滤器将继续使用旧值。这与您以后使用C ++ 14 lambdas(logJson_
通过捕获的this
指针进行访问)的尝试有很大的不同。如果您确实想logJson_
在过滤器中保存对成员的引用,则可以使用phoenix::ref
:
sink_->set_filter(
(expr::has_attr(tag_attr) && tag_attr == "JSON" && boost::phoenix::ref(logJson_)) ||
trivial::severity >= severityLevel
);
但是,您应该记住,可以在多个线程中同时调用筛选器,因此对访问logJson_
的保护不受保护。如果要logJson_
在运行时进行更新,则必须实现自己的线程同步。
除多线程问题外,您第二次尝试使用lambda几乎是正确的。编译器在抱怨,因为lambda函数是模板,并且attr_set["Tag"]
表达式的结果取决于模板参数之一(即的类型attr_set
)。在这种情况下,程序员必须确定以下extract<std::string>()
表达式是模板实例,而不是比较序列。这可以通过添加template
关键字来完成:
if (attr_set["Tag"].template extract<std::string>() == "JSON" && logJson_) {
return true;
} else if (attr_set["Severity"].template extract<trivial::severity_level>() >= severityLevel) {
return true;
} else {
return false;
}
请注意,您可以使用独立功能达到相同的效果,而无需模板限定:
if (boost::log::extract<std::string>("Tag", attr_set) == "JSON" && logJson_) {
return true;
} else if (boost::log::extract<trivial::severity_level>("Severity", attr_set) >= severityLevel) {
return true;
} else {
return false;
}
最后,提取属性值的首选方法是利用先前声明的属性关键字。这不仅可以避免模板鉴定错误,而且还消除了许多代码重复。
BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", trivial::severity_level)
BOOST_LOG_ATTRIBUTE_KEYWORD(tag_attr, "Tag", std::string)
if (attr_set[tag_attr] == "JSON" && logJson_) {
return true;
} else if (attr_set[severity] >= severityLevel) {
return true;
} else {
return false;
}
在这种情况下,从关键字声明中推断出属性值名称和类型。本部分末尾记录了对属性关键字的使用。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句