TurboFilters
TurboFilter对象全部继承于TurboFilter抽象类。像正则过滤器一样,它们都使用三进制逻辑返回对日志事件的判断。
它们的工作试类似于前面提到的过滤器。但,Filter与TurboFilter存在两点不一样。
TurboFilter对象绑定到日志上下文。因此,它们不光指定的appender被使用时触发,每一次日志请求也会触发。它们的应用范围远远大于appender附属的过滤器。
更重要的,它们会在LoggingEvent对象创建前被调用。TurboFilter对象过滤日志请求,不需要一个日志事件的实例化。因此,turboFilters用于高性能地过滤日志事件,即使在日志事件对象创建前。
实现自定义TruboFilter
只压根继承TurboFilter抽象类就可以创建自定义TurboFilter对象。像前面实现自定义过滤器一样,实现自定义过滤器只要实现decide()方法。下面的例子中,我们创建了一个稍微复杂的过滤器:
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接收饮食特殊标识的事件。如果未找到指定标识,过滤器则将责任传递给连上下一个过滤器。
为了增加灵活性,通过getter与setter,测试标识可能在配置文件中指定。我们也通过实现start()方法去验证在处理配置过程中选项是否已指定。
<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用于验证是否存在指定值;DynamicThresholdFilter基于MDC的key与level阀值过滤。另一个方面,MarkerFilter用于验证日志请求中包含指定标识。
下面是应用MDCFilter与MarkerFilter的一个例子:
<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>
DuplicateMessageFilter
DuplicateMessageFilter优点在与众不同。这个过滤器会监测重复的消息,超过一定数量后,会丢弃掉重复的消息。
为了监控重复,过滤器在消息中使用简单的String相等性。它不会监测到只有一些字符差异的非常相近的消息。例如:
logger.debug("Hello "+name0); logger.debug("Hello "+name1);
假设name0与name1有不同的值,则认为这两条"Hello"消息不相关。依赖于用户的使用,以后的发布版本有可能添加验证string相似性功能。
注意包含参数的日志情况,只有考虑到原始消息。例如:下面两个请求,原始消息为"Hello {}"一样,因此,它被视为重复。
重复的数量可能通过AllowedRepetitions属性配置。例如,如果属性值为1,则第2条及以后的相同消息会被丢弃。类似,如果属性值为2,则第3条及以后的相同消息会被丢弃。AllowedRepetitions默认值为5。
为了监测重复性,这个过滤器需要在内部缓存中保持旧消息的引用。这个缓存的大小取决于属性CacheSize。默认,属性值为100。
<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>
因此,配置了上面过滤器的FilterEvents输出为:
2008-12-19 15:04:26,156 [main] INFO chapters.filters.FilterEvents - logging statement 1
2008-12-19 15:04:26,156 [main] INFO chapters.filters.FilterEvents - logging statement 2
2008-12-19 15:04:26,156 [main] INFO chapters.filters.FilterEvents - logging statement 4
2008-12-19 15:04:26,156 [main] INFO chapters.filters.FilterEvents - logging statement 5
2008-12-19 15:04:26,171 [main] ERROR chapters.filters.FilterEvents - billing statement 6
“logging statement 0”是第一个"logging statement {}"的发生。"logging statement 1"是第1个重复,"logging statement 2"是第2个重复。有趣的是,虽然基本规则被丢弃了,DEBUG级别的"logging statement 3"是第3个重复。通过这个可以看出TurboFilter早于其它过滤器调用,包含基本规则。因此,DuplicateMessageFilter认为"logging statement 3"为重复。由于它被后面的连上的规则丢弃造成它常常被忘记。"logging statement 4"是第4个重复,"logging statement 5"第5个。由于默认只允许5个重复,Statements6以及之后的都将被丢弃。
logback-access
Logback-access提供了logback-classic里的大部分特点。特别是,除了一点不一样,Logback-access过滤器与Logback-classic采用一样的方式获得与工作。Logback-access通过AccessEvent取代LoggingEvent实例。现在,logback-access提供了下面介绍有限的过滤器。如果你想要建议增加过滤器,请联系logback邮件列表。
CountingFilter
通过CountingFilter,logback-access可以提供web-server的访问统计数据。初始化时,CountingFilter以MBean的形式将自己注册到JMX服务器。你可以通过访问那个MBean获取统计数据,如,每分钟、小时、天、星期、月平均值。其它统计,如,上周、前天、上一个小时、上个月的数量,以及获得的总数量。
下面的lobback-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查看JMX服务器上的任何统计数据
EvaluatorFilter
EvaluatorFilter是封装了EventEvaluator的泛型过滤器。就如名字介绍的,EventEvaluator判断指定事件是否满足条件。匹配与否,Evaluator会返回OnMatch与OnMismatch属性配置的值。EvaluatorFilter与前面类似,参考上一篇文章。
判断表达式用于处理当前访问事件。Logback-access自动将以event变量名,导入AccessEvent实例。你可以读取关于HTTP请求与响应的各种数据。
下面配置文件展示了过滤响应编码为404的,每个请求为404的都会打印到console中。
<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类型文件:
<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>
参考文档:https://logback.qos.ch/manual/filters.html