1. AsyncAppender 異步記錄日志
AsyncAppender僅僅是做為一個(gè)日志分發(fā)器存在,因此穗酥,它必須綁定到其它的Appender上面护赊。
AsyncAppender會(huì)將日志緩存在一個(gè)BlockingQueue之中惠遏,然后啟動(dòng)一個(gè)線程從隊(duì)列中取日志輸出。默認(rèn)情況下骏啰,緩存隊(duì)列的長(zhǎng)度是256爽哎。如果緩存占了隊(duì)列的80%的時(shí)候,AsyncAppender就會(huì)丟棄trace,debug,info級(jí)別的日志器一。如果不想丟掉日志,可以配置AsyncAppender的discardingThreshold為0厨内。
因?yàn)榫彺娴拇嬖谄盹酰趹?yīng)用退出的時(shí)候,需要等待將緩存的日志寫(xiě)到日志文件中雏胃,否則就有可能日志丟失请毛。可以使用下面的代碼關(guān)閉日志:
LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
context.stop();
在寫(xiě)入日志的時(shí)候瞭亮,會(huì)有一個(gè)超時(shí)時(shí)間方仿,默認(rèn)是1000ms,如果這個(gè)時(shí)間太短统翩,可以通過(guò)AsyncAppender的maxFlushTime配置這個(gè)超時(shí)時(shí)間仙蚜。
另外也可以在logback的配置文件中添加jvm的關(guān)閉時(shí)的回調(diào)鉤子:
<configuration debug="true">
<!-- in the absence of the class attribute, assume
ch.qos.logback.core.hook.DefaultShutdownHook
在舊的版本中,可能是:ch.qos.logback.core.hook.DelayingShutdownHook-->
<shutdownHook/>
....
</configuration>
這樣厂汗,當(dāng)jvm通過(guò)命令exit退出的時(shí)候委粉,logback會(huì)自動(dòng)關(guān)閉所有的appender,關(guān)把緩存在隊(duì)列中的日志輸出到日志文件里面娶桦。需要注意的一點(diǎn)是贾节,如果在jvm中添加多個(gè)回調(diào)鉤子,它們是并行執(zhí)行的衷畦,沒(méi)有順序性栗涂。如果在logback中配置了shutdownHook,有可能提前關(guān)閉了日志祈争,其它鉤子如果有日志打印就不會(huì)輸出了斤程,不可以配置logback的關(guān)閉鉤子的延遲執(zhí)行時(shí)間,
<shutdownHook class="ch.qos.logback.core.hook.DefaultShutdownHook">
<delay>5000</delay>
</shutdownHook>
下面是一個(gè)異步日志的輸出配置方式:
<configuration>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>myapp.log</file>
<encoder>
<pattern>%logger{35} - %msg%n</pattern>
</encoder>
</appender>
<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="FILE" />
</appender>
<root level="DEBUG">
<appender-ref ref="ASYNC" />
</root>
</configuration>
2. 自定義Appender
通過(guò)繼承AppenderBase可以自定義自己的Appender铛嘱。它只需要實(shí)現(xiàn)一個(gè)方法:append(Object eventObject)暖释。下面是一個(gè)例子,用來(lái)限制日志的輸出數(shù)據(jù)墨吓,當(dāng)日志數(shù)量達(dá)到限制之后就不再輸出了:
package chapters.appenders;
import java.io.IOException;
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.AppenderBase;
public class CountingConsoleAppender extends AppenderBase<ILoggingEvent> {
static int DEFAULT_LIMIT = 10;
int counter = 0;
int limit = DEFAULT_LIMIT;
PatternLayoutEncoder encoder;
public void setLimit(int limit) {
this.limit = limit;
}
public int getLimit() {
return limit;
}
@Override
public void start() {
if (this.encoder == null) {
addError("No encoder set for the appender named ["+ name +"].");
return;
}
try {
encoder.init(System.out);
} catch (IOException e) {
}
super.start();
}
public void append(ILoggingEvent event) {
if (counter >= limit) {//達(dá)到限制了球匕,不再輸出日志
return;
}
// output the events as formatted by our layout
try {
this.encoder.doEncode(event);
} catch (IOException e) {
}
// prepare for next event
counter++;
}
public PatternLayoutEncoder getEncoder() {
return encoder;
}
public void setEncoder(PatternLayoutEncoder encoder) {
this.encoder = encoder;
}
}
在類中的成員變量,只要有g(shù)etter/setter方法帖烘,就可以像配置其它Appender一樣亮曹,在logback配置文件中配置。
start()方法一般用來(lái)初始化。
3. Encoder
Encoder負(fù)責(zé)將日志事件轉(zhuǎn)化為byte[]并寫(xiě)入到OutputStream之中照卦。因此式矫,Encoder決定了何時(shí)寫(xiě)入OutputSteam,以及寫(xiě)入什么役耕。
目前最常用的Encoder是PatternLayoutEncoder采转,它取代了以前版本的Layout。
4. 日志過(guò)濾組件-Filters
logback有兩種不同類型的filters瞬痘,一個(gè)是Regular filters故慈,一個(gè)是turbo filters。最常用的是Regular Filters框全。
Regular Filters 有一個(gè)decide方法察绷,它的參數(shù)是ILogingEvent,多個(gè)filter是按順序執(zhí)行的津辩,decide方法返回一個(gè)枚舉類型:DENY,NETURAL,ACCEPT拆撼。如果返回的是DENY,日志事件就會(huì)被立刻丟棄喘沿,并且不會(huì)再執(zhí)行剩下的Filters闸度,如果返回的是NETURAL,日志事件會(huì)被傳到下一個(gè)filter,如果返回的是ACCEPT摹恨,日志將會(huì)被處理筋岛,并且不會(huì)再執(zhí)行剩下的filters。
Filters可以配置到Appender之中晒哄,可以配置多個(gè)睁宰,你可以在filter中添加任意的條件。
4.1 自定義Filter
自定義的Filter需要繼承實(shí)現(xiàn)Filter寝凌,如下所示:
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;
}
}
}
然后可以這樣配置:
<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>
4.2 LevelFilter
LevelFitler是根據(jù)日志的級(jí)別進(jìn)行判斷的柒傻,配置如下:
View as .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>
這表示,如果日志是INFO級(jí)別较木,就會(huì)被接收處理红符,如果不是,就拒絕并丟棄伐债。
4.3 ThresholdFilter
這個(gè)Filter需要設(shè)置一個(gè)臨界值预侯,大于等于這個(gè)臨界值會(huì)被接收,小于這個(gè)臨界值被拒絕峰锁。
View as .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>
像trace,debug小于info級(jí)別的日志會(huì)被拒絕萎馅,而info,warn虹蒋,error會(huì)被接收處理糜芳。