一、什么是Appender
logback将写入日志事件的任务委托给一个名为 appender 的组件,Appender 必须实现 ch.qos.logback.core.Appender接口。
Appender接口的源码:
package ch.qos.logback.core;
import ch.qos.logback.core.spi.ContextAware;
import ch.qos.logback.core.spi.FilterAttachable;
import ch.qos.logback.core.spi.LifeCycle;
public interface Appender extends LifeCycle, ContextAware, FilterAttachable {
String getName();
void doAppend(E var1) throws LogbackException;
void setName(String var1);
}
doAppender()方法接收一个泛型参数E作为唯一的参数。E的实际参数类型取决于logback模块。在logback-classic模块里面,E的类型是ILoggingEvent。在logback-access模块里面,E的类型是AccessEvent。doAppend()是logback框架里面最重要的模块。它的责任是将日志事件进行格式化,然后输出到对应的设备上。
Appender都是是实体类,这样可以确保他们通过名字被引用。Appender接口继承了FilterAttachable接口。使得一个一个或多个过滤器可以附加到appender实例上。
Appender 最基本的责任是将日志事件进行输出。然而,它们可以委托Layout 或者Encoder对象来对日志事件进行格式化。每一个 layout/encoder 有且只与一个 appender 相关联。例如,SocketAppender 仅仅序列化日志事件,然后再通过线路传输。
AppenderBase
ch.qos.logback.core.AppenderBase 是一个抽象类,实现了 Appender 接口。它提供了基本方法供所有 appender 使用。例如:获取和设置名称的方法、激活状态、布局以及过滤器。它是 logback 中所有appender 的父类。尽管是一个抽象类,但是AppenderBase还实现了Append接口中的doAppend()方法。
AppenderBase源码摘要:
public synchronized void doAppend(E eventObject) {
if (!this.guard) {
try {
this.guard = true;
if (this.started) {
if (this.getFilterChainDecision(eventObject) == FilterReply.DENY) {
return;
}
this.append(eventObject);
return;
}
if (this.statusRepeatCount++ < 5) {
this.addStatus(new WarnStatus("Attempted to append to non started appender [" + this.name + "].", this));
}
} catch (Exception var6) {
if (this.exceptionCount++ < 5) {
this.addError("Appender [" + this.name + "] failed to append.", var6);
}
return;
} finally {
this.guard = false;
}
}
}
doAppend() 的实现是 synchronized 的。不同的线程通过同一个 appender 打印日志是线程安全的。因为这种同步策略并不总是合适,所以logback提供了ch.logback.core.UnsynchronizedAppenderBase类,跟AppenderBase类十分相似。
二、Logback-core
Logback-core 为 logback 其他模块的构建奠定了基础。一般来说,logback-core 的组件需要一些定制,尽管很少。接下来我们介绍几种可以开箱即用的 appender。
1、OutputStreamAppender
OutputStreamAppender 将事件附加到java.io.OutputStream上。这个类提供了其它 appender 构建的基础服务。用户通常不会直接实例一个 OutputStreamAppender 实例。因为一般来说 java.io.OutputStream 类型不能方便的转为 String。因为在配置文件中没有方法去直接指定一个OutputStream 目标对象。简单来说,你不能通过配置文件配置一个 OutputStreamAppender。但是这并不意味着 OutputStreamAppender缺少配置属性。
OutputStreamAppender是其他三个appender的父类,分别是 ConsoleAppender、FileAppender以及 RollingFileAppender。FileAppender又是RollingFileAppender的父类。
类图:
2、ConsoleAppender
ConsoleAppender是将日志打印到控制台,更进一步说数通过System.out或System.error来进行输出。默认为System.out。ConsoleAppender通过用户指定的encoder类格式化日志事件。System.out和System.error被包装在OutputStreamWriter中。
3、FileAppender
FileAppender是OutputStreamAppender的子类,将日志输出到文件中。通过file来指定目标文件。如果该文件存在,根据append的值,要么将日志追加到文件中,要么该文件被截断。
4、文件唯一命名(使用时间戳)
在应用的开发阶段或者短期应用中,例如:批处理程序,在每次应用启动的时候创建一个新的日志文件。通过
${LOG_HOME}${bySecond}.log
timestamp元素需要两个强制的属性 key 跟 datePattern 以及可选的属性 timeReference。
...
5、RollingFileAppender
RollingFileAppender 继承自 FileAppender,具有轮转日志文件的功能。例如RollingFileAppender将日志输出到log.txt文件,在满足特定的条件之后,将日志输出到另一个文件。
与RollingFileAppenter 进行交互的有两个重要的子组件。第一个是RollingPolicy,它负责日志轮转的功能。另一个是TriggeringPolicy ,它负责日志轮转的时机。所以RollingPolicy 负责怎么轮转,TtiggeringPolicy负责什么时候轮转。
为了让 RollingFileAppender 生效,必须同时设置 RollingPolicy与 TriggeringPolicy 。但是,如果 RollingPolicy也实现了 TriggeringPolicy 接口,那么只需要设置前一个就好了。
RollingFileAppender 可以配置的属性,file、append、encoder和prident等,这些属性参见上面的介绍,除了这还有: