This is an automated email from the ASF dual-hosted git repository.
vy pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
The following commit(s) were added to refs/heads/master by this push:
new 791bf1e LOG4J2-3393 Improve JsonTemplateLayout performance. (#797)
791bf1e is described below
commit 791bf1e81e49c867b6f4119d03c372e4f1b51638
Author: Volkan Yazıcı <[email protected]>
AuthorDate: Mon Mar 21 10:48:41 2022 +0100
LOG4J2-3393 Improve JsonTemplateLayout performance. (#797)
* Replace hardcoded `8 * 1024` private value used for `byteBufferSize`
in `StringBuilderEncoder()` ctor with
`Constants.ENCODER_BYTE_BUFFER_SIZE`.
* Replace `StringBuilderEncoder` (uses an internal thread-local) and
`LockingStringBuilderEncoder` (uses locks) with custom
`JsonTemplateLayout.StringBuilderEncoder` class implementing
`Encoder<StringBuilder>` interface. This was made possible by making
`TextEncoderHelper.encodeText()` public. This makes use of JTL
recyclers and provides better allocation performance. For instance,
if JTL is configured with thread-local recycler, each encoding
request will trigger a single TLA, whereas previously it needed to
do two: one for `JsonTemplateLayout.Context` and
`StringBuilderEncoder`.
* Add `CharSequence` specialization in `MessageResolver`.
* Improve troubleshooting experience by replacing lambdas with classes
in `TemplateResolvers`.
* Improve locality and branching in `TemplateResolvers`.
* Improve JMH tests.
* Thanks so much to Carter Kozak for being the awesome sparring
partner.
---
.github/workflows/benchmark.yml | 4 +-
.../log4j/core/layout/StringBuilderEncoder.java | 9 +-
.../log4j/core/layout/TextEncoderHelper.java | 6 +-
.../layout/template/json/JsonTemplateLayout.java | 109 +++---
.../template/json/resolver/MessageResolver.java | 8 +-
.../template/json/resolver/PatternResolver.java | 2 +-
.../template/json/resolver/TemplateResolvers.java | 390 +++++++++++++++------
.../layout/template/json/util/JsonWriter.java | 28 +-
.../json/BlackHoleByteBufferDestination.java | 12 +-
.../layout/template/json/util/JsonWriterTest.java | 2 +-
log4j-perf/pom.xml | 4 +-
.../template/json/JsonTemplateLayoutBenchmark.java | 110 +++---
.../json/JsonTemplateLayoutBenchmarkState.java | 64 ++--
13 files changed, 493 insertions(+), 255 deletions(-)
diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml
index 6f9de13..58eacb8 100644
--- a/.github/workflows/benchmark.yml
+++ b/.github/workflows/benchmark.yml
@@ -67,8 +67,8 @@ jobs:
jdk: [ 11, 17 ]
concurrency: [ 1, 8 ]
jmhCommand:
- - "-t $CONCURRENCY -f 3 -wi 3 -w 10s -i 4 -r 20s -prof gc -rf json
-rff results-layout-jtl.json '.*JsonTemplateLayoutBenchmark.*'"
- - "-t $CONCURRENCY -f 3 -wi 3 -w 10s -i 4 -r 20s -prof gc -rf json
-rff results-util-instant-format.json '.*InstantFormatBenchmark.*'"
+ - "-t $CONCURRENCY -f 3 -wi 3 -w 10s -i 4 -r 20s -prof gc -prof
perfnorm -rf json -rff results-layout-jtl.json
'.*JsonTemplateLayoutBenchmark.*Jtl4EcsLayout'"
+ - "-t $CONCURRENCY -f 3 -wi 3 -w 10s -i 4 -r 20s -prof gc -prof
perfnorm -rf json -rff results-util-instant-format.json
'.*InstantFormatBenchmark.*'"
steps:
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
index fb02393..9af3316 100644
---
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
@@ -31,7 +31,6 @@ import org.apache.logging.log4j.status.StatusLogger;
*/
public class StringBuilderEncoder implements Encoder<StringBuilder> {
- private static final int DEFAULT_BYTE_BUFFER_SIZE = 8 * 1024;
/**
* This ThreadLocal uses raw and inconvenient Object[] to store three
heterogeneous objects (CharEncoder, CharBuffer
* and ByteBuffer) instead of a custom class, because it needs to contain
JDK classes, no custom (Log4j) classes.
@@ -49,7 +48,7 @@ public class StringBuilderEncoder implements
Encoder<StringBuilder> {
private final int byteBufferSize;
public StringBuilderEncoder(final Charset charset) {
- this(charset, Constants.ENCODER_CHAR_BUFFER_SIZE,
DEFAULT_BYTE_BUFFER_SIZE);
+ this(charset, Constants.ENCODER_CHAR_BUFFER_SIZE,
Constants.ENCODER_BYTE_BUFFER_SIZE);
}
public StringBuilderEncoder(final Charset charset, final int
charBufferSize, final int byteBufferSize) {
@@ -67,7 +66,7 @@ public class StringBuilderEncoder implements
Encoder<StringBuilder> {
final ByteBuffer byteBuffer = (ByteBuffer) threadLocalState[2];
TextEncoderHelper.encodeText(charsetEncoder, charBuffer,
byteBuffer, source, destination);
} catch (final Exception ex) {
- logEncodeTextException(ex, source, destination);
+ logEncodeTextException(ex, source);
TextEncoderHelper.encodeTextFallBack(charset, source, destination);
}
}
@@ -90,8 +89,8 @@ public class StringBuilderEncoder implements
Encoder<StringBuilder> {
return threadLocalState;
}
- private void logEncodeTextException(final Exception ex, final
StringBuilder text,
- final ByteBufferDestination destination) {
+ private static void logEncodeTextException(final Exception ex, final
StringBuilder text) {
StatusLogger.getLogger().error("Recovering from
StringBuilderEncoder.encode('{}') error: {}", text, ex, ex);
}
+
}
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 327386f..4191f57 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
@@ -48,11 +48,9 @@ public class TextEncoderHelper {
* @param byteBuf thread-local buffer to temporarily hold converted bytes
before copying them to the destination
* @param text the text to convert and write to the destination
* @param destination the destination to write the bytes to
- * @throws CharacterCodingException if conversion failed
*/
- static void encodeText(final CharsetEncoder charsetEncoder, final
CharBuffer charBuf, final ByteBuffer byteBuf,
- final StringBuilder text, final ByteBufferDestination destination)
- throws CharacterCodingException {
+ public static void encodeText(final CharsetEncoder charsetEncoder, final
CharBuffer charBuf, final ByteBuffer byteBuf,
+ final StringBuilder text, final ByteBufferDestination destination)
{
charsetEncoder.reset();
if (text.length() > charBuf.capacity()) {
encodeChunkedText(charsetEncoder, charBuf, byteBuf, text,
destination);
diff --git
a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayout.java
b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayout.java
index dc0c94e..d3792fd 100644
---
a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayout.java
+++
b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayout.java
@@ -24,18 +24,10 @@ import
org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
import org.apache.logging.log4j.core.layout.ByteBufferDestination;
import org.apache.logging.log4j.core.layout.Encoder;
-import org.apache.logging.log4j.core.layout.LockingStringBuilderEncoder;
-import org.apache.logging.log4j.core.layout.StringBuilderEncoder;
+import org.apache.logging.log4j.core.layout.TextEncoderHelper;
import org.apache.logging.log4j.core.util.Constants;
import org.apache.logging.log4j.core.util.StringEncoder;
-import
org.apache.logging.log4j.layout.template.json.resolver.EventResolverContext;
-import
org.apache.logging.log4j.layout.template.json.resolver.EventResolverFactories;
-import
org.apache.logging.log4j.layout.template.json.resolver.EventResolverFactory;
-import
org.apache.logging.log4j.layout.template.json.resolver.EventResolverInterceptor;
-import
org.apache.logging.log4j.layout.template.json.resolver.EventResolverInterceptors;
-import
org.apache.logging.log4j.layout.template.json.resolver.EventResolverStringSubstitutor;
-import org.apache.logging.log4j.layout.template.json.resolver.TemplateResolver;
-import
org.apache.logging.log4j.layout.template.json.resolver.TemplateResolvers;
+import org.apache.logging.log4j.layout.template.json.resolver.*;
import org.apache.logging.log4j.layout.template.json.util.JsonWriter;
import org.apache.logging.log4j.layout.template.json.util.Recycler;
import org.apache.logging.log4j.layout.template.json.util.RecyclerFactory;
@@ -44,9 +36,14 @@ import org.apache.logging.log4j.plugins.Node;
import org.apache.logging.log4j.plugins.Plugin;
import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
import org.apache.logging.log4j.plugins.PluginElement;
+import org.apache.logging.log4j.status.StatusLogger;
import org.apache.logging.log4j.util.Strings;
+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.Collections;
import java.util.List;
import java.util.Map;
@@ -71,8 +68,7 @@ public class JsonTemplateLayout implements StringLayout {
private final Recycler<Context> contextRecycler;
- // The class and fields are visible for tests.
- static final class Context implements AutoCloseable {
+ private static final class Context implements AutoCloseable {
final JsonWriter jsonWriter;
@@ -204,19 +200,57 @@ public class JsonTemplateLayout implements StringLayout {
final JsonWriter jsonWriter) {
return () -> {
final JsonWriter clonedJsonWriter = jsonWriter.clone();
- final Encoder<StringBuilder> encoder =
createStringBuilderEncoder(charset);
+ final Encoder<StringBuilder> encoder = new
StringBuilderEncoder(charset);
return new Context(clonedJsonWriter, encoder);
};
}
- private static Encoder<StringBuilder> createStringBuilderEncoder(
- final Charset charset) {
- if (Constants.ENABLE_DIRECT_ENCODERS) {
- return Constants.ENABLE_THREADLOCALS
- ? new StringBuilderEncoder(charset)
- : new LockingStringBuilderEncoder(charset);
+ /**
+ * {@link org.apache.logging.log4j.core.layout.StringBuilderEncoder} clone
replacing thread-local allocations with instance fields.
+ */
+ private static final class StringBuilderEncoder implements
Encoder<StringBuilder> {
+
+ private final Charset charset;
+
+ private final CharsetEncoder charsetEncoder;
+
+ private final CharBuffer charBuffer;
+
+ private final ByteBuffer byteBuffer;
+
+ private StringBuilderEncoder(final Charset charset) {
+ this.charset = charset;
+ this.charsetEncoder = charset
+ .newEncoder()
+ .onMalformedInput(CodingErrorAction.REPLACE)
+ .onUnmappableCharacter(CodingErrorAction.REPLACE);
+ this.charBuffer =
CharBuffer.allocate(Constants.ENCODER_CHAR_BUFFER_SIZE);
+ this.byteBuffer =
ByteBuffer.allocate(Constants.ENCODER_BYTE_BUFFER_SIZE);
}
- return null;
+
+ @Override
+ public void encode(
+ final StringBuilder source,
+ final ByteBufferDestination destination) {
+ try {
+ TextEncoderHelper.encodeText(charsetEncoder, charBuffer,
byteBuffer, source, destination);
+ } catch (final Exception error) {
+ fallbackEncode(charset, source, destination, error);
+ }
+ }
+
+ private /* for JIT-ergonomics: */ static void fallbackEncode(
+ final Charset charset,
+ final StringBuilder source,
+ final ByteBufferDestination destination,
+ final Exception error) {
+ StatusLogger
+ .getLogger()
+ .error("TextEncoderHelper.encodeText() failure", error);
+ final byte[] bytes = source.toString().getBytes(charset);
+ destination.writeBytes(bytes, 0, bytes.length);
+ }
+
}
@Override
@@ -227,42 +261,42 @@ public class JsonTemplateLayout implements StringLayout {
@Override
public String toSerializable(final LogEvent event) {
- final Context context = acquireContext();
+
+ // Acquire a context.
+ final Recycler<Context> contextRecycler = this.contextRecycler;
+ final Context context = contextRecycler.acquire();
final JsonWriter jsonWriter = context.jsonWriter;
final StringBuilder stringBuilder = jsonWriter.getStringBuilder();
+
+ // Render the JSON.
try {
eventResolver.resolve(event, jsonWriter);
stringBuilder.append(eventDelimiter);
return stringBuilder.toString();
- } finally {
+ }
+
+ // Release the context.
+ finally {
contextRecycler.release(context);
}
+
}
@Override
public void encode(final LogEvent event, final ByteBufferDestination
destination) {
// Acquire a context.
- final Context context = acquireContext();
+ final Recycler<Context> contextRecycler = this.contextRecycler;
+ final Context context = contextRecycler.acquire();
final JsonWriter jsonWriter = context.jsonWriter;
final StringBuilder stringBuilder = jsonWriter.getStringBuilder();
final Encoder<StringBuilder> encoder = context.encoder;
+ // Render & write the JSON.
try {
-
- // Render the JSON.
eventResolver.resolve(event, jsonWriter);
stringBuilder.append(eventDelimiter);
-
- // Write to the destination.
- if (encoder == null) {
- final String eventJson = stringBuilder.toString();
- final byte[] eventJsonBytes = StringEncoder.toBytes(eventJson,
charset);
- destination.writeBytes(eventJsonBytes, 0,
eventJsonBytes.length);
- } else {
- encoder.encode(stringBuilder, destination);
- }
-
+ encoder.encode(stringBuilder, destination);
}
// Release the context.
@@ -272,11 +306,6 @@ public class JsonTemplateLayout implements StringLayout {
}
- // Visible for tests.
- Context acquireContext() {
- return contextRecycler.acquire();
- }
-
@Override
public byte[] getFooter() {
return null;
diff --git
a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/MessageResolver.java
b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/MessageResolver.java
index 2975e66..59afef0 100644
---
a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/MessageResolver.java
+++
b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/MessageResolver.java
@@ -134,10 +134,10 @@ public final class MessageResolver implements
EventResolver {
jsonWriter.writeObjectStart();
jsonWriter.writeObjectKey(fallbackKey);
}
- if (message instanceof StringBuilderFormattable) {
- final StringBuilderFormattable formattable =
- (StringBuilderFormattable) message;
- jsonWriter.writeString(formattable);
+ if (message instanceof CharSequence) {
+ jsonWriter.writeString((CharSequence) message);
+ } else if (message instanceof StringBuilderFormattable) {
+ jsonWriter.writeString((StringBuilderFormattable) message);
} else {
final String formattedMessage = message.getFormattedMessage();
jsonWriter.writeString(formattedMessage);
diff --git
a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/PatternResolver.java
b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/PatternResolver.java
index 5eddb0f..83f87d1 100644
---
a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/PatternResolver.java
+++
b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/PatternResolver.java
@@ -20,10 +20,10 @@ import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.layout.PatternLayout;
import org.apache.logging.log4j.layout.template.json.JsonTemplateLayout;
import org.apache.logging.log4j.layout.template.json.util.JsonWriter;
-import org.apache.logging.log4j.util.BiConsumer;
import org.apache.logging.log4j.util.Strings;
import java.util.Optional;
+import java.util.function.BiConsumer;
/**
* Resolver delegating to {@link PatternLayout}.
diff --git
a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/TemplateResolvers.java
b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/TemplateResolvers.java
index 7390091..71a9c4d 100644
---
a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/TemplateResolvers.java
+++
b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/TemplateResolvers.java
@@ -24,6 +24,7 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
+import java.util.stream.IntStream;
/**
* Main class for compiling {@link TemplateResolver}s from a template.
@@ -50,30 +51,44 @@ public final class TemplateResolvers {
}
private static final TemplateResolver<?> EMPTY_ARRAY_RESOLVER =
- new UnresolvableTemplateResolver() {
- @Override
- public void resolve(final Object value, final JsonWriter
jsonWriter) {
- jsonWriter.writeArrayStart();
- jsonWriter.writeArrayEnd();
- }
- };
+ new EmptyArrayResolver();
+
+ private static final class EmptyArrayResolver
+ extends UnresolvableTemplateResolver {
+
+ @Override
+ public void resolve(final Object value, final JsonWriter jsonWriter) {
+ jsonWriter.writeArrayStart();
+ jsonWriter.writeArrayEnd();
+ }
+
+ }
private static final TemplateResolver<?> EMPTY_OBJECT_RESOLVER =
- new UnresolvableTemplateResolver() {
- @Override
- public void resolve(final Object value, final JsonWriter
jsonWriter) {
- jsonWriter.writeObjectStart();
- jsonWriter.writeObjectEnd();
- }
- };
+ new EmptyObjectResolver();
- private static final TemplateResolver<?> NULL_RESOLVER =
- new UnresolvableTemplateResolver() {
- @Override
- public void resolve(final Object value, final JsonWriter
jsonWriter) {
- jsonWriter.writeNull();
- }
- };
+ private static final class EmptyObjectResolver
+ extends UnresolvableTemplateResolver {
+
+ @Override
+ public void resolve(final Object value, final JsonWriter jsonWriter) {
+ jsonWriter.writeObjectStart();
+ jsonWriter.writeObjectEnd();
+ }
+
+ }
+
+ private static final TemplateResolver<?> NULL_RESOLVER = new
NullResolver();
+
+ private static final class NullResolver
+ extends UnresolvableTemplateResolver {
+
+ @Override
+ public void resolve(final Object value, final JsonWriter jsonWriter) {
+ jsonWriter.writeNull();
+ }
+
+ }
public static <V, C extends TemplateResolverContext<V, C>>
TemplateResolver<V> ofTemplate(
final C context,
@@ -145,7 +160,7 @@ public final class TemplateResolvers {
final C context,
final List<Object> list) {
- // Create resolver for each children.
+ // Create resolver for each child.
final List<TemplateResolver<V>> itemResolvers = list
.stream()
.map(item -> {
@@ -167,7 +182,20 @@ public final class TemplateResolvers {
}
// Create a parent resolver collecting each child resolver execution.
- return (final V value, final JsonWriter jsonWriter) -> {
+ return new ArrayResolver<>(itemResolvers);
+
+ }
+
+ private static final class ArrayResolver<V> implements TemplateResolver<V>
{
+
+ private final List<TemplateResolver<V>> itemResolvers;
+
+ private ArrayResolver(final List<TemplateResolver<V>> itemResolvers) {
+ this.itemResolvers = itemResolvers;
+ }
+
+ @Override
+ public void resolve(final V value, final JsonWriter jsonWriter) {
jsonWriter.writeArrayStart();
for (int itemResolverIndex = 0;
itemResolverIndex < itemResolvers.size();
@@ -175,11 +203,12 @@ public final class TemplateResolvers {
if (itemResolverIndex > 0) {
jsonWriter.writeSeparator();
}
- final TemplateResolver<V> itemResolver =
itemResolvers.get(itemResolverIndex);
+ final TemplateResolver<V> itemResolver =
+ itemResolvers.get(itemResolverIndex);
itemResolver.resolve(value, jsonWriter);
}
jsonWriter.writeArrayEnd();
- };
+ }
}
@@ -192,6 +221,28 @@ public final class TemplateResolvers {
return ofResolver(context, map);
}
+ // Collect field resolver contexts.
+ List<FieldResolverContext<V>> fieldResolverContexts =
+ populateFieldResolverMethods(context, map);
+
+ // Short-circuit if the object is empty.
+ final int fieldCount = fieldResolverContexts.size();
+ if (fieldCount == 0) {
+ @SuppressWarnings("unchecked")
+ final TemplateResolver<V> emptyObjectResolver =
+ (TemplateResolver<V>) EMPTY_OBJECT_RESOLVER;
+ return emptyObjectResolver;
+ }
+
+ // Create the resolver.
+ return new MapResolver<>(fieldResolverContexts);
+
+ }
+
+ private static <V, C extends TemplateResolverContext<V, C>>
List<FieldResolverContext<V>> populateFieldResolverMethods(
+ final C context,
+ final Map<String, Object> map) {
+
// Create resolver for each object field.
final List<String> fieldNames = new ArrayList<>();
final List<TemplateResolver<V>> fieldResolvers = new ArrayList<>();
@@ -204,15 +255,6 @@ public final class TemplateResolvers {
}
});
- // Short-circuit if the object is empty.
- final int fieldCount = fieldNames.size();
- if (fieldCount == 0) {
- @SuppressWarnings("unchecked")
- final TemplateResolver<V> emptyObjectResolver =
- (TemplateResolver<V>) EMPTY_OBJECT_RESOLVER;
- return emptyObjectResolver;
- }
-
// Prepare field names to avoid escape and truncation costs at runtime.
final List<String> fieldPrefixes = fieldNames
.stream()
@@ -225,70 +267,152 @@ public final class TemplateResolvers {
})
.collect(Collectors.toList());
- return new TemplateResolver<V>() {
-
- @Override
- public boolean isResolvable() {
- // We have already excluded unresolvable ones while collecting
- // the resolvers. Hence it is safe to return true here.
- return true;
- }
-
- /**
- * The parent resolver checking if each child is resolvable given
- * the passed {@code value}.
- *
- * This is an optimization to skip the rendering of a parent if all
- * its children are not resolvable given the passed {@code value}.
- */
- @Override
- public boolean isResolvable(final V value) {
- for (int fieldIndex = 0; fieldIndex < fieldCount;
fieldIndex++) {
- final TemplateResolver<V> fieldResolver =
fieldResolvers.get(fieldIndex);
- final boolean resolvable =
fieldResolver.isResolvable(value);
- if (resolvable) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * The parent resolver combining all child resolver executions.
- */
- @Override
- public void resolve(final V value, final JsonWriter jsonWriter) {
- final StringBuilder jsonWriterStringBuilder =
jsonWriter.getStringBuilder();
- jsonWriter.writeObjectStart();
- for (int resolvedFieldCount = 0, fieldIndex = 0; fieldIndex <
fieldCount; fieldIndex++) {
+ // Collect field resolver contexts.
+ final int fieldCount = fieldNames.size();
+ return IntStream
+ .range(0, fieldCount)
+ .mapToObj(fieldIndex -> {
final TemplateResolver<V> fieldResolver =
fieldResolvers.get(fieldIndex);
- final boolean resolvable =
fieldResolver.isResolvable(value);
- if (!resolvable) {
- continue;
- }
- final boolean succeedingEntry = resolvedFieldCount > 0;
+ final FieldResolverMethod<V> fieldResolverMethod;
final boolean flattening = fieldResolver.isFlattening();
if (flattening) {
- final int initLength =
jsonWriterStringBuilder.length();
- fieldResolver.resolve(value, jsonWriter,
succeedingEntry);
- final boolean resolved =
jsonWriterStringBuilder.length() > initLength;
- if (resolved) {
- resolvedFieldCount++;
- }
+ fieldResolverMethod = new
FlatteningFieldResolverMethod<>(fieldResolver);
} else {
- if (succeedingEntry) {
- jsonWriter.writeSeparator();
- }
final String fieldPrefix =
fieldPrefixes.get(fieldIndex);
- jsonWriter.writeRawString(fieldPrefix);
- fieldResolver.resolve(value, jsonWriter,
succeedingEntry);
- resolvedFieldCount++;
+ fieldResolverMethod = new
PrefixedFieldResolverMethod<>(fieldPrefix, fieldResolver);
}
+ return new FieldResolverContext<>(fieldResolver,
fieldResolverMethod);
+ })
+ .collect(Collectors.toList());
+
+ }
+
+ private static final class FieldResolverContext<V> {
+
+ private final TemplateResolver<V> resolver;
+
+ private final FieldResolverMethod<V> resolverMethod;
+
+ private FieldResolverContext(final TemplateResolver<V> resolver, final
FieldResolverMethod<V> resolverMethod) {
+ this.resolver = resolver;
+ this.resolverMethod = resolverMethod;
+ }
+
+ }
+
+ @FunctionalInterface
+ private interface FieldResolverMethod<V> {
+
+ boolean resolve(V value, JsonWriter jsonWriter, boolean
succeedingEntry);
+
+ }
+
+ private static final class FlatteningFieldResolverMethod<V> implements
FieldResolverMethod<V> {
+
+ private final TemplateResolver<V> fieldResolver;
+
+ private FlatteningFieldResolverMethod(final TemplateResolver<V>
fieldResolver) {
+ this.fieldResolver = fieldResolver;
+ }
+
+ @Override
+ public boolean resolve(final V value, final JsonWriter jsonWriter,
final boolean succeedingEntry) {
+ final boolean resolvable = fieldResolver.isResolvable(value);
+ if (!resolvable) {
+ return false;
+ }
+ final StringBuilder jsonWriterStringBuilder =
jsonWriter.getStringBuilder();
+ final int initLength = jsonWriterStringBuilder.length();
+ fieldResolver.resolve(value, jsonWriter, succeedingEntry);
+ return jsonWriterStringBuilder.length() > initLength;
+ }
+
+ }
+
+ private static final class PrefixedFieldResolverMethod<V> implements
FieldResolverMethod<V> {
+
+ private final String fieldPrefix;
+
+ private final TemplateResolver<V> fieldResolver;
+
+ private PrefixedFieldResolverMethod(final String fieldPrefix, final
TemplateResolver<V> fieldResolver) {
+ this.fieldPrefix = fieldPrefix;
+ this.fieldResolver = fieldResolver;
+ }
+
+ @Override
+ public boolean resolve(final V value, final JsonWriter jsonWriter,
final boolean succeedingEntry) {
+ final boolean resolvable = fieldResolver.isResolvable(value);
+ if (!resolvable) {
+ return false;
+ }
+ if (succeedingEntry) {
+ jsonWriter.writeSeparator();
+ }
+ jsonWriter.writeRawString(fieldPrefix);
+ fieldResolver.resolve(value, jsonWriter, succeedingEntry);
+ return true;
+ }
+
+ }
+
+ private static final class MapResolver<V> implements TemplateResolver<V> {
+
+ private final List<FieldResolverContext<V>> fieldResolverContexts;
+
+ private MapResolver(final List<FieldResolverContext<V>>
fieldResolverContexts) {
+ this.fieldResolverContexts = fieldResolverContexts;
+ }
+
+ @Override
+ public boolean isResolvable() {
+ // We have already excluded unresolvable ones while collecting
+ // the resolvers; it is safe to return true here.
+ return true;
+ }
+
+ /**
+ * The parent resolver checking if each child is resolvable given
+ * the passed {@code value}.
+ *
+ * This is an optimization to skip the rendering of a parent if all
+ * its children are not resolvable for the given {@code value}.
+ */
+ @Override
+ public boolean isResolvable(final V value) {
+ int fieldCount = fieldResolverContexts.size();
+ // noinspection ForLoopReplaceableByForEach (avoid iterator
instantiation)
+ for (int fieldIndex = 0; fieldIndex < fieldCount; fieldIndex++) {
+ final TemplateResolver<V> fieldResolver =
fieldResolverContexts.get(fieldIndex).resolver;
+ final boolean resolvable = fieldResolver.isResolvable(value);
+ if (resolvable) {
+ return true;
}
- jsonWriter.writeObjectEnd();
}
+ return false;
+ }
- };
+ /**
+ * The parent resolver combining all child resolver executions.
+ */
+ @Override
+ public void resolve(final V value, final JsonWriter jsonWriter) {
+ jsonWriter.writeObjectStart();
+ int fieldCount = fieldResolverContexts.size();
+ for (int resolvedFieldCount = 0, fieldIndex = 0; fieldIndex <
fieldCount; fieldIndex++) {
+ FieldResolverContext<V> fieldResolverContext =
fieldResolverContexts.get(fieldIndex);
+ final boolean resolvable =
fieldResolverContext.resolver.isResolvable(value);
+ if (!resolvable) {
+ continue;
+ }
+ final boolean succeedingEntry = resolvedFieldCount > 0;
+ final boolean resolved =
fieldResolverContext.resolverMethod.resolve(value, jsonWriter, succeedingEntry);
+ if (resolved) {
+ resolvedFieldCount++;
+ }
+ }
+ jsonWriter.writeObjectEnd();
+ }
}
@@ -344,18 +468,14 @@ public final class TemplateResolvers {
contextJsonWriter.use(() ->
contextJsonWriter.writeString(replacedText));
// Create a resolver dedicated to the escaped replacement.
- return (final V value, final JsonWriter jsonWriter) ->
- jsonWriter.writeRawString(escapedReplacedText);
+ return new RawStringResolver<>(escapedReplacedText);
}
}
// Otherwise, the unstable substitutor needs to be invoked always
at
// runtime.
else {
- return (final V value, final JsonWriter jsonWriter) -> {
- final String replacedText = substitutor.replace(value,
fieldValue);
- jsonWriter.writeString(replacedText);
- };
+ return new SubstitutingStringResolver<>(substitutor,
fieldValue);
}
}
@@ -365,21 +485,87 @@ public final class TemplateResolvers {
final String escapedFieldValue =
contextJsonWriter.use(() ->
contextJsonWriter.writeString(fieldValue));
- return (final V value, final JsonWriter jsonWriter) ->
- jsonWriter.writeRawString(escapedFieldValue);
+ return new RawStringResolver<>(escapedFieldValue);
+ }
+
+ }
+
+ private static final class SubstitutingStringResolver<V>
+ implements TemplateResolver<V> {
+
+ private final TemplateResolverStringSubstitutor<V> substitutor;
+
+ private final String string;
+
+ private SubstitutingStringResolver(
+ final TemplateResolverStringSubstitutor<V> substitutor,
+ final String string) {
+ this.substitutor = substitutor;
+ this.string = string;
+ }
+
+ @Override
+ public void resolve(final V value, final JsonWriter jsonWriter) {
+ final String replacedString = substitutor.replace(value, string);
+ jsonWriter.writeString(replacedString);
+ }
+
+ }
+
+ private static final class RawStringResolver<V>
+ implements TemplateResolver<V> {
+
+ private final String rawString;
+
+ private RawStringResolver(final String rawString) {
+ this.rawString = rawString;
+ }
+
+ @Override
+ public void resolve(final V ignored, final JsonWriter jsonWriter) {
+ jsonWriter.writeRawString(rawString);
}
}
private static <V> TemplateResolver<V> ofNumber(final Number number) {
- final String numberString = String.valueOf(number);
- return (final V ignored, final JsonWriter jsonWriter) ->
- jsonWriter.writeRawString(numberString);
+ return new NumberResolver<>(number);
+ }
+
+ private static final class NumberResolver<V>
+ implements TemplateResolver<V> {
+
+ private final String numberString;
+
+ private NumberResolver(final Number number) {
+ this.numberString = String.valueOf(number);
+ }
+
+ @Override
+ public void resolve(final V ignored, final JsonWriter jsonWriter) {
+ jsonWriter.writeRawString(numberString);
+ }
+
}
private static <V> TemplateResolver<V> ofBoolean(final boolean value) {
- return (final V ignored, final JsonWriter jsonWriter) ->
- jsonWriter.writeBoolean(value);
+ return new BooleanResolver<>(value);
+ }
+
+ private static final class BooleanResolver<V>
+ implements TemplateResolver<V> {
+
+ private final boolean value;
+
+ private BooleanResolver(final boolean value) {
+ this.value = value;
+ }
+
+ @Override
+ public void resolve(final V ignored, final JsonWriter jsonWriter) {
+ jsonWriter.writeBoolean(value);
+ }
+
}
}
diff --git
a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/JsonWriter.java
b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/JsonWriter.java
index 8fe9acf..82d0a7e 100644
---
a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/JsonWriter.java
+++
b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/JsonWriter.java
@@ -16,7 +16,6 @@
*/
package org.apache.logging.log4j.layout.template.json.util;
-import org.apache.logging.log4j.util.BiConsumer;
import org.apache.logging.log4j.util.IndexedReadOnlyStringMap;
import org.apache.logging.log4j.util.StringBuilderFormattable;
import org.apache.logging.log4j.util.StringMap;
@@ -27,6 +26,7 @@ import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.function.BiConsumer;
/**
* A simple JSON writer with support for common Java data types.
@@ -234,22 +234,24 @@ public final class JsonWriter implements AutoCloseable,
Cloneable {
} else {
writeObjectStart();
final boolean[] firstEntry = {true};
- map.forEach((final String key, final Object value) -> {
- if (key == null) {
- throw new IllegalArgumentException("null keys are not
allowed");
- }
- if (firstEntry[0]) {
- firstEntry[0] = false;
- } else {
- writeSeparator();
- }
- writeObjectKey(key);
- writeValue(value);
- });
+ map.forEach(this::writeStringMap, firstEntry);
writeObjectEnd();
}
}
+ private void writeStringMap(final String key, final Object value, final
boolean[] firstEntry) {
+ if (key == null) {
+ throw new IllegalArgumentException("null keys are not allowed");
+ }
+ if (firstEntry[0]) {
+ firstEntry[0] = false;
+ } else {
+ writeSeparator();
+ }
+ writeObjectKey(key);
+ writeValue(value);
+ }
+
public void writeObject(final IndexedReadOnlyStringMap map) {
if (map == null) {
writeNull();
diff --git
a/log4j-layout-template-json/src/test/java/org/apache/logging/log4j/layout/template/json/BlackHoleByteBufferDestination.java
b/log4j-layout-template-json/src/test/java/org/apache/logging/log4j/layout/template/json/BlackHoleByteBufferDestination.java
index 3c0f4fb..0fab5ab 100644
---
a/log4j-layout-template-json/src/test/java/org/apache/logging/log4j/layout/template/json/BlackHoleByteBufferDestination.java
+++
b/log4j-layout-template-json/src/test/java/org/apache/logging/log4j/layout/template/json/BlackHoleByteBufferDestination.java
@@ -17,6 +17,7 @@
package org.apache.logging.log4j.layout.template.json;
import org.apache.logging.log4j.core.layout.ByteBufferDestination;
+import org.apache.logging.log4j.core.layout.ByteBufferDestinationHelper;
import java.nio.ByteBuffer;
@@ -35,16 +36,23 @@ class BlackHoleByteBufferDestination implements
ByteBufferDestination {
@Override
public ByteBuffer drain(final ByteBuffer byteBuffer) {
+ byteBuffer.flip();
+ if (this.byteBuffer != byteBuffer) {
+ this.byteBuffer.clear();
+ this.byteBuffer.put(byteBuffer);
+ }
byteBuffer.clear();
return byteBuffer;
}
@Override
public void writeBytes(final ByteBuffer byteBuffer) {
- byteBuffer.clear();
+ ByteBufferDestinationHelper.writeToUnsynchronized(byteBuffer, this);
}
@Override
- public void writeBytes(final byte[] buffer, final int offset, final int
length) {}
+ public void writeBytes(final byte[] buffer, final int offset, final int
length) {
+ ByteBufferDestinationHelper.writeToUnsynchronized(buffer, offset,
length, this);
+ }
}
diff --git
a/log4j-layout-template-json/src/test/java/org/apache/logging/log4j/layout/template/json/util/JsonWriterTest.java
b/log4j-layout-template-json/src/test/java/org/apache/logging/log4j/layout/template/json/util/JsonWriterTest.java
index c519f75..5ce6e1f 100644
---
a/log4j-layout-template-json/src/test/java/org/apache/logging/log4j/layout/template/json/util/JsonWriterTest.java
+++
b/log4j-layout-template-json/src/test/java/org/apache/logging/log4j/layout/template/json/util/JsonWriterTest.java
@@ -18,7 +18,6 @@ package org.apache.logging.log4j.layout.template.json.util;
import org.apache.logging.log4j.core.impl.JdkMapAdapterStringMap;
import org.apache.logging.log4j.layout.template.json.JacksonFixture;
-import org.apache.logging.log4j.util.BiConsumer;
import org.apache.logging.log4j.util.IndexedReadOnlyStringMap;
import org.apache.logging.log4j.util.SortedArrayStringMap;
import org.apache.logging.log4j.util.StringBuilderFormattable;
@@ -39,6 +38,7 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
+import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
diff --git a/log4j-perf/pom.xml b/log4j-perf/pom.xml
index 2cd8304..6263e7f 100644
--- a/log4j-perf/pom.xml
+++ b/log4j-perf/pom.xml
@@ -33,7 +33,7 @@
<log4jParentDir>${basedir}/..</log4jParentDir>
<docLabel>Apache Log4J Performance Tests</docLabel>
<projectDir>/log4j-perf</projectDir>
- <jmh.version>1.21</jmh.version>
+ <jmh.version>1.34</jmh.version>
<javac.target>1.7</javac.target>
<uberjar.name>benchmarks</uberjar.name>
<revapi.skip>true</revapi.skip>
@@ -185,7 +185,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
- <version>2.2</version>
+ <version>3.2.4</version>
<executions>
<execution>
<phase>package</phase>
diff --git
a/log4j-perf/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutBenchmark.java
b/log4j-perf/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutBenchmark.java
index 1099625..f7ef08e 100644
---
a/log4j-perf/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutBenchmark.java
+++
b/log4j-perf/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutBenchmark.java
@@ -28,158 +28,164 @@ import java.util.List;
* Benchmark suite for various JSON layouts.
* <p>
* You can run this test as follows:
- * <pre>
+ * <pre>{@code
* java \
* -jar log4j-perf/target/benchmarks.jar \
* -f 2 \
* -wi 3 -w 20s \
* -i 5 -r 30s \
* -prof gc \
+ * -prof perfnorm \
+ * -prof "async:libPath=/path/to/libasyncProfiler.so;output=flamegraph" \
* -rf json -rff log4j-perf/target/JsonTemplateLayoutBenchmarkResult.json \
* ".*JsonTemplateLayoutBenchmark.*"
- * </pre>
+ * }</pre>
+ * </p>
*/
public class JsonTemplateLayoutBenchmark {
@Benchmark
- public static int fullJsonTemplateLayout4JsonLayout(
+ public static int fullJtl4JsonLayout(
final JsonTemplateLayoutBenchmarkState state) {
return benchmark(
- state.getJsonTemplateLayout4JsonLayout(),
- state.getFullLogEvents(),
- state.getByteBufferDestination());
+ state,
+ state.getJtl4JsonLayout(),
+ state.getFullLogEvents());
}
@Benchmark
- public static int liteJsonTemplateLayout4JsonLayout(
+ public static int liteJtl4JsonLayout(
final JsonTemplateLayoutBenchmarkState state) {
return benchmark(
- state.getJsonTemplateLayout4JsonLayout(),
- state.getLiteLogEvents(),
- state.getByteBufferDestination());
+ state,
+ state.getJtl4JsonLayout(),
+ state.getLiteLogEvents());
}
@Benchmark
- public static int fullJsonTemplateLayout4EcsLayout(
+ public static int fullJtl4EcsLayout(
final JsonTemplateLayoutBenchmarkState state) {
return benchmark(
- state.getJsonTemplateLayout4EcsLayout(),
- state.getFullLogEvents(),
- state.getByteBufferDestination());
+ state,
+ state.getJtl4EcsLayout(),
+ state.getFullLogEvents());
}
@Benchmark
- public static int liteJsonTemplateLayout4EcsLayout(
+ public static int liteJtl4EcsLayout(
final JsonTemplateLayoutBenchmarkState state) {
return benchmark(
- state.getJsonTemplateLayout4EcsLayout(),
- state.getLiteLogEvents(),
- state.getByteBufferDestination());
+ state,
+ state.getJtl4EcsLayout(),
+ state.getLiteLogEvents());
}
@Benchmark
- public static int fullJsonTemplateLayout4GelfLayout(
+ public static int fullJtl4GelfLayout(
final JsonTemplateLayoutBenchmarkState state) {
return benchmark(
- state.getJsonTemplateLayout4GelfLayout(),
- state.getFullLogEvents(),
- state.getByteBufferDestination());
+ state,
+ state.getJtl4GelfLayout(),
+ state.getFullLogEvents());
}
@Benchmark
- public static int liteJsonTemplateLayout4GelfLayout(
+ public static int liteJtl4GelfLayout(
final JsonTemplateLayoutBenchmarkState state) {
return benchmark(
- state.getJsonTemplateLayout4GelfLayout(),
- state.getLiteLogEvents(),
- state.getByteBufferDestination());
+ state,
+ state.getJtl4GelfLayout(),
+ state.getLiteLogEvents());
}
@Benchmark
public static int fullDefaultJsonLayout(
final JsonTemplateLayoutBenchmarkState state) {
return benchmark(
+ state,
state.getDefaultJsonLayout(),
- state.getFullLogEvents(),
- state.getByteBufferDestination());
+ state.getFullLogEvents());
}
@Benchmark
public static int liteDefaultJsonLayout(
final JsonTemplateLayoutBenchmarkState state) {
return benchmark(
+ state,
state.getDefaultJsonLayout(),
- state.getLiteLogEvents(),
- state.getByteBufferDestination());
+ state.getLiteLogEvents());
}
@Benchmark
public static int fullCustomJsonLayout(
final JsonTemplateLayoutBenchmarkState state) {
return benchmark(
+ state,
state.getCustomJsonLayout(),
- state.getFullLogEvents(),
- state.getByteBufferDestination());
+ state.getFullLogEvents());
}
@Benchmark
public static int liteCustomJsonLayout(
final JsonTemplateLayoutBenchmarkState state) {
return benchmark(
+ state,
state.getCustomJsonLayout(),
- state.getLiteLogEvents(),
- state.getByteBufferDestination());
+ state.getLiteLogEvents());
}
@Benchmark
public static int fullEcsLayout(
final JsonTemplateLayoutBenchmarkState state) {
return benchmark(
+ state,
state.getEcsLayout(),
- state.getFullLogEvents(),
- state.getByteBufferDestination());
+ state.getFullLogEvents());
}
@Benchmark
public static int liteEcsLayout(
final JsonTemplateLayoutBenchmarkState state) {
return benchmark(
+ state,
state.getEcsLayout(),
- state.getLiteLogEvents(),
- state.getByteBufferDestination());
+ state.getLiteLogEvents());
}
@Benchmark
public static int fullGelfLayout(
final JsonTemplateLayoutBenchmarkState state) {
return benchmark(
+ state,
state.getGelfLayout(),
- state.getFullLogEvents(),
- state.getByteBufferDestination());
+ state.getFullLogEvents());
}
@Benchmark
public static int liteGelfLayout(
final JsonTemplateLayoutBenchmarkState state) {
return benchmark(
+ state,
state.getGelfLayout(),
- state.getLiteLogEvents(),
- state.getByteBufferDestination());
+ state.getLiteLogEvents());
}
private static int benchmark(
- final Layout<String> layout,
- final List<LogEvent> logEvents,
+ final JsonTemplateLayoutBenchmarkState state,
+ final Layout<?> layout,
+ final List<LogEvent> logEvents) {
+ final int logEventIndex = state.nextLogEventIndex();
+ final LogEvent logEvent = logEvents.get(logEventIndex);
+ return benchmark(layout, logEvent, state.getByteBufferDestination());
+ }
+
+ private static int benchmark(
+ final Layout<?> layout,
+ final LogEvent logEvent,
final ByteBufferDestination destination) {
- // noinspection ForLoopReplaceableByForEach (avoid iterator
instantiation)
- for (int logEventIndex = 0; logEventIndex < logEvents.size();
logEventIndex++) {
- LogEvent logEvent = logEvents.get(logEventIndex);
- layout.encode(logEvent, destination);
- }
final ByteBuffer byteBuffer = destination.getByteBuffer();
- final int position = byteBuffer.position();
- byteBuffer.clear();
- return position;
+ layout.encode(logEvent, destination);
+ return byteBuffer.position();
}
}
diff --git
a/log4j-perf/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutBenchmarkState.java
b/log4j-perf/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutBenchmarkState.java
index 0a408a7..8edeac7 100644
---
a/log4j-perf/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutBenchmarkState.java
+++
b/log4j-perf/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutBenchmarkState.java
@@ -17,6 +17,7 @@
package org.apache.logging.log4j.layout.template.json;
import co.elastic.logging.log4j2.EcsLayout;
+import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.DefaultConfiguration;
@@ -34,48 +35,51 @@ import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.List;
-@State(Scope.Benchmark)
+@State(Scope.Thread)
public class JsonTemplateLayoutBenchmarkState {
private static final Configuration CONFIGURATION = new
DefaultConfiguration();
private static final Charset CHARSET = StandardCharsets.UTF_8;
+ private static final int LOG_EVENT_COUNT = 1_000;
+
private final ByteBufferDestination byteBufferDestination;
- private final JsonTemplateLayout jsonTemplateLayout4JsonLayout;
+ private final Layout<?> jtl4JsonLayout;
- private final JsonTemplateLayout jsonTemplateLayout4EcsLayout;
+ private final Layout<?> jtl4EcsLayout;
- private final JsonTemplateLayout jsonTemplateLayout4GelfLayout;
+ private final Layout<?> jtl4GelfLayout;
- private final JsonLayout defaultJsonLayout;
+ private final Layout<?> defaultJsonLayout;
- private final JsonLayout customJsonLayout;
+ private final Layout<?> customJsonLayout;
- private final EcsLayout ecsLayout;
+ private final Layout<?> ecsLayout;
- private final GelfLayout gelfLayout;
+ private final Layout<?> gelfLayout;
private final List<LogEvent> fullLogEvents;
private final List<LogEvent> liteLogEvents;
+ private int logEventIndex = 0;
+
public JsonTemplateLayoutBenchmarkState() {
this.byteBufferDestination = new BlackHoleByteBufferDestination(1024 *
512);
- this.jsonTemplateLayout4JsonLayout =
createJsonTemplateLayout4JsonLayout();
- this.jsonTemplateLayout4EcsLayout =
createJsonTemplateLayout4EcsLayout();
- this.jsonTemplateLayout4GelfLayout =
createJsonTemplateLayout4GelfLayout();
+ this.jtl4JsonLayout = createJtl4JsonLayout();
+ this.jtl4EcsLayout = createJtl4EcsLayout();
+ this.jtl4GelfLayout = createJtl4GelfLayout();
this.defaultJsonLayout = createDefaultJsonLayout();
this.customJsonLayout = createCustomJsonLayout();
this.ecsLayout = createEcsLayout();
this.gelfLayout = createGelfLayout();
- int logEventCount = 1_000;
- this.fullLogEvents =
LogEventFixture.createFullLogEvents(logEventCount);
- this.liteLogEvents =
LogEventFixture.createLiteLogEvents(logEventCount);
+ this.fullLogEvents =
LogEventFixture.createFullLogEvents(LOG_EVENT_COUNT);
+ this.liteLogEvents =
LogEventFixture.createLiteLogEvents(LOG_EVENT_COUNT);
}
- private static JsonTemplateLayout createJsonTemplateLayout4JsonLayout() {
+ private static JsonTemplateLayout createJtl4JsonLayout() {
return JsonTemplateLayout
.newBuilder()
.setConfiguration(CONFIGURATION)
@@ -85,7 +89,7 @@ public class JsonTemplateLayoutBenchmarkState {
.build();
}
- private static JsonTemplateLayout createJsonTemplateLayout4EcsLayout() {
+ private static JsonTemplateLayout createJtl4EcsLayout() {
final EventTemplateAdditionalField[] additionalFields =
new EventTemplateAdditionalField[]{
EventTemplateAdditionalField
@@ -104,7 +108,7 @@ public class JsonTemplateLayoutBenchmarkState {
.build();
}
- private static JsonTemplateLayout createJsonTemplateLayout4GelfLayout() {
+ private static JsonTemplateLayout createJtl4GelfLayout() {
return JsonTemplateLayout
.newBuilder()
.setConfiguration(CONFIGURATION)
@@ -173,31 +177,31 @@ public class JsonTemplateLayoutBenchmarkState {
return byteBufferDestination;
}
- JsonTemplateLayout getJsonTemplateLayout4JsonLayout() {
- return jsonTemplateLayout4JsonLayout;
+ Layout<?> getJtl4JsonLayout() {
+ return jtl4JsonLayout;
}
- JsonTemplateLayout getJsonTemplateLayout4EcsLayout() {
- return jsonTemplateLayout4EcsLayout;
+ Layout<?> getJtl4EcsLayout() {
+ return jtl4EcsLayout;
}
- JsonTemplateLayout getJsonTemplateLayout4GelfLayout() {
- return jsonTemplateLayout4GelfLayout;
+ Layout<?> getJtl4GelfLayout() {
+ return jtl4GelfLayout;
}
- JsonLayout getDefaultJsonLayout() {
+ Layout<?> getDefaultJsonLayout() {
return defaultJsonLayout;
}
- JsonLayout getCustomJsonLayout() {
+ Layout<?> getCustomJsonLayout() {
return customJsonLayout;
}
- EcsLayout getEcsLayout() {
+ Layout<?> getEcsLayout() {
return ecsLayout;
}
- GelfLayout getGelfLayout() {
+ Layout<?> getGelfLayout() {
return gelfLayout;
}
@@ -209,4 +213,10 @@ public class JsonTemplateLayoutBenchmarkState {
return liteLogEvents;
}
+ int nextLogEventIndex() {
+ final int currentLogEventIndex = logEventIndex;
+ logEventIndex = (logEventIndex + 1) % LOG_EVENT_COUNT;
+ return currentLogEventIndex;
+ }
+
}