日志收集在互联网企业尤其是大数据时代是一件非常重要的事情,日志记录着用户行为和系统行为,是一种重要的数据来源。Log4j是Java应用程序使用的最多的一种日志收集工作。目前大量的Java应用程序都使用着Lo4j 1.2.X版本,Log4j 1.X版本饱受诟病的原因是使用了大量的锁,在高并发的情况下影响了系统的性能。这篇简单提供一种思路,说说如何扩展一下Log4j,提升一下Log4j的性能。
网上有很多分析Log4j源码的文章,这里不重复说了,只简单分析一下最重要的几个组件。
先看一下Log4j的配置文件log4j.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="rootAppender" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="test.log" />
<param name="DatePattern" value="'.'yyyy-MM-dd" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %5p %c{1}:%L - %m%n" />
</layout>
</appender>
<logger name="com.test" additivity="false">
<level value="debug" />
<appender-ref ref="rootAppender" />
</logger>
<root>
<level value="debug" />
<appender-ref ref="rootAppender" />
</root>
</log4j:configuration>
从log4j.xml里面我们就可以看到Log4j最主要的几个组件
1. Logger,表示日志收集器,包含了各种Level下收集日志的方法,比如debug, info, error等。Logger的一个重要属性是additivity,表示是否附加到父Logger。Logger被设置成单根的树形结构,根就是Root,收集日志时,可以从叶子Logger一直往上直到Root。
Logger还包含了level表示级别,包含了一个appender列表,一个Logger可以对应多个Appender
2. Appender,表示如何处理日志,可以写本地文件,可以写远程文件,也可以输出到消息队列,等等。最常见的场景就是写本地文件。写文件的抽象是WriterAppender,封装了一个过滤器流QuietWriter。既然是过滤器流,那么可以包装节点流,默认的就是FileOutputStream流。Log4j也支持Buffer流,在WriterAppender的子类FileAppender里面有bufferedIO属性,如果采用Buffer流,就会在FileOutputStream外包一层BufferedWriter,最后在包到QuietWriter中。
public
synchronized
void setFile(String fileName, boolean append, boolean bufferedIO, int bufferSize)
throws IOException {
LogLog.debug("setFile called: "+fileName+", "+append);
if(bufferedIO) {
setImmediateFlush(false);
}
reset();
FileOutputStream ostream = null;
try {
ostream = new FileOutputStream(fileName, append);
} catch(FileNotFoundException ex) {
String parentName = new File(fileName).getParent();
if (parentName != null) {
File parentDir = new File(parentName);
if(!parentDir.exists() && parentDir.mkdirs()) {