On this page
第 7 章:过滤器
**有很多主意,可丢掉坏主意。除非您有很多想法和某种选择原则,否则您将不会有好的想法.
—LINUS PAULING**
在前面的章节中,介绍了基本选择规则,它是 logback-classic 的核心。在本章中,将介绍其他过滤方法。
Logback 过滤器基于三元逻辑,允许将它们组装或链接在一起以构成任意复杂的过滤策略。它们很大程度上受到 Linux iptables 的启发。
In logback-classic
Logback-classic 提供两种类型的过滤器,常规过滤器和 Turbine 过滤器。
Regular filters
常规的 logback-classic 过滤器扩展了Filter抽象类,该类基本上由一个以ILoggingEvent实例作为参数的decide()方法组成。
过滤器被组织成一个有序列表,并基于三元逻辑。依次调用每个过滤器的decide(ILoggingEvent event)方法。此方法返回FilterReply枚举值之一,即DENY,NEUTRAL或ACCEPT之一。如果decide()返回的值为DENY,则立即丢弃日志事件,而无需咨询其余过滤器。如果返回的值为NEUTRAL,则查询列表中的下一个过滤器。如果没有其他过滤器可参考,则将正常处理日志记录事件。如果返回的值为ACCEPT,则将立即跳过其余过滤器的调用来处理日志记录事件。
在经典的 logback 模式中,可以将过滤器添加到Appender个实例。通过将一个或多个过滤器添加到附加程序,可以按任意条件过滤事件,例如日志消息的内容,MDC 的内容,一天中的时间或日志事件的任何其他部分。
实施自己的过滤器
创建自己的过滤器很容易。您要做的就是扩展Filter抽象类并实现decide()方法。
下面显示的 SampleFilter 类提供了一个示例。其decide方法返回 ACCEPT 来记录其消息字段中包含字符串“ sample”的事件。对于其他事件,返回值 NEUTRAL。
例如:基本的自定义过滤器(logback-examples/src/main/java/chapters/filters/SampleFilter.java)
package chapters.filters;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.filter.Filter;
import ch.qos.logback.core.spi.FilterReply;
public class SampleFilter extends Filter<ILoggingEvent> {
@Override
public FilterReply decide(ILoggingEvent event) {
if (event.getMessage().contains("sample")) {
return FilterReply.ACCEPT;
} else {
return FilterReply.NEUTRAL;
}
}
}
接下来显示的配置文件将SampleFilter附加到ConsoleAppender。
*示例:SampleFilter 配置(logback-examples/src/main/resources/chapters/filters/SampleFilterConfig.xml)*查看为.groovy
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<filter class="chapters.filters.SampleFilter" />
<encoder>
<pattern>
%-4relative [%thread] %-5level %logger - %msg%n
</pattern>
</encoder>
</appender>
<root>
<appender-ref ref="STDOUT" />
</root>
</configuration>
借助 Logback 的配置框架 Joran 的帮助,为过滤器指定属性或子组件也很容易。在过滤器类中添加了相应的 setter 方法之后,请在以该属性命名的 xml 元素中指定该属性的值,并将其嵌套在<filter>元素内。
通常,所需的滤波器逻辑由两个正交部分组成,一个匹配/不匹配测试和一个取决于匹配/不匹配的响应。例如,对于给定的测试,例如消息等于“ foobar”,一个过滤器可能在匹配时响应 ACCEPT 而在不匹配时响应 NEUTRAL,而另一个过滤器可能在匹配时响应 NEUTRAL 而在不匹配时响应 DENY。
注意这一正交性,logback 附带了AbstractMatcherFilter类,该类提供了一个有用的框架,借助两个属性* OnMatch 和 OnMismatch *,可以指定对匹配和不匹配的适当响应。 logback 中包含的大多数常规过滤器均源自AbstractMatcherFilter。
LevelFilter
LevelFilter根据确切的级别匹配过滤事件。如果事件的级别等于已配置的级别,则过滤器将接受或拒绝事件,具体取决于 onMatch 和 onMismatch 属性的配置。这是一个示例配置文件。
*示例:示例 LevelFilter 配置(logback-examples/src/main/resources/chapters/filters/levelFilterConfig.xml)*查看为.groovy
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<encoder>
<pattern>
%-4relative [%thread] %-5level %logger{30} - %msg%n
</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="CONSOLE" />
</root>
</configuration>
ThresholdFilter
ThresholdFilter过滤低于指定阈值的事件。对于等于或高于阈值的事件,当ThresholdFilter的decide()方法被调用时,它将响应 NEUTRAL。但是,级别低于阈值的事件将被拒绝。这是一个示例配置文件。
*示例:示例 ThresholdFilter 配置(logback-examples/src/main/resources/chapters/filters/thresholdFilterConfig.xml)*查看为.groovy
<configuration>
<appender name="CONSOLE"
class="ch.qos.logback.core.ConsoleAppender">
<!-- deny all events with a level below INFO, that is TRACE and DEBUG -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<encoder>
<pattern>
%-4relative [%thread] %-5level %logger{30} - %msg%n
</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="CONSOLE" />
</root>
</configuration>
EvaluatorFilter
EvaluatorFilter是封装EventEvaluator的通用过滤器。顾名思义,EventEvaluator评估给定事件是否满足给定条件。在匹配和不匹配时,主机EvaluatorFilter将分别返回由 onMatch 或 onMismatch 属性指定的值。
请注意,EventEvaluator是抽象类。您可以通过子类EventEvaluator来实现自己的事件评估逻辑。
GEventEvaluator
GEventEvaluator是具体的EventEvaluator实现,它采用任意 Groovy 语言布尔表达式作为评估标准。我们将此类 Groovy 语言布尔表达式称为“ groovy 评估表达式”。 Groovy 评估表达式为事件过滤提供了前所未有的灵 Active。 GEventEvaluator需要 Groovy 运行时。在将 Groovy 运行时添加到 Classpath 时,请参阅安装文档的corresponding section。
评估表达式是在配置文件的解释过程中即时编译的。作为用户,您不必担心实际的管道问题。但是,您有责任确保 groovy 语言表达式有效。
评估表达式作用于当前的日志事件。 Logback 会自动将类型为ILoggingEvent的当前日志记录事件作为变量“ * event *”以及其简写形式“ * e *”插入。变量 TRACE,DEBUG,INFO,WARN 和 ERROR 也会导出到表达式的范围内。因此,“ event.level == DEBUG”和“ e.level == DEBUG”是等效且有效的常规表达式,仅当当前日志记录事件的级别与 DEBUG 相同时才返回true。对于级别上的其他比较运算符,应该使用toInt()运算符将级别字段转换为整数。
这是一个更完整的示例。
观看为.groovy
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
<evaluator class="ch.qos.logback.classic.boolex.GEventEvaluator">
<expression>
e.level.toInt() >= WARN.toInt() && <!-- Stands for && in XML -->
!(e.mdc?.get("req.userAgent") =~ /Googlebot|msnbot|Yahoo/ )
</expression>
</evaluator>
<OnMismatch>DENY</OnMismatch>
<OnMatch>NEUTRAL</OnMatch>
</filter>
<encoder>
<pattern>
%-4relative [%thread] %-5level %logger - %msg%n
</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="STDOUT" />
</root>
</configuration>
除非错误是由与 Google,MSN 或 Yahoo 关联的 Web 搜寻器生成的,否则上述过滤器将使 WARN 级及更高级别的事件通过控制台。通过检查与事件关联的 MDC 是否包含与/Googlebot|msnbot|Yahoo/正则表达式匹配的“ req.userAgent”的值来实现此目的。请注意,由于 MDCMap 可以为 null,因此我们也使用 Groovy 的安全解引用运算符,即?。操作员。如果用 Java 表示,等效逻辑将更长。
如果您想知道用户代理的标识符是如何在'req.userAgent'键下插入 MDC 的,那么我们应该提到 logback 附带了一个名为MDCInsertingServletFilter的 servlet 过滤器。将在下一章中进行描述。
JaninoEventEvaluator
Logback-classic 附带了另一个名为JaninoEventEvaluator的具体EventEvaluator实现,它采用任意 Java 语言块返回布尔值作为评估标准。我们将此类 Java 语言布尔表达式称为“ * evaluation expressions *”。评估表达式为事件过滤提供了极大的灵 Active。 JaninoEventEvaluator要求Janino library。请参阅安装文档的corresponding section。与JaninoEventEvaluator相比,借助 Groovy 语言,GEventEvaluator更加方便使用,但是JaninoEventEvaluator通常对于等效表达式运行(快得多)。
评估表达式是在配置文件的解释过程中即时编译的。作为用户,您不必担心实际的管道问题。但是,您有责任确保 Java 语言表达式返回一个布尔值,即它的计算结果为 true 或 false。
评估表达式是在当前日志记录事件上评估的。 Logback-classic 自动将日志记录事件的各个字段导出为可从评估表达式访问的变量。下面列出了这些导出变量的区分大小写的名称。
| Name | Type | Description |
|---|---|---|
| event | LoggingEvent |
与日志记录请求关联的原始日志记录事件。事件中还提供以下所有变量。例如,event.getMessage()返回与下面描述的* message *变量相同的 String 值。 |
| message | String |
日志记录请求的原始消息。对于某些 Logger* l *,当您编写 l.info(“ Hello{}”,name);其中为名称分配了值“ Alice”,则消息为“ Hello{}”。 |
| formattedMessage | String |
日志记录请求中的格式化消息。对于某些 Logger* l *,当您编写 l.info(“ Hello{}”,name);其中为名称分配了值“ Alice”,则“ Hello Alice”是格式化的消息。 |
| logger | String |
Logger 的名称。 |
| loggerContext | LoggerContextVO | 记录事件所属的 Logger 上下文的受限(值对象)视图。 |
| level | int |
对应于级别的 int 值。为了帮助轻松创建涉及级别的表达式,还提供了默认值* DEBUG , INFO , WARN 和 ERROR 。因此,使用 level> INFO *是正确的表达式。 |
| timeStamp | long |
与记录事件的创建相对应的时间戳。 |
| marker | Marker |
与日志记录请求关联的Marker对象。请注意,标记可以为 null,您有责任检查此条件以避免NullPointerException。 |
| mdc | Map |
在创建日志记录事件时包含所有 MDC 值的 Map。可以使用以下表达式访问值:* mdc.get(“ myKey”)*。从经典 logback 版本 0.9.30 开始,“ mdc”变量将永远不会为 null。 |
java.util.Map类型是非参数化的,因为 Janino 不支持泛型。因此,由mdc.get()返回的类型是Object而不是String。要对返回的值调用String方法,必须将其强制转换为String。例如((String) mdc.get("k")).contains("val")。
| throwable | java.lang.Throwable |如果没有异常与事件关联,则“ throwable”变量的值将为 null。不幸的是,“ throwable”无法在序列化中幸免。因此,在远程系统上,其值将始终为 null。对于位置无关的表达式,请使用下面描述的throwableProxy变量。 |
| throwableProxy | IThrowableProxy |与日志记录事件关联的异常的代理。如果没有异常与事件关联,则“ throwableProxy”变量的值将为 null。与“ throwable”相反,当异常与事件相关联时,即使在远程系统上(即在序列化之后),“ throwableProxy”的值也不会为空。 |
这是一个具体的例子。
*示例:基本事件评估程序的用法(logback-examples/src/main/resources/chapters/filters/basicEventEvaluator.xml)*查看为.groovy
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
<evaluator> <!-- defaults to type ch.qos.logback.classic.boolex.JaninoEventEvaluator -->
<expression>return message.contains("billing");</expression>
</evaluator>
<OnMismatch>NEUTRAL</OnMismatch>
<OnMatch>DENY</OnMatch>
</filter>
<encoder>
<pattern>
%-4relative [%thread] %-5level %logger - %msg%n
</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>
上面的配置文件中的粗体部分将EvaluatorFilter添加到ConsoleAppender。然后将类型JaninoEventEvaluator的评估器注入EvaluatorFilter。如果用户指定的<evaluator>元素中没有 class 属性,Joran 将为评估者推断默认类型JaninoEventEvaluator。这是few occurrences之一,其中 Joran 隐式推断组件的类型。
- expression 元素对应于刚刚讨论的评估表达式。表达式
return message.contains("billing");返回布尔值。注意, message *变量由JaninoEventEvaluator自动导出。
假定 OnMismatch 属性设置为 NEUTRAL 且 OnMatch 属性设置为 DENY,则此评估程序过滤器将删除其消息包含字符串“ billing”的所有日志记录事件。
FilterEvents应用程序发出 10 个日志记录请求,编号为 0 到 9.让我们首先运行FilterEvents类,不使用任何过滤器:
java chapters.filters.FilterEvents src/main/java/chapters/filters/basicConfiguration.xml
将显示所有请求,如下所示:
0 [main] INFO chapters.filters.FilterEvents - logging statement 0
0 [main] INFO chapters.filters.FilterEvents - logging statement 1
0 [main] INFO chapters.filters.FilterEvents - logging statement 2
0 [main] DEBUG chapters.filters.FilterEvents - logging statement 3
0 [main] INFO chapters.filters.FilterEvents - logging statement 4
0 [main] INFO chapters.filters.FilterEvents - logging statement 5
0 [main] ERROR chapters.filters.FilterEvents - billing statement 6
0 [main] INFO chapters.filters.FilterEvents - logging statement 7
0 [main] INFO chapters.filters.FilterEvents - logging statement 8
0 [main] INFO chapters.filters.FilterEvents - logging statement 9
假设我们要摆脱“计费声明”。上面列出的* basicEventEvaluator.xml *配置文件对包含字符串“ billing”的消息进行过滤,这恰好是所需的结果。
使用* basicEventEvaluator.xml *运行:
Java Chapters.filters.FilterEvents src/main/java/chapters/filters/basicEventEvaluator.xml
we obtain:
0 [main] INFO 的 chapters.filters.FilterEvents-日志记录语句 0 0 [main] INFO 的 chapters.filters.FilterEvents-日志记录语句 1 0 [main] INFO 的 chapters.filters.FilterEvents-日志记录语句 2 0 [main]调试的 Chapters.filters .FilterEvents-日志记录语句 3 0 [main] INFO 章.filters.FilterEvents-日志记录语句 4 0 [main] INFO 章.filters.FilterEvents-日志记录语句 5 0 [main] INFO Chapters.filters.FilterEvents-日志记录语句 7 0 [ [主] INFO 的 chapters.filters.FilterEvents-日志记录语句 8 0 [主] INFO 的 chapters.filters.FilterEvents-日志记录语句 9
评估表达式可以是 Java 块。例如,以下是有效的表达式。
<evaluator>
<expression>
if(logger.startsWith("org.apache.http"))
return true;
if(mdc == null || mdc.get("entity") == null)
return false;
String payee = (String) mdc.get("entity");
if(logger.equals("org.apache.http.wire") && <!-- & encoded as & -->
payee.contains("someSpecialValue") &&
!message.contains("someSecret")) {
return true;
}
return false;
</expression>
</evaluator>
Matchers
尽管可以通过调用String类中的matches()方法进行模式匹配,但这会导致每次调用过滤器时都要编译一个全新的Pattern对象。为了消除这种开销,您可以 sched 义一个或多个Matcher对象。定义匹配器后,可以在评估器表达式中按名称重复引用它。
一个例子可以阐明这一点:
*示例:在事件评估器中定义匹配器(logback-examples/src/main/resources/chapters/filters/evaluatorWithMatcher.xml)*查看为.groovy
<configuration debug="true">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
<evaluator>
<matcher>
<Name>odd</Name>
<!-- filter out odd numbered statements -->
<regex>statement [13579]</regex>
</matcher>
<expression>odd.matches(formattedMessage)</expression>
</evaluator>
<OnMismatch>NEUTRAL</OnMismatch>
<OnMatch>DENY</OnMatch>
</filter>
<encoder>
<pattern>%-4relative [%thread] %-5level %logger - %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="STDOUT" />
</root>
</configuration>
使用* evaluatorWithMatcher.xml *运行:
Java Chapters.filters.FilterEvents src/main/java/chapters/filters/evaluatorWithMatcher.xml
we obtain:
260 [main] INFO 的 chapters.filters.FilterEvents-日志记录语句 0 264 [main] INFO 的 chapters.filters.FilterEvents-日志记录语句 2264 [main] INFO 的 chapters.filters.FilterEvents-日志记录语句 4 266 [main] ERROR 的 chapters.filters .FilterEvents-结算语句 6 266 [main] INFO 章节。filters.FilterEvents-日志记录语句 8
如果需要定义其他匹配器,可以通过添加更多的<matcher>元素来实现。
TurboFilters
TurboFilter个对象都扩展了TurboFilter抽象类。像常规过滤器一样,它们使用三元逻辑返回对日志记录事件的评估。
总体而言,它们的工作方式与前面提到的过滤器非常相似。但是,Filter和TurboFilter对象之间有两个主要区别。
TurboFilter个对象绑定到日志记录上下文。因此,它们不仅在使用给定的附加程序时被调用,而且在每次发出日志记录请求时都被调用。它们的范围比附加附加过滤器的范围大。
更重要的是,它们在创建LoggingEvent对象之前被调用。 TurboFilter对象不需要实例化日志记录事件即可过滤日志记录请求。这样,即使在事件创建之前,turbo 过滤器也旨在对日志事件进行高性能过滤。
实现自己的 TurboFilter
要创建自己的TurboFilter组件,只需扩展TurboFilter抽象类。如前所述,实现自定义过滤器对象时,开发自定义TurboFilter仅要求实现decide()方法。在下一个示例中,我们创建一个稍微复杂一些的过滤器:
例如:基本自定义TurboFilter(logback-examples/src/main/java/chapters/filters/SampleTurboFilter.java)
package chapters.filters;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.turbo.TurboFilter;
import ch.qos.logback.core.spi.FilterReply;
public class SampleTurboFilter extends TurboFilter {
String marker;
Marker markerToAccept;
@Override
public FilterReply decide(Marker marker, Logger logger, Level level,
String format, Object[] params, Throwable t) {
if (!isStarted()) {
return FilterReply.NEUTRAL;
}
if ((markerToAccept.equals(marker))) {
return FilterReply.ACCEPT;
} else {
return FilterReply.NEUTRAL;
}
}
public String getMarker() {
return marker;
}
public void setMarker(String markerStr) {
this.marker = markerStr;
}
@Override
public void start() {
if (marker != null && marker.trim().length() > 0) {
markerToAccept = MarkerFactory.getMarker(marker);
super.start();
}
}
}
上面的TurboFilter接受包含特定标记的事件。如果找不到所述标记,则过滤器将责任传递给链中的下一个过滤器。
为了提供更大的灵 Active,可以在配置文件中指定要测试的标记,因此可以指定 getter 和 setter 方法。我们还实现了start()方法,以检查是否在配置过程中指定了该选项。
这是一个使用我们新创建的TurboFilter的示例配置。
*示例:基本的自定义TurboFilter配置(logback-examples/src/main/resources/chapters/filters/sampleTurboFilterConfig.xml)*以.groovy 格式查看
<configuration>
<turboFilter class="chapters.filters.SampleTurboFilter">
<Marker>sample</Marker>
</turboFilter>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>
%-4relative [%thread] %-5level %logger - %msg%n
</pattern>
</encoder>
</appender>
<root>
<appender-ref ref="STDOUT" />
</root>
</configuration>
经典的 Logback 附带了几个可供使用的TurboFilter类。 MDCFilter检查 MDC 中是否存在给定值,而DynamicThresholdFilter允许基于 MDC 密钥/级别阈值关联进行过滤。另一方面,MarkerFilter检查是否存在与日志记录请求关联的特定标记。
这是使用MDCFilter和MarkerFilter的示例配置。
*示例:MDCFilter和MarkerFilter配置(logback-examples/src/main/resources/chapters/filters/turboFilters.xml)*以.groovy 格式查看
<configuration>
<turboFilter class="ch.qos.logback.classic.turbo.MDCFilter">
<MDCKey>username</MDCKey>
<Value>sebastien</Value>
<OnMatch>ACCEPT</OnMatch>
</turboFilter>
<turboFilter class="ch.qos.logback.classic.turbo.MarkerFilter">
<Marker>billing</Marker>
<OnMatch>DENY</OnMatch>
</turboFilter>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%date [%thread] %-5level %logger - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="console" />
</root>
</configuration>
您可以通过发出以下命令来查看此配置的运行情况:
Java Chapters.filters.FilterEvents src/main/java/chapters/filters/turboFilters.xml
如我们先前所见,FilterEvents应用程序发出 10 个日志记录请求,编号为 0 到 9.除了请求 3 和 6,所有请求的级别均为* INFO ,与分配给根 Logger 的级别相同。第三请求以 DEBUG 级别发出,该级别低于有效级别。但是,由于 MDC 密钥“用户名”在第三个请求之前被设置为“ sebastien”,而在此之后被删除,因此MDCFilter专门接受该请求(并且仅接受该请求)。以 ERROR *级别发出的第六个请求被标记为“计费”。因此,它被 MarkerFilter(配置中的第二个 Turbine 过滤器)拒绝。
因此,使用上面显示的* turboFilters.xml *文件配置的FilterEvents应用程序的输出为:
2006 -12-04 15:17:22,859 [main] INFO pages.filters.FilterEvents-记录语句 0 2006-12-04 15:17:22,875 [main] INFO pages.filters.FilterEvents-记录语句 1 2006-12- 04 15:17:22,875 [主要] INFO pages.filters.FilterEvents-记录语句 2 2006-12-04 15:17:22,875 [主要]调试 chapters.filters.FilterEvents-记录语句 3 2006-12-04 15:17 :22,875 [main] INFO pages.filters.FilterEvents-日志记录语句 4 2006-12-04 15:17:22,875 [main] INFO chapters.filters.FilterEvents-日志记录语句 5 2006-12-04 15:17:22,875 [main] ] INFO chapters.filters.FilterEvents-日志记录语句 7 2006-12-04 15:17:22,875 [main] INFO CHAPTER..filters.FilterEvents-日志记录语句 8 2006-12-04 15:17:22,875 [main] INFO 章。 filter.FilterEvents-日志记录语句 9
可以看到,无论如何,如果我们只遵循整体* INFO *级别,则不应显示第三条请求,因为它符合第一个TurboFilter要求并被接受。
另一方面,应该已经显示了第六个请求,即* ERROR 级请求。但是它满足了第二个TurboFilter,其 OnMatch 选项设置为 DENY *。因此,没有显示第 6 个请求。
DuplicateMessageFilter
DuplicateMessageFilter值得单独介绍。该过滤器检测重复的消息,并在超过一定重复次数后丢弃重复的消息。
为了检测重复,此过滤器在消息之间使用简单的字符串相等性。它不会检测非常相似的消息(仅相差几个字符)。例如,如果您编写:
logger.debug("Hello "+name0);
logger.debug("Hello "+name1);
假设name0和name1具有不同的值,则两个“ Hello”消息将被视为无关。根据用户需求,将来的发行版可能会检查字符串的相似性,从而消除相似但不相同的消息的重复。
请注意,在参数化日志记录的情况下,仅考虑原始消息。例如,在接下来的两个请求中,原始消息即“ Hello{}”是相同的,因此被视为重复。
logger.debug("Hello {}.", name0);
logger.debug("Hello {}.", name1);
允许的重复次数可以由 AllowedRepetitions 属性指定。例如,如果该属性设置为 1,则将删除同一消息的第二次及以后出现。同样,如果将该属性设置为 2,则将删除同一消息的第 3 次及以后出现。默认情况下,AllowedRepetitions 属性设置为 5.
为了检测重复,此过滤器需要在内部缓存中保留对旧消息的引用。此缓存的大小由 CacheSize 属性确定。默认情况下,它设置为 100.
*示例:DuplicateMessageFilter配置(logback-examples/src/main/resources/chapters/filters/duplicateMessage.xml)*以.groovy 格式查看
<configuration>
<turboFilter class="ch.qos.logback.classic.turbo.DuplicateMessageFilter"/>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%date [%thread] %-5level %logger - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="console" />
</root>
</configuration>
因此,使用* duplicateMessage.xml *配置的FilterEvents应用程序的输出为:
2008 -12-19 15:04:26,156 [main] INFO pages.filters.FilterEvents-记录语句 0 2008-12-19 15:04:26,156 [main] INFO chapters.filters.FilterEvents-记录语句 1 2008-12- 19 15:04:26,156 [main] INFO pages.filters.FilterEvents-记录语句 2 2008-12-19 15:04:26,156 [main] INFO pages.filters.FilterEvents-记录语句 4 2008-12-19 15:04 :26,156 [main] INFO pages.filters.FilterEvents-记录语句 5 2008-12-19 15:04:26,171 [main]错误 chapters.filters.FilterEvents-帐单语句 6
“日志记录语句 0”是消息“日志记录语句\ {}”的第一个出现。 “ logging 语句 1”是第一个“重复”,“ logging 语句 2”是第二个重复。有趣的是,级别 DEBUG 的“ logging 语句 3”是第三重复,即使后来由于基本选择规则而被丢弃。这可以通过以下事实来解释:turbo 过滤器先于其他类型的过滤器(包括基本选择规则)被调用。因此,DuplicateMessageFilter将“记录语句 3”视为重复,而忽略了它将在处理链中进一步下降的事实。 “日志记录声明 4”是第四个重复,“日志记录声明 5”是第五个重复。因为默认情况下仅允许重复 5 次,所以删除了语句 6 及其以后的语句。
In logback-access
Logback-access 提供了经典 logback 可用的大多数功能。特别是,Filter个对象可用,并且以与经典 logback 对象相对应的方式工作,但有一个明显的不同。logback访问过滤器代替LoggingEvent个实例,而不是AccessEvent个实例。目前,logback-access 附带有限数量的以下所述过滤器。如果您想建议其他过滤器,请联系 logback-dev 邮件列表。
CountingFilter
借助CountingFilter类,logback-access 可以提供有关对 Web 服务器的访问的统计数据。初始化后,CountingFilter将自己作为 MBean 注册到平台的 JMX 服务器上。然后,您可以查询该 MBean 以获取统计数据,例如按分钟,小时,天,周或月平均。还可以提供其他统计信息,例如前一周,天,小时或月的计数以及总计数。
以下* logback-access.xml *配置文件声明了CountingFilter。
<configuration>
<statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener" />
<filter class="ch.qos.logback.access.filter.CountingFilter">
<name>countingFilter</name>
</filter>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%h %l %u %t \"%r\" %s %b</pattern>
</encoder>
</appender>
<appender-ref ref="STDOUT" />
</configuration>
您可以通过jconsole应用程序检查CountingFilter在平台的 JMX 服务器上维护的各种统计信息。

