logback官方文件中文翻譯第七章:Filters
第七章:Filters
在之前的章節中介紹的方法列印以及基本選擇規則是 logback-classic 的核心。在這章中,將介紹其它的過濾方法。
logback 過濾器基於三元邏輯,允許它們組裝或者連結在一起組成一個任意複雜的過濾策略。它們在很大程度上受到 Linux iptables 的啟發。
在 logback-classic 中
在 logback-classic 中,有兩種型別的過濾器,regular 過濾器以及 turbo 過濾器。
Regular 過濾器
reqular 過濾器繼承自 Filter
這個抽象類。本質上它由一個單一的 decide()
方法組成,接收一個 ILoggingEvent
例項作為引數。
過濾器通過一個有序列表進行管理,並且基於三元邏輯。每個過濾器的 decide(ILoggingEvent event)
被依次呼叫。這個方法返回 FilterReply
列舉值中的一個, DENY
, NEUTRAL
或者 ACCEPT
。如果 decide()
方法返回 DENY
,那麼日誌事件會被丟棄掉,並且不會考慮後續的過濾器。如果返回的值是 NEUTRAL
,那麼才會考慮後續的過濾器。如果沒有其它的過濾器了,那麼日誌事件會被正常處理。如果返回值是 ACCEPT
,那麼會跳過剩下的過濾器而直接被處理。
在 logback-classic 中,過濾器可以被直接新增到 Appender
例項上。通過將一個或者多個過濾器新增到 appender 上,你可以通過任意標準來過濾日誌事件。例如,日誌訊息的內容,MDC 的內容,時間,或者日誌事件的其它部分。
實現你自己的過濾器
建立一個自己的過濾器非常的簡單。只需要繼承 Filter
並且實現 decide()
方法就可以了。
如下所示的 SampleFilter 就是一個簡單的例子。如果日誌事件包含字元 "sample", decide
方法返回 ACCEPT。對於其他的日誌事件,則返回 NEUTRAL。
下面是關於將 SampleFilter
新增到 ConsoleAppender
上的配置示例:
Example: SampleFilterConfig.xml
<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 的幫助下,為過濾器指定屬性或者子元件也變得更加的簡單。在過濾器類中新增相應的 set 方法,通過 <filter>
元素巢狀一個以屬性命名的 xml 元素中指定屬性的值。
通常情況下,過濾器的邏輯由兩個正交的部分組成,match/mismatch 的檢驗以及基於 match/mismatch 的返回值。例如,對於給定的檢驗,訊息等於 "foobar",一個過濾器在 match 的情況下返回 ACCEPT,在 mismatch 的情況下返回 NEUTRAL。另一個過濾可能在 match 的情況下返回 NEUTRAL,在 mismatch 的情況下返回 DENY。
注意這種正交,logback 附帶了一個 AbstractMatcherFilter
類,提供了一個有用的骨架用來指定在 match 與 mismatch 情況下的返回值,這兩個屬性名分別叫做 OnMatch 與 OnMismatch。logback 中大部分的 regular 過濾器都源於 AbstractMatcherFilter
。
LevelFilter
LevelFilter
基於級別來過濾日誌事件。如果事件的級別與配置的級別相等,過濾器會根據配置的 onMatch
與 onMismatch
屬性,接受或者拒絕事件。如下是一個簡單的示例:
Example: levelFilterConfig.xml
<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
基於給定的臨界值來過濾事件。如果事件的級別等於或高於給定的臨界值,當呼叫 decide()
時,ThresholdFilter
將會返回 NEUTRAL。但是事件的級別低於臨界值將會被拒絕。下面是一個簡單的例子:
Example: thresholdFilterConfig.xml
<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
根據給定的標準來評估給定的事件是否符合標準。在 match 和 mismatch 的情況下,EvaluatorFilter
將會返回 onMatch
或 onMismatch
指定的值。
注意 EventEvaluator
是一個抽象類。你可以通過繼承 EventEvaluator
來實現自己事件評估邏輯。
GEventEvaluator
GEventEvaluator 是 EventEvaluator
具體的實現,它採用 Groovy 表示式作為評估的標準。我們把 Groovy 表示式稱為 "Groovy 評估表示式"。Groogy 評估表示式是目前為止進行事件過濾最靈活的方式。GEventEvaluator
需要 Groovy 執行環境。參考相關部分在類路徑下新增 Groovy 執行環境。
評估表示式在解析配置檔案期間被動態編譯。作為使用者,不需要考慮實際的情況。但是,你需要確保你的 Groovy 表示式是有效的。
評估表示式作用於當前的日誌事件。logback 會自動將 ILoggingEvent 型別的日誌事件作為變數插入,引用到 'event' 或者它的簡稱 'e'。TRACE, DEBUG, INFO, WARN 以及 ERROR 也能夠被匯入到表示式的範圍中。所以,"event.level == DEBUG" 與 "e.level == DEBUG" 是等價的。只有噹噹前日誌事件的級別為 DEBUG 時,Groovy 表示式才會返回 true
。對於其它的級別比較操作,應該通過 toInt()
操作將 level 欄位轉變為整型。
下面是一個比較複雜的例子:
<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() && <!-- 在 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>
上面的過濾器會讓級別在 WARN 及以上的日誌事件在控制檯顯示,除非是由於來自 Google,MSN,Yahoo 的網路爬蟲導致的錯誤。它通過檢查與事件相關的 MDC 包含 "req.userAgent" 的值是否匹配 /Googlebot|msbbot|Yahoo/
正規表示式。因為 MDC 的對映可能為 null,所以我們使用 Groovy 的安全解引用操作符,也就是 ?.
操作符。這個相等的邏輯在 Java 中的表示式更長。
如果你好奇 user agent 識別符號作為值怎樣被插入到 key 為 "req.userAgent " 的 MDC 中,那麼就會涉及到 logback 為了這個目的附帶了一個名為 MDCInsertingServletFilter
的 servlet 過濾器。它將會在接下來的章節中描述。
JaninoEventEvaluator
logback-classic 附帶的另外一個 EventEvaluator
的具體實現名為 JaninoEventEvaluator,它接受任意返回布林值的 Java 程式碼塊作為評判標準。我們把這種 Java 布林表示式稱為 "評估表示式"。評估表示式在事件過濾中可以更加的靈活。JaninoEventEvaluator
需要 Janino 類庫。請參見相關章節進行設定。跟 JaninoEventEvaluator
相比,GEventEvaluator
使用 Groovy 語言,使用起來非常方便。但是 JaninoEventEvaluator
將使用執行更快的等效表示式。
評估表示式在解析配置檔案期間被動態編譯。作為使用者,不需要考慮實際的情況。但是,你需要確保你的 Java 表示式是有效的,保證它的評估結果為 true 或 false。
評估表示式對當前日誌事件進行評估。logback-classic 自動匯出日誌事件的各種欄位作為變數,為了可以從評估表示式訪問。這些匯出的變數是大小寫敏感的,如下表所示:
名字 | 型別 | 描述 |
---|---|---|
event | LoggingEvent |
日誌請求的原始日誌事件。下面所有的變數都來自這個日誌事件。例如,event.getMessage() 返回的字串跟下面的 message 變數返回的字串一樣。 |
message | String |
日誌請求的原始資訊。例如,對於 logger I,當你寫的是 I.info("Hello {}", name); 時,name 的值被指定為 "Alice",訊息就為 "Hello {}"。 |
formattedMessage | String |
日誌請求中格式化後的訊息。例如,對於 logger I,當你寫的是 I.info("Hello {}", name); 時,name 的值被指定為 "Alice",格式化後的訊息就為 "Hello Alice"。 |
logger | String |
logger 的名字 |
loggerContext | LoggerContextVO |
日誌事件屬於 logger 上下文中哪個受限的檢視 (值物件) |
level | int |
事件級別對應的 int 值。用來建立包含級別的表示式。預設值是 DEBUG,INFO,WARN 以及 ERROR 也是有效的。所以 level > INFO 是有效的表示式。 |
timeStamp | long |
日誌事件建立的時間 |
marker | Marker |
與日誌請求相關的 Marker 物件。注意,marker 可能會為 null,因此你需要對這種情況進行檢查,進而避免 NullPointerException 。 |
mdc | Map |
建立日誌事件時包含的所有的 MDC 值的一個對映。可以通過 mdc.get("myKey") 來獲取 MDC 中對應的值。在 0.9.30 版本的 logback-classic,mdc 變數永遠不會為 null。<br />java.util.Map 型別是非引數化的,因為 Janino 不支援泛型。因此,mdc.get() 返回值的型別是 Object 而不是 String 。但是可以將返回值強制轉換為 String 。例如, ((String) mdc.get("k")).contains("val") 。 |
throwable | java.lang.Throwable | 如果日誌事件沒有相關的異常,那麼變數 "throwable" 的值為 null。"throwable" 不可以被序列化。所以在遠端伺服器上,這個值永遠為 null。想要使用與位置無關的表示式,可以使用下面的 throwableProxy 。 |
throwableProxy | IThrowableProxy |
日誌事件的異常代理。如果日誌事件沒有相關的異常,那麼 throwableProxy 的值為 null。與 "throwable" 相反,即使在遠端伺服器上序列化之後,日誌事件相關的異常也不會為 null。 |
下面是具體的例子。
Example: basicEventEvaluator.xml
<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
的 evaluator 之後被注入到 EvaluatorFilter
中。<evaluator
在缺少 class 屬性的情況下,Joran 會指定 evaluator 的預設型別為 JaninoEventEvaluator
。這是少數幾個需要 Joran 預設指定型別的元件。
expression 元素對應剛才討論過的評估表示式。表示式 return message.contains("billing");
返回一個布林值。message 變數會被 JaninoEventEvaluator
自動匯出。
由於 OnMismatch
屬性的值為 NEUTRAL 以及 OnMatch
屬性的值為 DENY,所以評估過濾器會丟掉訊息包含 "billing" 的日誌事件。
FilterEvents 發出十條日誌請求,編號為 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
假設我們想要丟棄 "billing statement"。basicEventEvaluator.xml 中配置的過濾器恰好可以滿足這個需求。
通過 basicEventEvaluator.xml 執行:
java chapters.filters.FilterEvents src/main/java/chapters/filters/basicEventEvaluator.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] 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
評估表示式可以是一個 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") &&
payee.contains("someSpecialValue") &&
!message.contains("someSecret")) {
return true;
}
return false;
</expression>
</evaluator>
Matchers
雖然可以通過呼叫 String
類的 matches() 方法來進行模式匹配,但是每次呼叫 filter 都需要耗費時間重新編譯一個新的 Pattern
物件。為了消除這種影響,你可以預先定義一個或者多個 Matcher 物件。一旦定義了一個 matcher,就可以在評估表示式中重複使用了。
通過一個簡單的例子來說明這一點:
Example: evaluatorWithMatcher.xml
<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
將會得到:
260 [main] INFO chapters.filters.FilterEvents - logging statement 0
264 [main] INFO chapters.filters.FilterEvents - logging statement 2
264 [main] INFO chapters.filters.FilterEvents - logging statement 4
266 [main] ERROR chapters.filters.FilterEvents - billing statement 6
266 [main] INFO chapters.filters.FilterEvents - logging statement 8
如果你想定義其它的 matcher,可以繼續增加 <matcher>
元素。
TurboFilters
TurboFilter
物件都繼承 TurboFilter
抽象類。對於 regular 過濾器,它們使用三元邏輯來返回對日誌事件的評估。
總之,它們跟之前提到的過濾工作原理差不多。主要的不同點在於 Filter
與 TurboFilter
物件。
TurboFilter
物件被繫結剛在 logger 上下文中。因此,在使用給定的 appender 以及每次發出的日誌請求都會呼叫 TurboFilter
物件。因此,turbo 過濾器可以為日誌事件提供高效能的過濾,即使是在事件被建立之前。
實現自己的 TurboFilter
想要建立自己的 TurboFilter
元件,只需要繼承 TurboFilter
這個抽象類就可以了。跟之前的一樣,想要實現定製的過濾器物件,開發自定義的 TurboFilter
,只需要實現 decide()
方法就可以了。下一個例子,我們會建立一個稍微複雜一點的過濾器:
Example: 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
接受一個指定的 marker,如果 marker 沒有被找到,那麼過濾器會將日誌事件傳遞給過濾器鏈中的下一個過濾器。
為了更加靈活,允許在配置檔案指定 marker 用於檢測,因此可以使用 get 和 set 方法。我們還可以通過實現 start()
方法來檢查在配置過程中,指定的選項是否滿足。
下面的配置充分利用了我們新建立的 TurboFilter
。
Example: sampleTurboFilterConfig.xml
<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>
loback-classic 附帶了幾個 TurboFilter
類可以開箱即用。MDCFilter
用來檢查給定的值在 MDC 中是否存在。DynamicThresholdFilter
根據 MDC key/level 相關的閥值來進行過濾。MarkerFilter
用來檢查日誌請求中指定的 marker 是否存在。
下面的例子使用了 MDCFilter
與 MarkerFilter
。
Example: turboFilters.xml
<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 級別的,與 root logger 的級別一致。第 3 條日誌請求是 DEBUG
級別的,在有效級別之下。但是,因為 MDC 的 key "username" 在第三條請求之前設定為 "sebastien",之後才被移除,所以 MDCFilter
接受這條請求 (僅僅只有這條請求)。第 6 條請求的級別為 ERROR
,被標記為 "billing"。因此,它會被 MarkerFilter
(配置檔案中第二個 turbo 過濾器) 拒絕。
因此,FilterEvents
通過 turboFilters.xml 輸出的資訊如下:
2018-08-20 23:19:28,807 [main] INFO chapters.filters.FilterEvents - logging statement 0
2018-08-20 23:19:28,810 [main] INFO chapters.filters.FilterEvents - logging statement 1
2018-08-20 23:19:28,810 [main] INFO chapters.filters.FilterEvents - logging statement 2
2018-08-20 23:19:28,810 [main] DEBUG chapters.filters.FilterEvents - logging statement 3
2018-08-20 23:19:28,810 [main] INFO chapters.filters.FilterEvents - logging statement 4
2018-08-20 23:19:28,810 [main] INFO chapters.filters.FilterEvents - logging statement 5
2018-08-20 23:19:28,810 [main] INFO chapters.filters.FilterEvents - logging statement 7
2018-08-20 23:19:28,811 [main] INFO chapters.filters.FilterEvents - logging statement 8
2018-08-20 23:19:28,811 [main] INFO chapters.filters.FilterEvents - logging statement 9
可以看到,第 3 條日誌請求,本來不應該被展示出來,因為我們僅僅只關注 INFO 級別的請求,但是它匹配了第一個 TurboFilter
,所以被接受了。
第 6 條日誌請求,它是 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,那麼第三條及後續的日誌訊息會被丟棄掉。這個值預設設定為 5。
為了檢測重複,過濾器需要在內部的快取中保留對舊訊息的引用。通過 CacheSize
來控制快取的大小。預設情況下,這個值為 100。
Example: duplicateMessage.xml
<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
通過 duplicateMessage.xml
配置後輸出如下:
2018-08-21 09:09:22,036 [main] INFO chapters.filters.FilterEvents - logging statement 0
2018-08-21 09:09:22,041 [main] INFO chapters.filters.FilterEvents - logging statement 1
2018-08-21 09:09:22,041 [main] INFO chapters.filters.FilterEvents - logging statement 2
2018-08-21 09:09:22,041 [main] INFO chapters.filters.FilterEvents - logging statement 4
2018-08-21 09:09:22,041 [main] INFO chapters.filters.FilterEvents - logging statement 5
2018-08-21 09:09:22,050 [main] ERROR chapters.filters.FilterEvents - billing statement 6
"logging statement 0" 是訊息 "logging statement {}"j 第一次出現。"logging statement 1" 是第一次重複。"logging statement 2" 是第二次重複。有趣的是,雖然 "logging statement 3" 的級別為 DEBUG,為第三次重複。但是根據方法列印以及基本選擇規則,它被丟棄了。這也說明了 turbo 過濾器會在其它過濾器之前呼叫,包括在基本選擇規則之前。因此 DuplicateMessageFilter
認為 "logging statement 3" 是第三次重複,而不會管它是否會在之後過濾器鏈的處理中被丟棄掉。"logging statement 4" 是第四次重複。"logging statement 5" 是第五次。因此預設的重複次數是 5,所以之後的語句都會被丟棄掉。(注:指的是 "logging statement {}")。
在 logback-access 中
logback-access 提供了 logback-classic 提供的大部分功能。特別地,Filter
物件同樣是有效的,並且以同樣的方式工作,就像 logback-classic 的副本一樣,但是有一個顯著的區別。logback-access 過濾器對 AccessEvent
例項起作用,而不是 LoggingEvent
例項。目前,logback-access 只提供了以下有限的過濾器。如果你想建議新增額外的過濾器,請通過 logback-dev 郵件列表進行聯絡。
CountingFilter
在 CountingFilter
類的幫助下,logback-access 可以提供對伺服器訪問資料的統計。在初始化的死後,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
檢視有 CountingFilte
在你平臺的 JMX 服務上維護的各種統計資訊。
[圖片上傳失敗...(image-9bfd4b-1547968754978)]
EvaluatorFilter
EvaluatorFilter
是一個通用的過濾器,維護了一個 EventEvaluator
。顧名思義,EventEvaluator
根據給定的標準判斷給定的日誌事件是否滿足,EvaluatorFilter
將會根據 match 與 mismatch 的情況,返回由 onMatch
或 onMismatch
屬性指定的值。EvaluatorFilter
在之前的 logback-classic 中已經討論過了 (見上面)。現在大部分都是對之前討論的重複。
注意 EventEvaluator
是一個抽象類。你可以通過繼承 EventEvaluator
來實現你自己的評估邏輯。logback-access 附帶了一個名為 JaninoEventEvaluator 的具體實現。它可以接收任意的 Java 表示式作為評估標準。我們把這種 Java 程式碼塊稱為 "評估表示式"。評估表示式在事件過濾中有較大的靈活性。JaninoEventEvaluator
需要 Janino 類庫。請檢視相應的文件進行設定。
評估表示式在解析配置檔案的過程中被動態編譯。作為使用者,你不需要知道實際的細節。但是,你需要保證 Java 表示式返回一個布林值,能夠計算為 true 或者 false。
評估表示式可以對當前訪問的事件進行評估。logback-access 會自動匯出當前 AccessEvent
例項到變數 event 下。你可以通過 event
變數讀取 HTTP 請求中以及 HTTP 響應中的各種資料。檢視 AccessEvent 類的原始碼來檢視具體的列表。
下個配置檔案基於 HTTP 響應碼 404 (Not Found) 來進行過濾。每一個 404 的請求都會在控制檯列印出來。
Example: 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 檔案的請求。
Example: 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)
&& <!-- & 符號需要被轉義 -->
!(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>
相關文章
- HTTPie 官方文件中文翻譯版HTTP
- Matlab最新的官方文件中文翻譯Matlab
- kotlinx協程官方文件中文翻譯版本Kotlin
- Moya官方文件翻譯
- docker官方文件翻譯3Docker
- docker官方文件翻譯4Docker
- rabbitmq 官方文件翻譯-2MQ
- docker官方文件翻譯5Docker
- docker官方文件翻譯2Docker
- docker官方文件翻譯1Docker
- Core Foundation 官方文件翻譯
- Detectron2-寫模型(Write Models)官方文件中文翻譯模型
- Dapr 官方文件中文翻譯 v1.5 版本正式釋出
- BBNorm官方指導文件翻譯ORM
- [翻譯]ElasticSearch官方文件-簡介Elasticsearch
- Redis-py官方文件翻譯Redis
- Akka官方文件翻譯:Cluster Specification
- ReactiveCocoa 4 官方文件翻譯React
- SnapKit 中文文件翻譯APK
- Python heapq模組官方文件翻譯Python
- Gin 框架中文文件(翻譯)框架
- ExoPlayer的使用與解析(官方文件翻譯)
- [翻譯]ElasticSearch官方文件-資料的修改Elasticsearch
- [翻譯]ElasticSearch官方文件-查詢語言Elasticsearch
- 【Tomcat 6.0官方文件翻譯】—— 簡介Tomcat
- 怎麼把Excel文件翻譯成中文?Excel文件翻譯方法介紹Excel
- SQLAlchemy 2.0 中文文件翻譯完成SQL
- 歡迎參與 KubeVela 官方文件翻譯活動
- Kotlin 官方參考文件翻譯完畢Kotlin
- WebSocket 協議 RFC 文件(全中文翻譯)Web協議
- 【翻譯】fancyBox3 中文文件
- 文件翻譯軟體怎麼用?怎麼把Excel文件翻譯成中文版Excel
- voltDB官方文件第三章翻譯
- PendingIntent 是個啥?官方文件描述的很到位。我給翻譯翻譯Intent
- 不錯的Oracle文件中文翻譯網站Oracle網站
- PDF英語文件怎麼翻譯成中文?
- Inkpad中文翻譯已合併到官方專案
- Spring系列(零) Spring Framework 文件中文翻譯SpringFramework