You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by mi...@apache.org on 2016/04/14 10:37:38 UTC
[1/6] logging-log4j2 git commit: LOG4J2-1274 added
StringBuilderEncoder
Repository: logging-log4j2
Updated Branches:
refs/heads/LOG4J2-1365 07723d5cf -> 8b59f231f
LOG4J2-1274 added StringBuilderEncoder
- client code now uses StringBuilderEncoder (or Encoder<StringBuilder>) instead of TextEncoderHelper
- LockingStringBuilderEncoder is a version that synchronizes on ByteBufferDestination during the whole encoding process
- StringBuilderEncoder has a ThreadLocal temp buffer used for the encoding, and only synchronizes on ByteBufferDestination during the final copy
- updated tests and benchmarks
Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/23cd33fc
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/23cd33fc
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/23cd33fc
Branch: refs/heads/LOG4J2-1365
Commit: 23cd33fcb253b318e4dab532e0ce68db274854ef
Parents: 90adca7
Author: rpopma <rp...@apache.org>
Authored: Thu Apr 14 01:17:42 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Thu Apr 14 01:17:42 2016 +0900
----------------------------------------------------------------------
.../log4j/core/layout/AbstractStringLayout.java | 21 +-
.../logging/log4j/core/layout/GelfLayout.java | 11 +-
.../layout/LockingStringBuilderEncoder.java | 52 ++++
.../log4j/core/layout/PatternLayout.java | 5 +-
.../log4j/core/layout/StringBuilderEncoder.java | 111 ++++++++
.../log4j/core/layout/TextEncoderHelper.java | 146 +++++-----
.../core/layout/StringBuilderEncoderTest.java | 277 +++++++++++++++++++
.../core/layout/TextEncoderHelperTest.java | 263 ------------------
.../perf/jmh/TextEncoderHelperBenchmark.java | 97 ++++---
.../logging/log4j/perf/nogc/NoGcLayout.java | 11 +-
10 files changed, 596 insertions(+), 398 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/23cd33fc/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 757e9da..6694943 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
@@ -59,7 +59,7 @@ public abstract class AbstractStringLayout extends AbstractLayout<String> implem
private static final ThreadLocal<StringBuilder> threadLocal = new ThreadLocal<>();
- private TextEncoderHelper textEncoderHelper;
+ private Encoder<StringBuilder> textEncoder;
/**
* Returns a {@code StringBuilder} that this Layout implementation can use to write the formatted log event to.
@@ -120,7 +120,7 @@ public abstract class AbstractStringLayout extends AbstractLayout<String> implem
this.charsetName = this.charset.name();
useCustomEncoding = isPreJava8()
&& (StandardCharsets.ISO_8859_1.equals(aCharset) || StandardCharsets.US_ASCII.equals(aCharset));
- textEncoderHelper = Constants.ENABLE_DIRECT_ENCODERS ? new TextEncoderHelper(charset) : null;
+ textEncoder = Constants.ENABLE_DIRECT_ENCODERS ? new StringBuilderEncoder(charset) : null;
}
/**
@@ -131,7 +131,8 @@ public abstract class AbstractStringLayout extends AbstractLayout<String> implem
* @param headerSerializer the header bytes serializer
* @param footerSerializer the footer bytes serializer
*/
- protected AbstractStringLayout(final Configuration config, final Charset aCharset, final Serializer headerSerializer, final Serializer footerSerializer) {
+ protected AbstractStringLayout(final Configuration config, final Charset aCharset,
+ final Serializer headerSerializer, final Serializer footerSerializer) {
super(config, null, null);
this.headerSerializer = headerSerializer;
this.footerSerializer = footerSerializer;
@@ -139,19 +140,19 @@ public abstract class AbstractStringLayout extends AbstractLayout<String> implem
this.charsetName = this.charset.name();
useCustomEncoding = isPreJava8()
&& (StandardCharsets.ISO_8859_1.equals(aCharset) || StandardCharsets.US_ASCII.equals(aCharset));
- textEncoderHelper = Constants.ENABLE_DIRECT_ENCODERS ? new TextEncoderHelper(charset) : null;
+ textEncoder = Constants.ENABLE_DIRECT_ENCODERS ? new StringBuilderEncoder(charset) : null;
}
/**
- * Returns a {@code TextEncoderHelper} that this Layout implementation can use for encoding log events.
+ * Returns a {@code Encoder<StringBuilder>} that this Layout implementation can use for encoding log events.
*
- * @return a {@code TextEncoderHelper}
+ * @return a {@code Encoder<StringBuilder>}
*/
- protected TextEncoderHelper getCachedTextEncoderHelper() {
- if (textEncoderHelper == null) {
- textEncoderHelper = new TextEncoderHelper(getCharset());
+ protected Encoder<StringBuilder> getStringBuilderEncoder() {
+ if (textEncoder == null) {
+ textEncoder = new StringBuilderEncoder(getCharset());
}
- return textEncoderHelper;
+ return textEncoder;
}
protected byte[] getBytes(final String s) {
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/23cd33fc/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/GelfLayout.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/GelfLayout.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/GelfLayout.java
index cef4e46..788ce73 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/GelfLayout.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/GelfLayout.java
@@ -25,7 +25,6 @@ import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
import org.apache.logging.log4j.core.config.plugins.PluginElement;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
import org.apache.logging.log4j.core.net.Severity;
-import org.apache.logging.log4j.core.util.Constants;
import org.apache.logging.log4j.core.util.JsonUtils;
import org.apache.logging.log4j.core.util.KeyValuePair;
import org.apache.logging.log4j.message.Message;
@@ -33,7 +32,11 @@ import org.apache.logging.log4j.status.StatusLogger;
import org.apache.logging.log4j.util.StringBuilderFormattable;
import org.apache.logging.log4j.util.Strings;
-import java.io.*;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.Map;
@@ -149,8 +152,8 @@ public final class GelfLayout extends AbstractStringLayout {
return;
}
final StringBuilder text = toText(event, getStringBuilder(), true);
- final TextEncoderHelper helper = getCachedTextEncoderHelper();
- helper.encodeText(text, destination);
+ final Encoder<StringBuilder> helper = getStringBuilderEncoder();
+ helper.encode(text, destination);
}
private byte[] compress(final byte[] bytes) {
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/23cd33fc/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/LockingStringBuilderEncoder.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/LockingStringBuilderEncoder.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/LockingStringBuilderEncoder.java
new file mode 100644
index 0000000..6224175
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/LockingStringBuilderEncoder.java
@@ -0,0 +1,52 @@
+package org.apache.logging.log4j.core.layout;
+
+import org.apache.logging.log4j.status.StatusLogger;
+
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CodingErrorAction;
+import java.util.Objects;
+
+/**
+ * Encoder for StringBuilders that locks on the ByteBufferDestination.
+ */
+public class LockingStringBuilderEncoder implements Encoder<StringBuilder> {
+
+ private final Charset charset;
+ private final CharsetEncoder charsetEncoder;
+ private final CharBuffer cachedCharBuffer;
+
+ public LockingStringBuilderEncoder(final Charset charset) {
+ this(charset, TextEncoderHelper.DEFAULT_CHAR_BUFFER_SIZE);
+ }
+
+ public LockingStringBuilderEncoder(final Charset charset, final int charBufferSize) {
+ this.charset = Objects.requireNonNull(charset, "charset");
+ this.charsetEncoder = charset.newEncoder().onMalformedInput(CodingErrorAction.REPLACE)
+ .onUnmappableCharacter(CodingErrorAction.REPLACE);
+ this.cachedCharBuffer = CharBuffer.wrap(new char[charBufferSize]);
+ }
+
+ private CharBuffer getCharBuffer() {
+ return cachedCharBuffer;
+ }
+
+ @Override
+ public void encode(final StringBuilder source, final ByteBufferDestination destination) {
+ synchronized (destination) {
+ try {
+ TextEncoderHelper.encodeText(charsetEncoder, cachedCharBuffer, destination.getByteBuffer(), source,
+ destination);
+ } catch (final Exception ex) {
+ logEncodeTextException(ex, source, destination);
+ TextEncoderHelper.encodeTextFallBack(charset, source, destination);
+ }
+ }
+ }
+
+ private void logEncodeTextException(final Exception ex, final StringBuilder text,
+ final ByteBufferDestination destination) {
+ StatusLogger.getLogger().error("Recovering from LockingStringBuilderEncoder.encode('{}') error", text, ex);
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/23cd33fc/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 ce04f52..67466be 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,7 +38,6 @@ 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;
/**
@@ -179,8 +178,8 @@ public final class PatternLayout extends AbstractStringLayout {
return;
}
final StringBuilder text = toText((Serializer2) eventSerializer, event, getStringBuilder());
- final TextEncoderHelper helper = getCachedTextEncoderHelper();
- helper.encodeText(text, destination);
+ final Encoder<StringBuilder> encoder = getStringBuilderEncoder();
+ encoder.encode(text, destination);
}
/**
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/23cd33fc/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/StringBuilderEncoder.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/StringBuilderEncoder.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/StringBuilderEncoder.java
new file mode 100644
index 0000000..22cb1b5
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/StringBuilderEncoder.java
@@ -0,0 +1,111 @@
+package org.apache.logging.log4j.core.layout;
+
+import org.apache.logging.log4j.status.StatusLogger;
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CodingErrorAction;
+import java.util.Objects;
+
+/**
+ * Encoder for StringBuilders that uses ThreadLocals to avoid locking as much as possible.
+ */
+public class StringBuilderEncoder implements Encoder<StringBuilder> {
+
+ private static final int DEFAULT_BYTE_BUFFER_SIZE = 8 * 1024;
+ private final ThreadLocal<CharBuffer> charBufferThreadLocal = new ThreadLocal<>();
+ private final ThreadLocal<ByteBuffer> byteBufferThreadLocal = new ThreadLocal<>();
+ private final ThreadLocal<CharsetEncoder> charsetEncoderThreadLocal = new ThreadLocal<>();
+ private final Charset charset;
+ private final int charBufferSize;
+ private final int byteBufferSize;
+
+ public StringBuilderEncoder(final Charset charset) {
+ this(charset, TextEncoderHelper.DEFAULT_CHAR_BUFFER_SIZE, DEFAULT_BYTE_BUFFER_SIZE);
+ }
+
+ public StringBuilderEncoder(final Charset charset, final int charBufferSize, final int byteBufferSize) {
+ this.charBufferSize = charBufferSize;
+ this.byteBufferSize = byteBufferSize;
+ this.charset = Objects.requireNonNull(charset, "charset");
+ }
+
+ @Override
+ public void encode(final StringBuilder source, final ByteBufferDestination destination) {
+ final ByteBuffer temp = getByteBuffer();
+ temp.clear();
+ temp.limit(Math.min(temp.capacity(), destination.getByteBuffer().capacity()));
+ final CharsetEncoder charsetEncoder = getCharsetEncoder();
+
+ final int estimatedBytes = estimateBytes(source.length(), charsetEncoder.maxBytesPerChar());
+ if (temp.remaining() < estimatedBytes) {
+ encodeSynchronized(getCharsetEncoder(), getCharBuffer(), source, destination);
+ } else {
+ encodeWithThreadLocals(charsetEncoder, getCharBuffer(), temp, source, destination);
+ }
+ }
+
+ private void encodeWithThreadLocals(final CharsetEncoder charsetEncoder, final CharBuffer charBuffer,
+ final ByteBuffer temp, final StringBuilder source, final ByteBufferDestination destination) {
+ try {
+ TextEncoderHelper.encodeTextWithCopy(charsetEncoder, charBuffer, temp, source, destination);
+ } catch (final Exception ex) {
+ ex.printStackTrace();
+ logEncodeTextException(ex, source, destination);
+ TextEncoderHelper.encodeTextFallBack(charset, source, destination);
+ }
+ }
+
+ private static int estimateBytes(final int charCount, final float maxBytesPerChar) {
+ return (int) (charCount * (double) maxBytesPerChar);
+ }
+
+ private void encodeSynchronized(final CharsetEncoder charsetEncoder, final CharBuffer charBuffer,
+ final StringBuilder source, final ByteBufferDestination destination) {
+ synchronized (destination) {
+ try {
+ TextEncoderHelper.encodeText(charsetEncoder, charBuffer, destination.getByteBuffer(), source,
+ destination);
+ } catch (final Exception ex) {
+ logEncodeTextException(ex, source, destination);
+ TextEncoderHelper.encodeTextFallBack(charset, source, destination);
+ }
+ }
+ }
+
+ private CharsetEncoder getCharsetEncoder() {
+ CharsetEncoder result = charsetEncoderThreadLocal.get();
+ if (result == null) {
+ result = charset.newEncoder().onMalformedInput(CodingErrorAction.REPLACE)
+ .onUnmappableCharacter(CodingErrorAction.REPLACE);
+ charsetEncoderThreadLocal.set(result);
+ }
+ return result;
+ }
+
+
+ private CharBuffer getCharBuffer() {
+ CharBuffer result = charBufferThreadLocal.get();
+ if (result == null) {
+ result = CharBuffer.wrap(new char[charBufferSize]);
+ charBufferThreadLocal.set(result);
+ }
+ return result;
+ }
+
+ private ByteBuffer getByteBuffer() {
+ ByteBuffer result = byteBufferThreadLocal.get();
+ if (result == null) {
+ result = ByteBuffer.wrap(new byte[byteBufferSize]);
+ byteBufferThreadLocal.set(result);
+ }
+ return result;
+ }
+
+ private void logEncodeTextException(final Exception ex, final StringBuilder text,
+ final ByteBufferDestination destination) {
+ StatusLogger.getLogger().error("Recovering from StringBuilderEncoder.encode('{}') error: {}", text, ex, ex);
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/23cd33fc/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/TextEncoderHelper.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/TextEncoderHelper.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/TextEncoderHelper.java
index 3e59c8a..136e2e6 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/TextEncoderHelper.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/TextEncoderHelper.java
@@ -22,7 +22,6 @@ import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
-import java.nio.charset.CodingErrorAction;
import java.util.Objects;
import org.apache.logging.log4j.status.StatusLogger;
@@ -33,43 +32,46 @@ import org.apache.logging.log4j.status.StatusLogger;
* @since 2.6
*/
public class TextEncoderHelper {
- private static final int DEFAULT_BUFFER_SIZE = 2048;
+ static final int DEFAULT_CHAR_BUFFER_SIZE = 2048;
private final Charset charset;
- private final CharBuffer cachedCharBuffer;
- private final CharsetEncoder charsetEncoder;
+// private final CharBuffer cachedCharBuffer;
+// private final CharsetEncoder charsetEncoder;
public TextEncoderHelper(final Charset charset) {
- this(charset, DEFAULT_BUFFER_SIZE);
+ this(charset, DEFAULT_CHAR_BUFFER_SIZE);
}
public TextEncoderHelper(final Charset charset, final int bufferSize) {
this.charset = Objects.requireNonNull(charset, "charset");
- this.charsetEncoder = charset.newEncoder().onMalformedInput(CodingErrorAction.REPLACE)
- .onUnmappableCharacter(CodingErrorAction.REPLACE);
- this.cachedCharBuffer = CharBuffer.wrap(new char[bufferSize]);
}
- public void encodeText(final StringBuilder text, final ByteBufferDestination destination) {
+ private void logEncodeTextException(final Exception ex, final StringBuilder text,
+ final ByteBufferDestination destination) {
+ StatusLogger.getLogger().error("Recovering from TextEncoderHelper.encodeText('{}') error", text, ex);
+ }
+
+ static void encodeTextWithCopy(final CharsetEncoder charsetEncoder, final CharBuffer charBuf, final ByteBuffer temp,
+ final StringBuilder text, final ByteBufferDestination destination) {
+ encodeText(charsetEncoder, charBuf, temp, text, destination);
+
synchronized (destination) {
- try {
- encodeText0(text, destination);
- } catch (final Exception ex) {
- logEncodeTextException(ex, text, destination);
- encodeTextFallBack(text, destination);
+ ByteBuffer destinationBuffer = destination.getByteBuffer();
+ if (destinationBuffer != temp) { // still need to write to the destination
+ temp.flip();
+ if (temp.remaining() > destinationBuffer.remaining()) {
+ destinationBuffer = destination.drain(destinationBuffer);
+ }
+ destinationBuffer.put(temp);
+ temp.clear();
}
}
}
- private void logEncodeTextException(final Exception ex, final StringBuilder text,
- final ByteBufferDestination destination) {
- StatusLogger.getLogger().error("Recovering from TextEncoderHelper.encodeText('{}') error", text, ex);
- }
-
- private void encodeText0(final StringBuilder text, final ByteBufferDestination destination) {
+ static void encodeText(final CharsetEncoder charsetEncoder, final CharBuffer charBuf, final ByteBuffer byteBuf,
+ final StringBuilder text, final ByteBufferDestination destination) {
charsetEncoder.reset();
- ByteBuffer byteBuf = destination.getByteBuffer();
- final CharBuffer charBuf = getCachedCharBuffer();
+ ByteBuffer temp = byteBuf; // may be the destination's buffer or a temporary buffer
int start = 0;
int todoChars = text.length();
boolean endOfInput = true;
@@ -81,38 +83,46 @@ public class TextEncoderHelper {
endOfInput = todoChars <= 0;
charBuf.flip(); // prepare for reading: set limit to position, position to zero
- byteBuf = encode(charBuf, endOfInput, destination, byteBuf);
+ temp = encode(charsetEncoder, charBuf, endOfInput, destination, temp);
} while (!endOfInput);
}
- private void encodeTextFallBack(final StringBuilder text, final ByteBufferDestination destination) {
+ static void encodeTextFallBack(final Charset charset, final StringBuilder text,
+ final ByteBufferDestination destination) {
final byte[] bytes = text.toString().getBytes(charset);
- ByteBuffer buffer = destination.getByteBuffer();
- int offset = 0;
- do {
- final int length = Math.min(bytes.length - offset, buffer.remaining());
- buffer.put(bytes, offset, length);
- offset += length;
- if (offset < bytes.length) {
- buffer = destination.drain(buffer);
- }
- } while (offset < bytes.length);
+ synchronized (destination) {
+ ByteBuffer buffer = destination.getByteBuffer();
+ int offset = 0;
+ do {
+ final int length = Math.min(bytes.length - offset, buffer.remaining());
+ buffer.put(bytes, offset, length);
+ offset += length;
+ if (offset < bytes.length) {
+ buffer = destination.drain(buffer);
+ }
+ } while (offset < bytes.length);
+ }
}
- public void encodeText(final CharBuffer charBuf, final ByteBufferDestination destination) {
+ /**
+ * For testing purposes only.
+ */
+ @Deprecated
+ public void encodeText(final CharsetEncoder charsetEncoder, final CharBuffer charBuf,
+ final ByteBufferDestination destination) {
synchronized (destination) {
charsetEncoder.reset();
final ByteBuffer byteBuf = destination.getByteBuffer();
- encode(charBuf, true, destination, byteBuf);
+ encode(charsetEncoder, charBuf, true, destination, byteBuf);
}
}
- private ByteBuffer encode(final CharBuffer charBuf, final boolean endOfInput,
- final ByteBufferDestination destination, ByteBuffer byteBuf) {
+ private static ByteBuffer encode(final CharsetEncoder charsetEncoder, final CharBuffer charBuf,
+ final boolean endOfInput, final ByteBufferDestination destination, ByteBuffer byteBuf) {
try {
- byteBuf = encodeAsMuchAsPossible(charBuf, endOfInput, destination, byteBuf);
+ byteBuf = encodeAsMuchAsPossible(charsetEncoder, charBuf, endOfInput, destination, byteBuf);
if (endOfInput) {
- byteBuf = flushRemainingBytes(destination, byteBuf);
+ byteBuf = flushRemainingBytes(charsetEncoder, destination, byteBuf);
}
} catch (final CharacterCodingException ex) {
throw new IllegalStateException(ex);
@@ -120,39 +130,53 @@ public class TextEncoderHelper {
return byteBuf;
}
- private ByteBuffer encodeAsMuchAsPossible(final CharBuffer charBuf, final boolean endOfInput,
- final ByteBufferDestination destination, ByteBuffer byteBuf) throws CharacterCodingException {
+ private static ByteBuffer encodeAsMuchAsPossible(final CharsetEncoder charsetEncoder, final CharBuffer charBuf,
+ final boolean endOfInput, final ByteBufferDestination destination, ByteBuffer temp)
+ throws CharacterCodingException {
CoderResult result;
do {
- result = charsetEncoder.encode(charBuf, byteBuf, endOfInput);
- if (result.isOverflow()) { // byteBuf full
- // destination consumes contents
- // and returns byte buffer with more capacity
- byteBuf = destination.drain(byteBuf);
- }
- } while (result.isOverflow()); // byteBuf has been drained: retry
+ result = charsetEncoder.encode(charBuf, temp, endOfInput);
+ temp = drainIfByteBufferFull(destination, temp, result);
+ } while (result.isOverflow()); // byte buffer has been drained: retry
if (!result.isUnderflow()) { // we should have fully read the char buffer contents
result.throwException();
}
- return byteBuf;
+ return temp;
+ }
+
+ private static ByteBuffer drainIfByteBufferFull(ByteBufferDestination destination, ByteBuffer temp, CoderResult result) {
+ if (result.isOverflow()) { // byte buffer full
+
+ // SHOULD NOT HAPPEN:
+ // CALLER SHOULD ONLY PASS TEMP ByteBuffer LARGE ENOUGH TO ENCODE ALL CHARACTERS,
+ // AND LOCK ON THE DESTINATION IF THIS IS NOT POSSIBLE
+ ByteBuffer destinationBuffer = destination.getByteBuffer();
+ if (destinationBuffer != temp) {
+ temp.flip();
+ destinationBuffer.put(temp);
+ temp.clear();
+ }
+ // destination consumes contents
+ // and returns byte buffer with more capacity
+ destinationBuffer = destination.drain(destinationBuffer);
+ temp = destinationBuffer;
+ }
+ return temp;
}
- private ByteBuffer flushRemainingBytes(final ByteBufferDestination destination, ByteBuffer byteBuf)
+ private static ByteBuffer flushRemainingBytes(final CharsetEncoder charsetEncoder,
+ final ByteBufferDestination destination, ByteBuffer temp)
throws CharacterCodingException {
CoderResult result;
do {
// write any final bytes to the output buffer once the overall input sequence has been read
- result = charsetEncoder.flush(byteBuf);
- if (result.isOverflow()) { // byteBuf full
- // destination consumes contents
- // and returns byte buffer with more capacity
- byteBuf = destination.drain(byteBuf);
- }
- } while (result.isOverflow()); // byteBuf has been drained: retry
+ result = charsetEncoder.flush(temp);
+ temp = drainIfByteBufferFull(destination, temp, result);
+ } while (result.isOverflow()); // byte buffer has been drained: retry
if (!result.isUnderflow()) { // we should have fully flushed the remaining bytes
result.throwException();
}
- return byteBuf;
+ return temp;
}
/**
@@ -170,8 +194,4 @@ public class TextEncoderHelper {
destination.position(start + length);
return length;
}
-
- CharBuffer getCachedCharBuffer() {
- return cachedCharBuffer;
- }
}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/23cd33fc/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/StringBuilderEncoderTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/StringBuilderEncoderTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/StringBuilderEncoderTest.java
new file mode 100644
index 0000000..40c9db8
--- /dev/null
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/StringBuilderEncoderTest.java
@@ -0,0 +1,277 @@
+package org.apache.logging.log4j.core.layout;/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+
+import org.junit.Test;
+
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+
+import static org.junit.Assert.*;
+
+/**
+ * Tests the {@code TextEncoderHelper} class.
+ */
+public class StringBuilderEncoderTest {
+
+ @Test
+ public void testEncodeText_TextFitCharBuff_BytesFitByteBuff() throws Exception {
+ final StringBuilderEncoder helper = new StringBuilderEncoder(StandardCharsets.UTF_8, 16, 8 * 1024);
+ final StringBuilder text = createText(15);
+ final SpyByteBufferDestination destination = new SpyByteBufferDestination(17, 17);
+ helper.encode(text, destination);
+
+ assertEquals("drained", 0, destination.drainPoints.size());
+ assertEquals("destination.buf.pos", text.length(), destination.buffer.position());
+
+ for (int i = 0; i < text.length(); i++) {
+ assertEquals("char at " + i, (byte) text.charAt(i), destination.buffer.get(i));
+ }
+ }
+
+ @Test
+ public void testEncodeText_TextFitCharBuff_BytesDontFitByteBuff() throws Exception {
+ final StringBuilderEncoder helper = new StringBuilderEncoder(StandardCharsets.UTF_8, 16, 8 * 1024);
+ final StringBuilder text = createText(15);
+ final SpyByteBufferDestination destination = new SpyByteBufferDestination(14, 15);
+ helper.encode(text, destination);
+
+ assertEquals("drained", 1, destination.drainPoints.size());
+ assertEquals("drained[0].from", 0, destination.drainPoints.get(0).position);
+ assertEquals("drained[0].to", destination.buffer.capacity(), destination.drainPoints.get(0).limit);
+ assertEquals("drained[0].length", destination.buffer.capacity(), destination.drainPoints.get(0).length());
+ assertEquals("destination.buf.pos", text.length() - destination.buffer.capacity(),
+ destination.buffer.position());
+
+ for (int i = 0; i < destination.buffer.capacity(); i++) {
+ assertEquals("char at " + i, (byte) text.charAt(i), destination.drained.get(i));
+ }
+ for (int i = destination.buffer.capacity(); i < text.length(); i++) {
+ int bufIx = i - destination.buffer.capacity();
+ assertEquals("char at " + i, (byte) text.charAt(i), destination.buffer.get(bufIx));
+ }
+ }
+
+ @Test
+ public void testEncodeText_TextFitCharBuff_BytesDontFitByteBuff_MultiplePasses() throws Exception {
+ final StringBuilderEncoder helper = new StringBuilderEncoder(StandardCharsets.UTF_8, 16, 8 * 1024);
+ final StringBuilder text = createText(15);
+ final SpyByteBufferDestination destination = new SpyByteBufferDestination(4, 20);
+ helper.encode(text, destination);
+
+ assertEquals("drained", 3, destination.drainPoints.size());
+ assertEquals("drained[0].from", 0, destination.drainPoints.get(0).position);
+ assertEquals("drained[0].to", destination.buffer.capacity(), destination.drainPoints.get(0).limit);
+ assertEquals("drained[0].length", destination.buffer.capacity(), destination.drainPoints.get(0).length());
+ assertEquals("drained[1].from", 0, destination.drainPoints.get(1).position);
+ assertEquals("drained[1].to", destination.buffer.capacity(), destination.drainPoints.get(1).limit);
+ assertEquals("drained[1].length", destination.buffer.capacity(), destination.drainPoints.get(1).length());
+ assertEquals("drained[2].from", 0, destination.drainPoints.get(2).position);
+ assertEquals("drained[2].to", destination.buffer.capacity(), destination.drainPoints.get(2).limit);
+ assertEquals("drained[2].length", destination.buffer.capacity(), destination.drainPoints.get(2).length());
+ assertEquals("destination.buf.pos", text.length() - 3 * destination.buffer.capacity(),
+ destination.buffer.position());
+
+ for (int i = 0; i < 3 * destination.buffer.capacity(); i++) {
+ assertEquals("char at " + i, (byte) text.charAt(i), destination.drained.get(i));
+ }
+ for (int i = 3 * destination.buffer.capacity(); i < text.length(); i++) {
+ int bufIx = i - 3 * destination.buffer.capacity();
+ assertEquals("char at " + i, (byte) text.charAt(i), destination.buffer.get(bufIx));
+ }
+ }
+
+ @Test
+ public void testEncodeText_TextDoesntFitCharBuff_BytesFitByteBuff() throws Exception {
+ final StringBuilderEncoder helper = new StringBuilderEncoder(StandardCharsets.UTF_8, 4, 8 * 1024);
+ final StringBuilder text = createText(15);
+ final SpyByteBufferDestination destination = new SpyByteBufferDestination(17, 17);
+ helper.encode(text, destination);
+
+ assertEquals("drained", 0, destination.drainPoints.size());
+ assertEquals("destination.buf.pos", text.length(), destination.buffer.position());
+
+ for (int i = 0; i < text.length(); i++) {
+ assertEquals("char at " + i, (byte) text.charAt(i), destination.buffer.get(i));
+ }
+ }
+
+ @Test
+ public void testEncodeText_JapaneseTextUtf8DoesntFitCharBuff_BytesFitByteBuff() throws Exception {
+ final StringBuilderEncoder helper = new StringBuilderEncoder(StandardCharsets.UTF_8, 4, 8 * 1024);
+ final StringBuilder text = new StringBuilder( // 日本語テスト文章
+ "\u65e5\u672c\u8a9e\u30c6\u30b9\u30c8\u6587\u7ae0");
+ final SpyByteBufferDestination destination = new SpyByteBufferDestination(50, 50);
+ helper.encode(text, destination);
+
+ assertEquals("drained", 0, destination.drainPoints.size());
+ destination.drain(destination.getByteBuffer());
+
+ final byte[] utf8 = text.toString().getBytes(StandardCharsets.UTF_8);
+ for (int i = 0; i < utf8.length; i++) {
+ assertEquals("byte at " + i, utf8[i], destination.drained.get(i));
+ }
+ }
+
+ @Test
+ public void testEncodeText_JapaneseTextShiftJisDoesntFitCharBuff_BytesFitByteBuff() throws Exception {
+ final Charset SHIFT_JIS = Charset.forName("Shift_JIS");
+ final StringBuilderEncoder helper = new StringBuilderEncoder(SHIFT_JIS, 4, 8 * 1024);
+ final StringBuilder text = new StringBuilder( // 日本語テスト文章
+ "\u65e5\u672c\u8a9e\u30c6\u30b9\u30c8\u6587\u7ae0");
+ final SpyByteBufferDestination destination = new SpyByteBufferDestination(50, 50);
+ helper.encode(text, destination);
+
+ assertEquals("drained", 0, destination.drainPoints.size());
+ destination.drain(destination.getByteBuffer());
+
+ final byte[] bytes = text.toString().getBytes(SHIFT_JIS);
+ for (int i = 0; i < bytes.length; i++) {
+ assertEquals("byte at " + i, bytes[i], destination.drained.get(i));
+ }
+ }
+
+ @Test
+ public void testEncodeText_TextDoesntFitCharBuff_BytesDontFitByteBuff() throws Exception {
+ final StringBuilderEncoder helper = new StringBuilderEncoder(StandardCharsets.UTF_8, 4, 8 * 1024);
+ final StringBuilder text = createText(15);
+ final SpyByteBufferDestination destination = new SpyByteBufferDestination(3, 17);
+ helper.encode(text, destination);
+
+ assertEquals("drained", 4, destination.drainPoints.size());
+ assertEquals("destination.buf.pos", 3, destination.buffer.position());
+
+ for (int i = 0; i < text.length() - 3; i++) {
+ assertEquals("char at " + i, (byte) text.charAt(i), destination.drained.get(i));
+ }
+ for (int i = 0; i < 3; i++) {
+ assertEquals("char at " + (12 + i), (byte) text.charAt(12 + i), destination.buffer.get(i));
+ }
+ }
+
+ @Test
+ public void testEncodeText_JapaneseTextUtf8DoesntFitCharBuff_BytesDontFitByteBuff() throws Exception {
+ final StringBuilderEncoder helper = new StringBuilderEncoder(StandardCharsets.UTF_8, 4, 8 * 1024);
+ final StringBuilder text = new StringBuilder( // 日本語テスト文章
+ "\u65e5\u672c\u8a9e\u30c6\u30b9\u30c8\u6587\u7ae0");
+ final SpyByteBufferDestination destination = new SpyByteBufferDestination(3, 50);
+ helper.encode(text, destination);
+
+ assertEquals("drained", 7, destination.drainPoints.size());
+ destination.drain(destination.getByteBuffer());
+
+ final byte[] utf8 = text.toString().getBytes(StandardCharsets.UTF_8);
+ for (int i = 0; i < utf8.length; i++) {
+ assertEquals("byte at " + i, utf8[i], destination.drained.get(i));
+ }
+ }
+
+ @Test
+ public void testEncodeText_JapaneseTextShiftJisDoesntFitCharBuff_BytesDontFitByteBuff() throws Exception {
+ final Charset SHIFT_JIS = Charset.forName("Shift_JIS");
+ final StringBuilderEncoder helper = new StringBuilderEncoder(SHIFT_JIS, 4, 8 * 1024);
+ final StringBuilder text = new StringBuilder( // 日本語テスト文章
+ "\u65e5\u672c\u8a9e\u30c6\u30b9\u30c8\u6587\u7ae0");
+ final SpyByteBufferDestination destination = new SpyByteBufferDestination(3, 50);
+ helper.encode(text, destination);
+
+ assertEquals("drained", 7, destination.drainPoints.size());
+ destination.drain(destination.getByteBuffer());
+
+ final byte[] bytes = text.toString().getBytes(SHIFT_JIS);
+ for (int i = 0; i < bytes.length; i++) {
+ assertEquals("byte at " + i, bytes[i], destination.drained.get(i));
+ }
+ }
+
+ @Test
+ public void testCopyCopiesAllDataIfSuffientRemainingSpace() throws Exception {
+ final CharBuffer buff = CharBuffer.wrap(new char[16]);
+ final StringBuilder text = createText(15);
+ final int length = TextEncoderHelper.copy(text, 0, buff);
+ assertEquals("everything fits", text.length(), length);
+ for (int i = 0; i < length; i++) {
+ assertEquals("char at " + i, text.charAt(i), buff.get(i));
+ }
+ assertEquals("position moved by length", text.length(), buff.position());
+ }
+
+ @Test
+ public void testCopyUpToRemainingSpace() throws Exception {
+ final CharBuffer buff = CharBuffer.wrap(new char[3]);
+ final StringBuilder text = createText(15);
+ final int length = TextEncoderHelper.copy(text, 0, buff);
+ assertEquals("partial copy", buff.capacity(), length);
+ for (int i = 0; i < length; i++) {
+ assertEquals("char at " + i, text.charAt(i), buff.get(i));
+ }
+ assertEquals("no space remaining", 0, buff.remaining());
+ assertEquals("position at end", buff.capacity(), buff.position());
+ }
+
+ @Test
+ public void testCopyDoesNotWriteBeyondStringText() throws Exception {
+ final CharBuffer buff = CharBuffer.wrap(new char[5]);
+ assertEquals("initial buffer position", 0, buff.position());
+ final StringBuilder text = createText(2);
+ final int length = TextEncoderHelper.copy(text, 0, buff);
+ assertEquals("full copy", text.length(), length);
+ for (int i = 0; i < length; i++) {
+ assertEquals("char at " + i, text.charAt(i), buff.get(i));
+ }
+ assertEquals("resulting buffer position", text.length(), buff.position());
+ for (int i = length; i < buff.capacity(); i++) {
+ assertEquals("unset char at " + i, 0, buff.get(i));
+ }
+ }
+
+ @Test
+ public void testCopyStartsAtBufferPosition() throws Exception {
+ final CharBuffer buff = CharBuffer.wrap(new char[10]);
+ final int START_POSITION = 5;
+ buff.position(START_POSITION); // set start position
+ final StringBuilder text = createText(15);
+ final int length = TextEncoderHelper.copy(text, 0, buff);
+ assertEquals("partial copy", buff.capacity() - START_POSITION, length);
+ for (int i = 0; i < length; i++) {
+ assertEquals("char at " + i, text.charAt(i), buff.get(START_POSITION + i));
+ }
+ assertEquals("buffer position at end", buff.capacity(), buff.position());
+ }
+
+ @Test
+ public void testEncode_ALotWithoutErrors() throws Exception {
+ final StringBuilderEncoder helper = new StringBuilderEncoder(Charset.defaultCharset());
+ final StringBuilder text = new StringBuilder("2016-04-13 21:07:47,487 DEBUG [org.apache.logging.log4j.perf.jmh.FileAppenderBenchmark.log4j2ParameterizedString-jmh-worker-1] FileAppenderBenchmark - This is a debug [2383178] message\r\n");
+ final int DESTINATION_SIZE = 1024 * 1024;
+ final SpyByteBufferDestination destination = new SpyByteBufferDestination(256 * 1024, DESTINATION_SIZE);
+
+ int max = DESTINATION_SIZE / text.length();
+ for (int i = 0; i < max; i++) {
+ helper.encode(text, destination);
+ }
+ // no error
+ }
+
+ private StringBuilder createText(final int length) {
+ final StringBuilder result = new StringBuilder(length);
+ for (int i = 0; i < length; i++) {
+ result.append((char) (' ' + i)); // space=0x20
+ }
+ return result;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/23cd33fc/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/TextEncoderHelperTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/TextEncoderHelperTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/TextEncoderHelperTest.java
deleted file mode 100644
index e98dfca..0000000
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/TextEncoderHelperTest.java
+++ /dev/null
@@ -1,263 +0,0 @@
-package org.apache.logging.log4j.core.layout;/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache license, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the license for the specific language governing permissions and
- * limitations under the license.
- */
-
-import java.nio.CharBuffer;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-
-import org.junit.Test;
-
-import static org.junit.Assert.*;
-
-/**
- * Tests the {@code TextEncoderHelper} class.
- */
-public class TextEncoderHelperTest {
-
- @Test
- public void testEncodeText_TextFitCharBuff_BytesFitByteBuff() throws Exception {
- final TextEncoderHelper helper = new TextEncoderHelper(StandardCharsets.UTF_8, 16);
- final StringBuilder text = createText(15);
- final SpyByteBufferDestination destination = new SpyByteBufferDestination(17, 17);
- helper.encodeText(text, destination);
-
- assertEquals("drained", 0, destination.drainPoints.size());
- assertEquals("destination.buf.pos", text.length(), destination.buffer.position());
-
- for (int i = 0; i < text.length(); i++) {
- assertEquals("char at " + i, (byte) text.charAt(i), destination.buffer.get(i));
- }
- }
-
- @Test
- public void testEncodeText_TextFitCharBuff_BytesDontFitByteBuff() throws Exception {
- final TextEncoderHelper helper = new TextEncoderHelper(StandardCharsets.UTF_8, 16);
- final StringBuilder text = createText(15);
- final SpyByteBufferDestination destination = new SpyByteBufferDestination(14, 15);
- helper.encodeText(text, destination);
-
- assertEquals("drained", 1, destination.drainPoints.size());
- assertEquals("drained[0].from", 0, destination.drainPoints.get(0).position);
- assertEquals("drained[0].to", destination.buffer.capacity(), destination.drainPoints.get(0).limit);
- assertEquals("drained[0].length", destination.buffer.capacity(), destination.drainPoints.get(0).length());
- assertEquals("destination.buf.pos", text.length() - destination.buffer.capacity(),
- destination.buffer.position());
-
- for (int i = 0; i < destination.buffer.capacity(); i++) {
- assertEquals("char at " + i, (byte) text.charAt(i), destination.drained.get(i));
- }
- for (int i = destination.buffer.capacity(); i < text.length(); i++) {
- int bufIx = i - destination.buffer.capacity();
- assertEquals("char at " + i, (byte) text.charAt(i), destination.buffer.get(bufIx));
- }
- }
-
- @Test
- public void testEncodeText_TextFitCharBuff_BytesDontFitByteBuff_MultiplePasses() throws Exception {
- final TextEncoderHelper helper = new TextEncoderHelper(StandardCharsets.UTF_8, 16);
- final StringBuilder text = createText(15);
- final SpyByteBufferDestination destination = new SpyByteBufferDestination(4, 20);
- helper.encodeText(text, destination);
-
- assertEquals("drained", 3, destination.drainPoints.size());
- assertEquals("drained[0].from", 0, destination.drainPoints.get(0).position);
- assertEquals("drained[0].to", destination.buffer.capacity(), destination.drainPoints.get(0).limit);
- assertEquals("drained[0].length", destination.buffer.capacity(), destination.drainPoints.get(0).length());
- assertEquals("drained[1].from", 0, destination.drainPoints.get(1).position);
- assertEquals("drained[1].to", destination.buffer.capacity(), destination.drainPoints.get(1).limit);
- assertEquals("drained[1].length", destination.buffer.capacity(), destination.drainPoints.get(1).length());
- assertEquals("drained[2].from", 0, destination.drainPoints.get(2).position);
- assertEquals("drained[2].to", destination.buffer.capacity(), destination.drainPoints.get(2).limit);
- assertEquals("drained[2].length", destination.buffer.capacity(), destination.drainPoints.get(2).length());
- assertEquals("destination.buf.pos", text.length() - 3 * destination.buffer.capacity(),
- destination.buffer.position());
-
- for (int i = 0; i < 3 * destination.buffer.capacity(); i++) {
- assertEquals("char at " + i, (byte) text.charAt(i), destination.drained.get(i));
- }
- for (int i = 3 * destination.buffer.capacity(); i < text.length(); i++) {
- int bufIx = i - 3 * destination.buffer.capacity();
- assertEquals("char at " + i, (byte) text.charAt(i), destination.buffer.get(bufIx));
- }
- }
-
- @Test
- public void testEncodeText_TextDoesntFitCharBuff_BytesFitByteBuff() throws Exception {
- final TextEncoderHelper helper = new TextEncoderHelper(StandardCharsets.UTF_8, 4);
- final StringBuilder text = createText(15);
- final SpyByteBufferDestination destination = new SpyByteBufferDestination(17, 17);
- helper.encodeText(text, destination);
-
- assertEquals("drained", 0, destination.drainPoints.size());
- assertEquals("destination.buf.pos", text.length(), destination.buffer.position());
-
- for (int i = 0; i < text.length(); i++) {
- assertEquals("char at " + i, (byte) text.charAt(i), destination.buffer.get(i));
- }
- }
-
- @Test
- public void testEncodeText_JapaneseTextUtf8DoesntFitCharBuff_BytesFitByteBuff() throws Exception {
- final TextEncoderHelper helper = new TextEncoderHelper(StandardCharsets.UTF_8, 4);
- final StringBuilder text = new StringBuilder( // 日本語テスト文章
- "\u65e5\u672c\u8a9e\u30c6\u30b9\u30c8\u6587\u7ae0");
- final SpyByteBufferDestination destination = new SpyByteBufferDestination(50, 50);
- helper.encodeText(text, destination);
-
- assertEquals("drained", 0, destination.drainPoints.size());
- destination.drain(destination.getByteBuffer());
-
- final byte[] utf8 = text.toString().getBytes(StandardCharsets.UTF_8);
- for (int i = 0; i < utf8.length; i++) {
- assertEquals("byte at " + i, utf8[i], destination.drained.get(i));
- }
- }
-
- @Test
- public void testEncodeText_JapaneseTextShiftJisDoesntFitCharBuff_BytesFitByteBuff() throws Exception {
- final Charset SHIFT_JIS = Charset.forName("Shift_JIS");
- final TextEncoderHelper helper = new TextEncoderHelper(SHIFT_JIS, 4);
- final StringBuilder text = new StringBuilder( // 日本語テスト文章
- "\u65e5\u672c\u8a9e\u30c6\u30b9\u30c8\u6587\u7ae0");
- final SpyByteBufferDestination destination = new SpyByteBufferDestination(50, 50);
- helper.encodeText(text, destination);
-
- assertEquals("drained", 0, destination.drainPoints.size());
- destination.drain(destination.getByteBuffer());
-
- final byte[] bytes = text.toString().getBytes(SHIFT_JIS);
- for (int i = 0; i < bytes.length; i++) {
- assertEquals("byte at " + i, bytes[i], destination.drained.get(i));
- }
- }
-
- @Test
- public void testEncodeText_TextDoesntFitCharBuff_BytesDontFitByteBuff() throws Exception {
- final TextEncoderHelper helper = new TextEncoderHelper(StandardCharsets.UTF_8, 4);
- final StringBuilder text = createText(15);
- final SpyByteBufferDestination destination = new SpyByteBufferDestination(3, 17);
- helper.encodeText(text, destination);
-
- assertEquals("drained", 4, destination.drainPoints.size());
- assertEquals("destination.buf.pos", 3, destination.buffer.position());
-
- for (int i = 0; i < text.length() - 3; i++) {
- assertEquals("char at " + i, (byte) text.charAt(i), destination.drained.get(i));
- }
- for (int i = 0; i < 3; i++) {
- assertEquals("char at " + (12 + i), (byte) text.charAt(12 + i), destination.buffer.get(i));
- }
- }
-
- @Test
- public void testEncodeText_JapaneseTextUtf8DoesntFitCharBuff_BytesDontFitByteBuff() throws Exception {
- final TextEncoderHelper helper = new TextEncoderHelper(StandardCharsets.UTF_8, 4);
- final StringBuilder text = new StringBuilder( // 日本語テスト文章
- "\u65e5\u672c\u8a9e\u30c6\u30b9\u30c8\u6587\u7ae0");
- final SpyByteBufferDestination destination = new SpyByteBufferDestination(3, 50);
- helper.encodeText(text, destination);
-
- assertEquals("drained", 7, destination.drainPoints.size());
- destination.drain(destination.getByteBuffer());
-
- final byte[] utf8 = text.toString().getBytes(StandardCharsets.UTF_8);
- for (int i = 0; i < utf8.length; i++) {
- assertEquals("byte at " + i, utf8[i], destination.drained.get(i));
- }
- }
-
- @Test
- public void testEncodeText_JapaneseTextShiftJisDoesntFitCharBuff_BytesDontFitByteBuff() throws Exception {
- final Charset SHIFT_JIS = Charset.forName("Shift_JIS");
- final TextEncoderHelper helper = new TextEncoderHelper(SHIFT_JIS, 4);
- final StringBuilder text = new StringBuilder( // 日本語テスト文章
- "\u65e5\u672c\u8a9e\u30c6\u30b9\u30c8\u6587\u7ae0");
- final SpyByteBufferDestination destination = new SpyByteBufferDestination(3, 50);
- helper.encodeText(text, destination);
-
- assertEquals("drained", 7, destination.drainPoints.size());
- destination.drain(destination.getByteBuffer());
-
- final byte[] bytes = text.toString().getBytes(SHIFT_JIS);
- for (int i = 0; i < bytes.length; i++) {
- assertEquals("byte at " + i, bytes[i], destination.drained.get(i));
- }
- }
-
- @Test
- public void testCopyCopiesAllDataIfSuffientRemainingSpace() throws Exception {
- final CharBuffer buff = CharBuffer.wrap(new char[16]);
- final StringBuilder text = createText(15);
- final int length = TextEncoderHelper.copy(text, 0, buff);
- assertEquals("everything fits", text.length(), length);
- for (int i = 0; i < length; i++) {
- assertEquals("char at " + i, text.charAt(i), buff.get(i));
- }
- assertEquals("position moved by length", text.length(), buff.position());
- }
-
- @Test
- public void testCopyUpToRemainingSpace() throws Exception {
- final CharBuffer buff = CharBuffer.wrap(new char[3]);
- final StringBuilder text = createText(15);
- final int length = TextEncoderHelper.copy(text, 0, buff);
- assertEquals("partial copy", buff.capacity(), length);
- for (int i = 0; i < length; i++) {
- assertEquals("char at " + i, text.charAt(i), buff.get(i));
- }
- assertEquals("no space remaining", 0, buff.remaining());
- assertEquals("position at end", buff.capacity(), buff.position());
- }
-
- @Test
- public void testCopyDoesNotWriteBeyondStringText() throws Exception {
- final CharBuffer buff = CharBuffer.wrap(new char[5]);
- assertEquals("initial buffer position", 0, buff.position());
- final StringBuilder text = createText(2);
- final int length = TextEncoderHelper.copy(text, 0, buff);
- assertEquals("full copy", text.length(), length);
- for (int i = 0; i < length; i++) {
- assertEquals("char at " + i, text.charAt(i), buff.get(i));
- }
- assertEquals("resulting buffer position", text.length(), buff.position());
- for (int i = length; i < buff.capacity(); i++) {
- assertEquals("unset char at " + i, 0, buff.get(i));
- }
- }
-
- @Test
- public void testCopyStartsAtBufferPosition() throws Exception {
- final CharBuffer buff = CharBuffer.wrap(new char[10]);
- final int START_POSITION = 5;
- buff.position(START_POSITION); // set start position
- final StringBuilder text = createText(15);
- final int length = TextEncoderHelper.copy(text, 0, buff);
- assertEquals("partial copy", buff.capacity() - START_POSITION, length);
- for (int i = 0; i < length; i++) {
- assertEquals("char at " + i, text.charAt(i), buff.get(START_POSITION + i));
- }
- assertEquals("buffer position at end", buff.capacity(), buff.position());
- }
-
- private StringBuilder createText(final int length) {
- final StringBuilder result = new StringBuilder(length);
- for (int i = 0; i < length; i++) {
- result.append((char) (' ' + i)); // space=0x20
- }
- return result;
- }
-}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/23cd33fc/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/TextEncoderHelperBenchmark.java
----------------------------------------------------------------------
diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/TextEncoderHelperBenchmark.java b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/TextEncoderHelperBenchmark.java
index bab01ff..888035d 100644
--- a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/TextEncoderHelperBenchmark.java
+++ b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/TextEncoderHelperBenchmark.java
@@ -29,7 +29,7 @@ import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.impl.Log4jLogEvent;
import org.apache.logging.log4j.core.layout.ByteBufferDestination;
import org.apache.logging.log4j.core.layout.PatternLayout;
-import org.apache.logging.log4j.core.layout.TextEncoderHelper;
+import org.apache.logging.log4j.core.layout.StringBuilderEncoder;
import org.apache.logging.log4j.message.Message;
import org.apache.logging.log4j.message.SimpleMessage;
import org.openjdk.jmh.annotations.Benchmark;
@@ -40,13 +40,13 @@ import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.State;
/**
- * Tests Log4j2 TextEncoderHelper performance.
+ * Tests Log4j2 StringBuilderEncoder performance.
*/
// ============================== HOW TO RUN THIS TEST: ====================================
//
// single thread:
-// java -Dfile.encoding=ISO-8859-1 -Dlog4j2.is.webapp=false -Dlog4j2.enable.threadlocals=true -jar log4j-perf/target/benchmarks.jar ".*TextEncoderHelper.*" -f 1 -wi 5 -i 10
-// java -Dfile.encoding=UTF8 -Dlog4j2.is.webapp=false -Dlog4j2.enable.threadlocals=true -jar log4j-perf/target/benchmarks.jar ".*TextEncoderHelper.*" -f 1 -wi 5 -i 10
+// java -Dfile.encoding=ISO-8859-1 -Dlog4j2.is.webapp=false -Dlog4j2.enable.threadlocals=true -jar log4j-perf/target/benchmarks.jar ".*StringBuilderEncoder.*" -f 1 -wi 5 -i 10
+// java -Dfile.encoding=UTF8 -Dlog4j2.is.webapp=false -Dlog4j2.enable.threadlocals=true -jar log4j-perf/target/benchmarks.jar ".*StringBuilderEncoder.*" -f 1 -wi 5 -i 10
//
// Usage help:
// java -jar log4j-perf/target/benchmarks.jar -help
@@ -116,13 +116,10 @@ public class TextEncoderHelperBenchmark {
return STR_TEXT.getBytes();
}
- private static final ThreadLocal<TextEncoderHelper> textEncoderHelper = new ThreadLocal<>();
- private TextEncoderHelper getCachedTextEncoderHelper() {
- TextEncoderHelper result = textEncoderHelper.get();
- if (result == null) {
- result = new TextEncoderHelper(CHARSET_DEFAULT);
- textEncoderHelper.set(result);
- }
+ //private static final ThreadLocal<StringBuilderEncoder> textEncoderHelper = new ThreadLocal<>();
+ private StringBuilderEncoder textEncoderHelper = new StringBuilderEncoder(CHARSET_DEFAULT);
+ private StringBuilderEncoder getEncoder() {
+ StringBuilderEncoder result = textEncoderHelper;
return result;
}
@@ -130,49 +127,49 @@ public class TextEncoderHelperBenchmark {
@BenchmarkMode(Mode.SampleTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public long textEncoderEncode() {
- final TextEncoderHelper helper = getCachedTextEncoderHelper();
- helper.encodeText(BUFF_TEXT, destination);
-
- return destination.count;
- }
-
- @Benchmark
- @BenchmarkMode(Mode.SampleTime)
- @OutputTimeUnit(TimeUnit.NANOSECONDS)
- public long charBufferEncode() {
- final TextEncoderHelper helper = getCachedTextEncoderHelper();
- CHAR_BUFFER.limit(CHAR_BUFFER.capacity());
- CHAR_BUFFER.position(0);
- helper.encodeText(CHAR_BUFFER, destination);
+ final StringBuilderEncoder helper = getEncoder();
+ helper.encode(BUFF_TEXT, destination);
return destination.count;
}
- @Benchmark
- @BenchmarkMode(Mode.SampleTime)
- @OutputTimeUnit(TimeUnit.NANOSECONDS)
- public long charBufferCopyAndEncode() {
- final TextEncoderHelper helper = getCachedTextEncoderHelper();
- CHAR_BUFFER.clear();
- CHAR_BUFFER.put(STR);
- CHAR_BUFFER.flip();
- helper.encodeText(CHAR_BUFFER, destination);
-
- return destination.count;
- }
-
- @Benchmark
- @BenchmarkMode(Mode.SampleTime)
- @OutputTimeUnit(TimeUnit.NANOSECONDS)
- public long textHelperCopyAndEncode() {
- final TextEncoderHelper helper = getCachedTextEncoderHelper();
- CHAR_BUFFER.clear();
- copy(BUFF_TEXT, 0, CHAR_BUFFER);
- CHAR_BUFFER.flip();
- helper.encodeText(CHAR_BUFFER, destination);
-
- return destination.count;
- }
+// @Benchmark
+// @BenchmarkMode(Mode.SampleTime)
+// @OutputTimeUnit(TimeUnit.NANOSECONDS)
+// public long charBufferEncode() {
+// final StringBuilderEncoder helper = getEncoder();
+// CHAR_BUFFER.limit(CHAR_BUFFER.capacity());
+// CHAR_BUFFER.position(0);
+// helper.encode(CHAR_BUFFER, destination);
+//
+// return destination.count;
+// }
+//
+// @Benchmark
+// @BenchmarkMode(Mode.SampleTime)
+// @OutputTimeUnit(TimeUnit.NANOSECONDS)
+// public long charBufferCopyAndEncode() {
+// final StringBuilderEncoder helper = getEncoder();
+// CHAR_BUFFER.clear();
+// CHAR_BUFFER.put(STR);
+// CHAR_BUFFER.flip();
+// helper.encode(CHAR_BUFFER, destination);
+//
+// return destination.count;
+// }
+//
+// @Benchmark
+// @BenchmarkMode(Mode.SampleTime)
+// @OutputTimeUnit(TimeUnit.NANOSECONDS)
+// public long textHelperCopyAndEncode() {
+// final StringBuilderEncoder helper = getEncoder();
+// CHAR_BUFFER.clear();
+// copy(BUFF_TEXT, 0, CHAR_BUFFER);
+// CHAR_BUFFER.flip();
+// helper.encode(CHAR_BUFFER, destination);
+//
+// return destination.count;
+// }
/**
* Copies characters from the CharSequence into the CharBuffer,
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/23cd33fc/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/NoGcLayout.java
----------------------------------------------------------------------
diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/NoGcLayout.java b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/NoGcLayout.java
index 345a231..4b1a4ad 100644
--- a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/NoGcLayout.java
+++ b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/NoGcLayout.java
@@ -20,6 +20,7 @@ import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.layout.ByteBufferDestination;
import org.apache.logging.log4j.core.layout.Encoder;
+import org.apache.logging.log4j.core.layout.StringBuilderEncoder;
import org.apache.logging.log4j.core.layout.TextEncoderHelper;
import org.apache.logging.log4j.core.pattern.FormattingInfo;
import org.apache.logging.log4j.core.pattern.PatternFormatter;
@@ -39,18 +40,18 @@ import java.util.Map;
public class NoGcLayout implements Layout<Serializable>, Encoder<LogEvent> {
private final StringBuilder cachedStringBuilder = new StringBuilder(2048);
private final PatternSerializer2 serializer = new PatternSerializer2();
- private final TextEncoderHelper cachedHelper;
+ private final StringBuilderEncoder cachedHelper;
public NoGcLayout(Charset charset) {
- cachedHelper = new TextEncoderHelper(charset);
+ cachedHelper = new StringBuilderEncoder(charset);
}
@Override
public void encode(LogEvent event, ByteBufferDestination destination) {
StringBuilder text = toText(event, getCachedStringBuilder());
- TextEncoderHelper helper = getCachedHelper();
- helper.encodeText(text, destination);
+ Encoder<StringBuilder> helper = getCachedHelper();
+ helper.encode(text, destination);
}
/**
@@ -69,7 +70,7 @@ public class NoGcLayout implements Layout<Serializable>, Encoder<LogEvent> {
return cachedStringBuilder;
}
- public TextEncoderHelper getCachedHelper() {
+ public Encoder<StringBuilder> getCachedHelper() {
return cachedHelper;
}
[6/6] logging-log4j2 git commit: Merge branch 'master' into
LOG4J2-1365
Posted by mi...@apache.org.
Merge branch 'master' into LOG4J2-1365
Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/8b59f231
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/8b59f231
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/8b59f231
Branch: refs/heads/LOG4J2-1365
Commit: 8b59f231fc741e69578c4c6e63ac63a8eb06cf62
Parents: 07723d5 c3463a8
Author: Mikael Ståldal <mi...@magine.com>
Authored: Thu Apr 14 10:32:55 2016 +0200
Committer: Mikael Ståldal <mi...@magine.com>
Committed: Thu Apr 14 10:32:55 2016 +0200
----------------------------------------------------------------------
.../logging/log4j/core/impl/Log4jLogEvent.java | 28 +-
.../log4j/core/impl/MutableLogEvent.java | 199 +++++++++++++
.../core/impl/ReusableLogEventFactory.java | 80 ++++++
.../log4j/core/layout/AbstractStringLayout.java | 21 +-
.../logging/log4j/core/layout/GelfLayout.java | 10 +-
.../layout/LockingStringBuilderEncoder.java | 52 ++++
.../log4j/core/layout/PatternLayout.java | 5 +-
.../log4j/core/layout/StringBuilderEncoder.java | 111 ++++++++
.../log4j/core/layout/TextEncoderHelper.java | 153 +++++-----
.../core/layout/StringBuilderEncoderTest.java | 277 +++++++++++++++++++
.../core/layout/TextEncoderHelperTest.java | 263 ------------------
.../perf/jmh/TextEncoderHelperBenchmark.java | 97 ++++---
.../logging/log4j/perf/nogc/NoGcLayout.java | 11 +-
src/site/xdoc/manual/garbagefree.xml | 6 +-
14 files changed, 901 insertions(+), 412 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/8b59f231/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/GelfLayout.java
----------------------------------------------------------------------
[4/6] logging-log4j2 git commit: LOG4J2-1334 bugfix: ThrowableProxy
is not cached, getter method is called in LogEventProxy constructor
Posted by mi...@apache.org.
LOG4J2-1334 bugfix: ThrowableProxy is not cached, getter method is called in LogEventProxy constructor
Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/89808ecb
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/89808ecb
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/89808ecb
Branch: refs/heads/LOG4J2-1365
Commit: 89808ecbbe50067ac3b5a1b60a38079002650d20
Parents: 5f461a7
Author: rpopma <rp...@apache.org>
Authored: Thu Apr 14 01:52:36 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Thu Apr 14 01:52:36 2016 +0900
----------------------------------------------------------------------
.../java/org/apache/logging/log4j/core/impl/MutableLogEvent.java | 1 -
1 file changed, 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/89808ecb/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java
index 2e2626f..876ce58 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java
@@ -190,7 +190,6 @@ public class MutableLogEvent implements LogEvent {
* @return a LogEventProxy.
*/
protected Object writeReplace() {
- getThrownProxy(); // ensure ThrowableProxy is initialized
return new Log4jLogEvent.LogEventProxy(this, this.includeLocation);
}
[3/6] logging-log4j2 git commit: LOG4J2-1334 initial version of
reusable LogEvent + factory
Posted by mi...@apache.org.
LOG4J2-1334 initial version of reusable LogEvent + factory
Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/5f461a72
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/5f461a72
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/5f461a72
Branch: refs/heads/LOG4J2-1365
Commit: 5f461a72203d5b729005db4690bfc4c9e2b4e64d
Parents: 0a06f8f
Author: rpopma <rp...@apache.org>
Authored: Thu Apr 14 01:49:55 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Thu Apr 14 01:49:55 2016 +0900
----------------------------------------------------------------------
.../logging/log4j/core/impl/Log4jLogEvent.java | 28 ++-
.../log4j/core/impl/MutableLogEvent.java | 200 +++++++++++++++++++
.../core/impl/ReusableLogEventFactory.java | 80 ++++++++
3 files changed, 306 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/5f461a72/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java
index 3f8961a..2e017dd 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java
@@ -396,7 +396,7 @@ public Log4jLogEvent(final String loggerName, final Marker marker, final String
this.nanoTime = nanoTime;
}
- private static Map<String, String> createMap(final List<Property> properties) {
+ static Map<String, String> createMap(final List<Property> properties) {
final Map<String, String> contextMap = ThreadContext.getImmutableContext();
if (properties == null || properties.isEmpty()) {
return contextMap; // may be ThreadContext.EMPTY_MAP but not null
@@ -766,7 +766,7 @@ public Log4jLogEvent(final String loggerName, final Marker marker, final String
/**
* Proxy pattern used to serialize the LogEvent.
*/
- private static class LogEventProxy implements Serializable {
+ static class LogEventProxy implements Serializable {
private static final long serialVersionUID = -8634075037355293699L;
private final String loggerFQCN;
@@ -812,6 +812,30 @@ public Log4jLogEvent(final String loggerName, final Marker marker, final String
this.nanoTime = event.nanoTime;
}
+ public LogEventProxy(final MutableLogEvent event, final boolean includeLocation) {
+ this.loggerFQCN = event.getLoggerFqcn();
+ this.marker = event.getMarker();
+ this.level = event.getLevel();
+ this.loggerName = event.getLoggerName();
+
+ final Message msg = event.getMessage();
+ this.message = msg instanceof ReusableMessage
+ ? memento((ReusableMessage) msg)
+ : msg;
+ this.timeMillis = event.getTimeMillis();
+ this.thrown = event.getThrown();
+ this.thrownProxy = event.getThrownProxy();
+ this.contextMap = event.getContextMap();
+ this.contextStack = event.getContextStack();
+ this.source = includeLocation ? event.getSource() : null;
+ this.threadId = event.getThreadId();
+ this.threadName = event.getThreadName();
+ this.threadPriority = event.getThreadPriority();
+ this.isLocationRequired = includeLocation;
+ this.isEndOfBatch = event.isEndOfBatch();
+ this.nanoTime = event.getNanoTime();
+ }
+
private Message memento(final ReusableMessage message) {
return new SimpleMessage(message.getFormattedMessage());
}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/5f461a72/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java
new file mode 100644
index 0000000..2e2626f
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java
@@ -0,0 +1,200 @@
+package org.apache.logging.log4j.core.impl;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.ThreadContext;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.message.Message;
+
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.util.Map;
+
+/**
+ * Mutable implementation of the {@code LogEvent} interface.
+ */
+public class MutableLogEvent implements LogEvent {
+ private String loggerFqcn;
+ private Marker marker;
+ private Level level;
+ private String loggerName;
+ private Message message;
+ private Throwable thrown;
+ private long timeMillis;
+ private Map<String, String> contextMap;
+ private ThreadContext.ContextStack contextStack;
+ private long threadId;
+ private String threadName;
+ private int threadPriority;
+ private boolean includeLocation;
+ private boolean endOfBatch = false;
+ private long nanoTime;
+ // private ThrowableProxy thrownProxy;
+ // private StackTraceElement source;
+
+ @Override
+ public String getLoggerFqcn() {
+ return loggerFqcn;
+ }
+
+ public void setLoggerFqcn(String loggerFqcn) {
+ this.loggerFqcn = loggerFqcn;
+ }
+
+ @Override
+ public Marker getMarker() {
+ return marker;
+ }
+
+ public void setMarker(Marker marker) {
+ this.marker = marker;
+ }
+
+ @Override
+ public Level getLevel() {
+ return level;
+ }
+
+ public void setLevel(Level level) {
+ this.level = level;
+ }
+
+ @Override
+ public String getLoggerName() {
+ return loggerName;
+ }
+
+ public void setLoggerName(String loggerName) {
+ this.loggerName = loggerName;
+ }
+
+ @Override
+ public Message getMessage() {
+ return message;
+ }
+
+ public void setMessage(Message message) {
+ this.message = message;
+ }
+
+ @Override
+ public Throwable getThrown() {
+ return thrown;
+ }
+
+ public void setThrown(Throwable thrown) {
+ this.thrown = thrown;
+ }
+
+ @Override
+ public long getTimeMillis() {
+ return timeMillis;
+ }
+
+ public void setTimeMillis(long timeMillis) {
+ this.timeMillis = timeMillis;
+ }
+
+ @Override
+ public ThrowableProxy getThrownProxy() {
+ if (thrown != null) {
+ return new ThrowableProxy(thrown);
+ }
+ return null;
+ }
+
+ @Override
+ public Map<String, String> getContextMap() {
+ return contextMap;
+ }
+
+ public void setContextMap(Map<String, String> contextMap) {
+ this.contextMap = contextMap;
+ }
+
+ @Override
+ public ThreadContext.ContextStack getContextStack() {
+ return contextStack;
+ }
+
+ public void setContextStack(ThreadContext.ContextStack contextStack) {
+ this.contextStack = contextStack;
+ }
+
+ @Override
+ public long getThreadId() {
+ return threadId;
+ }
+
+ public void setThreadId(long threadId) {
+ this.threadId = threadId;
+ }
+
+ @Override
+ public String getThreadName() {
+ return threadName;
+ }
+
+ public void setThreadName(String threadName) {
+ this.threadName = threadName;
+ }
+
+ @Override
+ public int getThreadPriority() {
+ return threadPriority;
+ }
+
+ public void setThreadPriority(int threadPriority) {
+ this.threadPriority = threadPriority;
+ }
+
+ @Override
+ public StackTraceElement getSource() {
+ if (loggerFqcn == null || !includeLocation) {
+ return null;
+ }
+ return Log4jLogEvent.calcLocation(loggerFqcn);
+ }
+
+ @Override
+ public boolean isIncludeLocation() {
+ return includeLocation;
+ }
+
+ @Override
+ public void setIncludeLocation(boolean includeLocation) {
+ this.includeLocation = includeLocation;
+ }
+
+ @Override
+ public boolean isEndOfBatch() {
+ return endOfBatch;
+ }
+
+ @Override
+ public void setEndOfBatch(boolean endOfBatch) {
+ this.endOfBatch = endOfBatch;
+ }
+
+ @Override
+ public long getNanoTime() {
+ return nanoTime;
+ }
+
+ public void setNanoTime(long nanoTime) {
+ this.nanoTime = nanoTime;
+ }
+
+ /**
+ * Creates a LogEventProxy that can be serialized.
+ * @return a LogEventProxy.
+ */
+ protected Object writeReplace() {
+ getThrownProxy(); // ensure ThrowableProxy is initialized
+ return new Log4jLogEvent.LogEventProxy(this, this.includeLocation);
+ }
+
+ private void readObject(final ObjectInputStream stream) throws InvalidObjectException {
+ throw new InvalidObjectException("Proxy required");
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/5f461a72/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactory.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactory.java
new file mode 100644
index 0000000..190b27a
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactory.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.core.impl;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.ThreadContext;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.config.Property;
+import org.apache.logging.log4j.core.util.Clock;
+import org.apache.logging.log4j.core.util.ClockFactory;
+import org.apache.logging.log4j.message.Message;
+
+import java.util.List;
+
+/**
+ * Garbage-free LogEventFactory that reuses a single mutable log event.
+ */
+public class ReusableLogEventFactory implements LogEventFactory {
+
+ private static ThreadLocal<MutableLogEvent> mutableLogEventThreadLocal = new ThreadLocal<>();
+ private static final Clock CLOCK = ClockFactory.getClock();
+ /**
+ * Creates a log event.
+ *
+ * @param loggerName The name of the Logger.
+ * @param marker An optional Marker.
+ * @param fqcn The fully qualified class name of the caller.
+ * @param level The event Level.
+ * @param data The Message.
+ * @param properties Properties to be added to the log event.
+ * @param t An optional Throwable.
+ * @return The LogEvent.
+ */
+ @Override
+ public LogEvent createEvent(final String loggerName, final Marker marker,
+ final String fqcn, final Level level, final Message data,
+ final List<Property> properties, final Throwable t) {
+ MutableLogEvent result = mutableLogEventThreadLocal.get();
+ if (result == null) {
+ result = new MutableLogEvent();
+ result.setThreadId(Thread.currentThread().getId());
+ result.setThreadName(Thread.currentThread().getName());
+ result.setThreadPriority(Thread.currentThread().getPriority());
+ mutableLogEventThreadLocal.set(result);
+ }
+
+ result.setLoggerName(loggerName);
+ result.setMarker(marker);
+ result.setLoggerFqcn(fqcn);
+ result.setLevel(level == null ? Level.OFF : level);
+ result.setMessage(data);
+ result.setThrown(t);
+ result.setContextMap(Log4jLogEvent.createMap(properties));
+ result.setContextStack(ThreadContext.getDepth() == 0 ? null : ThreadContext.cloneStack());// mutable copy
+ result.setTimeMillis(CLOCK.currentTimeMillis());
+ result.setNanoTime(Log4jLogEvent.getNanoClock().nanoTime());
+
+ // TODO
+// result.setEndOfBatch();
+// result.setIncludeLocation();
+// result.setSource();
+ //return new Log4jLogEvent(loggerName, marker, fqcn, level, data, properties, t);
+ return result;
+ }
+}
[2/6] logging-log4j2 git commit: LOG4J2-1274 TextEncoderHelper cleanup
Posted by mi...@apache.org.
LOG4J2-1274 TextEncoderHelper cleanup
Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/0a06f8f0
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/0a06f8f0
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/0a06f8f0
Branch: refs/heads/LOG4J2-1365
Commit: 0a06f8f0dea40cce08d987da3cc6e340835060d2
Parents: 23cd33f
Author: rpopma <rp...@apache.org>
Authored: Thu Apr 14 01:23:18 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Thu Apr 14 01:23:18 2016 +0900
----------------------------------------------------------------------
.../log4j/core/layout/TextEncoderHelper.java | 55 ++++++++------------
1 file changed, 21 insertions(+), 34 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0a06f8f0/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/TextEncoderHelper.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/TextEncoderHelper.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/TextEncoderHelper.java
index 136e2e6..09a49d8 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/TextEncoderHelper.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/TextEncoderHelper.java
@@ -22,9 +22,6 @@ import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
-import java.util.Objects;
-
-import org.apache.logging.log4j.status.StatusLogger;
/**
* Helper class to encode text to binary data without allocating temporary objects.
@@ -34,27 +31,34 @@ import org.apache.logging.log4j.status.StatusLogger;
public class TextEncoderHelper {
static final int DEFAULT_CHAR_BUFFER_SIZE = 2048;
- private final Charset charset;
-// private final CharBuffer cachedCharBuffer;
-// private final CharsetEncoder charsetEncoder;
-
- public TextEncoderHelper(final Charset charset) {
- this(charset, DEFAULT_CHAR_BUFFER_SIZE);
+ private TextEncoderHelper() {
}
- public TextEncoderHelper(final Charset charset, final int bufferSize) {
- this.charset = Objects.requireNonNull(charset, "charset");
- }
-
- private void logEncodeTextException(final Exception ex, final StringBuilder text,
- final ByteBufferDestination destination) {
- StatusLogger.getLogger().error("Recovering from TextEncoderHelper.encodeText('{}') error", text, ex);
+ static void encodeTextFallBack(final Charset charset, final StringBuilder text,
+ final ByteBufferDestination destination) {
+ final byte[] bytes = text.toString().getBytes(charset);
+ synchronized (destination) {
+ ByteBuffer buffer = destination.getByteBuffer();
+ int offset = 0;
+ do {
+ final int length = Math.min(bytes.length - offset, buffer.remaining());
+ buffer.put(bytes, offset, length);
+ offset += length;
+ if (offset < bytes.length) {
+ buffer = destination.drain(buffer);
+ }
+ } while (offset < bytes.length);
+ }
}
static void encodeTextWithCopy(final CharsetEncoder charsetEncoder, final CharBuffer charBuf, final ByteBuffer temp,
final StringBuilder text, final ByteBufferDestination destination) {
+
encodeText(charsetEncoder, charBuf, temp, text, destination);
+ copyDataToDestination(temp, destination);
+ }
+ private static void copyDataToDestination(final ByteBuffer temp, final ByteBufferDestination destination) {
synchronized (destination) {
ByteBuffer destinationBuffer = destination.getByteBuffer();
if (destinationBuffer != temp) { // still need to write to the destination
@@ -87,28 +91,11 @@ public class TextEncoderHelper {
} while (!endOfInput);
}
- static void encodeTextFallBack(final Charset charset, final StringBuilder text,
- final ByteBufferDestination destination) {
- final byte[] bytes = text.toString().getBytes(charset);
- synchronized (destination) {
- ByteBuffer buffer = destination.getByteBuffer();
- int offset = 0;
- do {
- final int length = Math.min(bytes.length - offset, buffer.remaining());
- buffer.put(bytes, offset, length);
- offset += length;
- if (offset < bytes.length) {
- buffer = destination.drain(buffer);
- }
- } while (offset < bytes.length);
- }
- }
-
/**
* For testing purposes only.
*/
@Deprecated
- public void encodeText(final CharsetEncoder charsetEncoder, final CharBuffer charBuf,
+ public static void encodeText(final CharsetEncoder charsetEncoder, final CharBuffer charBuf,
final ByteBufferDestination destination) {
synchronized (destination) {
charsetEncoder.reset();
[5/6] logging-log4j2 git commit: LOG4J2-1297 moved GelfLayout to
before PatternLayout in doc
Posted by mi...@apache.org.
LOG4J2-1297 moved GelfLayout to before PatternLayout in doc
Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/c3463a81
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/c3463a81
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/c3463a81
Branch: refs/heads/LOG4J2-1365
Commit: c3463a810539ffeace7db1c24e0be45f075ae47c
Parents: 89808ec
Author: rpopma <rp...@apache.org>
Authored: Thu Apr 14 02:03:45 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Thu Apr 14 02:03:45 2016 +0900
----------------------------------------------------------------------
src/site/xdoc/manual/garbagefree.xml | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/c3463a81/src/site/xdoc/manual/garbagefree.xml
----------------------------------------------------------------------
diff --git a/src/site/xdoc/manual/garbagefree.xml b/src/site/xdoc/manual/garbagefree.xml
index 60471f5..c1f3a7d 100644
--- a/src/site/xdoc/manual/garbagefree.xml
+++ b/src/site/xdoc/manual/garbagefree.xml
@@ -150,6 +150,9 @@
<em>Note:</em>Logging Exceptions and stack traces will create temporary objects with any layout.
</p>
+ <h5>GelfLayout</h5>
+ <p>GelfLayout is garbage-free when used with compressionType="OFF".</p>
+
<h5>PatternLayout</h5>
<p>
PatternLayout with the following limited set of conversion patterns is garbage-free.
@@ -282,9 +285,6 @@
</td></tr></table>
- <h5>GelfLayout</h5>
- <p>GelfLayout is garbage-free when used with compressionType="OFF".</p>
-
</subsubsection>
<a name="api" />
<subsubsection name="API Changes">