初始化
LoggerFactory
private static final Logger logger = LoggerFactory.getLogger(LogFilter.class);
LoggerFactory#getLogger()
public static Logger getLogger(Class<?> clazz) {
Logger logger = getLogger(clazz.getName());
if (DETECT_LOGGER_NAME_MISMATCH) {
Class<?> autoComputedCallingClass = Util.getCallingClass();
if (autoComputedCallingClass != null && nonMatchingClasses(clazz, autoComputedCallingClass)) {
Util.report(String.format("Detected logger name mismatch. Given name: \"%s\"; computed name: \"%s\".", logger.getName(), autoComputedCallingClass.getName()));
Util.report("See http://www.slf4j.org/codes.html#loggerNameMismatch for an explanation");
}
}
return logger;
}
public static Logger getLogger(String name) {
ILoggerFactory iLoggerFactory = getILoggerFactory();
return iLoggerFactory.getLogger(name);
}
AbstractLoggerAdapter#getLogger
,抽象方法,getContext
由子类重写。
@Override
public L getLogger(final String name) {
final LoggerContext context = getContext();
final ConcurrentMap<String, L> loggers = getLoggersInContext(context);
final L logger = loggers.get(name);
if (logger != null) {
return logger;
}
loggers.putIfAbsent(name, newLogger(name, context));
return loggers.get(name);
}
protected abstract LoggerContext getContext();
Log4jLoggerFactory#getContext
,调用LogManager.getContext()
protected LoggerContext getContext() {
Class<?> anchor = StackLocatorUtil.getCallerClass(FQCN, "org.slf4j");
return anchor == null ? LogManager.getContext() : this.getContext(StackLocatorUtil.getCallerClass(anchor));
}
LogManager
LogManager
初始化会调用静态方法块
- 根据特定配置文件的配置信息获取loggerContextFactory
- 没有找到对应的Factory的实现类,则通过ProviderUtil中的getProviders()方法载入providers。
- 如果provider中没有获取到
LoggerContextFactory
的实现类或provider为空,则使用SimpleLoggerContextFactory
作为LoggerContextFactory
。
static {
// Shortcut binding to force a specific logging implementation.
final PropertiesUtil managerProps = PropertiesUtil.getProperties();
final String factoryClassName = managerProps.getStringProperty(FACTORY_PROPERTY_NAME);
if (factoryClassName != null) {
try {
factory = LoaderUtil.newCheckedInstanceOf(factoryClassName, LoggerContextFactory.class);
} catch (final ClassNotFoundException cnfe) {
LOGGER.error("Unable to locate configured LoggerContextFactory {}", factoryClassName);
} catch (final Exception ex) {
LOGGER.error("Unable to create configured LoggerContextFactory {}", factoryClassName, ex);
}
}
if (factory == null) {
final SortedMap<Integer, LoggerContextFactory> factories = new TreeMap<>();
// note that the following initial call to ProviderUtil may block until a Provider has been installed when
// running in an OSGi environment
if (ProviderUtil.hasProviders()) {
for (final Provider provider : ProviderUtil.getProviders()) {
final Class<? extends LoggerContextFactory> factoryClass = provider.loadLoggerContextFactory();
if (factoryClass != null) {
try {
factories.put(provider.getPriority(), factoryClass.newInstance());
} catch (final Exception e) {
LOGGER.error("Unable to create class {} specified in provider URL {}", factoryClass.getName(), provider
.getUrl(), e);
}
}
}
if (factories.isEmpty()) {
LOGGER.error("Log4j2 could not find a logging implementation. "
+ "Please add log4j-core to the classpath. Using SimpleLogger to log to the console...");
factory = new SimpleLoggerContextFactory();
} else if (factories.size() == 1) {
factory = factories.get(factories.lastKey());
} else {
final StringBuilder sb = new StringBuilder("Multiple logging implementations found: \n");
for (final Map.Entry<Integer, LoggerContextFactory> entry : factories.entrySet()) {
sb.append("Factory: ").append(entry.getValue().getClass().getName());
sb.append(", Weighting: ").append(entry.getKey()).append('\n');
}
factory = factories.get(factories.lastKey());
sb.append("Using factory: ").append(factory.getClass().getName());
LOGGER.warn(sb.toString());
}
} else {
LOGGER.error("Log4j2 could not find a logging implementation. "
+ "Please add log4j-core to the classpath. Using SimpleLogger to log to the console...");
factory = new SimpleLoggerContextFactory();
}
}
}
ProviderUtil
,通过SPI加载Provider
,得到Log4jProvider
private ProviderUtil() {
for (final ClassLoader classLoader : LoaderUtil.getClassLoaders()) {
try {
loadProviders(classLoader);
} catch (final Throwable ex) {
LOGGER.debug("Unable to retrieve provider from ClassLoader {}", classLoader, ex);
}
}
for (final LoaderUtil.UrlResource resource : LoaderUtil.findUrlResources(PROVIDER_RESOURCE)) {
loadProvider(resource.getUrl(), resource.getClassLoader());
}
}
protected static void loadProviders(final ClassLoader classLoader) {
final ServiceLoader<Provider> serviceLoader = ServiceLoader.load(Provider.class, classLoader);
for (final Provider provider : serviceLoader) {
if (validVersion(provider.getVersions()) && !PROVIDERS.contains(provider)) {
PROVIDERS.add(provider);
}
}
}
Log4jProvider
对应的工厂类Log4jContextFactory
。
public class Log4jProvider extends Provider {
public Log4jProvider() {
super(10, "2.6.0", Log4jContextFactory.class);
}
}
LoggerContext
加载好LogManager
,初始化得到Log4jContextFactory
,会执行Log4jContextFactory#getContext
,得到LoggerContext
对象,并启动。
public LoggerContext getContext(String fqcn, ClassLoader loader, Object externalContext, boolean currentContext) {
LoggerContext ctx = this.selector.getContext(fqcn, loader, currentContext);
if (externalContext != null && ctx.getExternalContext() == null) {
ctx.setExternalContext(externalContext);
}
if (ctx.getState() == State.INITIALIZED) {
ctx.start();
}
return ctx;
}
LoggerContext#start()
public void start() {
LOGGER.debug("Starting LoggerContext[name={}, {}]...", this.getName(), this);
if (PropertiesUtil.getProperties().getBooleanProperty("log4j.LoggerContext.stacktrace.on.start", false)) {
LOGGER.debug("Stack trace to locate invoker", new Exception("Not a real error, showing stack trace to locate invoker"));
}
if (this.configLock.tryLock()) {
try {
if (this.isInitialized() || this.isStopped()) {
this.setStarting();
this.reconfigure();
if (this.configuration.isShutdownHookEnabled()) {
this.setUpShutdownHook();
}
this.setStarted();
}
} finally {
this.configLock.unlock();
}
}
LOGGER.debug("LoggerContext[name={}, {}] started OK.", this.getName(), this);
}
核心方法是reconfigure
。
Configuration instance = ConfigurationFactory.getInstance().getConfiguration();
,加载了一堆ConfigurationFactory
,通过ConfigurationFactory
去获取`Configuration``LoggerContext#setConfiguration
会执行config.start();
private void reconfigure(URI configURI) {
Object externalContext = this.externalMap.get("__EXTERNAL_CONTEXT_KEY__");
ClassLoader cl = ClassLoader.class.isInstance(externalContext) ? (ClassLoader)externalContext : null;
LOGGER.debug("Reconfiguration started for context[name={}] at URI {} ({}) with optional ClassLoader: {}", this.contextName, configURI, this, cl);
Configuration instance = ConfigurationFactory.getInstance().getConfiguration(this, this.contextName, configURI, cl);
if (instance == null) {
LOGGER.error("Reconfiguration failed: No configuration found for '{}' at '{}' in '{}'", this.contextName, configURI, cl);
} else {
this.setConfiguration(instance);
String location = this.configuration == null ? "?" : String.valueOf(this.configuration.getConfigurationSource());
LOGGER.debug("Reconfiguration complete for context[name={}] at URI {} ({}) with optional ClassLoader: {}", this.contextName, location, this, cl);
}
}
AbstractConfiguration#start
,进行启动
@Override
public void start() {
// Preserve the prior behavior of initializing during start if not initialized.
if (getState().equals(State.INITIALIZING)) {
initialize();
}
LOGGER.debug("Starting configuration {}", this);
this.setStarting();
if (watchManager.getIntervalSeconds() >= 0) {
watchManager.start();
}
if (hasAsyncLoggers()) {
asyncLoggerConfigDisruptor.start();
}
final Set<LoggerConfig> alreadyStarted = new HashSet<>();
for (final LoggerConfig logger : loggerConfigs.values()) {
logger.start();
alreadyStarted.add(logger);
}
for (final Appender appender : appenders.values()) {
appender.start();
}
if (!alreadyStarted.contains(root)) { // LOG4J2-392
root.start(); // LOG4J2-336
}
super.start();
LOGGER.debug("Started configuration {} OK.", this);
}
AbstractConfiguration#initialize
,进行初始化。
@Override
public void initialize() {
LOGGER.debug(Version.getProductString() + " initializing configuration {}", this);
subst.setConfiguration(this);
try {
scriptManager = new ScriptManager(this, watchManager);
} catch (final LinkageError | Exception e) {
// LOG4J2-1920 ScriptEngineManager is not available in Android
LOGGER.info("Cannot initialize scripting support because this JRE does not support it.", e);
}
pluginManager.collectPlugins(pluginPackages);
final PluginManager levelPlugins = new PluginManager(Level.CATEGORY);
levelPlugins.collectPlugins(pluginPackages);
final Map<String, PluginType<?>> plugins = levelPlugins.getPlugins();
if (plugins != null) {
for (final PluginType<?> type : plugins.values()) {
try {
// Cause the class to be initialized if it isn't already.
Loader.initializeClass(type.getPluginClass().getName(), type.getPluginClass().getClassLoader());
} catch (final Exception e) {
LOGGER.error("Unable to initialize {} due to {}", type.getPluginClass().getName(), e.getClass()
.getSimpleName(), e);
}
}
}
setup();
setupAdvertisement();
doConfigure();
setState(State.INITIALIZED);
LOGGER.debug("Configuration {} initialized", this);
}
XmlConfiguration#setup
,对xml进行解析,constructHierarchy
是一个递归方法。
@Override
public void setup() {
if (rootElement == null) {
LOGGER.error("No logging configuration");
return;
}
constructHierarchy(rootNode, rootElement);
if (status.size() > 0) {
for (final Status s : status) {
LOGGER.error("Error processing element {} ({}): {}", s.name, s.element, s.errorType);
}
return;
}
rootElement = null;
}
XmlConfiguration#constructHierarchy
,使用w3cNode
对xml进行解析
private void constructHierarchy(final Node node, final Element element) {
processAttributes(node, element);
final StringBuilder buffer = new StringBuilder();
final NodeList list = element.getChildNodes();
final List<Node> children = node.getChildren();
for (int i = 0; i < list.getLength(); i++) {
final org.w3c.dom.Node w3cNode = list.item(i);
if (w3cNode instanceof Element) {
final Element child = (Element) w3cNode;
final String name = getType(child);
final PluginType<?> type = pluginManager.getPluginType(name);
final Node childNode = new Node(node, name, type);
constructHierarchy(childNode, child);
if (type == null) {
final String value = childNode.getValue();
if (!childNode.hasChildren() && value != null) {
node.getAttributes().put(name, value);
} else {
status.add(new Status(name, element, ErrorType.CLASS_NOT_FOUND));
}
} else {
children.add(childNode);
}
} else if (w3cNode instanceof Text) {
final Text data = (Text) w3cNode;
buffer.append(data.getData());
}
}
final String text = buffer.toString().trim();
if (text.length() > 0 || (!node.hasChildren() && !node.isRoot())) {
node.setValue(text);
}
}
PluginManager
PluginManager#collectPlugins()
,根据包名加载插件
public void collectPlugins(List<String> packages) {
String categoryLowerCase = this.category.toLowerCase();
Map<String, PluginType<?>> newPlugins = new LinkedHashMap();
Map<String, List<PluginType<?>>> builtInPlugins = PluginRegistry.getInstance().loadFromMainClassLoader();
if (builtInPlugins.isEmpty()) {
builtInPlugins = PluginRegistry.getInstance().loadFromPackage("org.apache.logging.log4j.core");
}
mergeByName(newPlugins, (List)builtInPlugins.get(categoryLowerCase));
Iterator var5 = PluginRegistry.getInstance().getPluginsByCategoryByBundleId().values().iterator();
while(var5.hasNext()) {
Map<String, List<PluginType<?>>> pluginsByCategory = (Map)var5.next();
mergeByName(newPlugins, (List)pluginsByCategory.get(categoryLowerCase));
}
var5 = PACKAGES.iterator();
String pkg;
while(var5.hasNext()) {
pkg = (String)var5.next();
mergeByName(newPlugins, (List)PluginRegistry.getInstance().loadFromPackage(pkg).get(categoryLowerCase));
}
if (packages != null) {
var5 = packages.iterator();
while(var5.hasNext()) {
pkg = (String)var5.next();
mergeByName(newPlugins, (List)PluginRegistry.getInstance().loadFromPackage(pkg).get(categoryLowerCase));
}
}
LOGGER.debug("PluginManager '{}' found {} plugins", this.category, newPlugins.size());
this.plugins = newPlugins;
}
打印日志
Log4jLogger#info()
public void info(String format) {
this.logger.logIfEnabled(FQCN, Level.INFO, (org.apache.logging.log4j.Marker)null, format);
}
AbstractLogger#logIfEnabled()
,判断是否有权限。
public void logIfEnabled(final String fqcn, final Level level, final Marker marker, final String message) {
if (isEnabled(level, marker, message)) {
logMessage(fqcn, level, marker, message);
}
}
Logger#isEnabled()
,判断是否有权限
@Override
public boolean isEnabled(final Level level, final Marker marker, final String message) {
return privateConfig.filter(level, marker, message);
}
PrivateConfig#filter()
,判断当前的Logger的日志级别是否大于输出的日志级别。
boolean filter(final Level level, final Marker marker, final String msg) {
final Filter filter = config.getFilter();
if (filter != null) {
final Filter.Result r = filter.filter(logger, level, marker, msg);
if (r != Filter.Result.NEUTRAL) {
return r == Filter.Result.ACCEPT;
}
}
return level != null && intLevel >= level.intLevel();
}
AbstractLogger#tryLogMessage
,输出日志
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) {
// LOG4J2-1990 Log4j2 suppresses all exceptions that occur once application called the logger
handleLogMessageException(e, fqcn, msg);
}
}
Logger#log
,获取到ReliabilityStrategy
,进行日志输出。
@Override
protected void log(final Level level, final Marker marker, final String fqcn, final StackTraceElement location,
final Message message, final Throwable throwable) {
final ReliabilityStrategy strategy = privateConfig.loggerConfig.getReliabilityStrategy();
if (strategy instanceof LocationAwareReliabilityStrategy) {
((LocationAwareReliabilityStrategy) strategy).log(this, getName(), fqcn, location, marker, level,
message, throwable);
} else {
strategy.log(this, getName(), fqcn, marker, level, message, throwable);
}
}
AwaitCompletionReliabilityStrategy#log()
,获取到LoggerConfig
,执行log
方法。
@Override
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) {
final LoggerConfig config = getActiveLoggerConfig(reconfigured);
try {
config.log(loggerName, fqcn, location, marker, level, data, t);
} finally {
config.getReliabilityStrategy().afterLogEvent();
}
}
LoggerConfig#log()
,创建LogEvent
。
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;
} else {
if (properties != null) {
props = new ArrayList<>(properties.size());
final LogEvent event = Log4jLogEvent.newBuilder()
.setMessage(data)
.setMarker(marker)
.setLevel(level)
.setLoggerName(loggerName)
.setLoggerFqcn(fqcn)
.setThrown(t)
.build();
for (int i = 0; i < properties.size(); i++) {
final Property prop = properties.get(i);
final String value = prop.isValueNeedsLookup() // since LOG4J2-1575
? config.getStrSubstitutor().replace(event, prop.getValue()) //
: prop.getValue();
props.add(Property.createProperty(prop.getName(), value));
}
}
}
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 {
log(logEvent, LoggerConfigPredicate.ALL);
} finally {
// LOG4J2-1583 prevent scrambled logs when logging calls are nested (logging in toString())
ReusableLogEventFactory.release(logEvent);
}
}
protected void log(final LogEvent event, final LoggerConfigPredicate predicate) {
if (!isFiltered(event)) {
processLogEvent(event, predicate);
}
}
LoggerConfig#processLogEvent
,调用appender
private void processLogEvent(final LogEvent event, final LoggerConfigPredicate predicate) {
event.setIncludeLocation(isIncludeLocation());
if (predicate.allow(this)) {
callAppenders(event);
}
logParent(event, predicate);
}
ConsoleAppender
ConsoleAppender
,控制台输出器,获取Layout
,执行PatternLayout#encode
public void append(final LogEvent event) {
try {
tryAppend(event);
} catch (final AppenderLoggingException ex) {
error("Unable to write to stream " + manager.getName() + " for appender " + getName(), event, 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();
}
}
PatternLayout#encode
,布局器进行输出。
@Override
public void encode(final LogEvent event, final ByteBufferDestination destination) {
if (!(eventSerializer instanceof Serializer2)) {
super.encode(event, destination);
return;
}
final StringBuilder text = toText((Serializer2) eventSerializer, event, getStringBuilder());
final Encoder<StringBuilder> encoder = getStringBuilderEncoder();
encoder.encode(text, destination);
trimToMaxSize(text);
}
private StringBuilder toText(final Serializer2 serializer, final LogEvent event,
final StringBuilder destination) {
return serializer.toSerializable(event, destination);
}
PatternLayout.PatternSerializer#toSerializable()
,获取格式化器的集合,挨个处理
@Override
public StringBuilder toSerializable(final LogEvent event, final StringBuilder buffer) {
final int len = formatters.length;
for (int i = 0; i < len; i++) {
formatters[i].format(event, buffer);
}
if (replace != null) { // creates temporary objects
String str = buffer.toString();
str = replace.format(str);
buffer.setLength(0);
buffer.append(str);
}
return buffer;
}
LoggerPatternConverter
就是把pattern中的%c
转换为当前类名。
@Plugin(name = "LoggerPatternConverter", category = PatternConverter.CATEGORY)
@ConverterKeys({ "c", "logger" })
@PerformanceSensitive("allocation")
public final class LoggerPatternConverter extends NamePatternConverter {
/**
* Singleton.
*/
private static final LoggerPatternConverter INSTANCE =
new LoggerPatternConverter(null);
/**
* Private constructor.
*
* @param options options, may be null.
*/
private LoggerPatternConverter(final String[] options) {
super("Logger", "logger", options);
}
/**
* Obtains an instance of pattern converter.
*
* @param options options, may be null.
* @return instance of pattern converter.
*/
public static LoggerPatternConverter newInstance(
final String[] options) {
if (options == null || options.length == 0) {
return INSTANCE;
}
return new LoggerPatternConverter(options);
}
/**
* {@inheritDoc}
*/
@Override
public void format(final LogEvent event, final StringBuilder toAppendTo) {
abbreviate(event.getLoggerName(), toAppendTo);
}
}
AsyncAppender
AsyncAppender#append
,添加到队列中。
@Override
public void append(final LogEvent logEvent) {
if (!isStarted()) {
throw new IllegalStateException("AsyncAppender " + getName() + " is not active");
}
final Log4jLogEvent memento = Log4jLogEvent.createMemento(logEvent, includeLocation);
InternalAsyncUtil.makeMessageImmutable(logEvent.getMessage());
if (!transfer(memento)) {
if (blocking) {
if (AbstractLogger.getRecursionDepth() > 1) { // LOG4J2-1518, LOG4J2-2031
// If queue is full AND we are in a recursive call, call appender directly to prevent deadlock
AsyncQueueFullMessageUtil.logWarningToStatusLogger();
logMessageInCurrentThread(logEvent);
} else {
// delegate to the event router (which may discard, enqueue and block, or log in current thread)
final EventRoute route = asyncQueueFullPolicy.getRoute(thread.getId(), memento.getLevel());
route.logMessage(this, memento);
}
} else {
error("Appender " + getName() + " is unable to write primary appenders. queue is full");
logToErrorAppenderIfNecessary(false, memento);
}
}
}
private boolean transfer(final LogEvent memento) {
return queue instanceof TransferQueue
? ((TransferQueue<LogEvent>) queue).tryTransfer(memento)
: queue.offer(memento);
}
AsyncThread
,会不断的从队列中获取LogEvent
,进行消费
@Override
public void run() {
while (!shutdown) {
LogEvent event;
try {
event = queue.take();
if (event == SHUTDOWN_LOG_EVENT) {
shutdown = true;
continue;
}
} catch (final InterruptedException ex) {
break; // LOG4J2-830
}
event.setEndOfBatch(queue.isEmpty());
final boolean success = callAppenders(event);
if (!success && errorAppender != null) {
try {
errorAppender.callAppender(event);
} catch (final Exception ex) {
// Silently accept the error.
}
}
}
}
异步日志
AsyncLoggerContext
AsyncLoggerContext#start()
,启动loggerDisruptor
@Override
public void start() {
loggerDisruptor.start();
super.start();
}
AsyncLoggerDisruptor#start
,启动disruptor
,设置处理器RingBufferLogEventHandler
public synchronized void start() {
if (disruptor != null) {
LOGGER.trace(
"[{}] AsyncLoggerDisruptor not starting new disruptor for this context, using existing object.",
contextName);
return;
}
LOGGER.trace("[{}] AsyncLoggerDisruptor creating new disruptor for this context.", contextName);
ringBufferSize = DisruptorUtil.calculateRingBufferSize("AsyncLogger.RingBufferSize");
final WaitStrategy waitStrategy = DisruptorUtil.createWaitStrategy("AsyncLogger.WaitStrategy");
final ThreadFactory threadFactory = new Log4jThreadFactory("AsyncLogger[" + contextName + "]", true, Thread.NORM_PRIORITY) {
@Override
public Thread newThread(final Runnable r) {
final Thread result = super.newThread(r);
backgroundThreadId = result.getId();
return result;
}
};
asyncQueueFullPolicy = AsyncQueueFullPolicyFactory.create();
disruptor = new Disruptor<>(RingBufferLogEvent.FACTORY, ringBufferSize, threadFactory, ProducerType.MULTI,
waitStrategy);
final ExceptionHandler<RingBufferLogEvent> errorHandler = DisruptorUtil.getAsyncLoggerExceptionHandler();
disruptor.setDefaultExceptionHandler(errorHandler);
final RingBufferLogEventHandler[] handlers = {new RingBufferLogEventHandler()};
disruptor.handleEventsWith(handlers);
LOGGER.debug("[{}] Starting AsyncLogger disruptor for this context with ringbufferSize={}, waitStrategy={}, "
+ "exceptionHandler={}...", contextName, disruptor.getRingBuffer().getBufferSize(), waitStrategy
.getClass().getSimpleName(), errorHandler);
disruptor.start();
LOGGER.trace("[{}] AsyncLoggers use a {} translator", contextName, useThreadLocalTranslator ? "threadlocal"
: "vararg");
super.start();
}
AsyncLogger
AsyncLogger#log
,异步日志输出。
@Override
public void log(final Level level, final Marker marker, final String fqcn, final StackTraceElement location,
final Message message, final Throwable throwable) {
getTranslatorType().log(fqcn, location, level, marker, message, throwable);
}
AsyncLogger#logWithThreadLocalTranslator()
,将日志相关的信息转换成RingBufferLogEvent
(RingBuffer是Disruptor的无所队列),然后将其发布到RingBuffer中。
private void logWithThreadLocalTranslator(final String fqcn, final StackTraceElement location, final Level level,
final Marker marker, final Message message, final Throwable thrown) {
// Implementation note: this method is tuned for performance. MODIFY WITH CARE!
final RingBufferLogEventTranslator translator = getCachedTranslator();
initTranslator(translator, fqcn, location, level, marker, message, thrown);
initTranslatorThreadValues(translator);
publish(translator);
}
private void publish(final RingBufferLogEventTranslator translator) {
if (!loggerDisruptor.tryPublish(translator)) {
handleRingBufferFull(translator);
}
}
private void handleRingBufferFull(final RingBufferLogEventTranslator translator) {
if (AbstractLogger.getRecursionDepth() > 1) { // LOG4J2-1518, LOG4J2-2031
// If queue is full AND we are in a recursive call, call appender directly to prevent deadlock
AsyncQueueFullMessageUtil.logWarningToStatusLogger();
logMessageInCurrentThread(translator.fqcn, translator.level, translator.marker, translator.message,
translator.thrown);
translator.clear();
return;
}
final EventRoute eventRoute = loggerDisruptor.getEventRoute(translator.level);
switch (eventRoute) {
case ENQUEUE:
loggerDisruptor.enqueueLogMessageWhenQueueFull(translator);
break;
case SYNCHRONOUS:
logMessageInCurrentThread(translator.fqcn, translator.level, translator.marker, translator.message,
translator.thrown);
translator.clear();
break;
case DISCARD:
translator.clear();
break;
default:
throw new IllegalStateException("Unknown EventRoute " + eventRoute);
}
}
RingBufferLogEventHandler
日志处理器,调用RingBufferLogEvent
的execute
方法
@Override
public void onEvent(final RingBufferLogEvent event, final long sequence,
final boolean endOfBatch) throws Exception {
try {
event.execute(endOfBatch);
}
finally {
event.clear();
// notify the BatchEventProcessor that the sequence has progressed.
// Without this callback the sequence would not be progressed
// until the batch has completely finished.
notifyCallback(sequence);
}
}
RingBufferLogEvent#execute
,输出日志。
public void execute(final boolean endOfBatch) {
this.endOfBatch = endOfBatch;
asyncLogger.actualAsyncLog(this);
}
AsyncLogger#actualAsyncLog
public void actualAsyncLog(final RingBufferLogEvent event) {
final LoggerConfig privateConfigLoggerConfig = privateConfig.loggerConfig;
final List<Property> properties = privateConfigLoggerConfig.getPropertyList();
if (properties != null) {
onPropertiesPresent(event, properties);
}
privateConfigLoggerConfig.getReliabilityStrategy().log(this, event);
}
Log4j使用disruptor
实现异步日志
引入依赖
<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
<version>3.4.0</version>
</dependency>
JVM配置启动参数
-DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector
log4j2.xml
使用AsyncRoot/AsyncLogger
替代Root/Logger
<Loggers>
<AsyncRoot level="info">
<AppenderRef ref="STDOUT" />
<AppenderRef ref="CatAppender" />
<AppenderRef ref="rabbitmq" level="all"/>
</AsyncRoot>
</Loggers>