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`,