EvaluatorFilter
EvaluatorFilter是封装EventEvaluator的通用过滤器。顾名思义,EventEvaluator评估给定事件是否满足给定条件。在匹配和不匹配时,主机EvaluatorFilter将分别返回由 onMatch 或 onMismatch 属性指定的值。注意,EvaluatorFilter先前已在经典的 logback(see above)上下文中进行了讨论。本文主要是先前讨论的重复。
注意EventEvaluator是一个抽象类。您可以通过对EventEvaluator进行子类化来实现自己的事件评估逻辑。 Logback-access 附带了一个名为JaninoEventEvaluator的具体实现。它采用任意 Java 语言布尔表达式作为评估标准。我们将此类 Java 语言块称为“ 评估表达式”。评估表达式为事件过滤提供了极大的灵 Active。 JaninoEventEvaluator需要Janino library。请参阅安装文档的corresponding section。
评估表达式是在配置文件的解释过程中即时编译的。作为用户,您不必担心实际的管道问题。但是,您有责任确保 Java 语言表达式返回一个布尔值,即它的计算结果为 true 或 false。
评估表达式是在当前访问事件上评估的。 Logback-access 自动以变量名 event 导出当前的AccessEvent实例。您可以通过event变量读取与 HTTP 请求以及 HTTP 响应相关的各种数据。请参阅AccessEvent 类的源代码以获取确切列表。
下一个 logback-access 配置文件说明了基于404 (未找到) HTTP 响应代码的过滤。导致 404 的每个请求都将打印在控制台上。
示例:访问评估程序(logback-examples/src/main/resources/chapters/filters/accessEventEvaluator.xml)
<configuration>
<statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener" />
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
<evaluator>
<expression>event.getStatusCode() == 404</expression>
</evaluator>
<onMismatch>DENY</onMismatch>
</filter>
<encoder><pattern>%h %l %u %t %r %s %b</pattern></encoder>
</appender>
<appender-ref ref="STDOUT" />
</configuration>
在下一个示例中,我们仍然记录导致 404 错误的请求,但那些请求 CSS 文件的请求除外。
示例 6.10:访问评估程序(logback-examples/src/main/resources/chapters/filters/accessEventEvaluator2.xml)
<configuration>
<statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener" />
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
<evaluator name="Eval404">
<expression>
(event.getStatusCode() == 404)
&& <!-- ampersand characters need to be escaped -->
!(event.getRequestURI().contains(".css"))
</expression>
</evaluator>
<onMismatch>DENY</onMismatch>
</filter>
<encoder><pattern>%h %l %u %t %r %s %b</pattern></encoder>
</appender>
<appender-ref ref="STDOUT" />
</configuration>