This is an automated email from the ASF dual-hosted git repository. vy pushed a commit to branch release-2.x in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
commit 1112fd96b2e121611d2075261939cbecd0bbabd9 Author: Volkan Yazici <[email protected]> AuthorDate: Fri Jul 9 14:34:41 2021 +0200 LOG4J2-3067 Add "stringified" flag to CounterResolver. --- .../template/json/resolver/CounterResolver.java | 92 ++++++++++++++++++++-- .../json/resolver/CounterResolverFactory.java | 4 +- .../json/resolver/CounterResolverTest.java | 53 ++++++++++++- .../asciidoc/manual/json-template-layout.adoc.vm | 10 ++- 4 files changed, 145 insertions(+), 14 deletions(-) diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/CounterResolver.java b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/CounterResolver.java index 9071277..6ad6b06 100644 --- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/CounterResolver.java +++ b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/CounterResolver.java @@ -18,6 +18,7 @@ package org.apache.logging.log4j.layout.template.json.resolver; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.layout.template.json.util.JsonWriter; +import org.apache.logging.log4j.layout.template.json.util.Recycler; import java.math.BigInteger; import java.util.concurrent.atomic.AtomicLong; @@ -31,9 +32,10 @@ import java.util.function.Consumer; * <h3>Configuration</h3> * * <pre> - * config = [ start ] , [ overflow ] - * start = "start" -> number - * overflow = "overflow" -> boolean + * config = [ start ] , [ overflow ] , [ stringified ] + * start = "start" -> number + * overflow = "overflow" -> boolean + * stringified = "stringified" -> boolean * </pre> * * Unless provided, <tt>start</tt> and <tt>overflow</tt> are respectively set to @@ -43,6 +45,9 @@ import java.util.function.Consumer; * <tt>long</tt>, which is subject to overflow while incrementing, though * garbage-free. Otherwise, a {@link BigInteger} is used, which does not * overflow, but incurs allocation costs. + * <p> + * When <tt>stringified</tt> is enabled, which is set to <tt>false</tt> by + * default, the resolved number will be converted to a string. * * <h3>Examples</h3> * @@ -79,12 +84,29 @@ public class CounterResolver implements EventResolver { private final Consumer<JsonWriter> delegate; - public CounterResolver(final TemplateResolverConfig config) { + public CounterResolver( + final EventResolverContext context, + final TemplateResolverConfig config) { + this.delegate = createDelegate(context, config); + } + + private static Consumer<JsonWriter> createDelegate( + final EventResolverContext context, + final TemplateResolverConfig config) { final BigInteger start = readStart(config); final boolean overflow = config.getBoolean("overflow", true); - this.delegate = overflow - ? createLongResolver(start) - : createBigIntegerResolver(start); + final boolean stringified = config.getBoolean("stringified", false); + if (stringified) { + final Recycler<StringBuilder> stringBuilderRecycler = + createStringBuilderRecycler(context); + return overflow + ? createStringifiedLongResolver(start, stringBuilderRecycler) + : createStringifiedBigIntegerResolver(start, stringBuilderRecycler); + } else { + return overflow + ? createLongResolver(start) + : createBigIntegerResolver(start); + } } private static BigInteger readStart(final TemplateResolverConfig config) { @@ -120,6 +142,62 @@ public class CounterResolver implements EventResolver { }; } + private static Recycler<StringBuilder> createStringBuilderRecycler( + final EventResolverContext context) { + return context + .getRecyclerFactory() + .create( + StringBuilder::new, + stringBuilder -> { + final int maxLength = + context.getJsonWriter().getMaxStringLength(); + trimStringBuilder(stringBuilder, maxLength); + }); + } + + private static void trimStringBuilder( + final StringBuilder stringBuilder, + final int maxLength) { + if (stringBuilder.length() > maxLength) { + stringBuilder.setLength(maxLength); + stringBuilder.trimToSize(); + } + stringBuilder.setLength(0); + } + + private static Consumer<JsonWriter> createStringifiedLongResolver( + final BigInteger start, + final Recycler<StringBuilder> stringBuilderRecycler) { + final long effectiveStart = start.longValue(); + final AtomicLong counter = new AtomicLong(effectiveStart); + return (jsonWriter) -> { + final long number = counter.getAndIncrement(); + final StringBuilder stringBuilder = stringBuilderRecycler.acquire(); + try { + stringBuilder.append(number); + jsonWriter.writeString(stringBuilder); + } finally { + stringBuilderRecycler.release(stringBuilder); + } + }; + } + + private static Consumer<JsonWriter> createStringifiedBigIntegerResolver( + final BigInteger start, + final Recycler<StringBuilder> stringBuilderRecycler) { + final AtomicBigInteger counter = new AtomicBigInteger(start); + return jsonWriter -> { + final BigInteger number = counter.getAndIncrement(); + final StringBuilder stringBuilder = stringBuilderRecycler.acquire(); + try { + stringBuilder.append(number); + jsonWriter.writeString(stringBuilder); + } finally { + stringBuilderRecycler.release(stringBuilder); + } + }; + } + private static final class AtomicBigInteger { private final AtomicReference<BigInteger> lastNumber; diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/CounterResolverFactory.java b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/CounterResolverFactory.java index eb1daec..2f61a07 100644 --- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/CounterResolverFactory.java +++ b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/CounterResolverFactory.java @@ -42,9 +42,9 @@ public final class CounterResolverFactory implements EventResolverFactory { @Override public CounterResolver create( - final EventResolverContext ignored, + final EventResolverContext context, final TemplateResolverConfig config) { - return new CounterResolver(config); + return new CounterResolver(context, config); } } diff --git a/log4j-layout-template-json/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/CounterResolverTest.java b/log4j-layout-template-json/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/CounterResolverTest.java index 25f02f1..29e1f28 100644 --- a/log4j-layout-template-json/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/CounterResolverTest.java +++ b/log4j-layout-template-json/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/CounterResolverTest.java @@ -44,6 +44,15 @@ class CounterResolverTest { } @Test + void positive_start_should_work_when_stringified() { + final String eventTemplate = writeJson(asMap( + "$resolver", "counter", + "start", 3, + "stringified", true)); + verify(eventTemplate, "3", "4"); + } + + @Test void negative_start_should_work() { final String eventTemplate = writeJson(asMap( "$resolver", "counter", @@ -52,6 +61,15 @@ class CounterResolverTest { } @Test + void negative_start_should_work_when_stringified() { + final String eventTemplate = writeJson(asMap( + "$resolver", "counter", + "start", -3, + "stringified", true)); + verify(eventTemplate, "-3", "-2"); + } + + @Test void min_long_should_work_when_overflow_enabled() { final String eventTemplate = writeJson(asMap( "$resolver", "counter", @@ -60,6 +78,15 @@ class CounterResolverTest { } @Test + void min_long_should_work_when_overflow_enabled_and_stringified() { + final String eventTemplate = writeJson(asMap( + "$resolver", "counter", + "start", Long.MIN_VALUE, + "stringified", true)); + verify(eventTemplate, "" + Long.MIN_VALUE, "" + (Long.MIN_VALUE + 1L)); + } + + @Test void max_long_should_work_when_overflow_enabled() { final String eventTemplate = writeJson(asMap( "$resolver", "counter", @@ -68,6 +95,15 @@ class CounterResolverTest { } @Test + void max_long_should_work_when_overflow_enabled_and_stringified() { + final String eventTemplate = writeJson(asMap( + "$resolver", "counter", + "start", Long.MAX_VALUE, + "stringified", true)); + verify(eventTemplate, "" + Long.MAX_VALUE, "" + Long.MIN_VALUE); + } + + @Test void max_long_should_work_when_overflow_disabled() { final String eventTemplate = writeJson(asMap( "$resolver", "counter", @@ -79,10 +115,23 @@ class CounterResolverTest { BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE)); } + @Test + void max_long_should_work_when_overflow_disabled_and_stringified() { + final String eventTemplate = writeJson(asMap( + "$resolver", "counter", + "start", Long.MAX_VALUE, + "overflow", false, + "stringified", true)); + verify( + eventTemplate, + "" + Long.MAX_VALUE, + "" + BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE)); + } + private static void verify( final String eventTemplate, - final Number expectedNumber1, - final Number expectedNumber2) { + final Object expectedNumber1, + final Object expectedNumber2) { // Create the layout. final JsonTemplateLayout layout = JsonTemplateLayout diff --git a/src/site/asciidoc/manual/json-template-layout.adoc.vm b/src/site/asciidoc/manual/json-template-layout.adoc.vm index 77c2747..b90d790 100644 --- a/src/site/asciidoc/manual/json-template-layout.adoc.vm +++ b/src/site/asciidoc/manual/json-template-layout.adoc.vm @@ -459,9 +459,10 @@ detail. [source] ---- -config = [ start ] , [ overflow ] -start = "start" -> number -overflow = "overflow" -> boolean +config = [ start ] , [ overflow ] , [ stringified ] +start = "start" -> number +overflow = "overflow" -> boolean +stringified = "stringified" -> boolean ---- Resolves a number from an internal counter. @@ -469,6 +470,9 @@ Resolves a number from an internal counter. Unless provided, `start` and `overflow` are respectively set to zero and `true` by default. +When `stringified` is enabled, which is set to `false by default, the resolved +number will be converted to a string. + [WARNING] ==== When `overflow` is enabled, the internal counter is created using a `long`,
