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 <rpo...@apache.org> Authored: Wed Nov 9 01:41:33 2016 +0900 Committer: rpopma <rpo...@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>