@Override protectedvoidsubAppend(E event){ // The roll-over check must precede actual writing. This is the // only correct behavior for time driven triggers.
// We need to synchronize on triggeringPolicy so that only one rollover // occurs at a time synchronized (triggeringPolicy) { if (triggeringPolicy.isTriggeringEvent(currentlyActiveFile, event)) { rollover(); } } super.subAppend(event); }
/** * All synchronization in this class is done via the lock object. */ protected LogbackLock lock = new LogbackLock();
protectedvoidsubAppend(E event){ if (!isStarted()) { return; } try { // this step avoids LBCLASSIC-139 if (event instanceof DeferredProcessingAware) { ((DeferredProcessingAware) event).prepareForDeferredProcessing(); } // the synchronization prevents the OutputStream from being closed while we // are writing. It also prevents multiple threads from entering the same // converter. Converters assume that they are in a synchronized block. synchronized (lock) { writeOut(event); } } catch (IOException ioe) { // as soon as an exception occurs, move to non-started state // and add a single ErrorStatus to the SM. this.started = false; addStatus(new ErrorStatus("IO failure in appender", this, ioe)); } } // 通过 encode进行日志序列化,格式化写入 protectedvoidwriteOut(E event)throws IOException { this.encoder.doEncode(event); }
if (discardingThreshold == UNDEFINED) discardingThreshold = queueSize / 5; addInfo("Setting discardingThreshold to " + discardingThreshold); worker.setDaemon(true); worker.setName("AsyncAppender-Worker-" + worker.getName()); // make sure this instance is marked as "started" before staring the worker Thread super.start(); worker.start(); }
// loop while the parent is started while (parent.isStarted()) { try { // 从队列中获取数据,其实就是消费者 E e = parent.blockingQueue.take(); aai.appendLoopOnAppenders(e); } catch (InterruptedException ie) { break; } }
addInfo("Worker thread will flush remaining events before exiting. "); for (E e : parent.blockingQueue) { aai.appendLoopOnAppenders(e); }
异步写在JVM突然crash的时候有丢失数据的风险,但是性能很高,原因在于避免了直接写磁盘带来的性能消耗。但是需要注意的是多线程操作同一个阻塞队列也会因为锁争抢的问题影响性能。 a. 不同的模块配置不同的日志文件和Appender,能减少锁争抢的问题。 b. 减少不必要的日志输出。 c. 增加阻塞队列的大小,在neverBlock=false的情况下避免线程等待问题。 d. 多个Appender(SiftingAppender),底层还是写同一个文件。好处是减少了多线程在阻塞队列上的锁竞争问题。