1. AsyncAppender 异步记录日志
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的关闭时的回调钩子:
<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>
这样,当jvm通过命令exit退出的时候,logback会自动关闭所有的appender,关把缓存在队列中的日志输出到日志文件里面。需要注意的一点是,如果在jvm中添加多个回调钩子,它们是并行执行的,没有顺序性。如果在logback中配置了shutdownHook,有可能提前关闭了日志,其它钩子如果有日志打印就不会输出了,不可以配置logback的关闭钩子的延迟执行时间,
<shutdownHook class="ch.qos.logback.core.hook.DefaultShutdownHook">
<delay>5000</delay>
</shutdownHook>
下面是一个异步日志的输出配置方式:
<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
通过继承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<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) {//达到限制了,不再输出日志
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()方法一般用来初始化。
3. Encoder
Encoder负责将日志事件转化为byte[]并写入到OutputStream之中。因此,Encoder决定了何时写入OutputSteam,以及写入什么。
目前最常用的Encoder是PatternLayoutEncoder,它取代了以前版本的Layout。
4. 日志过滤组件-Filters
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中添加任意的条件。
4.1 自定义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<ILoggingEvent> {
@Override
public FilterReply decide(ILoggingEvent event) {
if (event.getMessage().contains("sample")) {
return FilterReply.ACCEPT;
} else {
return FilterReply.NEUTRAL;
}
}
}
然后可以这样配置:
View as .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>
4.2 LevelFilter
LevelFitler是根据日志的级别进行判断的,配置如下:
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级别,就会被接收处理,如果不是,就拒绝并丢弃。
4.3 ThresholdFilter
这个Filter需要设置一个临界值,大于等于这个临界值会被接收,小于这个临界值被拒绝。
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级别的日志会被拒绝,而info,warn,error会被接收处理。
公众号.png
网友评论