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 2021/07/09 13:17:27 UTC

[logging-log4j2] 01/02: LOG4J2-3067 Add "stringified" flag to CounterResolver.

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 <vo...@gmail.com>
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`,