源码基于logback 1.1.7app
本文将分析logger打印日志功能的源码,好比logger.info("hi"):oop
//ch.qos.logback.classic.Logger public void info(String msg) { filterAndLog_0_Or3Plus(FQCN, null, Level.INFO, msg, null, null); } /** * The next methods are not merged into one because of the time we gain by not * creating a new Object[] with the params. This reduces the cost of not * logging by about 20 nanoseconds. */ private void filterAndLog_0_Or3Plus(final String localFQCN, final Marker marker, final Level level, final String msg, final Object[] params,final Throwable t) { final FilterReply decision = loggerContext.getTurboFilterChainDecision_0_3OrMore(marker, this, level, msg, params, t); if (decision == FilterReply.NEUTRAL) { if (effectiveLevelInt > level.levelInt) { return; } } else if (decision == FilterReply.DENY) { return; } //构建loggingEvent并进行日志输出处理 buildLoggingEventAndAppend(localFQCN, marker, level, msg, params, t); } private void buildLoggingEventAndAppend(final String localFQCN, final Marker marker, final Level level, final String msg, final Object[] params,final Throwable t) { //构建loggingEvent对象,主要设置日志级别以及日志内容。 LoggingEvent le = new LoggingEvent(localFQCN, this, level, msg, t, params); le.setMarker(marker); //执行logger下全部的appender callAppenders(le); } //首先获取logger自己的appender list进行处理,处理完后判断logger的additive属性是否是true,false的当即中止,true的话 //获得他的父级logger,好比com.logback.test.LoggerTest对应的logger的父级logger是com.logback.test对应的logger。 //而后使用他的父级logger的appender list进行处理,处理完后并重复以前的逻辑,直到root或则additive为false。 public void callAppenders(ILoggingEvent event) { int writes = 0; for (Logger l = this; l != null; l = l.parent) { writes += l.appendLoopOnAppenders(event); if (!l.additive) { break; } } // No appenders in hierarchy if (writes == 0) { loggerContext.noAppenderDefinedWarning(this); } }
接下来分析Logger的appendLoopOnAppenders方法:ui
private int appendLoopOnAppenders(ILoggingEvent event) { if (aai != null) { return aai.appendLoopOnAppenders(event); } else { return 0; } } //AppenderAttachableImpl public int appendLoopOnAppenders(E e) { int size = 0; //appenderList是该logger的全部的appender,而后循环调用appender的doAppend方法 for (Appender<E> appender : appenderList) { appender.doAppend(e); size++; } return size; }
下面咱们用RollingFileAppender的doAppend方法来分析下:this
public void doAppend(E eventObject) { // WARNING: The guard check MUST be the first statement in the // doAppend() method. // prevent re-entry. if (Boolean.TRUE.equals(guard.get())) { return; } try { guard.set(Boolean.TRUE); if (!this.started) { if (statusRepeatCount++ < ALLOWED_REPEATS) { addStatus(new WarnStatus("Attempted to append to non started appender [" + name + "].", this)); } return; } if (getFilterChainDecision(eventObject) == FilterReply.DENY) { return; } // ok, we now invoke derived class' implementation of append //核心,下面分析 this.append(eventObject); } catch (Exception e) { if (exceptionCount++ < ALLOWED_REPEATS) { addError("Appender [" + name + "] failed to append.", e); } } finally { guard.set(Boolean.FALSE); } } //OutputStreamAppender protected void append(E eventObject) { if (!isStarted()) { return; } subAppend(eventObject); } //RollingFileAppender protected void subAppend(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) { //判断是否触发trigger policy,好比基于时间策略来归档日志的,会判断当前时间是否是大于下次检测的时间戳, //若是大于则会设置下次检测时间戳进行日志归档。 if (triggeringPolicy.isTriggeringEvent(currentlyActiveFile, event)) { //假如输出日志文件未info.log,这里便会关闭info.log输出流,而后对他进行归档,好比info.2017.06.08.log, //最后从新建立info.log,打开输出流,等待后续日志写入 rollover(); } } //调用OutputStreamAppender的subAppend方法 super.subAppend(event); } //OutputStreamAppender protected void subAppend(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. //正如上面所说,这里加锁是为了保护当咱们正在写的时候输出流被关闭,还有就是防止多个线程进入操做 lock.lock(); try { //输出日志 writeOut(event); } finally { lock.unlock(); } } 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)); } } protected void writeOut(E event) throws IOException { this.encoder.doEncode(event); } //LayoutWrappingEncoder public void doEncode(E event) throws IOException { //根据encoder partten转换msg为真正的输出内容 String txt = layout.doLayout(event); //转化成byte而后输出到日志文件中 outputStream.write(convertToBytes(txt)); if (immediateFlush) outputStream.flush(); }