深入Log4J源码之Log4J Core (七)

2014-11-24 08:26:37 · 作者: · 浏览: 8
inal Throwable throwable) {
18 StringWriter sw = new StringWriter();
19 PrintWriter pw = new PrintWriter(sw);
20 try {
21 throwable.printStackTrace(pw);
22 } catch (RuntimeException ex) {
23 }
24 pw.flush();
25 LineNumberReader reader = new LineNumberReader(new StringReader(
26 sw.toString()));
27 ArrayList lines = new ArrayList();
28 try {
29 String line = reader.readLine();
30 while (line != null) {
31 lines.add(line);
32 line = reader.readLine();
33 }
34 } catch (IOException ex) {
35 if (ex instanceof InterruptedIOException) {
36 Thread.currentThread().interrupt();
37 }
38 lines.add(ex.toString());
39 }
40 String[] tempRep = new String[lines.size()];
41 lines.toArray(tempRep);
42 return tempRep;
43 }
Layout类
Layout负责将LoggingEvent中的信息格式化成一行日志信息。对不同格式的日志可能还需要提供头和尾等信息。另外有些Layout不会处理异常信息,此时ignoresThrowable()方法返回false,并且异常信息需要Appender来处理,如PatternLayout。

1 public abstract class Layout implements OptionHandler {
2 public final static String LINE_SEP = System.getProperty("line.separator");
3 public final static int LINE_SEP_LEN = LINE_SEP.length();
4 abstract public String format(LoggingEvent event);
5 public String getContentType() {
6 return "text/plain";
7 }
8 public String getHeader() {
9 return null;
10 }
11 public String getFooter() {
12 return null;
13 }
14 abstract public boolean ignoresThrowable();
15 }
Layout的实现比较简单,如SimpleLayout对一行日志信息只是打印日志级别信息以及日志信息。

1 public class SimpleLayout extends Layout {
2 StringBuffer sbuf = new StringBuffer(128);
3 public SimpleLayout() {
4 }
5 public void activateOptions() {
6 }
7 public String format(LoggingEvent event) {
8 sbuf.setLength(0);
9 sbuf.append(event.getLevel().toString());
10 sbuf.append(" - ");
11 sbuf.append(event.getRenderedMessage());
12 sbuf.append(LINE_SEP);
13 return sbuf.toString();
14 }
15 public boolean ignoresThrowable() {
16 return true;
17 }
18 }
关于Layout更详细的信息将会在以后小节中介绍。

Appender接口
Appender负责定义日志输出的目的地,它可以是控制台(ConsoleAppender)、文件(FileAppender)、JMS服务器(JmsLogAppender)、以Email的形式发送出去(SMTPAppender)等。Appender是一个命名的实体,另外它还包含了对Layout、ErrorHandler、Filter等引用:

1 public interface Appender {
2 void addFilter(Filter newFilter);
3 public Filter getFilter();
4 public void clearFilters();
5 public void close();
6 public void doAppend(LoggingEvent event);
7 public String getName();
8 public void setErrorHandler(ErrorHandler errorHandler);
9 public ErrorHandler getErrorHandler();
10 public void setLayout(Layout layout);
11 public Layout getLayout();
12 public void setName(String name);
13 public boolean requiresLayout();
14 }
简单的,在配置文件中,Appender会注册到Logger中,Logger在写日志时,通过继承机制遍历所有注册到它本身和其父节点的Appender(在additivity为true的情况下),调用doAppend()方法,实现日志的写入。在doAppend方法中,若当前Appender注册了Filter,则doAppend还会判断当前日志时候通过了Filter的过滤,通过了Filter的过滤后,如果当前Appender继承自SkeletonAppender,还会检查当前日志级别时候要比当前Appender本身的日志级别阀门要打,所有这些都通过后,才会将LoggingEvent实例传递给Layout实例以格式化成一行日志信息,最后写入相应的目的地,在这些操作中,任何出现的错误都由ErrorHandler字段来处理。

SkeletonAppender类
目前Log4