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>

Reply via email to