You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by rp...@apache.org on 2016/11/08 16:41:37 UTC

logging-log4j2 git commit: LOG4J2-1679 (GC) Avoid allocating temporary objects in StructuredDataFilter.

Repository: logging-log4j2
Updated Branches:
  refs/heads/master 171f9a328 -> d494e5472


LOG4J2-1679 (GC) Avoid allocating temporary objects in StructuredDataFilter.


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/d494e547
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/d494e547
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/d494e547

Branch: refs/heads/master
Commit: d494e54728fde0bac26fd5785e1330c70d3e25e0
Parents: 171f9a3
Author: rpopma <rp...@apache.org>
Authored: Wed Nov 9 01:41:33 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Wed Nov 9 01:41:33 2016 +0900

----------------------------------------------------------------------
 .../log4j/core/filter/StructuredDataFilter.java | 73 +++++++++++++++++---
 log4j-core/src/test/resources/gcFreeLogging.xml |  4 ++
 .../resources/gcFreeMixedSyncAsyncLogging.xml   |  4 ++
 src/changes/changes.xml                         |  3 +
 4 files changed, 75 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/d494e547/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/StructuredDataFilter.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/StructuredDataFilter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/StructuredDataFilter.java
index 1feed36..a4a661a 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/StructuredDataFilter.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/StructuredDataFilter.java
@@ -34,13 +34,20 @@ import org.apache.logging.log4j.core.config.plugins.PluginFactory;
 import org.apache.logging.log4j.core.util.KeyValuePair;
 import org.apache.logging.log4j.message.Message;
 import org.apache.logging.log4j.message.StructuredDataMessage;
+import org.apache.logging.log4j.util.PerformanceSensitive;
+import org.apache.logging.log4j.util.SortedArrayStringMap;
+import org.apache.logging.log4j.util.StringBuilders;
 
 /**
  * Filter based on data in a StructuredDataMessage.
  */
 @Plugin(name = "StructuredDataFilter", category = Node.CATEGORY, elementType = Filter.ELEMENT_TYPE, printObject = true)
