Log4j AsyncAppender 源码
2016-08-10 21:26
357 查看
public class AsyncAppender extends AppenderSkeleton implements AppenderAttachable { // 默认缓冲区大小 public static final int DEFAULT_BUFFER_SIZE = 128; // 缓冲区(LoggerEvent) private final List buffer = new ArrayList(); private final Map discardMap = new HashMap(); // 缓冲区大小 private int bufferSize = 128; // Error->warn->info->debug appender AppenderAttachableImpl aai; private final AppenderAttachableImpl appenders = new AppenderAttachableImpl(); // 后台线程负责写入日志文件 private final Thread dispatcher; private boolean locationInfo = false; private boolean blocking = true; // 构造函数 public AsyncAppender() { this.aai = this.appenders; this.dispatcher = new Thread(new AsyncAppender.Dispatcher(this, this.buffer, this.discardMap, this.appenders)); this.dispatcher.setDaemon(true); this.dispatcher.setName("AsyncAppender-Dispatcher-" + this.dispatcher.getName()); // 启动后台线程 this.dispatcher.start(); } // 添加输出位置 public void addAppender(Appender newAppender) { AppenderAttachableImpl var2 = this.appenders; synchronized(this.appenders) { this.appenders.addAppender(newAppender); } } public void append(LoggingEvent event) { if(this.dispatcher != null && this.dispatcher.isAlive() && this.bufferSize > 0) { // 后台线程存活 event.getNDC(); event.getThreadName(); event.getMDCCopy(); if(this.locationInfo) { event.getLocationInformation(); } event.getRenderedMessage(); event.getThrowableStrRep(); // 得到当前Appender的缓冲区 List var11 = this.buffer; synchronized(this.buffer) { while(true) { int previousSize = this.buffer.size(); if(previousSize < this.bufferSize) { // 当前缓冲区里元素地数目小于最大的缓冲区大小,直接add this.buffer.add(event); if(previousSize == 0) { this.buffer.notifyAll(); } break; } boolean discard = true; if(this.blocking && !Thread.interrupted() && Thread.currentThread() != this.dispatcher) { try { // 停止所有生产者和消费者 this.buffer.wait(); discard = false; } catch (InterruptedException var8) { Thread.currentThread().interrupt(); } } if(discard) { String loggerName = event.getLoggerName(); AsyncAppender.DiscardSummary summary = (AsyncAppender.DiscardSummary)this.discardMap.get(loggerName); if(summary == null) { summary = new AsyncAppender.DiscardSummary(event); // 放入缓冲里 this.discardMap.put(loggerName, summary); } else { //加入event summary.add(event); } break; } } } } else { AppenderAttachableImpl var2 = this.appenders; synchronized(this.appenders) { this.appenders.appendLoopOnAppenders(event); } } } ... private static class Dispatcher implements Runnable { private final AsyncAppender parent; private final List buffer; private final Map discardMap; private final AppenderAttachableImpl appenders; public Dispatcher(AsyncAppender parent, List buffer, Map discardMap, AppenderAttachableImpl appenders) { this.parent = parent; this.buffer = buffer; this.appenders = appenders; this.discardMap = discardMap; } public void run() { boolean isActive = true; try { while(isActive) { LoggingEvent[] ex = null; List i = this.buffer; synchronized(this.buffer) { int bufferSize = this.buffer.size(); for(isActive = !this.parent.closed; bufferSize == 0 && isActive; isActive = !this.parent.closed) { // 停止所有生产者和消费者 this.buffer.wait(); bufferSize = this.buffer.size(); } if(bufferSize > 0) { ex = new LoggingEvent[bufferSize + this.discardMap.size()]; // 获得数组 this.buffer.toArray(ex); int index = bufferSize; for(Iterator iter = this.discardMap.values().iterator(); iter.hasNext(); ex[index++] = ((AsyncAppender.DiscardSummary)iter.next()).createEvent()) { ; // 将DiscardMap的数据重新保存在array里一同持久化 } // 清空 this.buffer.clear(); this.discardMap.clear(); // 生产者消费者重新被唤醒 this.buffer.notifyAll(); } } if(ex != null) { for(int var12 = 0; var12 < ex.length; ++var12) { AppenderAttachableImpl var13 = this.appenders; synchronized(this.appenders) { // 写入磁盘 this.appenders.appendLoopOnAppenders(ex[var12]); } } } } } catch (InterruptedException var11) { Thread.currentThread().interrupt(); } } } // 解决生产者生产速度远大于消费者消费的速度 private static final class DiscardSummary { private LoggingEvent maxEvent; // 丢失了几个 private int count; public DiscardSummary(LoggingEvent event) { this.maxEvent = event; this.count = 1; } public void add(LoggingEvent event) { if(event.getLevel().toInt() > this.maxEvent.getLevel().toInt()) { // 判断等级 this.maxEvent = event; } ++this.count; } public LoggingEvent createEvent() { String msg = MessageFormat.format("Discarded {0} messages due to full event buffer including: {1}", new Object[]{new Integer(this.count), this.maxEvent.getMessage()}); return new LoggingEvent("org.apache.log4j.AsyncAppender.DONT_REPORT_LOCATION", Logger.getLogger(this.maxEvent.getLoggerName()), this.maxEvent.getLevel(), msg, (Throwable)null); } } }
总结:
一个缓冲区buffer,为了减少读写硬盘次数,提高cpu效率,避免过多的中断切换。一个Map对生产者速度远大于消费者地补救措施
一个后台线程不断进行写入磁盘地操作
相关文章推荐
- 深入Log4J源码之Appender
- 详解log4j2(下) - Async/MongoDB/Flume Appender 按日志级别区分文件输出
- 详解log4j2(下) - Async/MongoDB/Flume Appender 按日志级别区分文件输出
- Log4j的AsyncAppender能否提升性能?
- log4j的异步哲学AsyncAppender
- log4j源码解析及一个log4j:ERROR Attempted to append to closed appender named 的问题
- 详解log4j2(下) - Async/MongoDB/Flume Appender 按日志级别区分文件输出
- Log4j的AsyncAppender能否提升性能?
- Log4j的AsyncAppender能否提升性能?
- 深入Log4J源码之Appender[转]
- 详解log4j2(下) - Async/MongoDB/Flume Appender 按日志级别区分文件输出
- Log4j的AsyncAppender能否提升性能?
- log4j之DailyRollingFileAppender源码 重写文件名后缀
- Log4j的AsyncAppender能否提升性能?什么场景用比较好?
- log4j各种appender配置
- Log4J学习【二十五】常用的Appender的使用二
- 关于log4j.properties例子:DailyRollingFileAppender
- 我们在使用Log4j的时候,总是出现: log4j:WARN No appenders could be found for logger (org.apache.ibatis.logging.Lo
- 8.Flume Log4J Appender
- MyEclipse中使用Hibernate时出现log4j:WARN No appenders could be found for logger 警告信息解决