LOG4J2-1447 MdcPatternConverter now appends ContextData without generating temporary objects
Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/3c1d7149 Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/3c1d7149 Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/3c1d7149 Branch: refs/heads/LOG4J2-1010&LOG4J2-1447-injectable-contextdata&better-datastructure Commit: 3c1d7149cf541ea8b128887681946f8d637c9347 Parents: cc72c04 Author: rpopma <[email protected]> Authored: Wed Jul 27 01:29:12 2016 +0900 Committer: rpopma <[email protected]> Committed: Wed Jul 27 01:29:12 2016 +0900 ---------------------------------------------------------------------- .../log4j/core/pattern/MdcPatternConverter.java | 112 +++++++++++++------ 1 file changed, 77 insertions(+), 35 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/3c1d7149/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/MdcPatternConverter.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/MdcPatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/MdcPatternConverter.java index 1663923..bcbdbd8 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/MdcPatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/MdcPatternConverter.java @@ -16,12 +16,12 @@ */ package org.apache.logging.log4j.core.pattern; -import java.util.Map; -import java.util.Set; -import java.util.TreeSet; - +import org.apache.logging.log4j.core.ContextData; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.plugins.Plugin; +import org.apache.logging.log4j.core.util.Constants; +import org.apache.logging.log4j.core.util.TriConsumer; +import org.apache.logging.log4j.util.StringBuilders; /** * Able to handle the contents of the LogEvent's MDC and either @@ -33,6 +33,11 @@ import org.apache.logging.log4j.core.config.plugins.Plugin; @Plugin(name = "MdcPatternConverter", category = PatternConverter.CATEGORY) @ConverterKeys({ "X", "mdc", "MDC" }) public final class MdcPatternConverter extends LogEventPatternConverter { + + private static final ThreadLocal<StringBuilder> threadLocal = new ThreadLocal<>(); + private static final int DEFAULT_STRING_BUILDER_SIZE = 64; + private static final int MAX_STRING_BUILDER_SIZE = Constants.MAX_REUSABLE_MESSAGE_SIZE; + /** * Name of property to output. */ @@ -51,6 +56,9 @@ public final class MdcPatternConverter extends LogEventPatternConverter { full = false; if (options[0].indexOf(',') > 0) { keys = options[0].split(","); + for (int i = 0; i < keys.length; i++) { + keys[i] = keys[i].trim(); + } key = null; } else { keys = null; @@ -73,57 +81,91 @@ public final class MdcPatternConverter extends LogEventPatternConverter { return new MdcPatternConverter(options); } + private static final TriConsumer<String, Object, StringBuilder> WRITE_KEY_VALUES_INTO = new TriConsumer<String, Object, StringBuilder>() { + @Override + public void accept(final String key, final Object value, final StringBuilder sb) { + if (sb.length() > 1) { + sb.append(", "); + } + sb.append(key).append('='); + StringBuilders.appendValue(sb, value); + } + }; + /** * {@inheritDoc} */ @Override public void format(final LogEvent event, final StringBuilder toAppendTo) { - final Map<String, String> contextMap = event.getContextMap(); + final ContextData contextData = event.getContextData(); // if there is no additional options, we output every single // Key/Value pair for the MDC in a similar format to Hashtable.toString() if (full) { - if (contextMap == null || contextMap.isEmpty()) { + if (contextData == null || contextData.size() == 0) { toAppendTo.append("{}"); return; } - final StringBuilder sb = new StringBuilder("{"); - final Set<String> eventKeys = new TreeSet<>(contextMap.keySet()); - for (final String eventKey : eventKeys) { - if (sb.length() > 1) { - sb.append(", "); - } - sb.append(eventKey).append('=').append(contextMap.get(eventKey)); - - } - sb.append('}'); - toAppendTo.append(sb); + appendFully(contextData, toAppendTo); } else { if (keys != null) { - if (contextMap == null || contextMap.isEmpty()) { + if (contextData == null || contextData.size() == 0) { toAppendTo.append("{}"); return; } - // Print all the keys in the array that have a value. - final StringBuilder sb = new StringBuilder("{"); - for (String key : keys) { - key = key.trim(); - if (contextMap.containsKey(key)) { - if (sb.length() > 1) { - sb.append(", "); - } - sb.append(key).append('=').append(contextMap.get(key)); - } - } - sb.append('}'); - toAppendTo.append(sb); - } else if (contextMap != null){ + appendSelectedKeys(keys, contextData, toAppendTo); + } else if (contextData != null){ // otherwise they just want a single key output - final Object val = contextMap.get(key); + final Object value = contextData.getValue(key); + if (value != null) { + StringBuilders.appendValue(toAppendTo, value); + } + } + } + } - if (val != null) { - toAppendTo.append(val); + private static void appendFully(final ContextData contextData, final StringBuilder toAppendTo) { + final StringBuilder sb = getStringBuilder(); + sb.append("{"); + contextData.forEach(WRITE_KEY_VALUES_INTO, sb); + sb.append('}'); + toAppendTo.append(sb); + trimToMaxSize(sb); + } + + private static void appendSelectedKeys(final String[] keys, final ContextData contextData, final StringBuilder toAppendTo) { + // Print all the keys in the array that have a value. + final StringBuilder sb = getStringBuilder(); + sb.append("{"); + for (int i = 0; i < keys.length; i++) { + final String theKey = keys[i]; + final Object value = contextData.getValue(theKey); + if (value != null) { // !contextData.containskey(theKey) + if (sb.length() > 1) { + sb.append(", "); } + sb.append(theKey).append('='); + StringBuilders.appendValue(sb, value); } } + sb.append('}'); + toAppendTo.append(sb); + trimToMaxSize(sb); + } + + private static StringBuilder getStringBuilder() { + StringBuilder result = threadLocal.get(); + if (result == null) { + result = new StringBuilder(DEFAULT_STRING_BUILDER_SIZE); + threadLocal.set(result); + } + result.setLength(0); + return result; + } + + private static void trimToMaxSize(final StringBuilder stringBuilder) { + if (stringBuilder.length() > MAX_STRING_BUILDER_SIZE) { + stringBuilder.setLength(MAX_STRING_BUILDER_SIZE); + stringBuilder.trimToSize(); + } } }
