Log4j2的日志輸出過(guò)程

系列

背景

?該篇文章主要介紹Log4j2的日志輸出過(guò)程,核心流程包含獲取Logger對(duì)象和通過(guò)Logger輸出日志。

  • Logger的獲取過(guò)程主要通過(guò)LoggerContext和LoggerRegistry來(lái)獲取。
  • Logger的日志輸出主要通過(guò)Logger、LoggerConfig、AppenderControl、Appender進(jìn)行日志輸出

Logger獲取過(guò)程

Log4j2獲取Logger的過(guò)程主要從LoggerContext、LoggerRegistry處獲取Logger對(duì)象。

public class LogManager {

    public static Logger getLogger(final String name) {
        return name != null ? getContext(false).getLogger(name) : 
                   getLogger(StackLocatorUtil.getCallerClass(2));
    }
}
  • LogManager通過(guò)LoggerContext來(lái)獲取Logger對(duì)象。
public class LoggerContext

    public Logger getLogger(final String name, final MessageFactory messageFactory) {

        // 通過(guò)LoggerRegistry來(lái)獲取Logger對(duì)象
        Logger logger = loggerRegistry.getLogger(name, messageFactory);
        if (logger != null) {
            AbstractLogger.checkMessageFactory(logger, messageFactory);
            return logger;
        }

        logger = newInstance(this, name, messageFactory);
        loggerRegistry.putIfAbsent(name, messageFactory, logger);
        return loggerRegistry.getLogger(name, messageFactory);
    }
}
  • LoggerContext通過(guò)LoggerRegistry來(lái)獲取Logger對(duì)象。
public class LoggerRegistry<T extends ExtendedLogger> {

    public T getLogger(final String name, final MessageFactory messageFactory) {
        return getOrCreateInnerMap(factoryKey(messageFactory)).get(name);
    }

    private Map<String, T> getOrCreateInnerMap(final String factoryName) {
        Map<String, T> inner = map.get(factoryName);
        if (inner == null) {
            inner = factory.createInnerMap();
            map.put(factoryName, inner);
        }
        return inner;
    }
}
  • LoggerRegistry內(nèi)部維護(hù)Logger對(duì)象。

日志輸出過(guò)程

  • 整體日志輸出流程通過(guò)Logger、LoggerConfig、AppenderControl、Appender進(jìn)行日志輸出。

日志輸出源碼

public abstract class AbstractLogger

    public void logIfEnabled(final String fqcn, final Level level, final Marker marker, final String message,final Throwable t) {
        // 全局Filter和全局的日志級(jí)別進(jìn)行過(guò)濾
        if (isEnabled(level, marker, message, t)) {
            // 輸出日志
            logMessage(fqcn, level, marker, message, t);
        }
    }

    protected void logMessage(final String fqcn, final Level level, 
          final Marker marker, final String message,final Throwable t) {
        // 通過(guò)ReusableMessageFactory組建消息體
        logMessageSafely(fqcn, level, marker, 
                 messageFactory.newMessage(message), t);
    }

    private void logMessageSafely(final String fqcn, final Level level, 
           final Marker marker, final Message msg, final Throwable throwable) {
        try {
            logMessageTrackRecursion(fqcn, level, marker, msg, throwable);
        } finally {
            ReusableMessageFactory.release(msg);
        }
    }

    private void logMessageTrackRecursion(final String fqcn,
                                          final Level level,
                                          final Marker marker,
                                          final Message msg,
                                          final Throwable throwable) {
        try {
            incrementRecursionDepth(); // LOG4J2-1518, LOG4J2-2031
            tryLogMessage(fqcn, getLocation(fqcn), level, 
                           marker, msg, throwable);
        } finally {
            decrementRecursionDepth();
        }
    }

    private void tryLogMessage(final String fqcn,
                               final StackTraceElement location,
                               final Level level,
                               final Marker marker,
                               final Message msg,
                               final Throwable throwable) {
        try {
            log(level, marker, fqcn, location, msg, throwable);
        } catch (final Exception e) {
            handleLogMessageException(e, fqcn, msg);
        }
    }

    protected void log(final Level level, final Marker marker, 
                  final String fqcn, final StackTraceElement location,
                  final Message message, final Throwable throwable) {
        // strategy為AwaitCompletionReliabilityStrategy
        final ReliabilityStrategy strategy = 
             privateConfig.loggerConfig.getReliabilityStrategy();
        if (strategy instanceof LocationAwareReliabilityStrategy) {
            // 繼續(xù)跟進(jìn)log過(guò)程
            ((LocationAwareReliabilityStrategy) strategy)
              .log(this, getName(), fqcn, location, marker, level,
                     message, throwable);
        } else {
            // 省略代碼
        }
    }
}
  • Logger通過(guò)PrivateConfig的isEnabled進(jìn)行過(guò)濾。
  • Logger通過(guò)strategy的log方法進(jìn)行日志輸出。
public class Logger extends AbstractLogger implements Supplier<LoggerConfig> {

    public boolean isEnabled(final Level level, final Marker marker, 
                               final String message, final Throwable t) {
        return privateConfig.filter(level, marker, message, t);
    }

