You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by vy...@apache.org on 2022/03/14 21:04:40 UTC

[logging-log4j2] branch LOG4J2-3393 updated (9ecef90 -> 51e5112)

This is an automated email from the ASF dual-hosted git repository.

vy pushed a change to branch LOG4J2-3393
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git.


 discard 9ecef90  LOG4J2-3393 Clean up LcsLayout and all other mess.
 discard 227d598  LOG4J2-3393 Optimize MessageResolver for CharSequence.
 discard 6e6bd23  LOG4J2-3393 Fix revapi issues.
 discard 69608b9  LOG4J2-3393 Clean-up wrong BiConsumer usages.
 discard 6a19108  LOG4J2-3393 Make JsonWriter garbage-free for StringMaps.
 discard 81905f9  LOG4J2-3393 Make TextEncoderHelper.encodeText() fallbacks JIT-friendly.
 discard 8a48540  LOG4J2-3393 JTL benchmark updates.
 discard c907fcd  LOG4J2-3393 Inline context acquisition in JsonTemplateLayout.
 discard 970e80e  LOG4J2-3393 Remove redundant branching in JsonTemplateLayout.
 discard 264ae84  LOG4J2-3393 Avoid StringBuilderEncoder thread-local allocation in JsonTemplateLayout.
 discard 3f6a9af  LOG4J2-3393 Replace lambdas with classes to ease performance troubleshooting.
 discard 7136e8c  LOG4J2-3393 Use a single LogEvent in JMH benchmarks.
 discard 35e0c20  LOG4J2-3393 Bump JMH from 1.21 to 1.34.
 discard a604623  LOG4J2-3393 Improve "blackhole" behavior in ByteBuffer consumption.
 discard c4cac94  LOG4J2-3393 Go wild and embed ECS Layout for troubleshooting!
 discard cdade74  LOG4J2-3393 Create JTL benchmark main() for easy testing.
 discard a0a310f  LOG4J2-3393 Refactor JTL TemplateResolvers into smaller components.
     add 28b1ae6  Bump logbackVersion from 1.2.3 to 1.2.11 (#793)
     add c73c804  Changes Cassandra's port to an ephemeral one
     new f3a8d4f  LOG4J2-3393 Refactor JTL TemplateResolvers into smaller components.
     new f8cbf61  LOG4J2-3393 Create JTL benchmark main() for easy testing.
     new 3668ed9  LOG4J2-3393 Go wild and embed ECS Layout for troubleshooting!
     new b45c682  LOG4J2-3393 Improve "blackhole" behavior in ByteBuffer consumption.
     new f3c3d8b  LOG4J2-3393 Bump JMH from 1.21 to 1.34.
     new 3542030  LOG4J2-3393 Use a single LogEvent in JMH benchmarks.
     new 9e87b52  LOG4J2-3393 Replace lambdas with classes to ease performance troubleshooting.
     new 8b12d69  LOG4J2-3393 Avoid StringBuilderEncoder thread-local allocation in JsonTemplateLayout.
     new 8fdbe5c  LOG4J2-3393 Remove redundant branching in JsonTemplateLayout.
     new f5b172e  LOG4J2-3393 Inline context acquisition in JsonTemplateLayout.
     new 041dd8a  LOG4J2-3393 JTL benchmark updates.
     new 0ada371  LOG4J2-3393 Make TextEncoderHelper.encodeText() fallbacks JIT-friendly.
     new aaef74c  LOG4J2-3393 Make JsonWriter garbage-free for StringMaps.
     new 04a8214  LOG4J2-3393 Clean-up wrong BiConsumer usages.
     new 1695044  LOG4J2-3393 Fix revapi issues.
     new fcf85c7  LOG4J2-3393 Optimize MessageResolver for CharSequence.
     new 51e5112  LOG4J2-3393 Clean up LcsLayout and all other mess.

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (9ecef90)
            \
             N -- N -- N   refs/heads/LOG4J2-3393 (51e5112)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

The 17 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../logging/log4j/cassandra/CassandraRule.java     | 42 ++++++++++++++++++----
 pom.xml                                            |  2 +-
 2 files changed, 37 insertions(+), 7 deletions(-)

[logging-log4j2] 02/17: LOG4J2-3393 Create JTL benchmark main() for easy testing.

Posted by vy...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

vy pushed a commit to branch LOG4J2-3393
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit f8cbf611f548e66dd9f3e5d27f3b67e86cc33509
Author: Volkan Yazici <vo...@yazi.ci>
AuthorDate: Mon Feb 7 10:54:30 2022 +0100

    LOG4J2-3393 Create JTL benchmark main() for easy testing.
---
 .../template/json/JsonTemplateLayoutBenchmark.java | 26 ++++++++++++++++++++++
 1 file changed, 26 insertions(+)

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..dce0690 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
@@ -21,6 +21,7 @@ import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.layout.ByteBufferDestination;
 import org.openjdk.jmh.annotations.Benchmark;
 
+import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.util.List;
 
@@ -182,4 +183,29 @@ public class JsonTemplateLayoutBenchmark {
         return position;
     }
 
+    public static void main(String[] args) throws IOException {
+        System.out.format("Ready?");
+        System.in.read();
+        JsonTemplateLayoutBenchmarkState state = new JsonTemplateLayoutBenchmarkState();
+        int retryCount = 10_000;
+        measureEcs(state, retryCount);
+        measureJtl(state, retryCount);
+    }
+
+    private static void measureJtl(JsonTemplateLayoutBenchmarkState state, int retryCount) {
+        long startInstantNanos = System.nanoTime();
+        for (int i = 0; i < retryCount; i++) {
+            liteJsonTemplateLayout4EcsLayout(state);
+        }
+        System.out.format("%.3fs%n", (System.nanoTime() - startInstantNanos) / 1e9);
+    }
+
+    private static void measureEcs(JsonTemplateLayoutBenchmarkState state, int retryCount) {
+        long startInstantNanos = System.nanoTime();
+        for (int i = 0; i < retryCount; i++) {
+            liteEcsLayout(state);
+        }
+        System.out.format("%.3fs%n", (System.nanoTime() - startInstantNanos) / 1e9);
+    }
+
 }

[logging-log4j2] 05/17: LOG4J2-3393 Bump JMH from 1.21 to 1.34.

Posted by vy...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

vy pushed a commit to branch LOG4J2-3393
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit f3c3d8b381f07648f8980250db2a64391217d21c
Author: Volkan Yazici <vo...@yazi.ci>
AuthorDate: Fri Feb 18 16:49:34 2022 +0100

    LOG4J2-3393 Bump JMH from 1.21 to 1.34.
---
 log4j-perf/pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/log4j-perf/pom.xml b/log4j-perf/pom.xml
index 95e0db0..863dfb1 100644
--- a/log4j-perf/pom.xml
+++ b/log4j-perf/pom.xml
@@ -37,7 +37,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>
     <uberjar.name>benchmarks</uberjar.name>
     <revapi.skip>true</revapi.skip>
     <maven.doap.skip>true</maven.doap.skip>

[logging-log4j2] 07/17: LOG4J2-3393 Replace lambdas with classes to ease performance troubleshooting.

Posted by vy...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

vy pushed a commit to branch LOG4J2-3393
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit 9e87b52226c0e418c93b2a997287c6f4f700d953
Author: Volkan Yazici <vo...@yazi.ci>
AuthorDate: Sat Feb 19 19:52:11 2022 +0100

    LOG4J2-3393 Replace lambdas with classes to ease performance troubleshooting.
---
 .../template/json/resolver/TemplateResolvers.java  | 166 ++++++++++++++++-----
 1 file changed, 128 insertions(+), 38 deletions(-)

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 450b874..125d5c4 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
@@ -51,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,
@@ -146,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 -> {
@@ -168,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();
@@ -176,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();
-        };
+        }
 
     }
 
@@ -440,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);
             }
 
         }
@@ -461,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);
+        }
+
     }
 
 }

[logging-log4j2] 12/17: LOG4J2-3393 Make TextEncoderHelper.encodeText() fallbacks JIT-friendly.

Posted by vy...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

vy pushed a commit to branch LOG4J2-3393
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit 0ada37170dbfc9d1845cf3ba4a99c94ce41d1fe9
Author: Volkan Yazici <vo...@yazi.ci>
AuthorDate: Tue Feb 22 09:56:20 2022 +0100

    LOG4J2-3393 Make TextEncoderHelper.encodeText() fallbacks JIT-friendly.
---
 .../log4j/core/layout/StringBuilderEncoder.java        |  2 +-
 .../log4j/layout/template/json/JsonTemplateLayout.java | 18 +++++++++++++-----
 2 files changed, 14 insertions(+), 6 deletions(-)

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 d300a74..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
@@ -89,7 +89,7 @@ public class StringBuilderEncoder implements Encoder<StringBuilder> {
         return threadLocalState;
     }
 
-    private void logEncodeTextException(final Exception ex, final StringBuilder text) {
+    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-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 5e36817..4266dfc 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
@@ -240,14 +240,22 @@ public class JsonTemplateLayout implements StringLayout {
             try {
                 TextEncoderHelper.encodeText(charsetEncoder, charBuffer, byteBuffer, source, destination);
             } catch (final Exception error) {
-                StatusLogger
-                        .getLogger()
-                        .error("TextEncoderHelper.encodeText() failure", error);
-                final byte[] bytes = source.toString().getBytes(charset);
-                destination.writeBytes(bytes, 0, bytes.length);
+                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

[logging-log4j2] 06/17: LOG4J2-3393 Use a single LogEvent in JMH benchmarks.

Posted by vy...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

vy pushed a commit to branch LOG4J2-3393
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit 3542030ea45f86041da0a941ba7ba9860c2b4c63
Author: Volkan Yazici <vo...@yazi.ci>
AuthorDate: Fri Feb 18 16:50:32 2022 +0100

    LOG4J2-3393 Use a single LogEvent in JMH benchmarks.
---
 .../json/BlackHoleByteBufferDestination.java       |  6 +-
 .../template/json/JsonTemplateLayoutBenchmark.java | 80 +++++++++++-----------
 .../json/JsonTemplateLayoutBenchmarkState.java     | 18 +++--
 3 files changed, 58 insertions(+), 46 deletions(-)

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 ca6041b..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
@@ -37,8 +37,10 @@ class BlackHoleByteBufferDestination implements ByteBufferDestination {
     @Override
     public ByteBuffer drain(final ByteBuffer byteBuffer) {
         byteBuffer.flip();
-        this.byteBuffer.clear();
-        this.byteBuffer.put(byteBuffer);
+        if (this.byteBuffer != byteBuffer) {
+            this.byteBuffer.clear();
+            this.byteBuffer.put(byteBuffer);
+        }
         byteBuffer.clear();
         return byteBuffer;
     }
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 0b3ca8b..58c5852 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
@@ -46,149 +46,151 @@ public class JsonTemplateLayoutBenchmark {
     public static int fullJsonTemplateLayout4JsonLayout(
             final JsonTemplateLayoutBenchmarkState state) {
         return benchmark(
+                state,
                 state.getJsonTemplateLayout4JsonLayout(),
-                state.getFullLogEvents(),
-                state.getByteBufferDestination());
+                state.getFullLogEvents());
     }
 
     @Benchmark
     public static int liteJsonTemplateLayout4JsonLayout(
             final JsonTemplateLayoutBenchmarkState state) {
         return benchmark(
+                state,
                 state.getJsonTemplateLayout4JsonLayout(),
-                state.getLiteLogEvents(),
-                state.getByteBufferDestination());
+                state.getLiteLogEvents());
     }
 
     @Benchmark
     public static int fullJsonTemplateLayout4EcsLayout(
             final JsonTemplateLayoutBenchmarkState state) {
         return benchmark(
+                state,
                 state.getJsonTemplateLayout4EcsLayout(),
-                state.getFullLogEvents(),
-                state.getByteBufferDestination());
+                state.getFullLogEvents());
     }
 
     @Benchmark
     public static int liteJsonTemplateLayout4EcsLayout(
             final JsonTemplateLayoutBenchmarkState state) {
         return benchmark(
+                state,
                 state.getJsonTemplateLayout4EcsLayout(),
-                state.getLiteLogEvents(),
-                state.getByteBufferDestination());
+                state.getLiteLogEvents());
     }
 
     @Benchmark
     public static int fullJsonTemplateLayout4GelfLayout(
             final JsonTemplateLayoutBenchmarkState state) {
         return benchmark(
+                state,
                 state.getJsonTemplateLayout4GelfLayout(),
-                state.getFullLogEvents(),
-                state.getByteBufferDestination());
+                state.getFullLogEvents());
     }
 
     @Benchmark
     public static int liteJsonTemplateLayout4GelfLayout(
             final JsonTemplateLayoutBenchmarkState state) {
         return benchmark(
+                state,
                 state.getJsonTemplateLayout4GelfLayout(),
-                state.getLiteLogEvents(),
-                state.getByteBufferDestination());
+                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 JsonTemplateLayoutBenchmarkState state,
             final Layout<String> layout,
-            final List<LogEvent> logEvents,
+            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<String> layout,
+            final LogEvent logEvent,
             final ByteBufferDestination destination) {
         final ByteBuffer byteBuffer = destination.getByteBuffer();
-        int checksum = 0;
-        // noinspection ForLoopReplaceableByForEach (avoid iterator instantiation)
-        for (int logEventIndex = 0; logEventIndex < logEvents.size(); logEventIndex++) {
-            LogEvent logEvent = logEvents.get(logEventIndex);
-            layout.encode(logEvent, destination);
-            checksum += byteBuffer.position();
-            byteBuffer.clear();
-        }
-        return checksum;
+        layout.encode(logEvent, destination);
+        return byteBuffer.position();
     }
 
     public static void main(String[] args) throws IOException {
 //        System.out.format("Ready?");
 //        System.in.read();
         JsonTemplateLayoutBenchmarkState state = new JsonTemplateLayoutBenchmarkState();
-        int retryCount = 200_000;
+        int retryCount = 200_000_000;
         measureEcs(state, retryCount);
         measureJtl(state, retryCount);
     }
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 54c8c0b..3fc5c5b 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
@@ -16,7 +16,6 @@
  */
 package org.apache.logging.log4j.layout.template.json;
 
-import co.elastic.logging.log4j2.EcsLayout;
 import co.elastic.logging.log4j2.LcsLayout;
 import org.apache.logging.log4j.core.Layout;
 import org.apache.logging.log4j.core.LogEvent;