+@PerformanceSensitive("allocation")
 public final class StructuredDataFilter extends MapFilter {
 
+    private static final int MAX_BUFFER_SIZE = 2048;
+    private static ThreadLocal<StringBuilder> threadLocalStringBuilder = new ThreadLocal<>();
+
     private StructuredDataFilter(final Map<String, List<String>> map, final boolean oper, final Result onMatch,
                                  final Result onMismatch) {
         super(map, oper, onMatch, onMismatch);
@@ -66,10 +73,11 @@ public final class StructuredDataFilter extends MapFilter {
 
     protected Result filter(final StructuredDataMessage message) {
         boolean match = false;
-        for (final Map.Entry<String, List<String>> entry : getMap().entrySet()) {
-            final String toMatch = getValue(message, entry.getKey());
+        final SortedArrayStringMap map = getStringMap();
+        for (int i = 0; i < map.size(); i++) {
+            final StringBuilder toMatch = getValue(message, map.getKeyAt(i));
             if (toMatch != null) {
-                match = entry.getValue().contains(toMatch);
+                match = listContainsValue((List<String>) map.getValueAt(i), toMatch);
             } else {
                 match = false;
             }
@@ -80,18 +88,65 @@ public final class StructuredDataFilter extends MapFilter {
         return match ? onMatch : onMismatch;
     }
 
-    private String getValue(final StructuredDataMessage data, final String key) {
+    private StringBuilder getValue(final StructuredDataMessage data, final String key) {
+        final StringBuilder sb = getStringBuilder();
         if (key.equalsIgnoreCase("id")) {
-            return data.getId().toString();
+            data.getId().formatTo(sb);
+            return sb;
         } else if (key.equalsIgnoreCase("id.name")) {
-            return data.getId().getName();
+            return appendOrNull(data.getId().getName(), sb);
         } else if (key.equalsIgnoreCase("type")) {
-            return data.getType();
+            return appendOrNull(data.getType(), sb);
         } else if (key.equalsIgnoreCase("message")) {
-            return data.getFormattedMessage();
+            data.formatTo(sb);
+            return sb;
         } else {
-            return data.getData().get(key);
+            return appendOrNull(data.getDataValue(key), sb);
+        }
+    }
+
+    private StringBuilder getStringBuilder() {
+        StringBuilder result = threadLocalStringBuilder.get();
+        if (result == null) {
+            result = new StringBuilder();
+            threadLocalStringBuilder.set(result);
+        }
+        if (result.length() > MAX_BUFFER_SIZE) {
+            result.setLength(MAX_BUFFER_SIZE);
+            result.trimToSize();
+        }
+        result.setLength(0);
+        return result;
+    }
+
+    private StringBuilder appendOrNull(final String value, final StringBuilder sb) {
+        if (value == null) {
+            return null;
+        }
+        sb.append(value);
+        return sb;
+    }
+
+    private boolean listContainsValue(final List<String> candidates, final StringBuilder toMatch) {
+        if (toMatch == null) {
+            for (int i = 0; i < candidates.size(); i++) {
+                final String candidate = candidates.get(i);
+                if (candidate == null) {
+                    return true;
+                }
+            }
+        } else {
+            for (int i = 0; i < candidates.size(); i++) {
+                final String candidate = candidates.get(i);
+                if (candidate == null) {
+                    return false;
+                }
+                if (StringBuilders.equals(candidate, 0, candidate.length(), toMatch, 0, toMatch.length())) {
+                    return true;
+                }
+            }
         }
+        return false;
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/d494e547/log4j-core/src/test/resources/gcFreeLogging.xml
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/resources/gcFreeLogging.xml b/log4j-core/src/test/resources/gcFreeLogging.xml
index 1b38047..2c92e8c 100644
--- a/log4j-core/src/test/resources/gcFreeLogging.xml
+++ b/log4j-core/src/test/resources/gcFreeLogging.xml
@@ -14,6 +14,10 @@
       <KeyValuePair key="User1" value="DEBUG"/>
       <KeyValuePair key="User2" value="WARN"/>
     </ContextMapFilter>
+    <StructuredDataFilter onMatch="ACCEPT" onMismatch="NEUTRAL" operator="or">
+      <KeyValuePair key="id" value="Login"/>
+      <KeyValuePair key="id" value="Logout"/>
+    </StructuredDataFilter>
   </Filters>
   <Appenders>
     <Console name="Console" target="SYSTEM_OUT">

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/d494e547/log4j-core/src/test/resources/gcFreeMixedSyncAsyncLogging.xml
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/resources/gcFreeMixedSyncAsyncLogging.xml b/log4j-core/src/test/resources/gcFreeMixedSyncAsyncLogging.xml
index 73c7d4b..24d1c90 100644
--- a/log4j-core/src/test/resources/gcFreeMixedSyncAsyncLogging.xml
+++ b/log4j-core/src/test/resources/gcFreeMixedSyncAsyncLogging.xml
@@ -14,6 +14,10 @@
       <KeyValuePair key="User1" value="DEBUG"/>
       <KeyValuePair key="User2" value="WARN"/>
     </ContextMapFilter>
+    <StructuredDataFilter onMatch="ACCEPT" onMismatch="NEUTRAL" operator="or">
+      <KeyValuePair key="id" value="Login"/>
+      <KeyValuePair key="id" value="Logout"/>
+    </StructuredDataFilter>
   </Filters>
   <Appenders>
     <Console name="Console" target="SYSTEM_OUT">

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/d494e547/src/changes/changes.xml
----------------------------------------------------------------------
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 1f69bde..ec8d7f1 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -24,6 +24,9 @@
   </properties>
   <body>
     <release version="2.8" date="2016-MM-DD" description="GA Release 2.8">
+      <action issue="LOG4J2-1679" dev="rpopma" type="fix">
+        (GC) Avoid allocating temporary objects in StructuredDataFilter.
+      </action>
       <action issue="LOG4J2-1678" dev="rpopma" type="fix">
         (GC) Avoid allocating temporary objects in ThreadContextMapFilter.
       </action>