"Log4j2-TF-7-AsyncLoggerConfig-8" Id=52 BLOCKED on sun.misc.URLClassPath@26eb1b56 owned by "Log4j2-TF-7-AsyncLoggerConfig-4" Id=17 at sun.misc.URLClassPath.getNextLoader(URLClassPath.java:479) - blocked on sun.misc.URLClassPath@26eb1b56 at sun.misc.URLClassPath.getResource(URLClassPath.java:248) at java.net.URLClassLoader$1.run(URLClassLoader.java:366) at java.net.URLClassLoader$1.run(URLClassLoader.java:363) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:362) at java.lang.ClassLoader.loadClass(ClassLoader.java:448) at com.alipay.sofa.ark.container.service.classloader.AbstractClasspathClassLoader.resolveLocalClass(AbstractClasspathClassLoader.java:302) at com.alipay.sofa.ark.container.service.classloader.PluginClassLoader.loadClassInternal(PluginClassLoader.java:102) // 插件加载 at com.alipay.sofa.ark.container.service.classloader.AbstractClasspathClassLoader.loadClass(AbstractClasspathClassLoader.java:71) at java.lang.ClassLoader.loadClass(ClassLoader.java:380) at org.apache.logging.log4j.core.impl.ThrowableProxy.loadClass(ThrowableProxy.java:563) at org.apache.logging.log4j.core.impl.ThrowableProxy.toExtendedStackTrace(ThrowableProxy.java:689) at org.apache.logging.log4j.core.impl.ThrowableProxy.<init>(ThrowableProxy.java:138) at org.apache.logging.log4j.core.impl.ThrowableProxy.<init>(ThrowableProxy.java:122) at org.apache.logging.log4j.core.impl.Log4jLogEvent.getThrownProxy(Log4jLogEvent.java:564) at org.apache.logging.log4j.core.pattern.ExtendedThrowablePatternConverter.format(ExtendedThrowablePatternConverter.java:63) at org.apache.logging.log4j.core.pattern.PatternFormatter.format(PatternFormatter.java:38) at org.apache.logging.log4j.core.layout.PatternLayout$PatternSerializer.toSerializable(PatternLayout.java:333) at org.apache.logging.log4j.core.layout.PatternLayout.toText(PatternLayout.java:232) at org.apache.logging.log4j.core.layout.PatternLayout.encode(PatternLayout.java:217) at org.apache.logging.log4j.core.layout.PatternLayout.encode(PatternLayout.java:57) at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.directEncodeEvent(AbstractOutputStreamAppender.java:177) at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.tryAppend(AbstractOutputStreamAppender.java:170) at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.append(AbstractOutputStreamAppender.java:161) at org.apache.logging.log4j.core.appender.RollingFileAppender.append(RollingFileAppender.java:268) at org.apache.logging.log4j.core.config.AppenderControl.tryCallAppender(AppenderControl.java:156) at org.apache.logging.log4j.core.config.AppenderControl.callAppender0(AppenderControl.java:129) at org.apache.logging.log4j.core.config.AppenderControl.callAppenderPreventRecursion(AppenderControl.java:120) at org.apache.logging.log4j.core.config.AppenderControl.callAppender(AppenderControl.java:84) at org.apache.logging.log4j.core.config.LoggerConfig.callAppenders(LoggerConfig.java:448) at org.apache.logging.log4j.core.async.AsyncLoggerConfig.asyncCallAppenders(AsyncLoggerConfig.java:115) at org.apache.logging.log4j.core.async.AsyncLoggerConfigDisruptor$Log4jEventWrapperHandler.onEvent(AsyncLoggerConfigDisruptor.java:112) at org.apache.logging.log4j.core.async.AsyncLoggerConfigDisruptor$Log4jEventWrapperHandler.onEvent(AsyncLoggerConfigDisruptor.java:98) at com.lmax.disruptor.BatchEventProcessor.run(BatchEventProcessor.java:128) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1152) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:627) at java.lang.Thread.run(Thread.java:861)
@Override publicvoidformat(final LogEvent event, final StringBuilder toAppendTo) { // 这里多了一个 getThrownProxy finalThrowableProxyproxy= event.getThrownProxy(); finalThrowablethrowable= event.getThrown(); if ((throwable != null || proxy != null) && options.anyLines()) { if (proxy == null) { super.format(event, toAppendTo); return; } Stringsuffix= getSuffix(event); finalStringextStackTrace= proxy.getExtendedStackTraceAsString(options.getIgnorePackages(), options.getTextRenderer(), suffix); finalintlen= toAppendTo.length(); if (len > 0 && !Character.isWhitespace(toAppendTo.charAt(len - 1))) { toAppendTo.append(' '); } if (!options.allLines() || !Strings.LINE_SEPARATOR.equals(options.getSeparator())) { finalStringBuildersb=newStringBuilder(); final String[] array = extStackTrace.split(Strings.LINE_SEPARATOR); finalintlimit= options.minLines(array.length) - 1; for (inti=0; i <= limit; ++i) { sb.append(array[i]); if (i < limit) { sb.append(options.getSeparator()); } } toAppendTo.append(sb.toString()); } else { toAppendTo.append(extStackTrace); } } }
final ThrowableProxy proxy = event.getThrownProxy() 结合最上面的异常堆栈来看,在构建 ThrowableProxy 对象实例时会去对堆栈中的数据进行序列化操作构建 CacheEntry(toExtendedStackTrace),从而触发类加载动作。
A proxy is used to represent a throwable that may not exist in a different class loader or JVM. When an application deserializes a ThrowableProxy, the throwable may not be set, but the throwable’s information is preserved in other fields of the proxy like the message and stack trace.
publicclassDefaultAsyncQueueFullPolicyimplementsAsyncQueueFullPolicy { @Override public EventRoute getRoute(finallong backgroundThreadId, final Level level) {
// LOG4J2-1518: prevent deadlock when RingBuffer is full and object being logged calls // Logger.log in application thread // See also LOG4J2-471: prevent deadlock when RingBuffer is full and object // being logged calls Logger.log() from its toString() method in background thread return EventRoute.SYNCHRONOUS; } }
2、DiscardingAsyncQueueFullPolicy—按照日志等级抛弃日志策略
1 2 3 4 5 6 7 8 9 10 11 12 13
@Override public EventRoute getRoute(finallong backgroundThreadId, final Level level) { if (level.isLessSpecificThan(thresholdLevel)) { if (discardCount.getAndIncrement() == 0) { LOGGER.warn("Async queue is full, discarding event with level {}. " + "This message will only appear once; future events from {} " + "are silently discarded until queue capacity becomes available.", level, thresholdLevel); } return EventRoute.DISCARD; } returnsuper.getRoute(backgroundThreadId, level); }
Constants.ENABLE_THREADLOCALS 这个值分为 web 和 非 web 应用两种情况,非 web 应用时,默认是 true,web 应用默认是 false,判断依据是,classpath 是否有 javax.servlet.Servlet 类。可以通过 -Dlog4j2.is.webapp=true/false 来手动设定。
ps: -Dlog4j2.enable.threadlocals: This system property can be used to switch off the use of threadlocals, which will partly disable Log4j’s garbage-free behaviour: to be fully garbage-free, Log4j stores objects in ThreadLocal fields to reuse them, otherwise new objects are created for each log event. Note that this property is not effective when Log4j detects it is running in a web application.