LOG4J2-1291 Update PatternLayout to utilize gc-free mechanism for LogEvent processing.
Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/daf2c930 Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/daf2c930 Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/daf2c930 Branch: refs/heads/LOG4J2-1278-gc-free-logger Commit: daf2c93064042f27256fb97a214807a23a57a27b Parents: 6a0c2e6 Author: rpopma <[email protected]> Authored: Mon Feb 22 01:04:35 2016 +0900 Committer: rpopma <[email protected]> Committed: Mon Feb 22 01:04:35 2016 +0900 ---------------------------------------------------------------------- .../apache/logging/log4j/core/jmx/Server.java | 11 +-- .../log4j/core/layout/AbstractStringLayout.java | 9 ++- .../log4j/core/layout/PatternLayout.java | 79 ++++++++++++++++---- .../logging/log4j/core/util/Constants.java | 21 +++++- src/changes/changes.xml | 3 + 5 files changed, 95 insertions(+), 28 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/daf2c930/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/Server.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/Server.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/Server.java index 8472175..dc01507 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/Server.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/Server.java @@ -40,6 +40,7 @@ import org.apache.logging.log4j.core.async.DaemonThreadFactory; import org.apache.logging.log4j.core.config.LoggerConfig; import org.apache.logging.log4j.core.impl.Log4jContextFactory; import org.apache.logging.log4j.core.selector.ContextSelector; +import org.apache.logging.log4j.core.util.Constants; import org.apache.logging.log4j.core.util.Loader; import org.apache.logging.log4j.spi.LoggerContextFactory; import org.apache.logging.log4j.status.StatusLogger; @@ -74,20 +75,12 @@ public final class Server { * @see <a href="https://issues.apache.org/jira/browse/LOG4J2-938">LOG4J2-938</a> */ private static ExecutorService createExecutor() { - final boolean defaultAsync = !isWebApp(); + final boolean defaultAsync = !Constants.IS_WEB_APP; final boolean async = PropertiesUtil.getProperties().getBooleanProperty(PROPERTY_ASYNC_NOTIF, defaultAsync); return async ? Executors.newFixedThreadPool(1, new DaemonThreadFactory(THREAD_NAME_PREFIX)) : null; } /** - * Returns {@code true} if we think we are running in a web container, based on the presence of the - * {@code javax.servlet.Servlet} class in the classpath. - */ - private static boolean isWebApp() { - return Loader.isClassAvailable("javax.servlet.Servlet"); - } - - /** * Either returns the specified name as is, or returns a quoted value containing the specified name with the special * characters (comma, equals, colon, quote, asterisk, or question mark) preceded with a backslash. * http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/daf2c930/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/AbstractStringLayout.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/AbstractStringLayout.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/AbstractStringLayout.java index 8bd787d..8db1004 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/AbstractStringLayout.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/AbstractStringLayout.java @@ -43,11 +43,18 @@ import org.apache.logging.log4j.util.Strings; public abstract class AbstractStringLayout extends AbstractLayout<String> implements StringLayout { public interface Serializer { - String toSerializable(final LogEvent event); } /** + * Variation of {@link Serializer} that avoids allocating temporary objects. + * @since 2.6 + */ + public interface Serializer2 { + StringBuilder toSerializable(final LogEvent event, final StringBuilder buffer); + } + + /** * Default length for new StringBuilder instances: {@value} . */ protected static final int DEFAULT_STRING_BUILDER_SIZE = 1024; http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/daf2c930/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternLayout.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternLayout.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternLayout.java index 518f6a4..bbfd8d7 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternLayout.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternLayout.java @@ -38,6 +38,7 @@ import org.apache.logging.log4j.core.pattern.LogEventPatternConverter; import org.apache.logging.log4j.core.pattern.PatternFormatter; import org.apache.logging.log4j.core.pattern.PatternParser; import org.apache.logging.log4j.core.pattern.RegexReplacement; +import org.apache.logging.log4j.core.util.Constants; import org.apache.logging.log4j.util.Strings; /** @@ -78,13 +79,13 @@ public final class PatternLayout extends AbstractStringLayout { private static final long serialVersionUID = 1L; + private static final ThreadLocal<TextEncoderHelper> textEncoderHelper = new ThreadLocal<>(); + /** * Conversion pattern. */ private final String conversionPattern; - private final PatternSelector patternSelector; - private final Serializer eventSerializer; /** @@ -152,7 +153,7 @@ public final class PatternLayout extends AbstractStringLayout { * <li>Key: "formatType" Value: "conversion" (format uses the keywords supported by OptionConverter)</li> * <li>Key: "format" Value: provided "conversionPattern" param</li> * </ul> - * + * * @return Map of content format keys supporting PatternLayout */ @Override @@ -175,6 +176,38 @@ public final class PatternLayout extends AbstractStringLayout { return eventSerializer.toSerializable(event); } + @Override + public void encode(final LogEvent event, final ByteBufferDestination destination) { + if (!Constants.ENABLE_OBJECT_POOLING || !(eventSerializer instanceof Serializer2)) { + super.encode(event, destination); + return; + } + final StringBuilder text = toText((Serializer2) eventSerializer, event, getStringBuilder()); + final TextEncoderHelper helper = getCachedTextEncoderHelper(); + helper.encodeText(text, destination); + } + + /** + * Creates a text representation of the specified log event + * and writes it into the specified StringBuilder. + * <p> + * Implementations are free to return a new StringBuilder if they can + * detect in advance that the specified StringBuilder is too small. + */ + private StringBuilder toText(final Serializer2 serializer, final LogEvent event, + final StringBuilder destination) { + return serializer.toSerializable(event, destination); + } + + private TextEncoderHelper getCachedTextEncoderHelper() { + TextEncoderHelper result = textEncoderHelper.get(); + if (result == null) { + result = new TextEncoderHelper(getCharset()); + textEncoderHelper.set(result); + } + return result; + } + /** * Creates a PatternParser. * @param config The Configuration. @@ -203,7 +236,7 @@ public final class PatternLayout extends AbstractStringLayout { * * @param pattern * The pattern. If not specified, defaults to DEFAULT_CONVERSION_PATTERN. - * @param patternSelector + * @param patternSelector * Allows different patterns to be used based on some selection criteria. * @param config * The Configuration. Some Converters require access to the Interpolator. @@ -246,7 +279,7 @@ public final class PatternLayout extends AbstractStringLayout { .build(); } - private static class PatternSerializer implements Serializer { + private static class PatternSerializer implements Serializer, Serializer2 { private final PatternFormatter[] formatters; private final RegexReplacement replace; @@ -260,15 +293,22 @@ public final class PatternLayout extends AbstractStringLayout { @Override public String toSerializable(final LogEvent event) { final StringBuilder buf = getStringBuilder(); + return toSerializable(event, buf).toString(); + } + + @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, buf); + formatters[i].format(event, buffer); } - String str = buf.toString(); - if (replace != null) { + if (replace != null) { // creates temporary objects + String str = buffer.toString(); str = replace.format(str); + buffer.setLength(0); + buffer.append(str); } - return str; + return buffer; } @Override @@ -284,7 +324,7 @@ public final class PatternLayout extends AbstractStringLayout { } } - private static class PatternSelectorSerializer implements Serializer { + private static class PatternSelectorSerializer implements Serializer, Serializer2 { private final PatternSelector patternSelector; private final RegexReplacement replace; @@ -298,16 +338,23 @@ public final class PatternLayout extends AbstractStringLayout { @Override public String toSerializable(final LogEvent event) { final StringBuilder buf = getStringBuilder(); + return toSerializable(event, buf).toString(); + } + + @Override + public StringBuilder toSerializable(final LogEvent event, final StringBuilder buffer) { final PatternFormatter[] formatters = patternSelector.getFormatters(event); final int len = formatters.length; for (int i = 0; i < len; i++) { - formatters[i].format(event, buf); + formatters[i].format(event, buffer); } - String str = buf.toString(); - if (replace != null) { + if (replace != null) { // creates temporary objects + String str = buffer.toString(); str = replace.format(str); + buffer.setLength(0); + buffer.append(str); } - return str; + return buffer; } @Override @@ -337,7 +384,7 @@ public final class PatternLayout extends AbstractStringLayout { /** * Creates a PatternLayout using the default options and the given configuration. These options include using UTF-8, * the default conversion pattern, exceptions being written, and with ANSI escape codes. - * + * * @param configuration The Configuration. * * @return the PatternLayout. @@ -349,7 +396,7 @@ public final class PatternLayout extends AbstractStringLayout { /** * Creates a builder for a custom PatternLayout. - * + * * @return a PatternLayout builder. */ @PluginBuilderFactory http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/daf2c930/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Constants.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Constants.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Constants.java index d51368d..07b2457 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Constants.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Constants.java @@ -56,10 +56,10 @@ public final class Constants { * Number of milliseconds in a second. */ public static final int MILLIS_IN_SECONDS = 1000; - + /** * Equivalent to StandardCharsets.UTF_8. - * + * * @deprecated Use {@link StandardCharsets#UTF_8}. Will be removed in 2.5. */ @Deprecated @@ -72,6 +72,23 @@ public final class Constants { "log4j.format.msg.async", false); /** + * Returns {@code true} if we think we are running in a web container, based on the presence of the + * {@code javax.servlet.Servlet} class in the classpath. + */ + public static final boolean IS_WEB_APP = Loader.isClassAvailable("javax.servlet.Servlet"); + + /** + * Kill switch for object pooling in ThreadLocals that enables much of the LOG4J2-1270 no-GC behaviour. + * <p> + * {@code True} for non-{@link #IS_WEB_APP web apps}, disable by setting system property + * "log4j2.enable.threadlocals" to "false". + * + * @since 2.6 + */ + public static final boolean ENABLE_THREADLOCALS = !IS_WEB_APP && PropertiesUtil.getProperties().getBooleanProperty( + "log4j2.enable.threadlocals", true); + + /** * Prevent class instantiation. */ private Constants() { http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/daf2c930/src/changes/changes.xml ---------------------------------------------------------------------- diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 264bc4d..d1ec6d9 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -24,6 +24,9 @@ </properties> <body> <release version="2.6" date="2016-MM-DD" description="GA Release 2.6"> + <action issue="LOG4J2-1291" dev="rpopma" type="update"> + Update PatternLayout to utilize gc-free mechanism for LogEvent processing. + </action> <action issue="LOG4J2-1292" dev="rpopma" type="update"> Update RandomAccessFileAppender and RollingRandomAccessFileAppender to utilize gc-free Layout.encode() method. </action>
