为带有自定义属性和严重性级别的增强日志接收器设置自定义过滤器

ThaMe90

我有一个日志设置,其中有两种类型的日志消息:

  • 1仅基于严重性级别
  • 1仅基于自定义标签属性

这些属性定义如下:

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;
    }
});
安德烈·谢马舍夫(Andrey Semashev)

过滤器可以用多种方式编写,我将演示一些替代方法。

首先,使用表达式模板可以这样编写:

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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

Chrome自定义标签和意图过滤器

带有自定义过滤器的Kendo MVVM网格

如何使用自定义规则严重性设置从SonarQube下载Visual Studio的最新SonarLint规则集?

AngularJS按属性和自定义过滤器排序

带有自定义按钮文本和多列的外部过滤器

使用带有ServiceStack.Logging.Serilog的自定义接收器?

在Logcat中设置自定义过滤器

alertmanager:具有自定义POST负载的自定义接收器还是Webhook接收器?

使用自定义属性过滤器的LDAP搜索

ElasticSearch-带有过滤器的自定义分析器-未应用过滤器

带有重音字符和特殊配置的jQuery Tablesorter自定义过滤器出现问题

自定义过滤器属性注入依赖性

Magento自定义属性过滤器

没有媒体的Chromecast自定义接收器

带有自定义过滤器的Protobuf错误

带有自定义过滤器的angularjs ng-options不起作用

没有使用自定义过滤器的XML的安全性配置?

AutoCompleteTextView自定义ArrayAdapter和过滤器性能

自定义查询过滤器

编写自定义方法和自定义过滤器有什么区别?

自定义过滤器排序

带有复选框和单选按钮的AngularJS自定义过滤器

DataTables自定义渲染和自定义过滤器

为 angular ui grid 中的所有自定义过滤器设置一个控制器

FOSElasticaBundle / 自定义过滤器

带有 keras 的卷积网络中的自定义过滤器

带有自定义过滤器的 Ajax 分页器

带有 Django 过滤器的自定义过滤器

kakfa connect - 带有自定义组名称的接收器连接器