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>