@@ -36,13 +35,15 @@ 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;
@@ -63,6 +64,8 @@ public class JsonTemplateLayoutBenchmarkState {
 
     private final List<LogEvent> liteLogEvents;
 
+    private int logEventIndex = 0;
+
     public JsonTemplateLayoutBenchmarkState() {
         this.byteBufferDestination = new BlackHoleByteBufferDestination(1024 * 512);
         this.jsonTemplateLayout4JsonLayout = createJsonTemplateLayout4JsonLayout();
@@ -72,9 +75,8 @@ public class JsonTemplateLayoutBenchmarkState {
         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() {
@@ -212,4 +214,10 @@ public class JsonTemplateLayoutBenchmarkState {
         return liteLogEvents;
     }
 
+    int nextLogEventIndex() {
+        final int currentLogEventIndex = logEventIndex;
+        logEventIndex = (logEventIndex + 1) % LOG_EVENT_COUNT;
+        return currentLogEventIndex;
+    }
+
 }

[logging-log4j2] 09/17: LOG4J2-3393 Remove redundant branching in JsonTemplateLayout.

Posted by vy...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

vy pushed a commit to branch LOG4J2-3393
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit 8fdbe5cb0eed7e3e12b97406482da838b93cd074
Author: Volkan Yazici <vo...@yazi.ci>
AuthorDate: Mon Feb 21 20:43:12 2022 +0100

    LOG4J2-3393 Remove redundant branching in JsonTemplateLayout.
---
 .../logging/log4j/layout/template/json/JsonTemplateLayout.java    | 8 +-------
 1 file changed, 1 insertion(+), 7 deletions(-)

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 a585bc5..8747c98 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
@@ -287,13 +287,7 @@ public class JsonTemplateLayout implements StringLayout {
             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);
 
         }
 

[logging-log4j2] 03/17: LOG4J2-3393 Go wild and embed ECS Layout for troubleshooting!

Posted by vy...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

vy pushed a commit to branch LOG4J2-3393
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit 3668ed90980a07fa2d3960f13753f764e420779c
Author: Volkan Yazici <vo...@yazi.ci>
AuthorDate: Sun Feb 13 21:16:34 2022 +0100

    LOG4J2-3393 Go wild and embed ECS Layout for troubleshooting!
---
 .../java/co/elastic/logging/log4j2/LcsLayout.java  | 390 +++++++++++++++++++++
 .../template/json/JsonTemplateLayoutBenchmark.java |   6 +-
 .../json/JsonTemplateLayoutBenchmarkState.java     |  27 +-
 3 files changed, 408 insertions(+), 15 deletions(-)

diff --git a/log4j-perf/src/main/java/co/elastic/logging/log4j2/LcsLayout.java b/log4j-perf/src/main/java/co/elastic/logging/log4j2/LcsLayout.java
new file mode 100644
index 0000000..07d0f86
--- /dev/null
+++ b/log4j-perf/src/main/java/co/elastic/logging/log4j2/LcsLayout.java
@@ -0,0 +1,390 @@
+package co.elastic.logging.log4j2;
+
+
+import co.elastic.logging.EcsJsonSerializer;
+import co.elastic.logging.JsonUtils;
+import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.ThreadContext;
+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.Node;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
+import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
+import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
+import org.apache.logging.log4j.core.config.plugins.PluginElement;
+import org.apache.logging.log4j.core.layout.AbstractStringLayout;
+import org.apache.logging.log4j.core.layout.ByteBufferDestination;
+import org.apache.logging.log4j.core.layout.Encoder;
+import org.apache.logging.log4j.core.layout.PatternLayout;
+import org.apache.logging.log4j.core.lookup.StrSubstitutor;
+import org.apache.logging.log4j.core.pattern.PatternFormatter;
+import org.apache.logging.log4j.core.util.KeyValuePair;
+import org.apache.logging.log4j.message.Message;
+import org.apache.logging.log4j.message.MultiformatMessage;
+import org.apache.logging.log4j.message.ObjectMessage;
+import org.apache.logging.log4j.util.StringBuilderFormattable;
+
+import java.nio.charset.Charset;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+@Plugin(name = "LcsLayout", category = Node.CATEGORY, elementType = Layout.ELEMENT_TYPE)
+public class LcsLayout extends AbstractStringLayout {
+
+    public static final Charset UTF_8 = Charset.forName("UTF-8");
+    private static final ObjectMessageJacksonSerializer JACKSON_SERIALIZER = ObjectMessageJacksonSerializer.Resolver.resolve();
+    private static final MdcSerializer MDC_SERIALIZER = MdcSerializer.Resolver.resolve();
+    private static final MultiFormatHandler MULTI_FORMAT_HANDLER = MultiFormatHandler.Resolver.resolve();
+
+    private final KeyValuePair[] additionalFields;
+    private final PatternFormatter[][] fieldValuePatternFormatter;
+    private final boolean stackTraceAsArray;
+    private final String serviceName;
+    private final String eventDataset;
+    private final boolean includeMarkers;
+    private final boolean includeOrigin;
+    private final ConcurrentMap<Class<? extends MultiformatMessage>, Boolean> supportsJson = new ConcurrentHashMap<Class<? extends MultiformatMessage>, Boolean>();
+
+    private LcsLayout(Configuration config, String serviceName, String eventDataset, boolean includeMarkers, KeyValuePair[] additionalFields, boolean includeOrigin, boolean stackTraceAsArray) {
+        super(config, UTF_8, null, null);
+        this.serviceName = serviceName;
+        this.eventDataset = eventDataset;
+        this.includeMarkers = includeMarkers;
+        this.includeOrigin = includeOrigin;
+        this.stackTraceAsArray = stackTraceAsArray;
+        this.additionalFields = additionalFields;
+        fieldValuePatternFormatter = new PatternFormatter[additionalFields.length][];
+        for (int i = 0; i < additionalFields.length; i++) {
+            KeyValuePair additionalField = additionalFields[i];
+            if (additionalField.getValue().contains("%")) {
+                fieldValuePatternFormatter[i] = PatternLayout.createPatternParser(config)
+                        .parse(additionalField.getValue())
+                        .toArray(new PatternFormatter[0]);
+            }
+        }
+    }
+
+    @PluginBuilderFactory
+    public static LcsLayout.Builder newBuilder() {
+        return new LcsLayout.Builder();
+    }
+
+    private static boolean valueNeedsLookup(final String value) {
+        return value != null && value.contains("${");
+    }
+
+    @Override
+    public String toSerializable(LogEvent event) {
+        final StringBuilder text = toText(event, getStringBuilder(), false);
+        return text.toString();
+    }
+
+    @Override
+    public void encode(LogEvent event, ByteBufferDestination destination) {
+        final StringBuilder text = toText(event, getStringBuilder(), true);
+        final Encoder<StringBuilder> helper = getStringBuilderEncoder();
+        helper.encode(text, destination);
+    }
+
+    @Override
+    public String getContentType() {
+        return "application/json";
+    }
+
+    private StringBuilder toText(LogEvent event, StringBuilder builder, boolean gcFree) {
+        builder.append('{');//EcsJsonSerializer.serializeObjectStart(builder, event.getTimeMillis());
+//        EcsJsonSerializer.serializeLogLevel(builder, event.getLevel().toString());
+//        serializeMessage(builder, gcFree, event.getMessage(), event.getThrown());
+//        EcsJsonSerializer.serializeEcsVersion(builder);
+//        EcsJsonSerializer.serializeServiceName(builder, serviceName);
+//        EcsJsonSerializer.serializeEventDataset(builder, eventDataset);
+//        EcsJsonSerializer.serializeThreadName(builder, event.getThreadName());
+//        EcsJsonSerializer.serializeLoggerName(builder, event.getLoggerName());
+//        serializeAdditionalFieldsAndMDC(event, builder);
+//        serializeTags(event, builder);
+//        if (includeOrigin) {
+//            EcsJsonSerializer.serializeOrigin(builder, event.getSource());
+//        }
+//        EcsJsonSerializer.serializeException(builder, event.getThrown(), stackTraceAsArray);
+        EcsJsonSerializer.serializeObjectEnd(builder);
+        return builder;
+    }
+
+    private void serializeAdditionalFieldsAndMDC(LogEvent event, StringBuilder builder) {
+        final int length = additionalFields.length;
+        if (length > 0) {
+            final StrSubstitutor strSubstitutor = getConfiguration().getStrSubstitutor();
+            for (int i = 0; i < length; i++) {
+                KeyValuePair additionalField = additionalFields[i];
+                PatternFormatter[] formatters = fieldValuePatternFormatter[i];
+                CharSequence value = null;
+                if (formatters != null) {
+                    StringBuilder buffer = EcsJsonSerializer.getMessageStringBuilder();
+                    formatPattern(event, formatters, buffer);
+                    if (buffer.length() > 0) {
+                        value = buffer;
+                    }
+                } else if (valueNeedsLookup(additionalField.getValue())) {
+                    StringBuilder lookupValue = EcsJsonSerializer.getMessageStringBuilder();
+                    lookupValue.append(additionalField.getValue());
+                    if (strSubstitutor.replaceIn(event, lookupValue)) {
+                        value = lookupValue;
+                    }
+                } else {
+                    value = additionalField.getValue();
+                }
+
+                if (value != null) {
+                    builder.append('\"');
+                    JsonUtils.quoteAsString(additionalField.getKey(), builder);
+                    builder.append("\":\"");
+                    JsonUtils.quoteAsString(EcsJsonSerializer.toNullSafeString(value), builder);
+                    builder.append("\",");
+                }
+            }
+        }
+        MDC_SERIALIZER.serializeMdc(event, builder);
+    }
+
+    private static void formatPattern(LogEvent event, PatternFormatter[] formatters, StringBuilder buffer) {
+        final int len = formatters.length;
+        for (int i = 0; i < len; i++) {
+            formatters[i].format(event, buffer);
+        }
+    }
+
+    private void serializeTags(LogEvent event, StringBuilder builder) {
+        ThreadContext.ContextStack stack = event.getContextStack();
+        List<String> contextStack;
+        if (stack == null) {
+            contextStack = Collections.emptyList();
+        } else {
+            contextStack = stack.asList();
+        }
+        Marker marker = event.getMarker();
+        boolean hasTags = !contextStack.isEmpty() || (includeMarkers && marker != null);
+        if (hasTags) {
+            EcsJsonSerializer.serializeTagStart(builder);
+        }
+
+        if (!contextStack.isEmpty()) {
+            final int len = contextStack.size();
+            for (int i = 0; i < len; i++) {
+                builder.append('\"');
+                JsonUtils.quoteAsString(contextStack.get(i), builder);
+                builder.append("\",");
+            }
+        }
+
+        if (includeMarkers && marker != null) {
+            serializeMarker(builder, marker);
+        }
+
+        if (hasTags) {
+            EcsJsonSerializer.serializeTagEnd(builder);
+        }
+    }
+
+    private void serializeMarker(StringBuilder builder, Marker marker) {
+        EcsJsonSerializer.serializeSingleTag(builder, marker.getName());
+        if (marker.hasParents()) {
+            Marker[] parents = marker.getParents();
+            for (int i = 0; i < parents.length; i++) {
+                serializeMarker(builder, parents[i]);
+            }
+        }
+    }
+
+    private void serializeMessage(StringBuilder builder, boolean gcFree, Message message, Throwable thrown) {
+        if (message instanceof MultiformatMessage) {
+            MultiformatMessage multiformatMessage = (MultiformatMessage) message;
+            if (supportsJson(multiformatMessage)) {
+                serializeJsonMessage(builder, multiformatMessage);
+            } else {
+                serializeSimpleMessage(builder, gcFree, message, thrown);
+            }
+        } else if (JACKSON_SERIALIZER != null && message instanceof ObjectMessage) {
+            final StringBuilder jsonBuffer = EcsJsonSerializer.getMessageStringBuilder();
+            JACKSON_SERIALIZER.formatTo(jsonBuffer, (ObjectMessage) message);
+            addJson(builder, jsonBuffer);
+        } else {
+            serializeSimpleMessage(builder, gcFree, message, thrown);
+        }
+    }
+
+    private static void serializeJsonMessage(StringBuilder builder, MultiformatMessage message) {
+        final StringBuilder messageBuffer = EcsJsonSerializer.getMessageStringBuilder();
+        MULTI_FORMAT_HANDLER.formatJsonTo(message, messageBuffer);
+        addJson(builder, messageBuffer);
+    }
+
+    private static void addJson(StringBuilder buffer, StringBuilder jsonBuffer) {
+        if (isObject(jsonBuffer)) {
+            moveToRoot(jsonBuffer);
+            buffer.append(jsonBuffer);
+            buffer.append(", ");
+        } else {
+            buffer.append("\"message\":");
+            if (isString(jsonBuffer)) {
+                buffer.append(jsonBuffer);
+            } else {
+                // message always has to be a string to avoid mapping conflicts
+                buffer.append('"');
+                JsonUtils.quoteAsString(jsonBuffer, buffer);
+                buffer.append('"');
+            }
+            buffer.append(", ");
+        }
+    }
+
+    private void serializeSimpleMessage(StringBuilder builder, boolean gcFree, Message message, Throwable thrown) {
+        builder.append("\"message\":\"");
+        if (message instanceof CharSequence) {
+            JsonUtils.quoteAsString(((CharSequence) message), builder);
+        } else if (gcFree && message instanceof StringBuilderFormattable) {
+            final StringBuilder messageBuffer = EcsJsonSerializer.getMessageStringBuilder();
+            try {
+                ((StringBuilderFormattable) message).formatTo(messageBuffer);
+                JsonUtils.quoteAsString(messageBuffer, builder);
+            } finally {
+                trimToMaxSizeCopy(messageBuffer);
+            }
+        } else {
+            JsonUtils.quoteAsString(EcsJsonSerializer.toNullSafeString(message.getFormattedMessage()), builder);
+        }
+        builder.append("\", ");
+    }
+
+    static void trimToMaxSizeCopy(final StringBuilder stringBuilder) {
+        if (stringBuilder.length() > MAX_STRING_BUILDER_SIZE) {
+            stringBuilder.setLength(MAX_STRING_BUILDER_SIZE);
+            stringBuilder.trimToSize();
+        }
+    }
+
+    private static boolean isObject(StringBuilder messageBuffer) {
+        return messageBuffer.length() > 1 && messageBuffer.charAt(0) == '{' && messageBuffer.charAt(messageBuffer.length() - 1) == '}';
+    }
+
+    private static boolean isString(StringBuilder messageBuffer) {
+        return messageBuffer.length() > 1 && messageBuffer.charAt(0) == '"' && messageBuffer.charAt(messageBuffer.length() - 1) == '"';
+    }
+
+    private static void moveToRoot(StringBuilder messageBuffer) {
+        messageBuffer.setCharAt(0, ' ');
+        messageBuffer.setCharAt(messageBuffer.length() -1, ' ');
+    }
+
+    private boolean supportsJson(MultiformatMessage message) {
+        Boolean supportsJson = this.supportsJson.get(message.getClass());
+        if (supportsJson == null) {
+            supportsJson = false;
+            for (String format : message.getFormats()) {
+                if (format.equalsIgnoreCase("JSON")) {
+                    supportsJson = true;
+                    break;
+                }
+            }
+            this.supportsJson.put(message.getClass(), supportsJson);
+        }
+        return supportsJson;
+    }
+
+    public static class Builder implements org.apache.logging.log4j.core.util.Builder<LcsLayout> {
+
+        @PluginConfiguration
+        private Configuration configuration;
+        @PluginBuilderAttribute("serviceName")
+        private String serviceName;
+        @PluginBuilderAttribute("eventDataset")
+        private String eventDataset;
+        @PluginBuilderAttribute("includeMarkers")
+        private boolean includeMarkers = false;
+        @PluginBuilderAttribute("stackTraceAsArray")
+        private boolean stackTraceAsArray = false;
+        @PluginElement("AdditionalField")
+        private KeyValuePair[] additionalFields = new KeyValuePair[]{};
+        @PluginBuilderAttribute("includeOrigin")
+        private boolean includeOrigin = false;
+
+        Builder() {
+        }
+
+        public Configuration getConfiguration() {
+            return configuration;
+        }
+
+        public LcsLayout.Builder setConfiguration(final Configuration configuration) {
+            this.configuration = configuration;
+            return this;
+        }
+
+        public KeyValuePair[] getAdditionalFields() {
+            return additionalFields.clone();
+        }
+
+        public String getServiceName() {
+            return serviceName;
+        }
+
+        public String getEventDataset() {
+            return eventDataset;
+        }
+
+        public boolean isIncludeMarkers() {
+            return includeMarkers;
+        }
+
+        public boolean isIncludeOrigin() {
+            return includeOrigin;
+        }
+
+        /**
+         * Additional fields to set on each log event.
+         *
+         * @return this builder
+         */
+        public LcsLayout.Builder setAdditionalFields(final KeyValuePair[] additionalFields) {
+            this.additionalFields = additionalFields.clone();
+            return this;
+        }
+
+        public LcsLayout.Builder setServiceName(final String serviceName) {
+            this.serviceName = serviceName;
+            return this;
+        }
+
+        public LcsLayout.Builder setEventDataset(String eventDataset) {
+            this.eventDataset = eventDataset;
+            return this;
+        }
+
+        public LcsLayout.Builder setIncludeMarkers(final boolean includeMarkers) {
+            this.includeMarkers = includeMarkers;
+            return this;
+        }
+
+        public LcsLayout.Builder setIncludeOrigin(final boolean includeOrigin) {
+            this.includeOrigin = includeOrigin;
+            return this;
+        }
+
+        public LcsLayout.Builder setStackTraceAsArray(boolean stackTraceAsArray) {
+            this.stackTraceAsArray = stackTraceAsArray;
+            return this;
+        }
+
+        @Override
+        public LcsLayout build() {
+            return new LcsLayout(getConfiguration(), serviceName, EcsJsonSerializer.computeEventDataset(eventDataset, serviceName), includeMarkers, additionalFields, includeOrigin, stackTraceAsArray);
+        }
+
+        public boolean isStackTraceAsArray() {
+            return stackTraceAsArray;
+        }
+    }
+}
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 dce0690..2f865fa 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
@@ -184,10 +184,10 @@ public class JsonTemplateLayoutBenchmark {
     }
 
     public static void main(String[] args) throws IOException {
-        System.out.format("Ready?");
-        System.in.read();
+//        System.out.format("Ready?");
+//        System.in.read();
         JsonTemplateLayoutBenchmarkState state = new JsonTemplateLayoutBenchmarkState();
-        int retryCount = 10_000;
+        int retryCount = 200_000;
         measureEcs(state, retryCount);
         measureJtl(state, retryCount);
     }
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 093af99..54c8c0b 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,8 @@
 package org.apache.logging.log4j.layout.template.json;
 
 import co.elastic.logging.log4j2.EcsLayout;
+import co.elastic.logging.log4j2.LcsLayout;
+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;
@@ -53,7 +55,7 @@ public class JsonTemplateLayoutBenchmarkState {
 
     private final JsonLayout customJsonLayout;
 
-    private final EcsLayout ecsLayout;
+    private final LcsLayout ecsLayout;
 
     private final GelfLayout gelfLayout;
 
@@ -98,9 +100,10 @@ public class JsonTemplateLayoutBenchmarkState {
                 .newBuilder()
                 .setConfiguration(CONFIGURATION)
                 .setCharset(CHARSET)
-                .setEventTemplateUri("classpath:EcsLayout.json")
+                .setEventTemplate("{}")
+//                .setEventTemplateUri("classpath:EcsLayout.json")
                 .setRecyclerFactory(ThreadLocalRecyclerFactory.getInstance())
-                .setEventTemplateAdditionalFields(additionalFields)
+//                .setEventTemplateAdditionalFields(additionalFields)
                 .build();
     }
 
@@ -144,8 +147,8 @@ public class JsonTemplateLayoutBenchmarkState {
                 .build();
     }
 
-    private static EcsLayout createEcsLayout() {
-        final EcsLayout layout = EcsLayout
+    private static LcsLayout createEcsLayout() {
+        final LcsLayout layout = LcsLayout
                 .newBuilder()
                 .setConfiguration(CONFIGURATION)
                 .setServiceName("benchmark")
@@ -173,31 +176,31 @@ public class JsonTemplateLayoutBenchmarkState {
         return byteBufferDestination;
     }
 
-    JsonTemplateLayout getJsonTemplateLayout4JsonLayout() {
+    Layout<String> getJsonTemplateLayout4JsonLayout() {
         return jsonTemplateLayout4JsonLayout;
     }
 
-    JsonTemplateLayout getJsonTemplateLayout4EcsLayout() {
+    Layout<String> getJsonTemplateLayout4EcsLayout() {
         return jsonTemplateLayout4EcsLayout;
     }
 
-    JsonTemplateLayout getJsonTemplateLayout4GelfLayout() {
+    Layout<String> getJsonTemplateLayout4GelfLayout() {
         return jsonTemplateLayout4GelfLayout;
     }
 
-    JsonLayout getDefaultJsonLayout() {
+    Layout<String> getDefaultJsonLayout() {
         return defaultJsonLayout;
     }
 
-    JsonLayout getCustomJsonLayout() {
+    Layout<String> getCustomJsonLayout() {
         return customJsonLayout;
     }
 
-    EcsLayout getEcsLayout() {
+    Layout<String> getEcsLayout() {
         return ecsLayout;
     }
 
-    GelfLayout getGelfLayout() {
+    Layout<String> getGelfLayout() {
         return gelfLayout;
     }
 

[logging-log4j2] 04/17: LOG4J2-3393 Improve "blackhole" behavior in ByteBuffer consumption.

Posted by vy...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

vy pushed a commit to branch LOG4J2-3393
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit b45c682ea33bec2200da3ce39f9dbbf0ea95c21e
Author: Volkan Yazici <vo...@yazi.ci>
AuthorDate: Mon Feb 14 22:57:30 2022 +0100

    LOG4J2-3393 Improve "blackhole" behavior in ByteBuffer consumption.
---
 .../layout/template/json/BlackHoleByteBufferDestination.java   | 10 ++++++++--
 .../layout/template/json/JsonTemplateLayoutBenchmark.java      |  9 +++++----
 2 files changed, 13 insertions(+), 6 deletions(-)

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..ca6041b 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,21 @@ class BlackHoleByteBufferDestination implements ByteBufferDestination {
 
     @Override
     public ByteBuffer drain(final ByteBuffer byteBuffer) {
+        byteBuffer.flip();
+        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-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 2f865fa..0b3ca8b 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
@@ -172,15 +172,16 @@ public class JsonTemplateLayoutBenchmark {
             final Layout<String> layout,
             final List<LogEvent> logEvents,
             final ByteBufferDestination destination) {
+        final ByteBuffer byteBuffer = destination.getByteBuffer();
+        int checksum = 0;
         // noinspection ForLoopReplaceableByForEach (avoid iterator instantiation)
         for (int logEventIndex = 0; logEventIndex < logEvents.size(); logEventIndex++) {
             LogEvent logEvent = logEvents.get(logEventIndex);
             layout.encode(logEvent, destination);
+            checksum += byteBuffer.position();
+            byteBuffer.clear();
         }
-        final ByteBuffer byteBuffer = destination.getByteBuffer();
-        final int position = byteBuffer.position();
-        byteBuffer.clear();
-        return position;
+        return checksum;
     }
 
     public static void main(String[] args) throws IOException {

[logging-log4j2] 15/17: LOG4J2-3393 Fix revapi issues.

Posted by vy...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

vy pushed a commit to branch LOG4J2-3393
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit 16950442c0aef219dc23dde6fed2e0c91396f4da
Author: Volkan Yazici <vo...@yazi.ci>
AuthorDate: Mon Feb 28 12:09:20 2022 +0100

    LOG4J2-3393 Fix revapi issues.
---
 log4j-layout-template-json/revapi.json | 1596 ++++++++++++++++++--------------
 1 file changed, 880 insertions(+), 716 deletions(-)

diff --git a/log4j-layout-template-json/revapi.json b/log4j-layout-template-json/revapi.json
index 5737d30..a9745c1 100644
--- a/log4j-layout-template-json/revapi.json
+++ b/log4j-layout-template-json/revapi.json
@@ -16,721 +16,885 @@
     }
   },
   {
-    "extension": "revapi.ignore",
-    "configuration": [
-      {
-        "code": "java.method.returnTypeChanged",
-        "old": "method org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.EventTemplateAdditionalFields org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.Builder::getEventTemplateAdditionalFields()",
-        "new": "method org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.EventTemplateAdditionalField[] org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.Builder::getEventTemplateAdditionalFields()",
-        "justification": "LOG4J2-2961 Refactored for simplicity since it was already broken due to missing @PluginBuilderAttribute annotations"
-      },
-      {
-        "code": "java.method.parameterTypeChanged",
-        "old": "parameter org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.Builder org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.Builder::setEventTemplateAdditionalFields(===org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.EventTemplateAdditionalFields===)",
-        "new": "parameter org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.Builder org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.Builder::setEventTemplateAdditionalFields(===org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.EventTemplateAdditionalField[]===)",
-        "justification": "LOG4J2-2961 Refactored for simplicity since it was already broken due to missing @PluginBuilderAttribute annotations"
-      },
-      {
-        "code": "java.class.removed",
-        "old": "class org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.EventTemplateAdditionalFields",
-        "justification": "LOG4J2-2961 Refactored for simplicity since it was already broken due to missing @PluginBuilderAttribute annotations"
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method java.lang.String org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults::getMdcKeyPattern()",
-        "justification": "Removed unused property getter."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method java.lang.String org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults::getNdcPattern()",
-        "justification": "Removed unused property getter."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method int java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::compareTo(E) @ org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method java.lang.Class<E> java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::getDeclaringClass() @ org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method java.lang.String java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::name() @ org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method int java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::ordinal() @ org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.class.noLongerImplementsInterface",
-        "old": "enum org.apache.logging.log4j.layout.template.json.util.Uris",
-        "new": "class org.apache.logging.log4j.layout.template.json.util.Uris",
-        "interface": "java.lang.Comparable<org.apache.logging.log4j.layout.template.json.util.Uris>",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.class.noLongerImplementsInterface",
-        "old": "enum org.apache.logging.log4j.layout.template.json.util.Uris",
-        "new": "class org.apache.logging.log4j.layout.template.json.util.Uris",
-        "interface": "java.io.Serializable",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method <T extends java.lang.Enum<T extends java.lang.Enum<T>>> T java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::valueOf(java.lang.Class<T>, java.lang.String) @ org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults::valueOf(java.lang.String)",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults[] org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults::values()",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.class.noLongerInheritsFromClass",
-        "old": "enum org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults",
-        "new": "class org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.class.kindChanged",
-        "old": "enum org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults",
-        "new": "class org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.class.noLongerImplementsInterface",
-        "old": "enum org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults",
-        "new": "class org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults",
-        "interface": "java.lang.Comparable<org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults>",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.class.noLongerImplementsInterface",
-        "old": "enum org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults",
-        "new": "class org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults",
-        "interface": "java.io.Serializable",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method int java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::compareTo(E) @ org.apache.logging.log4j.layout.template.json.resolver.TemplateResolvers",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method java.lang.Class<E> java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::getDeclaringClass() @ org.apache.logging.log4j.layout.template.json.resolver.TemplateResolvers",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method java.lang.String java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::name() @ org.apache.logging.log4j.layout.template.json.resolver.TemplateResolvers",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method int java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::ordinal() @ org.apache.logging.log4j.layout.template.json.resolver.TemplateResolvers",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method <T extends java.lang.Enum<T extends java.lang.Enum<T>>> T java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::valueOf(java.lang.Class<T>, java.lang.String) @ org.apache.logging.log4j.layout.template.json.resolver.TemplateResolvers",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method org.apache.logging.log4j.layout.template.json.resolver.TemplateResolvers org.apache.logging.log4j.layout.template.json.resolver.TemplateResolvers::valueOf(java.lang.String)",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method org.apache.logging.log4j.layout.template.json.resolver.TemplateResolvers[] org.apache.logging.log4j.layout.template.json.resolver.TemplateResolvers::values()",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.class.noLongerInheritsFromClass",
-        "old": "enum org.apache.logging.log4j.layout.template.json.resolver.TemplateResolvers",
-        "new": "class org.apache.logging.log4j.layout.template.json.resolver.TemplateResolvers",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.class.kindChanged",
-        "old": "enum org.apache.logging.log4j.layout.template.json.resolver.TemplateResolvers",
-        "new": "class org.apache.logging.log4j.layout.template.json.resolver.TemplateResolvers",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.class.noLongerImplementsInterface",
-        "old": "enum org.apache.logging.log4j.layout.template.json.resolver.TemplateResolvers",
-        "new": "class org.apache.logging.log4j.layout.template.json.resolver.TemplateResolvers",
-        "interface": "java.lang.Comparable<org.apache.logging.log4j.layout.template.json.resolver.TemplateResolvers>",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.class.noLongerImplementsInterface",
-        "old": "enum org.apache.logging.log4j.layout.template.json.resolver.TemplateResolvers",
-        "new": "class org.apache.logging.log4j.layout.template.json.resolver.TemplateResolvers",
-        "interface": "java.io.Serializable",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method int java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::compareTo(E) @ org.apache.logging.log4j.layout.template.json.util.RecyclerFactories",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method java.lang.Class<E> java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::getDeclaringClass() @ org.apache.logging.log4j.layout.template.json.util.RecyclerFactories",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method java.lang.String java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::name() @ org.apache.logging.log4j.layout.template.json.util.RecyclerFactories",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method int java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::ordinal() @ org.apache.logging.log4j.layout.template.json.util.RecyclerFactories",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method <T extends java.lang.Enum<T extends java.lang.Enum<T>>> T java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::valueOf(java.lang.Class<T>, java.lang.String) @ org.apache.logging.log4j.layout.template.json.util.RecyclerFactories",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method org.apache.logging.log4j.layout.template.json.util.RecyclerFactories org.apache.logging.log4j.layout.template.json.util.RecyclerFactories::valueOf(java.lang.String)",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method org.apache.logging.log4j.layout.template.json.util.RecyclerFactories[] org.apache.logging.log4j.layout.template.json.util.RecyclerFactories::values()",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.class.noLongerInheritsFromClass",
-        "old": "enum org.apache.logging.log4j.layout.template.json.util.RecyclerFactories",
-        "new": "class org.apache.logging.log4j.layout.template.json.util.RecyclerFactories",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.class.kindChanged",
-        "old": "enum org.apache.logging.log4j.layout.template.json.util.RecyclerFactories",
-        "new": "class org.apache.logging.log4j.layout.template.json.util.RecyclerFactories",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.class.noLongerImplementsInterface",
-        "old": "enum org.apache.logging.log4j.layout.template.json.util.RecyclerFactories",
-        "new": "class org.apache.logging.log4j.layout.template.json.util.RecyclerFactories",
-        "interface": "java.lang.Comparable<org.apache.logging.log4j.layout.template.json.util.RecyclerFactories>",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.class.noLongerImplementsInterface",
-        "old": "enum org.apache.logging.log4j.layout.template.json.util.RecyclerFactories",
-        "new": "class org.apache.logging.log4j.layout.template.json.util.RecyclerFactories",
-        "interface": "java.io.Serializable",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method int java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::compareTo(E) @ org.apache.logging.log4j.layout.template.json.util.StringParameterParser.Values",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method java.lang.Class<E> java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::getDeclaringClass() @ org.apache.logging.log4j.layout.template.json.util.StringParameterParser.Values",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method java.lang.String java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::name() @ org.apache.logging.log4j.layout.template.json.util.StringParameterParser.Values",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method int java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::ordinal() @ org.apache.logging.log4j.layout.template.json.util.StringParameterParser.Values",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method <T extends java.lang.Enum<T extends java.lang.Enum<T>>> T java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::valueOf(java.lang.Class<T>, java.lang.String) @ org.apache.logging.log4j.layout.template.json.util.StringParameterParser.Values",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method org.apache.logging.log4j.layout.template.json.util.StringParameterParser.Values org.apache.logging.log4j.layout.template.json.util.StringParameterParser.Values::valueOf(java.lang.String)",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method org.apache.logging.log4j.layout.template.json.util.StringParameterParser.Values[] org.apache.logging.log4j.layout.template.json.util.StringParameterParser.Values::values()",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.class.noLongerInheritsFromClass",
-        "old": "enum org.apache.logging.log4j.layout.template.json.util.StringParameterParser.Values",
-        "new": "class org.apache.logging.log4j.layout.template.json.util.StringParameterParser.Values",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.class.kindChanged",
-        "old": "enum org.apache.logging.log4j.layout.template.json.util.StringParameterParser.Values",
-        "new": "class org.apache.logging.log4j.layout.template.json.util.StringParameterParser.Values",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.class.noLongerImplementsInterface",
-        "old": "enum org.apache.logging.log4j.layout.template.json.util.StringParameterParser.Values",
-        "new": "class org.apache.logging.log4j.layout.template.json.util.StringParameterParser.Values",
-        "interface": "java.lang.Comparable<org.apache.logging.log4j.layout.template.json.util.StringParameterParser.Values>",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.class.noLongerImplementsInterface",
-        "old": "enum org.apache.logging.log4j.layout.template.json.util.StringParameterParser.Values",
-        "new": "class org.apache.logging.log4j.layout.template.json.util.StringParameterParser.Values",
-        "interface": "java.io.Serializable",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method int java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::compareTo(E) @ org.apache.logging.log4j.layout.template.json.util.StringParameterParser",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method java.lang.Class<E> java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::getDeclaringClass() @ org.apache.logging.log4j.layout.template.json.util.StringParameterParser",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method java.lang.String java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::name() @ org.apache.logging.log4j.layout.template.json.util.StringParameterParser",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method int java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::ordinal() @ org.apache.logging.log4j.layout.template.json.util.StringParameterParser",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method <T extends java.lang.Enum<T extends java.lang.Enum<T>>> T java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::valueOf(java.lang.Class<T>, java.lang.String) @ org.apache.logging.log4j.layout.template.json.util.StringParameterParser",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method org.apache.logging.log4j.layout.template.json.util.StringParameterParser org.apache.logging.log4j.layout.template.json.util.StringParameterParser::valueOf(java.lang.String)",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method org.apache.logging.log4j.layout.template.json.util.StringParameterParser[] org.apache.logging.log4j.layout.template.json.util.StringParameterParser::values()",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.class.noLongerInheritsFromClass",
-        "old": "enum org.apache.logging.log4j.layout.template.json.util.StringParameterParser",
-        "new": "class org.apache.logging.log4j.layout.template.json.util.StringParameterParser",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.class.kindChanged",
-        "old": "enum org.apache.logging.log4j.layout.template.json.util.StringParameterParser",
-        "new": "class org.apache.logging.log4j.layout.template.json.util.StringParameterParser",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.class.noLongerImplementsInterface",
-        "old": "enum org.apache.logging.log4j.layout.template.json.util.StringParameterParser",
-        "new": "class org.apache.logging.log4j.layout.template.json.util.StringParameterParser",
-        "interface": "java.lang.Comparable<org.apache.logging.log4j.layout.template.json.util.StringParameterParser>",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.class.noLongerImplementsInterface",
-        "old": "enum org.apache.logging.log4j.layout.template.json.util.StringParameterParser",
-        "new": "class org.apache.logging.log4j.layout.template.json.util.StringParameterParser",
-        "interface": "java.io.Serializable",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method int java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::compareTo(E) @ org.apache.logging.log4j.layout.template.json.util.Uris",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method java.lang.Class<E> java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::getDeclaringClass() @ org.apache.logging.log4j.layout.template.json.util.Uris",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method java.lang.String java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::name() @ org.apache.logging.log4j.layout.template.json.util.Uris",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method int java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::ordinal() @ org.apache.logging.log4j.layout.template.json.util.Uris",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method <T extends java.lang.Enum<T extends java.lang.Enum<T>>> T java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::valueOf(java.lang.Class<T>, java.lang.String) @ org.apache.logging.log4j.layout.template.json.util.Uris",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method org.apache.logging.log4j.layout.template.json.util.Uris org.apache.logging.log4j.layout.template.json.util.Uris::valueOf(java.lang.String)",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method org.apache.logging.log4j.layout.template.json.util.Uris[] org.apache.logging.log4j.layout.template.json.util.Uris::values()",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.class.noLongerInheritsFromClass",
-        "old": "enum org.apache.logging.log4j.layout.template.json.util.Uris",
-        "new": "class org.apache.logging.log4j.layout.template.json.util.Uris",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.class.kindChanged",
-        "old": "enum org.apache.logging.log4j.layout.template.json.util.Uris",
-        "new": "class org.apache.logging.log4j.layout.template.json.util.Uris",
-        "justification": "Replaced 'enum' singletons with 'final class'es."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method char[] org.apache.logging.log4j.layout.template.json.util.TruncatingBufferedPrintWriter::getBuffer()",
-        "justification": "LOG4J2-2993 Massaged (internal) API to make method names more Java-like and restrict access if possible."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method int org.apache.logging.log4j.layout.template.json.util.TruncatingBufferedPrintWriter::getCapacity()",
-        "justification": "LOG4J2-2993 Massaged (internal) API to make method names more Java-like and restrict access if possible."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method int org.apache.logging.log4j.layout.template.json.util.TruncatingBufferedPrintWriter::getPosition()",
-        "justification": "LOG4J2-2993 Massaged (internal) API to make method names more Java-like and restrict access if possible."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method boolean org.apache.logging.log4j.layout.template.json.util.TruncatingBufferedPrintWriter::isTruncated()",
-        "justification": "LOG4J2-2993 Massaged (internal) API to make method names more Java-like and restrict access if possible."
-      },
-      {
-        "code": "java.class.visibilityReduced",
-        "old": "class org.apache.logging.log4j.layout.template.json.util.TruncatingBufferedWriter",
-        "new": "class org.apache.logging.log4j.layout.template.json.util.TruncatingBufferedWriter",
-        "justification": "LOG4J2-2993 Massaged (internal) API to make method names more Java-like and restrict access if possible."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.EventTemplateAdditionalField.Builder org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.EventTemplateAdditionalField.Builder::setType(org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.EventTemplateAdditionalField.Type)",
-        "justification": "LOG4J2-2973 Rename EventTemplateAdditionalField#type (conflicting with properties file parser) to #format."
-      },
-      {
-        "code": "java.class.removed",
-        "old": "enum org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.EventTemplateAdditionalField.Type",
-        "justification": "LOG4J2-2973 Rename EventTemplateAdditionalField#type (conflicting with properties file parser) to #format."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.EventTemplateAdditionalField.Type org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.EventTemplateAdditionalField::getType()",
-        "justification": "LOG4J2-2973 Rename EventTemplateAdditionalField#type (conflicting with properties file parser) to #format."
-      },
-      {
-        "code": "java.annotation.added",
-        "old": "method org.apache.logging.log4j.layout.template.json.resolver.EndOfBatchResolverFactory org.apache.logging.log4j.layout.template.json.resolver.EndOfBatchResolverFactory::getInstance()",
-        "new": "method org.apache.logging.log4j.layout.template.json.resolver.EndOfBatchResolverFactory org.apache.logging.log4j.layout.template.json.resolver.EndOfBatchResolverFactory::getInstance()",
-        "annotation": "@org.apache.logging.log4j.core.config.plugins.PluginFactory",
-        "justification": "LOG4J2-3004 Add plugin support."
-      },
-      {
-        "code": "java.annotation.added",
-        "old": "class org.apache.logging.log4j.layout.template.json.resolver.EndOfBatchResolverFactory",
-        "new": "class org.apache.logging.log4j.layout.template.json.resolver.EndOfBatchResolverFactory",
-        "annotation": "@org.apache.logging.log4j.core.config.plugins.Plugin(name = \"EndOfBatchResolverFactory\", category = \"JsonTemplateResolverFactory\")",
-        "justification": "LOG4J2-3004 Add plugin support."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method java.lang.String org.apache.logging.log4j.layout.template.json.resolver.EventResolverContext.Builder::getTruncatedStringSuffix()",
-        "justification": "LOG4J2-3004 Add plugin support."
-      },
-      {
-        "code": "java.method.removed",
-        "old": "method org.apache.logging.log4j.layout.template.json.resolver.EventResolverContext.Builder org.apache.logging.log4j.layout.template.json.resolver.EventResolverContext.Builder::setStackTraceElementObjectResolver(org.apache.logging.log4j.layout.template.json.resolver.TemplateResolver<java.lang.StackTraceElement>)",
-        "justification": "LOG4J2-3004 Add plugin support."
-      },
-      {
-        "code": "java.method.parameterTypeChanged",
-        "old": "parameter org.apache.logging.log4j.layout.template.json.resolver.EventResolverContext.Builder org.apache.logging.log4j.layout.template.json.resolver.EventResolverContext.Builder::setSubstitutor(===org.apache.logging.log4j.core.lookup.StrSubstitutor===)",
-        "new": "parameter org.apache.logging.log4j.layout.template.json.resolver.EventResolverContext.Builder org.apache.logging.log4j.layout.template.json.resolver.EventResolverContext.Builder::setSubstitutor(===org.apache.logging.log4j.layout.template.json.resolver.EventResolverStringSubstitutor===)",
-        "justification": "LOG4J2-3004 Add plugin support."
-      },
-      {
-        "code": "java.method.returnTypeTypeParametersChanged",
-        "old": "method java.util.Map<java.lang.String, org.apache.logging.log4j.layout.template.json.resolver.TemplateResolverFactory<org.apache.logging.log4j.core.LogEvent, org.apache.logging.log4j.layout.template.json.resolver.EventResolverContext, ? extends org.apache.logging.log4j.layout.template.json.resolver.TemplateResolver<org.apache.logging.log4j.core.LogEvent>>> org.apache.logging.log4j.layout.template.json.resolver.EventResolverContext::getResolverFactoryByName()",
-        "new": "method java.util.Map<java.lang.String, org.apache.logging.log4j.layout.template.json.resolver.EventResolverFactory> org.apache.logging.log4j.layout.template.json.resolver.EventResolverContext::getResolverFactoryByName()",
-        "justification": "LOG4J2-3004 Add plugin support."
-      },
-      {
-        "code": "java.method.returnTypeChanged",
-        "old": "method org.apache.logging.log4j.core.lookup.StrSubstitutor org.apache.logging.log4j.layout.template.json.resolver.EventResolverContext::getSubstitutor()",
-        "new": "method org.apache.logging.log4j.layout.template.json.resolver.EventResolverStringSubstitutor org.apache.logging.log4j.layout.template.json.resolver.EventResolverContext::getSubstitutor()",
-        "justification": "LOG4J2-3004 Add plugin support."
-      },
-      {
-        "code": "java.annotation.added",
-        "old": "method org.apache.logging.log4j.layout.template.json.resolver.ExceptionResolverFactory org.apache.logging.log4j.layout.template.json.resolver.ExceptionResolverFactory::getInstance()",
-        "new": "method org.apache.logging.log4j.layout.template.json.resolver.ExceptionResolverFactory org.apache.logging.log4j.layout.template.json.resolver.ExceptionResolverFactory::getInstance()",
-        "annotation": "@org.apache.logging.log4j.core.config.plugins.PluginFactory",
-        "justification": "LOG4J2-3004 Add plugin support."
-      },
-      {
-        "code": "java.annotation.added",
-        "old": "class org.apache.logging.log4j.layout.template.json.resolver.ExceptionResolverFactory",
-        "new": "class org.apache.logging.log4j.layout.template.json.resolver.ExceptionResolverFactory",
-        "annotation": "@org.apache.logging.log4j.core.config.plugins.Plugin(name = \"ExceptionResolverFactory\", category = \"JsonTemplateResolverFactory\")",
-        "justification": "LOG4J2-3004 Add plugin support."
-      },
-      {
-        "code": "java.annotation.added",
-        "old": "method org.apache.logging.log4j.layout.template.json.resolver.ExceptionRootCauseResolverFactory org.apache.logging.log4j.layout.template.json.resolver.ExceptionRootCauseResolverFactory::getInstance()",
-        "new": "method org.apache.logging.log4j.layout.template.json.resolver.ExceptionRootCauseResolverFactory org.apache.logging.log4j.layout.template.json.resolver.ExceptionRootCauseResolverFactory::getInstance()",
-        "annotation": "@org.apache.logging.log4j.core.config.plugins.PluginFactory",
-        "justification": "LOG4J2-3004 Add plugin support."
-      },
-      {
-        "code": "java.annotation.added",
-        "old": "class org.apache.logging.log4j.layout.template.json.resolver.ExceptionRootCauseResolverFactory",
-        "new": "class org.apache.logging.log4j.layout.template.json.resolver.ExceptionRootCauseResolverFactory",
-        "annotation": "@org.apache.logging.log4j.core.config.plugins.Plugin(name = \"ExceptionRootCauseResolverFactory\", category = \"JsonTemplateResolverFactory\")",
-        "justification": "LOG4J2-3004 Add plugin support."
-      },
-      {
-        "code": "java.annotation.added",
-        "old": "method org.apache.logging.log4j.layout.template.json.resolver.LevelResolverFactory org.apache.logging.log4j.layout.template.json.resolver.LevelResolverFactory::getInstance()",
-        "new": "method org.apache.logging.log4j.layout.template.json.resolver.LevelResolverFactory org.apache.logging.log4j.layout.template.json.resolver.LevelResolverFactory::getInstance()",
-        "annotation": "@org.apache.logging.log4j.core.config.plugins.PluginFactory",
-        "justification": "LOG4J2-3004 Add plugin support."
-      },
-      {
-        "code": "java.annotation.added",
-        "old": "class org.apache.logging.log4j.layout.template.json.resolver.LevelResolverFactory",
-        "new": "class org.apache.logging.log4j.layout.template.json.resolver.LevelResolverFactory",
-        "annotation": "@org.apache.logging.log4j.core.config.plugins.Plugin(name = \"LevelResolverFactory\", category = \"JsonTemplateResolverFactory\")",
-        "justification": "LOG4J2-3004 Add plugin support."
-      },
-      {
-        "code": "java.annotation.added",
-        "old": "method org.apache.logging.log4j.layout.template.json.resolver.LoggerResolverFactory org.apache.logging.log4j.layout.template.json.resolver.LoggerResolverFactory::getInstance()",
-        "new": "method org.apache.logging.log4j.layout.template.json.resolver.LoggerResolverFactory org.apache.logging.log4j.layout.template.json.resolver.LoggerResolverFactory::getInstance()",
-        "annotation": "@org.apache.logging.log4j.core.config.plugins.PluginFactory",
-        "justification": "LOG4J2-3004 Add plugin support."
-      },
-      {
-        "code": "java.annotation.added",
-        "old": "class org.apache.logging.log4j.layout.template.json.resolver.LoggerResolverFactory",
-        "new": "class org.apache.logging.log4j.layout.template.json.resolver.LoggerResolverFactory",
-        "annotation": "@org.apache.logging.log4j.core.config.plugins.Plugin(name = \"LoggerResolverFactory\", category = \"JsonTemplateResolverFactory\")",
-        "justification": "LOG4J2-3004 Add plugin support."
-      },
-      {
-        "code": "java.annotation.added",
-        "old": "method org.apache.logging.log4j.layout.template.json.resolver.MainMapResolverFactory org.apache.logging.log4j.layout.template.json.resolver.MainMapResolverFactory::getInstance()",
-        "new": "method org.apache.logging.log4j.layout.template.json.resolver.MainMapResolverFactory org.apache.logging.log4j.layout.template.json.resolver.MainMapResolverFactory::getInstance()",
-        "annotation": "@org.apache.logging.log4j.core.config.plugins.PluginFactory",
-        "justification": "LOG4J2-3004 Add plugin support."
-      },
-      {
-        "code": "java.annotation.added",
-        "old": "class org.apache.logging.log4j.layout.template.json.resolver.MainMapResolverFactory",
-        "new": "class org.apache.logging.log4j.layout.template.json.resolver.MainMapResolverFactory",
-        "annotation": "@org.apache.logging.log4j.core.config.plugins.Plugin(name = \"MainMapResolverFactory\", category = \"JsonTemplateResolverFactory\")",
-        "justification": "LOG4J2-3004 Add plugin support."
-      },
-      {
-        "code": "java.annotation.added",
-        "old": "method org.apache.logging.log4j.layout.template.json.resolver.MapResolverFactory org.apache.logging.log4j.layout.template.json.resolver.MapResolverFactory::getInstance()",
-        "new": "method org.apache.logging.log4j.layout.template.json.resolver.MapResolverFactory org.apache.logging.log4j.layout.template.json.resolver.MapResolverFactory::getInstance()",
-        "annotation": "@org.apache.logging.log4j.core.config.plugins.PluginFactory",
-        "justification": "LOG4J2-3004 Add plugin support."
-      },
-      {
-        "code": "java.annotation.added",
-        "old": "class org.apache.logging.log4j.layout.template.json.resolver.MapResolverFactory",
-        "new": "class org.apache.logging.log4j.layout.template.json.resolver.MapResolverFactory",
-        "annotation": "@org.apache.logging.log4j.core.config.plugins.Plugin(name = \"MapResolverFactory\", category = \"JsonTemplateResolverFactory\")",
-        "justification": "LOG4J2-3004 Add plugin support."
-      },
-      {
-        "code": "java.annotation.added",
-        "old": "method org.apache.logging.log4j.layout.template.json.resolver.MarkerResolverFactory org.apache.logging.log4j.layout.template.json.resolver.MarkerResolverFactory::getInstance()",
-        "new": "method org.apache.logging.log4j.layout.template.json.resolver.MarkerResolverFactory org.apache.logging.log4j.layout.template.json.resolver.MarkerResolverFactory::getInstance()",
-        "annotation": "@org.apache.logging.log4j.core.config.plugins.PluginFactory",
-        "justification": "LOG4J2-3004 Add plugin support."
-      },
-      {
-        "code": "java.annotation.added",
-        "old": "class org.apache.logging.log4j.layout.template.json.resolver.MarkerResolverFactory",
-        "new": "class org.apache.logging.log4j.layout.template.json.resolver.MarkerResolverFactory",
-        "annotation": "@org.apache.logging.log4j.core.config.plugins.Plugin(name = \"MarkerResolverFactory\", category = \"JsonTemplateResolverFactory\")",
-        "justification": "LOG4J2-3004 Add plugin support."
-      },
-      {
-        "code": "java.annotation.added",
-        "old": "method org.apache.logging.log4j.layout.template.json.resolver.MessageParameterResolverFactory org.apache.logging.log4j.layout.template.json.resolver.MessageParameterResolverFactory::getInstance()",
-        "new": "method org.apache.logging.log4j.layout.template.json.resolver.MessageParameterResolverFactory org.apache.logging.log4j.layout.template.json.resolver.MessageParameterResolverFactory::getInstance()",
-        "annotation": "@org.apache.logging.log4j.core.config.plugins.PluginFactory",
-        "justification": "LOG4J2-3004 Add plugin support."
-      },
-      {
-        "code": "java.annotation.added",
-        "old": "class org.apache.logging.log4j.layout.template.json.resolver.MessageParameterResolverFactory",
-        "new": "class org.apache.logging.log4j.layout.template.json.resolver.MessageParameterResolverFactory",
-        "annotation": "@org.apache.logging.log4j.core.config.plugins.Plugin(name = \"MessageParameterResolverFactory\", category = \"JsonTemplateResolverFactory\")",
-        "justification": "LOG4J2-3004 Add plugin support."
-      },
-      {
-        "code": "java.annotation.added",
-        "old": "method org.apache.logging.log4j.layout.template.json.resolver.MessageResolverFactory org.apache.logging.log4j.layout.template.json.resolver.MessageResolverFactory::getInstance()",
-        "new": "method org.apache.logging.log4j.layout.template.json.resolver.MessageResolverFactory org.apache.logging.log4j.layout.template.json.resolver.MessageResolverFactory::getInstance()",
-        "annotation": "@org.apache.logging.log4j.core.config.plugins.PluginFactory",
-        "justification": "LOG4J2-3004 Add plugin support."
-      },
-      {
-        "code": "java.annotation.added",
-        "old": "class org.apache.logging.log4j.layout.template.json.resolver.MessageResolverFactory",
-        "new": "class org.apache.logging.log4j.layout.template.json.resolver.MessageResolverFactory",
-        "annotation": "@org.apache.logging.log4j.core.config.plugins.Plugin(name = \"MessageResolverFactory\", category = \"JsonTemplateResolverFactory\")",
-        "justification": "LOG4J2-3004 Add plugin support."
-      },
-      {
-        "code": "java.annotation.added",
-        "old": "method org.apache.logging.log4j.layout.template.json.resolver.PatternResolverFactory org.apache.logging.log4j.layout.template.json.resolver.PatternResolverFactory::getInstance()",
-        "new": "method org.apache.logging.log4j.layout.template.json.resolver.PatternResolverFactory org.apache.logging.log4j.layout.template.json.resolver.PatternResolverFactory::getInstance()",
-        "annotation": "@org.apache.logging.log4j.core.config.plugins.PluginFactory",
-        "justification": "LOG4J2-3004 Add plugin support."
-      },
-      {
-        "code": "java.annotation.added",
-        "old": "class org.apache.logging.log4j.layout.template.json.resolver.PatternResolverFactory",
-        "new": "class org.apache.logging.log4j.layout.template.json.resolver.PatternResolverFactory",
-        "annotation": "@org.apache.logging.log4j.core.config.plugins.Plugin(name = \"PatternResolverFactory\", category = \"JsonTemplateResolverFactory\")",
-        "justification": "LOG4J2-3004 Add plugin support."
-      },
-      {
-        "code": "java.annotation.added",
-        "old": "method org.apache.logging.log4j.layout.template.json.resolver.SourceResolverFactory org.apache.logging.log4j.layout.template.json.resolver.SourceResolverFactory::getInstance()",
-        "new": "method org.apache.logging.log4j.layout.template.json.resolver.SourceResolverFactory org.apache.logging.log4j.layout.template.json.resolver.SourceResolverFactory::getInstance()",
-        "annotation": "@org.apache.logging.log4j.core.config.plugins.PluginFactory",
-        "justification": "LOG4J2-3004 Add plugin support."
-      },
-      {
-        "code": "java.annotation.added",
-        "old": "class org.apache.logging.log4j.layout.template.json.resolver.SourceResolverFactory",
-        "new": "class org.apache.logging.log4j.layout.template.json.resolver.SourceResolverFactory",
-        "annotation": "@org.apache.logging.log4j.core.config.plugins.Plugin(name = \"SourceResolverFactory\", category = \"JsonTemplateResolverFactory\")",
-        "justification": "LOG4J2-3004 Add plugin support."
-      },
-      {
-        "code": "java.class.removed",
-        "old": "class org.apache.logging.log4j.layout.template.json.resolver.StackTraceElementObjectResolverContext",
-        "justification": "LOG4J2-3004 Add plugin support."
-      },
-      {
-        "code": "java.annotation.added",
-        "old": "method org.apache.logging.log4j.layout.template.json.resolver.ThreadContextDataResolverFactory org.apache.logging.log4j.layout.template.json.resolver.ThreadContextDataResolverFactory::getInstance()",
-        "new": "method org.apache.logging.log4j.layout.template.json.resolver.ThreadContextDataResolverFactory org.apache.logging.log4j.layout.template.json.resolver.ThreadContextDataResolverFactory::getInstance()",
-        "annotation": "@org.apache.logging.log4j.core.config.plugins.PluginFactory",
-        "justification": "LOG4J2-3004 Add plugin support."
-      },
-      {
-        "code": "java.annotation.added",
-        "old": "class org.apache.logging.log4j.layout.template.json.resolver.ThreadContextDataResolverFactory",
-        "new": "class org.apache.logging.log4j.layout.template.json.resolver.ThreadContextDataResolverFactory",
-        "annotation": "@org.apache.logging.log4j.core.config.plugins.Plugin(name = \"ThreadContextDataResolverFactory\", category = \"JsonTemplateResolverFactory\")",
-        "justification": "LOG4J2-3004 Add plugin support."
-      },
-      {
-        "code": "java.annotation.added",
-        "old": "method org.apache.logging.log4j.layout.template.json.resolver.ThreadContextStackResolverFactory org.apache.logging.log4j.layout.template.json.resolver.ThreadContextStackResolverFactory::getInstance()",
-        "new": "method org.apache.logging.log4j.layout.template.json.resolver.ThreadContextStackResolverFactory org.apache.logging.log4j.layout.template.json.resolver.ThreadContextStackResolverFactory::getInstance()",
-        "annotation": "@org.apache.logging.log4j.core.config.plugins.PluginFactory",
-        "justification": "LOG4J2-3004 Add plugin support."
-      },
-      {
-        "code": "java.annotation.added",
-        "old": "class org.apache.logging.log4j.layout.template.json.resolver.ThreadContextStackResolverFactory",
-        "new": "class org.apache.logging.log4j.layout.template.json.resolver.ThreadContextStackResolverFactory",
-        "annotation": "@org.apache.logging.log4j.core.config.plugins.Plugin(name = \"ThreadContextDataResolverFactory\", category = \"JsonTemplateResolverFactory\")",
-        "justification": "LOG4J2-3004 Add plugin support."
-      },
-      {
-        "code": "java.annotation.added",
-        "old": "method org.apache.logging.log4j.layout.template.json.resolver.ThreadResolverFactory org.apache.logging.log4j.layout.template.json.resolver.ThreadResolverFactory::getInstance()",
-        "new": "method org.apache.logging.log4j.layout.template.json.resolver.ThreadResolverFactory org.apache.logging.log4j.layout.template.json.resolver.ThreadResolverFactory::getInstance()",
-        "annotation": "@org.apache.logging.log4j.core.config.plugins.PluginFactory",
-        "justification": "LOG4J2-3004 Add plugin support."
-      },
-      {
-        "code": "java.annotation.added",
-        "old": "class org.apache.logging.log4j.layout.template.json.resolver.ThreadResolverFactory",
-        "new": "class org.apache.logging.log4j.layout.template.json.resolver.ThreadResolverFactory",
-        "annotation": "@org.apache.logging.log4j.core.config.plugins.Plugin(name = \"ThreadResolverFactory\", category = \"JsonTemplateResolverFactory\")",
-        "justification": "LOG4J2-3004 Add plugin support."
-      },
-      {
-        "code": "java.annotation.added",
-        "old": "method org.apache.logging.log4j.layout.template.json.resolver.TimestampResolverFactory org.apache.logging.log4j.layout.template.json.resolver.TimestampResolverFactory::getInstance()",
-        "new": "method org.apache.logging.log4j.layout.template.json.resolver.TimestampResolverFactory org.apache.logging.log4j.layout.template.json.resolver.TimestampResolverFactory::getInstance()",
-        "annotation": "@org.apache.logging.log4j.core.config.plugins.PluginFactory",
-        "justification": "LOG4J2-3004 Add plugin support."
-      },
-      {
-        "code": "java.annotation.added",
-        "old": "class org.apache.logging.log4j.layout.template.json.resolver.TimestampResolverFactory",
-        "new": "class org.apache.logging.log4j.layout.template.json.resolver.TimestampResolverFactory",
-        "annotation": "@org.apache.logging.log4j.core.config.plugins.Plugin(name = \"TimestampResolverFactory\", category = \"JsonTemplateResolverFactory\")",
-        "justification": "LOG4J2-3004 Add plugin support."
-      },
-      {
-        "code": "java.annotation.added",
-        "old": "class org.apache.logging.log4j.layout.template.json.resolver.ThreadContextStackResolverFactory",
-        "new": "class org.apache.logging.log4j.layout.template.json.resolver.ThreadContextStackResolverFactory",
-        "annotation": "@org.apache.logging.log4j.core.config.plugins.Plugin(name = \"ThreadContextStackResolverFactory\", category = \"JsonTemplateResolverFactory\")",
-        "justification": "LOG4J2-3004 Add plugin support."
-      },
-      {
-        "code": "java.annotation.attributeValueChanged",
-        "old": "class org.apache.logging.log4j.layout.template.json.util.RecyclerFactories.RecyclerFactoryConverter",
-        "new": "class org.apache.logging.log4j.layout.template.json.util.RecyclerFactories.RecyclerFactoryConverter",
-        "annotationType": "org.apache.logging.log4j.core.config.plugins.Plugin",
-        "attribute": "name",
-        "oldValue": "\"RecyclerFactory\"",
-        "newValue": "\"RecyclerFactoryConverter\"",
-        "justification": "LOG4J2-3004 Add plugin support."
-      },
-      {
-        "code": "java.class.removed",
-        "old": "class org.apache.logging.log4j.layout.template.json.util.RecyclerFactories.RecyclerFactoryConverter",
-        "justification": "LOG4J2-3004 Add plugin support."
-      }
-    ]
+    "extension": "revapi.differences",
+    "configuration": {
+      "differences": [
+        {
+          "ignore": true,
+          "code": "java.method.returnTypeChanged",
+          "old": "method org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.EventTemplateAdditionalFields org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.Builder::getEventTemplateAdditionalFields()",
+          "new": "method org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.EventTemplateAdditionalField[] org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.Builder::getEventTemplateAdditionalFields()",
+          "justification": "LOG4J2-2961 Refactored for simplicity since it was already broken due to missing @PluginBuilderAttribute annotations"
+        },
+        {
+          "ignore": true,
+          "code": "java.method.parameterTypeChanged",
+          "old": "parameter org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.Builder org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.Builder::setEventTemplateAdditionalFields(===org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.EventTemplateAdditionalFields===)",
+          "new": "parameter org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.Builder org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.Builder::setEventTemplateAdditionalFields(===org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.EventTemplateAdditionalField[]===)",
+          "justification": "LOG4J2-2961 Refactored for simplicity since it was already broken due to missing @PluginBuilderAttribute annotations"
+        },
+        {
+          "ignore": true,
+          "code": "java.class.removed",
+          "old": "class org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.EventTemplateAdditionalFields",
+          "justification": "LOG4J2-2961 Refactored for simplicity since it was already broken due to missing @PluginBuilderAttribute annotations"
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method java.lang.String org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults::getMdcKeyPattern()",
+          "justification": "Removed unused property getter."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method java.lang.String org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults::getNdcPattern()",
+          "justification": "Removed unused property getter."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method int java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::compareTo(E) @ org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method java.lang.Class<E> java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::getDeclaringClass() @ org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method java.lang.String java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::name() @ org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method int java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::ordinal() @ org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.class.noLongerImplementsInterface",
+          "old": "enum org.apache.logging.log4j.layout.template.json.util.Uris",
+          "new": "class org.apache.logging.log4j.layout.template.json.util.Uris",
+          "interface": "java.lang.Comparable<org.apache.logging.log4j.layout.template.json.util.Uris>",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.class.noLongerImplementsInterface",
+          "old": "enum org.apache.logging.log4j.layout.template.json.util.Uris",
+          "new": "class org.apache.logging.log4j.layout.template.json.util.Uris",
+          "interface": "java.io.Serializable",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method <T extends java.lang.Enum<T extends java.lang.Enum<T>>> T java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::valueOf(java.lang.Class<T>, java.lang.String) @ org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults::valueOf(java.lang.String)",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults[] org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults::values()",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.class.noLongerInheritsFromClass",
+          "old": "enum org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults",
+          "new": "class org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.class.kindChanged",
+          "old": "enum org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults",
+          "new": "class org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.class.noLongerImplementsInterface",
+          "old": "enum org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults",
+          "new": "class org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults",
+          "interface": "java.lang.Comparable<org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults>",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.class.noLongerImplementsInterface",
+          "old": "enum org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults",
+          "new": "class org.apache.logging.log4j.layout.template.json.JsonTemplateLayoutDefaults",
+          "interface": "java.io.Serializable",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method int java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::compareTo(E) @ org.apache.logging.log4j.layout.template.json.resolver.TemplateResolvers",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method java.lang.Class<E> java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::getDeclaringClass() @ org.apache.logging.log4j.layout.template.json.resolver.TemplateResolvers",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method java.lang.String java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::name() @ org.apache.logging.log4j.layout.template.json.resolver.TemplateResolvers",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method int java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::ordinal() @ org.apache.logging.log4j.layout.template.json.resolver.TemplateResolvers",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method <T extends java.lang.Enum<T extends java.lang.Enum<T>>> T java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::valueOf(java.lang.Class<T>, java.lang.String) @ org.apache.logging.log4j.layout.template.json.resolver.TemplateResolvers",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method org.apache.logging.log4j.layout.template.json.resolver.TemplateResolvers org.apache.logging.log4j.layout.template.json.resolver.TemplateResolvers::valueOf(java.lang.String)",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method org.apache.logging.log4j.layout.template.json.resolver.TemplateResolvers[] org.apache.logging.log4j.layout.template.json.resolver.TemplateResolvers::values()",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.class.noLongerInheritsFromClass",
+          "old": "enum org.apache.logging.log4j.layout.template.json.resolver.TemplateResolvers",
+          "new": "class org.apache.logging.log4j.layout.template.json.resolver.TemplateResolvers",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.class.kindChanged",
+          "old": "enum org.apache.logging.log4j.layout.template.json.resolver.TemplateResolvers",
+          "new": "class org.apache.logging.log4j.layout.template.json.resolver.TemplateResolvers",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.class.noLongerImplementsInterface",
+          "old": "enum org.apache.logging.log4j.layout.template.json.resolver.TemplateResolvers",
+          "new": "class org.apache.logging.log4j.layout.template.json.resolver.TemplateResolvers",
+          "interface": "java.lang.Comparable<org.apache.logging.log4j.layout.template.json.resolver.TemplateResolvers>",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.class.noLongerImplementsInterface",
+          "old": "enum org.apache.logging.log4j.layout.template.json.resolver.TemplateResolvers",
+          "new": "class org.apache.logging.log4j.layout.template.json.resolver.TemplateResolvers",
+          "interface": "java.io.Serializable",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method int java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::compareTo(E) @ org.apache.logging.log4j.layout.template.json.util.RecyclerFactories",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method java.lang.Class<E> java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::getDeclaringClass() @ org.apache.logging.log4j.layout.template.json.util.RecyclerFactories",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method java.lang.String java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::name() @ org.apache.logging.log4j.layout.template.json.util.RecyclerFactories",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method int java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::ordinal() @ org.apache.logging.log4j.layout.template.json.util.RecyclerFactories",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method <T extends java.lang.Enum<T extends java.lang.Enum<T>>> T java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::valueOf(java.lang.Class<T>, java.lang.String) @ org.apache.logging.log4j.layout.template.json.util.RecyclerFactories",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method org.apache.logging.log4j.layout.template.json.util.RecyclerFactories org.apache.logging.log4j.layout.template.json.util.RecyclerFactories::valueOf(java.lang.String)",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method org.apache.logging.log4j.layout.template.json.util.RecyclerFactories[] org.apache.logging.log4j.layout.template.json.util.RecyclerFactories::values()",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.class.noLongerInheritsFromClass",
+          "old": "enum org.apache.logging.log4j.layout.template.json.util.RecyclerFactories",
+          "new": "class org.apache.logging.log4j.layout.template.json.util.RecyclerFactories",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.class.kindChanged",
+          "old": "enum org.apache.logging.log4j.layout.template.json.util.RecyclerFactories",
+          "new": "class org.apache.logging.log4j.layout.template.json.util.RecyclerFactories",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.class.noLongerImplementsInterface",
+          "old": "enum org.apache.logging.log4j.layout.template.json.util.RecyclerFactories",
+          "new": "class org.apache.logging.log4j.layout.template.json.util.RecyclerFactories",
+          "interface": "java.lang.Comparable<org.apache.logging.log4j.layout.template.json.util.RecyclerFactories>",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.class.noLongerImplementsInterface",
+          "old": "enum org.apache.logging.log4j.layout.template.json.util.RecyclerFactories",
+          "new": "class org.apache.logging.log4j.layout.template.json.util.RecyclerFactories",
+          "interface": "java.io.Serializable",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method int java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::compareTo(E) @ org.apache.logging.log4j.layout.template.json.util.StringParameterParser.Values",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method java.lang.Class<E> java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::getDeclaringClass() @ org.apache.logging.log4j.layout.template.json.util.StringParameterParser.Values",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method java.lang.String java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::name() @ org.apache.logging.log4j.layout.template.json.util.StringParameterParser.Values",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method int java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::ordinal() @ org.apache.logging.log4j.layout.template.json.util.StringParameterParser.Values",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method <T extends java.lang.Enum<T extends java.lang.Enum<T>>> T java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::valueOf(java.lang.Class<T>, java.lang.String) @ org.apache.logging.log4j.layout.template.json.util.StringParameterParser.Values",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method org.apache.logging.log4j.layout.template.json.util.StringParameterParser.Values org.apache.logging.log4j.layout.template.json.util.StringParameterParser.Values::valueOf(java.lang.String)",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method org.apache.logging.log4j.layout.template.json.util.StringParameterParser.Values[] org.apache.logging.log4j.layout.template.json.util.StringParameterParser.Values::values()",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.class.noLongerInheritsFromClass",
+          "old": "enum org.apache.logging.log4j.layout.template.json.util.StringParameterParser.Values",
+          "new": "class org.apache.logging.log4j.layout.template.json.util.StringParameterParser.Values",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.class.kindChanged",
+          "old": "enum org.apache.logging.log4j.layout.template.json.util.StringParameterParser.Values",
+          "new": "class org.apache.logging.log4j.layout.template.json.util.StringParameterParser.Values",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.class.noLongerImplementsInterface",
+          "old": "enum org.apache.logging.log4j.layout.template.json.util.StringParameterParser.Values",
+          "new": "class org.apache.logging.log4j.layout.template.json.util.StringParameterParser.Values",
+          "interface": "java.lang.Comparable<org.apache.logging.log4j.layout.template.json.util.StringParameterParser.Values>",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.class.noLongerImplementsInterface",
+          "old": "enum org.apache.logging.log4j.layout.template.json.util.StringParameterParser.Values",
+          "new": "class org.apache.logging.log4j.layout.template.json.util.StringParameterParser.Values",
+          "interface": "java.io.Serializable",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method int java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::compareTo(E) @ org.apache.logging.log4j.layout.template.json.util.StringParameterParser",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method java.lang.Class<E> java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::getDeclaringClass() @ org.apache.logging.log4j.layout.template.json.util.StringParameterParser",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method java.lang.String java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::name() @ org.apache.logging.log4j.layout.template.json.util.StringParameterParser",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method int java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::ordinal() @ org.apache.logging.log4j.layout.template.json.util.StringParameterParser",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method <T extends java.lang.Enum<T extends java.lang.Enum<T>>> T java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::valueOf(java.lang.Class<T>, java.lang.String) @ org.apache.logging.log4j.layout.template.json.util.StringParameterParser",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method org.apache.logging.log4j.layout.template.json.util.StringParameterParser org.apache.logging.log4j.layout.template.json.util.StringParameterParser::valueOf(java.lang.String)",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method org.apache.logging.log4j.layout.template.json.util.StringParameterParser[] org.apache.logging.log4j.layout.template.json.util.StringParameterParser::values()",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.class.noLongerInheritsFromClass",
+          "old": "enum org.apache.logging.log4j.layout.template.json.util.StringParameterParser",
+          "new": "class org.apache.logging.log4j.layout.template.json.util.StringParameterParser",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.class.kindChanged",
+          "old": "enum org.apache.logging.log4j.layout.template.json.util.StringParameterParser",
+          "new": "class org.apache.logging.log4j.layout.template.json.util.StringParameterParser",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.class.noLongerImplementsInterface",
+          "old": "enum org.apache.logging.log4j.layout.template.json.util.StringParameterParser",
+          "new": "class org.apache.logging.log4j.layout.template.json.util.StringParameterParser",
+          "interface": "java.lang.Comparable<org.apache.logging.log4j.layout.template.json.util.StringParameterParser>",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.class.noLongerImplementsInterface",
+          "old": "enum org.apache.logging.log4j.layout.template.json.util.StringParameterParser",
+          "new": "class org.apache.logging.log4j.layout.template.json.util.StringParameterParser",
+          "interface": "java.io.Serializable",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method int java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::compareTo(E) @ org.apache.logging.log4j.layout.template.json.util.Uris",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method java.lang.Class<E> java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::getDeclaringClass() @ org.apache.logging.log4j.layout.template.json.util.Uris",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method java.lang.String java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::name() @ org.apache.logging.log4j.layout.template.json.util.Uris",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method int java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::ordinal() @ org.apache.logging.log4j.layout.template.json.util.Uris",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method <T extends java.lang.Enum<T extends java.lang.Enum<T>>> T java.lang.Enum<E extends java.lang.Enum<E extends java.lang.Enum<E>>>::valueOf(java.lang.Class<T>, java.lang.String) @ org.apache.logging.log4j.layout.template.json.util.Uris",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method org.apache.logging.log4j.layout.template.json.util.Uris org.apache.logging.log4j.layout.template.json.util.Uris::valueOf(java.lang.String)",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method org.apache.logging.log4j.layout.template.json.util.Uris[] org.apache.logging.log4j.layout.template.json.util.Uris::values()",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.class.noLongerInheritsFromClass",
+          "old": "enum org.apache.logging.log4j.layout.template.json.util.Uris",
+          "new": "class org.apache.logging.log4j.layout.template.json.util.Uris",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.class.kindChanged",
+          "old": "enum org.apache.logging.log4j.layout.template.json.util.Uris",
+          "new": "class org.apache.logging.log4j.layout.template.json.util.Uris",
+          "justification": "Replaced 'enum' singletons with 'final class'es."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method char[] org.apache.logging.log4j.layout.template.json.util.TruncatingBufferedPrintWriter::getBuffer()",
+          "justification": "LOG4J2-2993 Massaged (internal) API to make method names more Java-like and restrict access if possible."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method int org.apache.logging.log4j.layout.template.json.util.TruncatingBufferedPrintWriter::getCapacity()",
+          "justification": "LOG4J2-2993 Massaged (internal) API to make method names more Java-like and restrict access if possible."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method int org.apache.logging.log4j.layout.template.json.util.TruncatingBufferedPrintWriter::getPosition()",
+          "justification": "LOG4J2-2993 Massaged (internal) API to make method names more Java-like and restrict access if possible."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method boolean org.apache.logging.log4j.layout.template.json.util.TruncatingBufferedPrintWriter::isTruncated()",
+          "justification": "LOG4J2-2993 Massaged (internal) API to make method names more Java-like and restrict access if possible."
+        },
+        {
+          "ignore": true,
+          "code": "java.class.visibilityReduced",
+          "old": "class org.apache.logging.log4j.layout.template.json.util.TruncatingBufferedWriter",
+          "new": "class org.apache.logging.log4j.layout.template.json.util.TruncatingBufferedWriter",
+          "justification": "LOG4J2-2993 Massaged (internal) API to make method names more Java-like and restrict access if possible."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.EventTemplateAdditionalField.Builder org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.EventTemplateAdditionalField.Builder::setType(org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.EventTemplateAdditionalField.Type)",
+          "justification": "LOG4J2-2973 Rename EventTemplateAdditionalField#type (conflicting with properties file parser) to #format."
+        },
+        {
+          "ignore": true,
+          "code": "java.class.removed",
+          "old": "enum org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.EventTemplateAdditionalField.Type",
+          "justification": "LOG4J2-2973 Rename EventTemplateAdditionalField#type (conflicting with properties file parser) to #format."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.EventTemplateAdditionalField.Type org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.EventTemplateAdditionalField::getType()",
+          "justification": "LOG4J2-2973 Rename EventTemplateAdditionalField#type (conflicting with properties file parser) to #format."
+        },
+        {
+          "ignore": true,
+          "code": "java.annotation.added",
+          "old": "method org.apache.logging.log4j.layout.template.json.resolver.EndOfBatchResolverFactory org.apache.logging.log4j.layout.template.json.resolver.EndOfBatchResolverFactory::getInstance()",
+          "new": "method org.apache.logging.log4j.layout.template.json.resolver.EndOfBatchResolverFactory org.apache.logging.log4j.layout.template.json.resolver.EndOfBatchResolverFactory::getInstance()",
+          "annotation": "@org.apache.logging.log4j.core.config.plugins.PluginFactory",
+          "justification": "LOG4J2-3004 Add plugin support."
+        },
+        {
+          "ignore": true,
+          "code": "java.annotation.added",
+          "old": "class org.apache.logging.log4j.layout.template.json.resolver.EndOfBatchResolverFactory",
+          "new": "class org.apache.logging.log4j.layout.template.json.resolver.EndOfBatchResolverFactory",
+          "annotation": "@org.apache.logging.log4j.core.config.plugins.Plugin(name = \"EndOfBatchResolverFactory\", category = \"JsonTemplateResolverFactory\")",
+          "justification": "LOG4J2-3004 Add plugin support."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method java.lang.String org.apache.logging.log4j.layout.template.json.resolver.EventResolverContext.Builder::getTruncatedStringSuffix()",
+          "justification": "LOG4J2-3004 Add plugin support."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.removed",
+          "old": "method org.apache.logging.log4j.layout.template.json.resolver.EventResolverContext.Builder org.apache.logging.log4j.layout.template.json.resolver.EventResolverContext.Builder::setStackTraceElementObjectResolver(org.apache.logging.log4j.layout.template.json.resolver.TemplateResolver<java.lang.StackTraceElement>)",
+          "justification": "LOG4J2-3004 Add plugin support."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.parameterTypeChanged",
+          "old": "parameter org.apache.logging.log4j.layout.template.json.resolver.EventResolverContext.Builder org.apache.logging.log4j.layout.template.json.resolver.EventResolverContext.Builder::setSubstitutor(===org.apache.logging.log4j.core.lookup.StrSubstitutor===)",
+          "new": "parameter org.apache.logging.log4j.layout.template.json.resolver.EventResolverContext.Builder org.apache.logging.log4j.layout.template.json.resolver.EventResolverContext.Builder::setSubstitutor(===org.apache.logging.log4j.layout.template.json.resolver.EventResolverStringSubstitutor===)",
+          "justification": "LOG4J2-3004 Add plugin support."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.returnTypeTypeParametersChanged",
+          "old": "method java.util.Map<java.lang.String, org.apache.logging.log4j.layout.template.json.resolver.TemplateResolverFactory<org.apache.logging.log4j.core.LogEvent, org.apache.logging.log4j.layout.template.json.resolver.EventResolverContext, ? extends org.apache.logging.log4j.layout.template.json.resolver.TemplateResolver<org.apache.logging.log4j.core.LogEvent>>> org.apache.logging.log4j.layout.template.json.resolver.EventResolverContext::getResolverFactoryByName()",
+          "new": "method java.util.Map<java.lang.String, org.apache.logging.log4j.layout.template.json.resolver.EventResolverFactory> org.apache.logging.log4j.layout.template.json.resolver.EventResolverContext::getResolverFactoryByName()",
+          "justification": "LOG4J2-3004 Add plugin support."
+        },
+        {
+          "ignore": true,
+          "code": "java.method.returnTypeChanged",
+          "old": "method org.apache.logging.log4j.core.lookup.StrSubstitutor org.apache.logging.log4j.layout.template.json.resolver.EventResolverContext::getSubstitutor()",
+          "new": "method org.apache.logging.log4j.layout.template.json.resolver.EventResolverStringSubstitutor org.apache.logging.log4j.layout.template.json.resolver.EventResolverContext::getSubstitutor()",
+          "justification": "LOG4J2-3004 Add plugin support."
+        },
+        {
+          "ignore": true,
+          "code": "java.annotation.added",
+          "old": "method org.apache.logging.log4j.layout.template.json.resolver.ExceptionResolverFactory org.apache.logging.log4j.layout.template.json.resolver.ExceptionResolverFactory::getInstance()",
+          "new": "method org.apache.logging.log4j.layout.template.json.resolver.ExceptionResolverFactory org.apache.logging.log4j.layout.template.json.resolver.ExceptionResolverFactory::getInstance()",
+          "annotation": "@org.apache.logging.log4j.core.config.plugins.PluginFactory",
+          "justification": "LOG4J2-3004 Add plugin support."
+        },
+        {
+          "ignore": true,
+          "code": "java.annotation.added",
+          "old": "class org.apache.logging.log4j.layout.template.json.resolver.ExceptionResolverFactory",
+          "new": "class org.apache.logging.log4j.layout.template.json.resolver.ExceptionResolverFactory",
+          "annotation": "@org.apache.logging.log4j.core.config.plugins.Plugin(name = \"ExceptionResolverFactory\", category = \"JsonTemplateResolverFactory\")",
+          "justification": "LOG4J2-3004 Add plugin support."
+        },
+        {
+          "ignore": true,
+          "code": "java.annotation.added",
+          "old": "method org.apache.logging.log4j.layout.template.json.resolver.ExceptionRootCauseResolverFactory org.apache.logging.log4j.layout.template.json.resolver.ExceptionRootCauseResolverFactory::getInstance()",
+          "new": "method org.apache.logging.log4j.layout.template.json.resolver.ExceptionRootCauseResolverFactory org.apache.logging.log4j.layout.template.json.resolver.ExceptionRootCauseResolverFactory::getInstance()",
+          "annotation": "@org.apache.logging.log4j.core.config.plugins.PluginFactory",
+          "justification": "LOG4J2-3004 Add plugin support."
+        },
+        {
+          "ignore": true,
+          "code": "java.annotation.added",
+          "old": "class org.apache.logging.log4j.layout.template.json.resolver.ExceptionRootCauseResolverFactory",
+          "new": "class org.apache.logging.log4j.layout.template.json.resolver.ExceptionRootCauseResolverFactory",
+          "annotation": "@org.apache.logging.log4j.core.config.plugins.Plugin(name = \"ExceptionRootCauseResolverFactory\", category = \"JsonTemplateResolverFactory\")",
+          "justification": "LOG4J2-3004 Add plugin support."
+        },
+        {
+          "ignore": true,
+          "code": "java.annotation.added",
+          "old": "method org.apache.logging.log4j.layout.template.json.resolver.LevelResolverFactory org.apache.logging.log4j.layout.template.json.resolver.LevelResolverFactory::getInstance()",
+          "new": "method org.apache.logging.log4j.layout.template.json.resolver.LevelResolverFactory org.apache.logging.log4j.layout.template.json.resolver.LevelResolverFactory::getInstance()",
+          "annotation": "@org.apache.logging.log4j.core.config.plugins.PluginFactory",
+          "justification": "LOG4J2-3004 Add plugin support."
+        },
+        {
+          "ignore": true,
+          "code": "java.annotation.added",
+          "old": "class org.apache.logging.log4j.layout.template.json.resolver.LevelResolverFactory",
+          "new": "class org.apache.logging.log4j.layout.template.json.resolver.LevelResolverFactory",
+          "annotation": "@org.apache.logging.log4j.core.config.plugins.Plugin(name = \"LevelResolverFactory\", category = \"JsonTemplateResolverFactory\")",
+          "justification": "LOG4J2-3004 Add plugin support."
+        },
+        {
+          "ignore": true,
+          "code": "java.annotation.added",
+          "old": "method org.apache.logging.log4j.layout.template.json.resolver.LoggerResolverFactory org.apache.logging.log4j.layout.template.json.resolver.LoggerResolverFactory::getInstance()",
+          "new": "method org.apache.logging.log4j.layout.template.json.resolver.LoggerResolverFactory org.apache.logging.log4j.layout.template.json.resolver.LoggerResolverFactory::getInstance()",
+          "annotation": "@org.apache.logging.log4j.core.config.plugins.PluginFactory",
+          "justification": "LOG4J2-3004 Add plugin support."
+        },
+        {
+          "ignore": true,
+          "code": "java.annotation.added",
+          "old": "class org.apache.logging.log4j.layout.template.json.resolver.LoggerResolverFactory",
+          "new": "class org.apache.logging.log4j.layout.template.json.resolver.LoggerResolverFactory",
+          "annotation": "@org.apache.logging.log4j.core.config.plugins.Plugin(name = \"LoggerResolverFactory\", category = \"JsonTemplateResolverFactory\")",
+          "justification": "LOG4J2-3004 Add plugin support."
+        },
+        {
+          "ignore": true,
+          "code": "java.annotation.added",
+          "old": "method org.apache.logging.log4j.layout.template.json.resolver.MainMapResolverFactory org.apache.logging.log4j.layout.template.json.resolver.MainMapResolverFactory::getInstance()",
+          "new": "method org.apache.logging.log4j.layout.template.json.resolver.MainMapResolverFactory org.apache.logging.log4j.layout.template.json.resolver.MainMapResolverFactory::getInstance()",
+          "annotation": "@org.apache.logging.log4j.core.config.plugins.PluginFactory",
+          "justification": "LOG4J2-3004 Add plugin support."
+        },
+        {
+          "ignore": true,
+          "code": "java.annotation.added",
+          "old": "class org.apache.logging.log4j.layout.template.json.resolver.MainMapResolverFactory",
+          "new": "class org.apache.logging.log4j.layout.template.json.resolver.MainMapResolverFactory",
+          "annotation": "@org.apache.logging.log4j.core.config.plugins.Plugin(name = \"MainMapResolverFactory\", category = \"JsonTemplateResolverFactory\")",
+          "justification": "LOG4J2-3004 Add plugin support."
+        },
+        {
+          "ignore": true,
+          "code": "java.annotation.added",
+          "old": "method org.apache.logging.log4j.layout.template.json.resolver.MapResolverFactory org.apache.logging.log4j.layout.template.json.resolver.MapResolverFactory::getInstance()",
+          "new": "method org.apache.logging.log4j.layout.template.json.resolver.MapResolverFactory org.apache.logging.log4j.layout.template.json.resolver.MapResolverFactory::getInstance()",
+          "annotation": "@org.apache.logging.log4j.core.config.plugins.PluginFactory",
+          "justification": "LOG4J2-3004 Add plugin support."
+        },
+        {
+          "ignore": true,
+          "code": "java.annotation.added",
+          "old": "class org.apache.logging.log4j.layout.template.json.resolver.MapResolverFactory",
+          "new": "class org.apache.logging.log4j.layout.template.json.resolver.MapResolverFactory",
+          "annotation": "@org.apache.logging.log4j.core.config.plugins.Plugin(name = \"MapResolverFactory\", category = \"JsonTemplateResolverFactory\")",
+          "justification": "LOG4J2-3004 Add plugin support."
+        },
+        {
+          "ignore": true,
+          "code": "java.annotation.added",
+          "old": "method org.apache.logging.log4j.layout.template.json.resolver.MarkerResolverFactory org.apache.logging.log4j.layout.template.json.resolver.MarkerResolverFactory::getInstance()",
+          "new": "method org.apache.logging.log4j.layout.template.json.resolver.MarkerResolverFactory org.apache.logging.log4j.layout.template.json.resolver.MarkerResolverFactory::getInstance()",
+          "annotation": "@org.apache.logging.log4j.core.config.plugins.PluginFactory",
+          "justification": "LOG4J2-3004 Add plugin support."
+        },
+        {
+          "ignore": true,
+          "code": "java.annotation.added",
+          "old": "class org.apache.logging.log4j.layout.template.json.resolver.MarkerResolverFactory",
+          "new": "class org.apache.logging.log4j.layout.template.json.resolver.MarkerResolverFactory",
+          "annotation": "@org.apache.logging.log4j.core.config.plugins.Plugin(name = \"MarkerResolverFactory\", category = \"JsonTemplateResolverFactory\")",
+          "justification": "LOG4J2-3004 Add plugin support."
+        },
+        {
+          "ignore": true,
+          "code": "java.annotation.added",
+          "old": "method org.apache.logging.log4j.layout.template.json.resolver.MessageParameterResolverFactory org.apache.logging.log4j.layout.template.json.resolver.MessageParameterResolverFactory::getInstance()",
+          "new": "method org.apache.logging.log4j.layout.template.json.resolver.MessageParameterResolverFactory org.apache.logging.log4j.layout.template.json.resolver.MessageParameterResolverFactory::getInstance()",
+          "annotation": "@org.apache.logging.log4j.core.config.plugins.PluginFactory",
+          "justification": "LOG4J2-3004 Add plugin support."
+        },
+        {
+          "ignore": true,
+          "code": "java.annotation.added",
+          "old": "class org.apache.logging.log4j.layout.template.json.resolver.MessageParameterResolverFactory",
+          "new": "class org.apache.logging.log4j.layout.template.json.resolver.MessageParameterResolverFactory",
+          "annotation": "@org.apache.logging.log4j.core.config.plugins.Plugin(name = \"MessageParameterResolverFactory\", category = \"JsonTemplateResolverFactory\")",
+          "justification": "LOG4J2-3004 Add plugin support."
+        },
+        {
+          "ignore": true,
+          "code": "java.annotation.added",
+          "old": "method org.apache.logging.log4j.layout.template.json.resolver.MessageResolverFactory org.apache.logging.log4j.layout.template.json.resolver.MessageResolverFactory::getInstance()",
+          "new": "method org.apache.logging.log4j.layout.template.json.resolver.MessageResolverFactory org.apache.logging.log4j.layout.template.json.resolver.MessageResolverFactory::getInstance()",
+          "annotation": "@org.apache.logging.log4j.core.config.plugins.PluginFactory",
+          "justification": "LOG4J2-3004 Add plugin support."
+        },
+        {
+          "ignore": true,
+          "code": "java.annotation.added",
+          "old": "class org.apache.logging.log4j.layout.template.json.resolver.MessageResolverFactory",
+          "new": "class org.apache.logging.log4j.layout.template.json.resolver.MessageResolverFactory",
+          "annotation": "@org.apache.logging.log4j.core.config.plugins.Plugin(name = \"MessageResolverFactory\", category = \"JsonTemplateResolverFactory\")",
+          "justification": "LOG4J2-3004 Add plugin support."
+        },
+        {
+          "ignore": true,
+          "code": "java.annotation.added",
+          "old": "method org.apache.logging.log4j.layout.template.json.resolver.PatternResolverFactory org.apache.logging.log4j.layout.template.json.resolver.PatternResolverFactory::getInstance()",
+          "new": "method org.apache.logging.log4j.layout.template.json.resolver.PatternResolverFactory org.apache.logging.log4j.layout.template.json.resolver.PatternResolverFactory::getInstance()",
+          "annotation": "@org.apache.logging.log4j.core.config.plugins.PluginFactory",
+          "justification": "LOG4J2-3004 Add plugin support."
+        },
+        {
+          "ignore": true,
+          "code": "java.annotation.added",
+          "old": "class org.apache.logging.log4j.layout.template.json.resolver.PatternResolverFactory",
+          "new": "class org.apache.logging.log4j.layout.template.json.resolver.PatternResolverFactory",
+          "annotation": "@org.apache.logging.log4j.core.config.plugins.Plugin(name = \"PatternResolverFactory\", category = \"JsonTemplateResolverFactory\")",
+          "justification": "LOG4J2-3004 Add plugin support."
+        },
+        {
+          "ignore": true,
+          "code": "java.annotation.added",
+          "old": "method org.apache.logging.log4j.layout.template.json.resolver.SourceResolverFactory org.apache.logging.log4j.layout.template.json.resolver.SourceResolverFactory::getInstance()",
+          "new": "method org.apache.logging.log4j.layout.template.json.resolver.SourceResolverFactory org.apache.logging.log4j.layout.template.json.resolver.SourceResolverFactory::getInstance()",
+          "annotation": "@org.apache.logging.log4j.core.config.plugins.PluginFactory",
+          "justification": "LOG4J2-3004 Add plugin support."
+        },
+        {
+          "ignore": true,
+          "code": "java.annotation.added",
+          "old": "class org.apache.logging.log4j.layout.template.json.resolver.SourceResolverFactory",
+          "new": "class org.apache.logging.log4j.layout.template.json.resolver.SourceResolverFactory",
+          "annotation": "@org.apache.logging.log4j.core.config.plugins.Plugin(name = \"SourceResolverFactory\", category = \"JsonTemplateResolverFactory\")",
+          "justification": "LOG4J2-3004 Add plugin support."
+        },
+        {
+          "ignore": true,
+          "code": "java.class.removed",
+          "old": "class org.apache.logging.log4j.layout.template.json.resolver.StackTraceElementObjectResolverContext",
+          "justification": "LOG4J2-3004 Add plugin support."
+        },
+        {
+          "ignore": true,
+          "code": "java.annotation.added",
+          "old": "method org.apache.logging.log4j.layout.template.json.resolver.ThreadContextDataResolverFactory org.apache.logging.log4j.layout.template.json.resolver.ThreadContextDataResolverFactory::getInstance()",
+          "new": "method org.apache.logging.log4j.layout.template.json.resolver.ThreadContextDataResolverFactory org.apache.logging.log4j.layout.template.json.resolver.ThreadContextDataResolverFactory::getInstance()",
+          "annotation": "@org.apache.logging.log4j.core.config.plugins.PluginFactory",
+          "justification": "LOG4J2-3004 Add plugin support."
+        },
+        {
+          "ignore": true,
+          "code": "java.annotation.added",
+          "old": "class org.apache.logging.log4j.layout.template.json.resolver.ThreadContextDataResolverFactory",
+          "new": "class org.apache.logging.log4j.layout.template.json.resolver.ThreadContextDataResolverFactory",
+          "annotation": "@org.apache.logging.log4j.core.config.plugins.Plugin(name = \"ThreadContextDataResolverFactory\", category = \"JsonTemplateResolverFactory\")",
+          "justification": "LOG4J2-3004 Add plugin support."
+        },
+        {
+          "ignore": true,
+          "code": "java.annotation.added",
+          "old": "method org.apache.logging.log4j.layout.template.json.resolver.ThreadContextStackResolverFactory org.apache.logging.log4j.layout.template.json.resolver.ThreadContextStackResolverFactory::getInstance()",
+          "new": "method org.apache.logging.log4j.layout.template.json.resolver.ThreadContextStackResolverFactory org.apache.logging.log4j.layout.template.json.resolver.ThreadContextStackResolverFactory::getInstance()",
+          "annotation": "@org.apache.logging.log4j.core.config.plugins.PluginFactory",
+          "justification": "LOG4J2-3004 Add plugin support."
+        },
+        {
+          "ignore": true,
+          "code": "java.annotation.added",
+          "old": "class org.apache.logging.log4j.layout.template.json.resolver.ThreadContextStackResolverFactory",
+          "new": "class org.apache.logging.log4j.layout.template.json.resolver.ThreadContextStackResolverFactory",
+          "annotation": "@org.apache.logging.log4j.core.config.plugins.Plugin(name = \"ThreadContextDataResolverFactory\", category = \"JsonTemplateResolverFactory\")",
+          "justification": "LOG4J2-3004 Add plugin support."
+        },
+        {
+          "ignore": true,
+          "code": "java.annotation.added",
+          "old": "method org.apache.logging.log4j.layout.template.json.resolver.ThreadResolverFactory org.apache.logging.log4j.layout.template.json.resolver.ThreadResolverFactory::getInstance()",
+          "new": "method org.apache.logging.log4j.layout.template.json.resolver.ThreadResolverFactory org.apache.logging.log4j.layout.template.json.resolver.ThreadResolverFactory::getInstance()",
+          "annotation": "@org.apache.logging.log4j.core.config.plugins.PluginFactory",
+          "justification": "LOG4J2-3004 Add plugin support."
+        },
+        {
+          "ignore": true,
+          "code": "java.annotation.added",
+          "old": "class org.apache.logging.log4j.layout.template.json.resolver.ThreadResolverFactory",
+          "new": "class org.apache.logging.log4j.layout.template.json.resolver.ThreadResolverFactory",
+          "annotation": "@org.apache.logging.log4j.core.config.plugins.Plugin(name = \"ThreadResolverFactory\", category = \"JsonTemplateResolverFactory\")",
+          "justification": "LOG4J2-3004 Add plugin support."
+        },
+        {
+          "ignore": true,
+          "code": "java.annotation.added",
+          "old": "method org.apache.logging.log4j.layout.template.json.resolver.TimestampResolverFactory org.apache.logging.log4j.layout.template.json.resolver.TimestampResolverFactory::getInstance()",
+          "new": "method org.apache.logging.log4j.layout.template.json.resolver.TimestampResolverFactory org.apache.logging.log4j.layout.template.json.resolver.TimestampResolverFactory::getInstance()",
+          "annotation": "@org.apache.logging.log4j.core.config.plugins.PluginFactory",
+          "justification": "LOG4J2-3004 Add plugin support."
+        },
+        {
+          "ignore": true,
+          "code": "java.annotation.added",
+          "old": "class org.apache.logging.log4j.layout.template.json.resolver.TimestampResolverFactory",
+          "new": "class org.apache.logging.log4j.layout.template.json.resolver.TimestampResolverFactory",
+          "annotation": "@org.apache.logging.log4j.core.config.plugins.Plugin(name = \"TimestampResolverFactory\", category = \"JsonTemplateResolverFactory\")",
+          "justification": "LOG4J2-3004 Add plugin support."
+        },
+        {
+          "ignore": true,
+          "code": "java.annotation.added",
+          "old": "class org.apache.logging.log4j.layout.template.json.resolver.ThreadContextStackResolverFactory",
+          "new": "class org.apache.logging.log4j.layout.template.json.resolver.ThreadContextStackResolverFactory",
+          "annotation": "@org.apache.logging.log4j.core.config.plugins.Plugin(name = \"ThreadContextStackResolverFactory\", category = \"JsonTemplateResolverFactory\")",
+          "justification": "LOG4J2-3004 Add plugin support."
+        },
+        {
+          "ignore": true,
+          "code": "java.annotation.attributeValueChanged",
+          "old": "class org.apache.logging.log4j.layout.template.json.util.RecyclerFactories.RecyclerFactoryConverter",
+          "new": "class org.apache.logging.log4j.layout.template.json.util.RecyclerFactories.RecyclerFactoryConverter",
+          "annotationType": "org.apache.logging.log4j.core.config.plugins.Plugin",
+          "attribute": "name",
+          "oldValue": "\"RecyclerFactory\"",
+          "newValue": "\"RecyclerFactoryConverter\"",
+          "justification": "LOG4J2-3004 Add plugin support."
+        },
+        {
+          "ignore": true,
+          "code": "java.class.removed",
+          "old": "class org.apache.logging.log4j.layout.template.json.util.RecyclerFactories.RecyclerFactoryConverter",
+          "justification": "LOG4J2-3004 Add plugin support."
+        },
+        {
+          "ignore": true,
+          "code": "java.class.externalClassExposedInAPI",
+          "new": "missing-class org.apache.logging.log4j.util.IndexedReadOnlyStringMap",
+          "justification": "Used by org.apache.logging.log4j.layout.template.json.util.JsonWriter."
+        },
+        {
+          "ignore": true,
+          "code": "java.missing.newClass",
+          "new": "missing-class org.apache.logging.log4j.util.IndexedReadOnlyStringMap",
+          "justification": "Used by org.apache.logging.log4j.layout.template.json.util.JsonWriter."
+        },
+        {
+          "ignore": true,
+          "code": "java.class.externalClassExposedInAPI",
+          "new": "missing-class org.apache.logging.log4j.util.StringBuilderFormattable",
+          "justification": "Used by org.apache.logging.log4j.layout.template.json.util.JsonWriter."
+        },
+        {
+          "ignore": true,
+          "code": "java.missing.newClass",
+          "new": "missing-class org.apache.logging.log4j.util.StringBuilderFormattable",
+          "justification": "Used by org.apache.logging.log4j.layout.template.json.util.JsonWriter."
+        },
+        {
+          "ignore": true,
+          "code": "java.class.externalClassExposedInAPI",
+          "new": "missing-class org.apache.logging.log4j.util.StringMap",
+          "justification": "Used by org.apache.logging.log4j.layout.template.json.util.JsonWriter."
+        },
+        {
+          "ignore": true,
+          "code": "java.missing.newClass",
+          "new": "missing-class org.apache.logging.log4j.util.StringMap",
+          "justification": "Used by org.apache.logging.log4j.layout.template.json.util.JsonWriter."
+        },
+        {
+          "ignore": true,
+          "code": "java.class.nonPublicPartOfAPI",
+          "new": "interface org.apache.logging.log4j.layout.template.json.resolver.TemplateResolverContext<V, C extends org.apache.logging.log4j.layout.template.json.resolver.TemplateResolverContext<V, C>>",
+          "justification": "LOG4J2-3004 Add plugin support."
+        }
+      ]
+    }
   }
 ]

[logging-log4j2] 10/17: LOG4J2-3393 Inline context acquisition in JsonTemplateLayout.

Posted by vy...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

vy pushed a commit to branch LOG4J2-3393
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit f5b172e9b4525042b3205e3d3b0fafb803f9a419
Author: Volkan Yazici <vo...@yazi.ci>
AuthorDate: Mon Feb 21 21:48:52 2022 +0100

    LOG4J2-3393 Inline context acquisition in JsonTemplateLayout.
---
 .../layout/template/json/JsonTemplateLayout.java   | 30 +++++++++++-----------
 1 file changed, 15 insertions(+), 15 deletions(-)

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 8747c98..5e36817 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
@@ -73,8 +73,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;
 
@@ -259,36 +258,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.
             encoder.encode(stringBuilder, destination);
-
         }
 
         // Release the context.
@@ -298,11 +303,6 @@ public class JsonTemplateLayout implements StringLayout {
 
     }
 
-    // Visible for tests.
-    Context acquireContext() {
-        return contextRecycler.acquire();
-    }
-
     @Override
     public byte[] getFooter() {
         return null;

[logging-log4j2] 01/17: LOG4J2-3393 Refactor JTL TemplateResolvers into smaller components.

Posted by vy...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

vy pushed a commit to branch LOG4J2-3393
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit f3a8d4f535b1e862b3362147b594859491e47907
Author: Volkan Yazici <vo...@yazi.ci>
AuthorDate: Mon Feb 7 10:53:48 2022 +0100

    LOG4J2-3393 Refactor JTL TemplateResolvers into smaller components.
---
 .../template/json/resolver/TemplateResolvers.java  | 224 +++++++++++++++------
 1 file changed, 160 insertions(+), 64 deletions(-)

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 20ad802..450b874 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.
@@ -192,6 +193,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 +227,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 +239,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();
+        }
 
     }
 

[logging-log4j2] 13/17: LOG4J2-3393 Make JsonWriter garbage-free for StringMaps.

Posted by vy...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

vy pushed a commit to branch LOG4J2-3393
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit aaef74c3c9fa18dda4dd4b3b15769cacdf219cb1
Author: Volkan Yazici <vo...@yazi.ci>
AuthorDate: Mon Feb 28 11:26:03 2022 +0100

    LOG4J2-3393 Make JsonWriter garbage-free for StringMaps.
---
 .../layout/template/json/util/JsonWriter.java      | 26 ++++++++++++----------
 1 file changed, 14 insertions(+), 12 deletions(-)

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 2d5df72..991ef5b 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
@@ -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();

[logging-log4j2] 14/17: LOG4J2-3393 Clean-up wrong BiConsumer usages.

Posted by vy...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

vy pushed a commit to branch LOG4J2-3393
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit 04a8214215471f0f4c74410904e4a161f6f6fdb6
Author: Volkan Yazici <vo...@yazi.ci>
AuthorDate: Mon Feb 28 11:26:37 2022 +0100

    LOG4J2-3393 Clean-up wrong BiConsumer usages.
---
 .../logging/log4j/layout/template/json/resolver/PatternResolver.java    | 2 +-
 .../org/apache/logging/log4j/layout/template/json/util/JsonWriter.java  | 2 +-
 .../apache/logging/log4j/layout/template/json/util/JsonWriterTest.java  | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

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 8cd2991..02ffcf9 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/util/JsonWriter.java b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/JsonWriter.java
index 991ef5b..300c7c1 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.
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;
 

[logging-log4j2] 11/17: LOG4J2-3393 JTL benchmark updates.

Posted by vy...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

vy pushed a commit to branch LOG4J2-3393
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit 041dd8a23b7cd53a3f5f0833f4fbdf3ffe60255a
Author: Volkan Yazici <vo...@yazi.ci>
AuthorDate: Mon Feb 21 21:49:34 2022 +0100

    LOG4J2-3393 JTL benchmark updates.
---
 .../log4j/layout/template/json/JsonTemplateLayoutBenchmark.java    | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

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 58c5852..0ee01b8 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
@@ -190,9 +190,14 @@ public class JsonTemplateLayoutBenchmark {
 //        System.out.format("Ready?");
 //        System.in.read();
         JsonTemplateLayoutBenchmarkState state = new JsonTemplateLayoutBenchmarkState();
-        int retryCount = 200_000_000;
+        int retryCount = 500_000_000;
         measureEcs(state, retryCount);
         measureJtl(state, retryCount);
+//        while (true) {
+//            measureEcs(state, retryCount);
+//        }
+//        measureEcs(state, retryCount);
+//        measureJtl(state, retryCount);
     }
 
     private static void measureJtl(JsonTemplateLayoutBenchmarkState state, int retryCount) {

[logging-log4j2] 17/17: LOG4J2-3393 Clean up LcsLayout and all other mess.

Posted by vy...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

vy pushed a commit to branch LOG4J2-3393
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit 51e5112235cf25a8f965df5a2f763219dbf9c24a
Author: Volkan Yazici <vo...@yazi.ci>
AuthorDate: Mon Mar 14 22:03:44 2022 +0100

    LOG4J2-3393 Clean up LcsLayout and all other mess.
---
 .../java/co/elastic/logging/log4j2/LcsLayout.java  | 390 ---------------------
 .../template/json/JsonTemplateLayoutBenchmark.java |  66 +---
 .../json/JsonTemplateLayoutBenchmarkState.java     |  57 ++-
 3 files changed, 47 insertions(+), 466 deletions(-)

diff --git a/log4j-perf/src/main/java/co/elastic/logging/log4j2/LcsLayout.java b/log4j-perf/src/main/java/co/elastic/logging/log4j2/LcsLayout.java
deleted file mode 100644
index 07d0f86..0000000
--- a/log4j-perf/src/main/java/co/elastic/logging/log4j2/LcsLayout.java
+++ /dev/null
@@ -1,390 +0,0 @@
-package co.elastic.logging.log4j2;
-
-
-import co.elastic.logging.EcsJsonSerializer;
-import co.elastic.logging.JsonUtils;
-import org.apache.logging.log4j.Marker;
-import org.apache.logging.log4j.ThreadContext;
-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.Node;
-import org.apache.logging.log4j.core.config.plugins.Plugin;
-import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
-import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
-import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
-import org.apache.logging.log4j.core.config.plugins.PluginElement;
-import org.apache.logging.log4j.core.layout.AbstractStringLayout;
-import org.apache.logging.log4j.core.layout.ByteBufferDestination;
-import org.apache.logging.log4j.core.layout.Encoder;
-import org.apache.logging.log4j.core.layout.PatternLayout;
-import org.apache.logging.log4j.core.lookup.StrSubstitutor;
-import org.apache.logging.log4j.core.pattern.PatternFormatter;
-import org.apache.logging.log4j.core.util.KeyValuePair;
-import org.apache.logging.log4j.message.Message;
-import org.apache.logging.log4j.message.MultiformatMessage;
-import org.apache.logging.log4j.message.ObjectMessage;
-import org.apache.logging.log4j.util.StringBuilderFormattable;
-
-import java.nio.charset.Charset;
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
-@Plugin(name = "LcsLayout", category = Node.CATEGORY, elementType = Layout.ELEMENT_TYPE)
-public class LcsLayout extends AbstractStringLayout {
-
-    public static final Charset UTF_8 = Charset.forName("UTF-8");
-    private static final ObjectMessageJacksonSerializer JACKSON_SERIALIZER = ObjectMessageJacksonSerializer.Resolver.resolve();
-    private static final MdcSerializer MDC_SERIALIZER = MdcSerializer.Resolver.resolve();
-    private static final MultiFormatHandler MULTI_FORMAT_HANDLER = MultiFormatHandler.Resolver.resolve();
-
-    private final KeyValuePair[] additionalFields;
-    private final PatternFormatter[][] fieldValuePatternFormatter;
-    private final boolean stackTraceAsArray;
-    private final String serviceName;
-    private final String eventDataset;
-    private final boolean includeMarkers;
-    private final boolean includeOrigin;
-    private final ConcurrentMap<Class<? extends MultiformatMessage>, Boolean> supportsJson = new ConcurrentHashMap<Class<? extends MultiformatMessage>, Boolean>();
-
-    private LcsLayout(Configuration config, String serviceName, String eventDataset, boolean includeMarkers, KeyValuePair[] additionalFields, boolean includeOrigin, boolean stackTraceAsArray) {
-        super(config, UTF_8, null, null);
-        this.serviceName = serviceName;
-        this.eventDataset = eventDataset;
-        this.includeMarkers = includeMarkers;
-        this.includeOrigin = includeOrigin;
-        this.stackTraceAsArray = stackTraceAsArray;
-        this.additionalFields = additionalFields;
-        fieldValuePatternFormatter = new PatternFormatter[additionalFields.length][];
-        for (int i = 0; i < additionalFields.length; i++) {
-            KeyValuePair additionalField = additionalFields[i];
-            if (additionalField.getValue().contains("%")) {
-                fieldValuePatternFormatter[i] = PatternLayout.createPatternParser(config)
-                        .parse(additionalField.getValue())
-                        .toArray(new PatternFormatter[0]);
-            }
-        }
-    }
-
-    @PluginBuilderFactory
-    public static LcsLayout.Builder newBuilder() {
-        return new LcsLayout.Builder();
-    }
-
-    private static boolean valueNeedsLookup(final String value) {
-        return value != null && value.contains("${");
-    }
-
-    @Override
-    public String toSerializable(LogEvent event) {
-        final StringBuilder text = toText(event, getStringBuilder(), false);
-        return text.toString();
-    }
-
-    @Override
-    public void encode(LogEvent event, ByteBufferDestination destination) {
-        final StringBuilder text = toText(event, getStringBuilder(), true);
-        final Encoder<StringBuilder> helper = getStringBuilderEncoder();
-        helper.encode(text, destination);
-    }
-
-    @Override
-    public String getContentType() {
-        return "application/json";
-    }
-
-    private StringBuilder toText(LogEvent event, StringBuilder builder, boolean gcFree) {
-        builder.append('{');//EcsJsonSerializer.serializeObjectStart(builder, event.getTimeMillis());
-//        EcsJsonSerializer.serializeLogLevel(builder, event.getLevel().toString());
-//        serializeMessage(builder, gcFree, event.getMessage(), event.getThrown());
-//        EcsJsonSerializer.serializeEcsVersion(builder);
-//        EcsJsonSerializer.serializeServiceName(builder, serviceName);
-//        EcsJsonSerializer.serializeEventDataset(builder, eventDataset);
-//        EcsJsonSerializer.serializeThreadName(builder, event.getThreadName());
-//        EcsJsonSerializer.serializeLoggerName(builder, event.getLoggerName());
-//        serializeAdditionalFieldsAndMDC(event, builder);
-//        serializeTags(event, builder);
-//        if (includeOrigin) {
-//            EcsJsonSerializer.serializeOrigin(builder, event.getSource());
-//        }
-//        EcsJsonSerializer.serializeException(builder, event.getThrown(), stackTraceAsArray);
-        EcsJsonSerializer.serializeObjectEnd(builder);
-        return builder;
-    }
-
-    private void serializeAdditionalFieldsAndMDC(LogEvent event, StringBuilder builder) {
-        final int length = additionalFields.length;
-        if (length > 0) {
-            final StrSubstitutor strSubstitutor = getConfiguration().getStrSubstitutor();
-            for (int i = 0; i < length; i++) {
-                KeyValuePair additionalField = additionalFields[i];
-                PatternFormatter[] formatters = fieldValuePatternFormatter[i];
-                CharSequence value = null;
-                if (formatters != null) {
-                    StringBuilder buffer = EcsJsonSerializer.getMessageStringBuilder();
-                    formatPattern(event, formatters, buffer);
-                    if (buffer.length() > 0) {
-                        value = buffer;
-                    }
-                } else if (valueNeedsLookup(additionalField.getValue())) {
-                    StringBuilder lookupValue = EcsJsonSerializer.getMessageStringBuilder();
-                    lookupValue.append(additionalField.getValue());
-                    if (strSubstitutor.replaceIn(event, lookupValue)) {
-                        value = lookupValue;
-                    }
-                } else {
-                    value = additionalField.getValue();
-                }
-
-                if (value != null) {
-                    builder.append('\"');
-                    JsonUtils.quoteAsString(additionalField.getKey(), builder);
-                    builder.append("\":\"");
-                    JsonUtils.quoteAsString(EcsJsonSerializer.toNullSafeString(value), builder);
-                    builder.append("\",");
-                }
-            }
-        }
-        MDC_SERIALIZER.serializeMdc(event, builder);
-    }
-
-    private static void formatPattern(LogEvent event, PatternFormatter[] formatters, StringBuilder buffer) {
-        final int len = formatters.length;
-        for (int i = 0; i < len; i++) {
-            formatters[i].format(event, buffer);
-        }
-    }
-
-    private void serializeTags(LogEvent event, StringBuilder builder) {
-        ThreadContext.ContextStack stack = event.getContextStack();
-        List<String> contextStack;
-        if (stack == null) {
-            contextStack = Collections.emptyList();
-        } else {
-            contextStack = stack.asList();
-        }
-        Marker marker = event.getMarker();
-        boolean hasTags = !contextStack.isEmpty() || (includeMarkers && marker != null);
-        if (hasTags) {
-            EcsJsonSerializer.serializeTagStart(builder);
-        }
-
-        if (!contextStack.isEmpty()) {
-            final int len = contextStack.size();
-            for (int i = 0; i < len; i++) {
-                builder.append('\"');
-                JsonUtils.quoteAsString(contextStack.get(i), builder);
-                builder.append("\",");
-            }
-        }
-
-        if (includeMarkers && marker != null) {
-            serializeMarker(builder, marker);
-        }
-
-        if (hasTags) {
-            EcsJsonSerializer.serializeTagEnd(builder);
-        }
-    }
-
-    private void serializeMarker(StringBuilder builder, Marker marker) {
-        EcsJsonSerializer.serializeSingleTag(builder, marker.getName());
-        if (marker.hasParents()) {
-            Marker[] parents = marker.getParents();
-            for (int i = 0; i < parents.length; i++) {
-                serializeMarker(builder, parents[i]);
-            }
-        }
-    }
-
-    private void serializeMessage(StringBuilder builder, boolean gcFree, Message message, Throwable thrown) {
-        if (message instanceof MultiformatMessage) {
-            MultiformatMessage multiformatMessage = (MultiformatMessage) message;
-            if (supportsJson(multiformatMessage)) {
-                serializeJsonMessage(builder, multiformatMessage);
-            } else {
-                serializeSimpleMessage(builder, gcFree, message, thrown);
-            }
-        } else if (JACKSON_SERIALIZER != null && message instanceof ObjectMessage) {
-            final StringBuilder jsonBuffer = EcsJsonSerializer.getMessageStringBuilder();
-            JACKSON_SERIALIZER.formatTo(jsonBuffer, (ObjectMessage) message);
-            addJson(builder, jsonBuffer);
-        } else {
-            serializeSimpleMessage(builder, gcFree, message, thrown);
-        }
-    }
-
-    private static void serializeJsonMessage(StringBuilder builder, MultiformatMessage message) {
-        final StringBuilder messageBuffer = EcsJsonSerializer.getMessageStringBuilder();
-        MULTI_FORMAT_HANDLER.formatJsonTo(message, messageBuffer);
-        addJson(builder, messageBuffer);
-    }
-
-    private static void addJson(StringBuilder buffer, StringBuilder jsonBuffer) {
-        if (isObject(jsonBuffer)) {
-            moveToRoot(jsonBuffer);
-            buffer.append(jsonBuffer);
-            buffer.append(", ");
-        } else {
-            buffer.append("\"message\":");
-            if (isString(jsonBuffer)) {
-                buffer.append(jsonBuffer);
-            } else {
-                // message always has to be a string to avoid mapping conflicts
-                buffer.append('"');
-                JsonUtils.quoteAsString(jsonBuffer, buffer);
-                buffer.append('"');
-            }
-            buffer.append(", ");
-        }
-    }
-
-    private void serializeSimpleMessage(StringBuilder builder, boolean gcFree, Message message, Throwable thrown) {
-        builder.append("\"message\":\"");
-        if (message instanceof CharSequence) {
-            JsonUtils.quoteAsString(((CharSequence) message), builder);
-        } else if (gcFree && message instanceof StringBuilderFormattable) {
-            final StringBuilder messageBuffer = EcsJsonSerializer.getMessageStringBuilder();
-            try {
-                ((StringBuilderFormattable) message).formatTo(messageBuffer);
-                JsonUtils.quoteAsString(messageBuffer, builder);
-            } finally {
-                trimToMaxSizeCopy(messageBuffer);
-            }
-        } else {
-            JsonUtils.quoteAsString(EcsJsonSerializer.toNullSafeString(message.getFormattedMessage()), builder);
-        }
-        builder.append("\", ");
-    }
-
-    static void trimToMaxSizeCopy(final StringBuilder stringBuilder) {
-        if (stringBuilder.length() > MAX_STRING_BUILDER_SIZE) {
-            stringBuilder.setLength(MAX_STRING_BUILDER_SIZE);
-            stringBuilder.trimToSize();
-        }
-    }
-
-    private static boolean isObject(StringBuilder messageBuffer) {
-        return messageBuffer.length() > 1 && messageBuffer.charAt(0) == '{' && messageBuffer.charAt(messageBuffer.length() - 1) == '}';
-    }
-
-    private static boolean isString(StringBuilder messageBuffer) {
-        return messageBuffer.length() > 1 && messageBuffer.charAt(0) == '"' && messageBuffer.charAt(messageBuffer.length() - 1) == '"';
-    }
-
-    private static void moveToRoot(StringBuilder messageBuffer) {
-        messageBuffer.setCharAt(0, ' ');
-        messageBuffer.setCharAt(messageBuffer.length() -1, ' ');
-    }
-
-    private boolean supportsJson(MultiformatMessage message) {
-        Boolean supportsJson = this.supportsJson.get(message.getClass());
-        if (supportsJson == null) {
-            supportsJson = false;
-            for (String format : message.getFormats()) {
-                if (format.equalsIgnoreCase("JSON")) {
-                    supportsJson = true;
-                    break;
-                }
-            }
-            this.supportsJson.put(message.getClass(), supportsJson);
-        }
-        return supportsJson;
-    }
-
-    public static class Builder implements org.apache.logging.log4j.core.util.Builder<LcsLayout> {
-
-        @PluginConfiguration
-        private Configuration configuration;
-        @PluginBuilderAttribute("serviceName")
-        private String serviceName;
-        @PluginBuilderAttribute("eventDataset")
-        private String eventDataset;
-        @PluginBuilderAttribute("includeMarkers")
-        private boolean includeMarkers = false;
-        @PluginBuilderAttribute("stackTraceAsArray")
-        private boolean stackTraceAsArray = false;
-        @PluginElement("AdditionalField")
-        private KeyValuePair[] additionalFields = new KeyValuePair[]{};
-        @PluginBuilderAttribute("includeOrigin")
-        private boolean includeOrigin = false;
-
-        Builder() {
-        }
-
-        public Configuration getConfiguration() {
-            return configuration;
-        }
-
-        public LcsLayout.Builder setConfiguration(final Configuration configuration) {
-            this.configuration = configuration;
-            return this;
-        }
-
-        public KeyValuePair[] getAdditionalFields() {
-            return additionalFields.clone();
-        }
-
-        public String getServiceName() {
-            return serviceName;
-        }
-
-        public String getEventDataset() {
-            return eventDataset;
-        }
-
-        public boolean isIncludeMarkers() {
-            return includeMarkers;
-        }
-
-        public boolean isIncludeOrigin() {
-            return includeOrigin;
-        }
-
-        /**
-         * Additional fields to set on each log event.
-         *
-         * @return this builder
-         */
-        public LcsLayout.Builder setAdditionalFields(final KeyValuePair[] additionalFields) {
-            this.additionalFields = additionalFields.clone();
-            return this;
-        }
-
-        public LcsLayout.Builder setServiceName(final String serviceName) {
-            this.serviceName = serviceName;
-            return this;
-        }
-
-        public LcsLayout.Builder setEventDataset(String eventDataset) {
-            this.eventDataset = eventDataset;
-            return this;
-        }
-
-        public LcsLayout.Builder setIncludeMarkers(final boolean includeMarkers) {
-            this.includeMarkers = includeMarkers;
-            return this;
-        }
-
-        public LcsLayout.Builder setIncludeOrigin(final boolean includeOrigin) {
-            this.includeOrigin = includeOrigin;
-            return this;
-        }
-
-        public LcsLayout.Builder setStackTraceAsArray(boolean stackTraceAsArray) {
-            this.stackTraceAsArray = stackTraceAsArray;
-            return this;
-        }
-
-        @Override
-        public LcsLayout build() {
-            return new LcsLayout(getConfiguration(), serviceName, EcsJsonSerializer.computeEventDataset(eventDataset, serviceName), includeMarkers, additionalFields, includeOrigin, stackTraceAsArray);
-        }
-
-        public boolean isStackTraceAsArray() {
-            return stackTraceAsArray;
-        }
-    }
-}
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 0ee01b8..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
@@ -21,7 +21,6 @@ import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.layout.ByteBufferDestination;
 import org.openjdk.jmh.annotations.Benchmark;
 
-import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.util.List;
 
@@ -29,70 +28,73 @@ 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,
-                state.getJsonTemplateLayout4JsonLayout(),
+                state.getJtl4JsonLayout(),
                 state.getFullLogEvents());
     }
 
     @Benchmark
-    public static int liteJsonTemplateLayout4JsonLayout(
+    public static int liteJtl4JsonLayout(
             final JsonTemplateLayoutBenchmarkState state) {
         return benchmark(
                 state,
-                state.getJsonTemplateLayout4JsonLayout(),
+                state.getJtl4JsonLayout(),
                 state.getLiteLogEvents());
     }
 
     @Benchmark
-    public static int fullJsonTemplateLayout4EcsLayout(
+    public static int fullJtl4EcsLayout(
             final JsonTemplateLayoutBenchmarkState state) {
         return benchmark(
                 state,
-                state.getJsonTemplateLayout4EcsLayout(),
+                state.getJtl4EcsLayout(),
                 state.getFullLogEvents());
     }
 
     @Benchmark
-    public static int liteJsonTemplateLayout4EcsLayout(
+    public static int liteJtl4EcsLayout(
             final JsonTemplateLayoutBenchmarkState state) {
         return benchmark(
                 state,
-                state.getJsonTemplateLayout4EcsLayout(),
+                state.getJtl4EcsLayout(),
                 state.getLiteLogEvents());
     }
 
     @Benchmark
-    public static int fullJsonTemplateLayout4GelfLayout(
+    public static int fullJtl4GelfLayout(
             final JsonTemplateLayoutBenchmarkState state) {
         return benchmark(
                 state,
-                state.getJsonTemplateLayout4GelfLayout(),
+                state.getJtl4GelfLayout(),
                 state.getFullLogEvents());
     }
 
     @Benchmark
-    public static int liteJsonTemplateLayout4GelfLayout(
+    public static int liteJtl4GelfLayout(
             final JsonTemplateLayoutBenchmarkState state) {
         return benchmark(
                 state,
-                state.getJsonTemplateLayout4GelfLayout(),
+                state.getJtl4GelfLayout(),
                 state.getLiteLogEvents());
     }
 
@@ -170,7 +172,7 @@ public class JsonTemplateLayoutBenchmark {
 
     private static int benchmark(
             final JsonTemplateLayoutBenchmarkState state,
-            final Layout<String> layout,
+            final Layout<?> layout,
             final List<LogEvent> logEvents) {
         final int logEventIndex = state.nextLogEventIndex();
         final LogEvent logEvent = logEvents.get(logEventIndex);
@@ -178,7 +180,7 @@ public class JsonTemplateLayoutBenchmark {
     }
 
     private static int benchmark(
-            final Layout<String> layout,
+            final Layout<?> layout,
             final LogEvent logEvent,
             final ByteBufferDestination destination) {
         final ByteBuffer byteBuffer = destination.getByteBuffer();
@@ -186,34 +188,4 @@ public class JsonTemplateLayoutBenchmark {
         return byteBuffer.position();
     }
 
-    public static void main(String[] args) throws IOException {
-//        System.out.format("Ready?");
-//        System.in.read();
-        JsonTemplateLayoutBenchmarkState state = new JsonTemplateLayoutBenchmarkState();
-        int retryCount = 500_000_000;
-        measureEcs(state, retryCount);
-        measureJtl(state, retryCount);
-//        while (true) {
-//            measureEcs(state, retryCount);
-//        }
-//        measureEcs(state, retryCount);
-//        measureJtl(state, retryCount);
-    }
-
-    private static void measureJtl(JsonTemplateLayoutBenchmarkState state, int retryCount) {
-        long startInstantNanos = System.nanoTime();
-        for (int i = 0; i < retryCount; i++) {
-            liteJsonTemplateLayout4EcsLayout(state);
-        }
-        System.out.format("%.3fs%n", (System.nanoTime() - startInstantNanos) / 1e9);
-    }
-
-    private static void measureEcs(JsonTemplateLayoutBenchmarkState state, int retryCount) {
-        long startInstantNanos = System.nanoTime();
-        for (int i = 0; i < retryCount; i++) {
-            liteEcsLayout(state);
-        }
-        System.out.format("%.3fs%n", (System.nanoTime() - startInstantNanos) / 1e9);
-    }
-
 }
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 3fc5c5b..56d8ec3 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
@@ -16,7 +16,7 @@
  */
 package org.apache.logging.log4j.layout.template.json;
 
-import co.elastic.logging.log4j2.LcsLayout;
+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;
@@ -46,19 +46,19 @@ public class JsonTemplateLayoutBenchmarkState {
 
     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 LcsLayout ecsLayout;
+    private final Layout<?> ecsLayout;
 
-    private final GelfLayout gelfLayout;
+    private final Layout<?> gelfLayout;
 
     private final List<LogEvent> fullLogEvents;
 
@@ -68,9 +68,9 @@ public class JsonTemplateLayoutBenchmarkState {
 
     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();
@@ -79,7 +79,7 @@ public class JsonTemplateLayoutBenchmarkState {
         this.liteLogEvents = LogEventFixture.createLiteLogEvents(LOG_EVENT_COUNT);
     }
 
-    private static JsonTemplateLayout createJsonTemplateLayout4JsonLayout() {
+    private static JsonTemplateLayout createJtl4JsonLayout() {
         return JsonTemplateLayout
                 .newBuilder()
                 .setConfiguration(CONFIGURATION)
@@ -89,7 +89,7 @@ public class JsonTemplateLayoutBenchmarkState {
                 .build();
     }
 
-    private static JsonTemplateLayout createJsonTemplateLayout4EcsLayout() {
+    private static JsonTemplateLayout createJtl4EcsLayout() {
         final EventTemplateAdditionalField[] additionalFields =
                 new EventTemplateAdditionalField[]{
                         EventTemplateAdditionalField
@@ -102,14 +102,13 @@ public class JsonTemplateLayoutBenchmarkState {
                 .newBuilder()
                 .setConfiguration(CONFIGURATION)
                 .setCharset(CHARSET)
-                .setEventTemplate("{}")
-//                .setEventTemplateUri("classpath:EcsLayout.json")
+                .setEventTemplateUri("classpath:EcsLayout.json")
                 .setRecyclerFactory(ThreadLocalRecyclerFactory.getInstance())
-//                .setEventTemplateAdditionalFields(additionalFields)
+                .setEventTemplateAdditionalFields(additionalFields)
                 .build();
     }
 
-    private static JsonTemplateLayout createJsonTemplateLayout4GelfLayout() {
+    private static JsonTemplateLayout createJtl4GelfLayout() {
         return JsonTemplateLayout
                 .newBuilder()
                 .setConfiguration(CONFIGURATION)
@@ -149,8 +148,8 @@ public class JsonTemplateLayoutBenchmarkState {
                 .build();
     }
 
-    private static LcsLayout createEcsLayout() {
-        final LcsLayout layout = LcsLayout
+    private static EcsLayout createEcsLayout() {
+        final EcsLayout layout = EcsLayout
                 .newBuilder()
                 .setConfiguration(CONFIGURATION)
                 .setServiceName("benchmark")
@@ -178,31 +177,31 @@ public class JsonTemplateLayoutBenchmarkState {
         return byteBufferDestination;
     }
 
-    Layout<String> getJsonTemplateLayout4JsonLayout() {
-        return jsonTemplateLayout4JsonLayout;
+    Layout<?> getJtl4JsonLayout() {
+        return jtl4JsonLayout;
     }
 
-    Layout<String> getJsonTemplateLayout4EcsLayout() {
-        return jsonTemplateLayout4EcsLayout;
+    Layout<?> getJtl4EcsLayout() {
+        return jtl4EcsLayout;
     }
 
-    Layout<String> getJsonTemplateLayout4GelfLayout() {
-        return jsonTemplateLayout4GelfLayout;
+    Layout<?> getJtl4GelfLayout() {
+        return jtl4GelfLayout;
     }
 
-    Layout<String> getDefaultJsonLayout() {
+    Layout<?> getDefaultJsonLayout() {
         return defaultJsonLayout;
     }
 
-    Layout<String> getCustomJsonLayout() {
+    Layout<?> getCustomJsonLayout() {
         return customJsonLayout;
     }
 
-    Layout<String> getEcsLayout() {
+    Layout<?> getEcsLayout() {
         return ecsLayout;
     }
 
-    Layout<String> getGelfLayout() {
+    Layout<?> getGelfLayout() {
         return gelfLayout;
     }
 

[logging-log4j2] 16/17: LOG4J2-3393 Optimize MessageResolver for CharSequence.

Posted by vy...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

vy pushed a commit to branch LOG4J2-3393
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit fcf85c7cc46bbfc1e7c972a4d37d8b34c5e03af2
Author: Volkan Yazici <vo...@yazi.ci>
AuthorDate: Mon Mar 14 11:55:31 2022 +0100

    LOG4J2-3393 Optimize MessageResolver for CharSequence.
---
 .../logging/log4j/layout/template/json/resolver/MessageResolver.java | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

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..aa5e366 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,7 +134,10 @@ public final class MessageResolver implements EventResolver {
             jsonWriter.writeObjectStart();
             jsonWriter.writeObjectKey(fallbackKey);
         }
-        if (message instanceof StringBuilderFormattable) {
+        if (message instanceof CharSequence) {
+            final CharSequence sequence = (CharSequence) message;
+            jsonWriter.writeString(sequence);
+        } else if (message instanceof StringBuilderFormattable) {
             final StringBuilderFormattable formattable =
                     (StringBuilderFormattable) message;
             jsonWriter.writeString(formattable);

[logging-log4j2] 08/17: LOG4J2-3393 Avoid StringBuilderEncoder thread-local allocation in JsonTemplateLayout.

Posted by vy...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

vy pushed a commit to branch LOG4J2-3393
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit 8b12d69e2afb393a7360dbedc70dc9238fabc021
Author: Volkan Yazici <vo...@yazi.ci>
AuthorDate: Sun Feb 20 21:34:34 2022 +0100

    LOG4J2-3393 Avoid StringBuilderEncoder thread-local allocation in JsonTemplateLayout.
---
 .../log4j/core/layout/StringBuilderEncoder.java    |  9 ++--
 .../log4j/core/layout/TextEncoderHelper.java       |  6 +--
 .../layout/template/json/JsonTemplateLayout.java   | 56 +++++++++++++++++-----
 3 files changed, 50 insertions(+), 21 deletions(-)

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..d300a74 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 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 cf8658e..a585bc5 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
@@ -26,10 +26,7 @@ import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
 import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
 import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
 import org.apache.logging.log4j.core.config.plugins.PluginElement;
-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.*;
 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;
@@ -44,9 +41,14 @@ 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;
 import org.apache.logging.log4j.layout.template.json.util.Uris;
+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;
@@ -204,19 +206,49 @@ 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) {
+                StatusLogger
+                        .getLogger()
+                        .error("TextEncoderHelper.encodeText() failure", error);
+                final byte[] bytes = source.toString().getBytes(charset);
+                destination.writeBytes(bytes, 0, bytes.length);
+            }
+        }
+
     }
 
     @Override