AsyncAppender仅仅是做为一个日志分发器存在,因此,它必须绑定到其它的Appender上面。
AsyncAppender会将日志缓存在一个BlockingQueue之中,然后启动一个线程从队列中取日志输出。默认情况下,缓存队列的长度是256。如果缓存占了队列的80%的时候,AsyncAppender就会丢弃trace,debug,info级别的日志。如果不想丢掉日志,可以配置AsyncAppender的discardingThreshold为0。
因为缓存的存在,在应用退出的时候,需要等待将缓存的日志写到日志文件中,否则就有可能日志丢失。可以使用下面的代码关闭日志:
LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
context.stop();
在写入日志的时候,会有一个超时时间,默认是1000ms,如果这个时间太短,可以通过AsyncAppender的maxFlushTime配置这个超时时间。
另外也可以在logback的配置文件中添加jvm的关闭时的回调钩子:
....
这样,当jvm通过命令exit退出的时候,logback会自动关闭所有的appender,关把缓存在队列中的日志输出到日志文件里面。需要注意的一点是,如果在jvm中添加多个回调钩子,它们是并行执行的,没有顺序性。如果在logback中配置了shutdownHook,有可能提前关闭了日志,其它钩子如果有日志打印就不会输出了,不可以配置logback的关闭钩子的延迟执行时间,
5000
下面是一个异步日志的输出配置方式:
myapp.log
%logger{35} - %msg%n
通过继承AppenderBase可以自定义自己的Appender。它只需要实现一个方法:append(Object eventObject)。下面是一个例子,用来限制日志的输出数据,当日志数量达到限制之后就不再输出了:
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 {
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) {//达到限制了,不再输出日志
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;
}
}
在类中的成员变量,只要有getter/setter方法,就可以像配置其它Appender一样,在logback配置文件中配置。
start()方法一般用来初始化。
Encoder负责将日志事件转化为byte[]并写入到OutputStream之中。因此,Encoder决定了何时写入OutputSteam,以及写入什么。
目前最常用的Encoder是PatternLayoutEncoder,它取代了以前版本的Layout。
logback有两种不同类型的filters,一个是Regular filters,一个是turbo filters。最常用的是Regular Filters。
Regular Filters 有一个decide方法,它的参数是ILogingEvent,多个filter是按顺序执行的,decide方法返回一个枚举类型:DENY,NETURAL,ACCEPT。如果返回的是DENY,日志事件就会被立刻丢弃,并且不会再执行剩下的Filters,如果返回的是NETURAL,日志事件会被传到下一个filter,如果返回的是ACCEPT,日志将会被处理,并且不会再执行剩下的filters。
Filters可以配置到Appender之中,可以配置多个,你可以在filter中添加任意的条件。
自定义的Filter需要继承实现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 {
@Override
public FilterReply decide(ILoggingEvent event) {
if (event.getMessage().contains("sample")) {
return FilterReply.ACCEPT;
} else {
return FilterReply.NEUTRAL;
}
}
}
然后可以这样配置:
View as .groovy
%-4relative [%thread] %-5level %logger - %msg%n
LevelFitler是根据日志的级别进行判断的,配置如下:
View as .groovy
INFO
ACCEPT
DENY
%-4relative [%thread] %-5level %logger{30} - %msg%n
这表示,如果日志是INFO级别,就会被接收处理,如果不是,就拒绝并丢弃。
这个Filter需要设置一个临界值,大于等于这个临界值会被接收,小于这个临界值被拒绝。
View as .groovy
INFO
%-4relative [%thread] %-5level %logger{30} - %msg%n