    protected class PrivateConfig {
        boolean filter(final Level level, final Marker marker, 
                            final String msg, final Throwable t) {
            // 先通過(guò)全局的Filter進(jìn)行過(guò)濾
            final Filter filter = config.getFilter();
            if (filter != null) {
                final Filter.Result r = 
                      filter.filter(logger, level, marker, (Object) msg, t);
                if (r != Filter.Result.NEUTRAL) {
                    return r == Filter.Result.ACCEPT;
                }
            }
            // 再判斷日志等級(jí)是否滿(mǎn)足要求
            return level != null && intLevel >= level.intLevel();
        }
    }
}
  • PrivateConfig的filter負(fù)責(zé)日志輸出過(guò)濾。
public class AwaitCompletionReliabilityStrategy 

    public void log(final Supplier<LoggerConfig> reconfigured, 
        final String loggerName, final String fqcn,
        final StackTraceElement location, final Marker marker, 
        final Level level, final Message data, final Throwable t) {

        // 通過(guò)LoggerConfig的進(jìn)行日志打印
        final LoggerConfig config = getActiveLoggerConfig(reconfigured);
        try {
            config.log(loggerName, fqcn, location, marker, level, data, t);
        } finally {
            config.getReliabilityStrategy().afterLogEvent();
        }
    }
}
  • AwaitCompletionReliabilityStrategy通過(guò)LoggerConfig進(jìn)行日志輸出。
public class LoggerConfig extends AbstractFilterable implements LocationAware {

    public void log(final String loggerName, final String fqcn, 
        final StackTraceElement location, final Marker marker,
        final Level level, final Message data, final Throwable t) {
        List<Property> props = null;
        if (!propertiesRequireLookup) {
            props = properties;
        } 

        // 創(chuàng)建LogEvent對(duì)象
        final LogEvent logEvent = 
         logEventFactory instanceof LocationAwareLogEventFactory ?
            ((LocationAwareLogEventFactory) logEventFactory).createEvent(
                loggerName, marker, fqcn, location, level, data, props, t) : 
           logEventFactory.createEvent(
            loggerName, marker, fqcn, level, data, props, t);

        try {
            // 繼續(xù)執(zhí)行
            log(logEvent, LoggerConfigPredicate.ALL);
        } finally {
            ReusableLogEventFactory.release(logEvent);
        }
    }

    protected void log(final LogEvent event, 
                 final LoggerConfigPredicate predicate) {
        if (!isFiltered(event)) {
            processLogEvent(event, predicate);
        }
    }

    private void processLogEvent(final LogEvent event, 
                    final LoggerConfigPredicate predicate) {
        event.setIncludeLocation(isIncludeLocation());
        if (predicate.allow(this)) {
            callAppenders(event);
        }
        logParent(event, predicate);
    }

    protected void callAppenders(final LogEvent event) {
        final AppenderControl[] controls = appenders.get();
        //noinspection ForLoopReplaceableByForEach
        for (int i = 0; i < controls.length; i++) {
            controls[i].callAppender(event);
        }
    }
}
  • LoggerConfig通過(guò)AppenderControl的callAppender進(jìn)行日志輸出。
public class AppenderControl extends AbstractFilterable {

    public void callAppender(final LogEvent event) {
        if (shouldSkip(event)) {
            return;
        }
        callAppenderPreventRecursion(event);
    }

    private void callAppenderPreventRecursion(final LogEvent event) {
        try {
            recursive.set(this);
            callAppender0(event);
        } finally {
            recursive.set(null);
        }
    }

    private void callAppender0(final LogEvent event) {
        ensureAppenderStarted();
        if (!isFilteredByAppender(event)) {
            tryCallAppender(event);
        }
    }

    private void tryCallAppender(final LogEvent event) {
        try {
            appender.append(event);
        } catch (final RuntimeException ex) {
            handleAppenderError(event, ex);
        } catch (final Exception ex) {
            handleAppenderError(event, new AppenderLoggingException(ex));
        }
    }

    private boolean shouldSkip(final LogEvent event) {
        return isFilteredByAppenderControl(event) 
                  || isFilteredByLevel(event) || isRecursiveCall();
    }
}
  • AppenderControl通過(guò)Appender的append進(jìn)行日志輸出。
public abstract class AbstractOutputStreamAppender<
        M extends OutputStreamManager> extends AbstractAppender {

    public void append(final LogEvent event) {
        try {
            tryAppend(event);
        } catch (final AppenderLoggingException ex) {
            throw ex;
        }
    }

    private void tryAppend(final LogEvent event) {
        if (Constants.ENABLE_DIRECT_ENCODERS) {
            directEncodeEvent(event);
        } else {
            writeByteArrayToManager(event);
        }
    }

    protected void directEncodeEvent(final LogEvent event) {
        getLayout().encode(event, manager);
        if (this.immediateFlush || event.isEndOfBatch()) {
            manager.flush();
        }
    }
}
  • 具體的Appender進(jìn)行格式化并輸出日志。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容