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 2020/11/06 16:20:47 UTC
[logging-log4j2] branch master updated: LOG4J2-2936 Make JSON
template layout message parameter resolver garbage-free.
This is an automated email from the ASF dual-hosted git repository.
vy pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
The following commit(s) were added to refs/heads/master by this push:
new 5b0a153 LOG4J2-2936 Make JSON template layout message parameter resolver garbage-free.
5b0a153 is described below
commit 5b0a153b6609ca82f00ea7b808b5b4fc28279797
Author: Volkan Yazici <vo...@gmail.com>
AuthorDate: Fri Nov 6 17:18:43 2020 +0100
LOG4J2-2936 Make JSON template layout message parameter resolver garbage-free.
---
.../json/resolver/MessageParameterResolver.java | 80 +++++++++++++++++++++-
.../resolver/MessageParameterResolverFactory.java | 2 +-
.../template/json/JsonTemplateLayoutTest.java | 17 ++++-
.../asciidoc/manual/json-template-layout.adoc.vm | 5 +-
4 files changed, 96 insertions(+), 8 deletions(-)
diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/MessageParameterResolver.java b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/MessageParameterResolver.java
index a21dff6..b4d39f3 100644
--- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/MessageParameterResolver.java
+++ b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/MessageParameterResolver.java
@@ -18,7 +18,10 @@ 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 org.apache.logging.log4j.message.Message;
+import org.apache.logging.log4j.message.ParameterConsumer;
+import org.apache.logging.log4j.message.ParameterVisitable;
/**
* {@link Message} parameter (i.e., {@link Message#getParameters()}) resolver.
@@ -70,11 +73,18 @@ import org.apache.logging.log4j.message.Message;
*/
final class MessageParameterResolver implements EventResolver {
+ private final Recycler<ParameterConsumerState> parameterConsumerStateRecycler;
+
private final boolean stringified;
private final int index;
- MessageParameterResolver(final TemplateResolverConfig config) {
+ MessageParameterResolver(
+ final EventResolverContext context,
+ final TemplateResolverConfig config) {
+ this.parameterConsumerStateRecycler = context
+ .getRecyclerFactory()
+ .create(ParameterConsumerState::new);
this.stringified = config.getBoolean("stringified", false);
final Integer index = config.getInteger("index");
if (index != null && index < 0) {
@@ -90,9 +100,17 @@ final class MessageParameterResolver implements EventResolver {
@Override
public void resolve(final LogEvent logEvent, final JsonWriter jsonWriter) {
+ // If possible, perform a garbage-free resolution.
+ final Message message = logEvent.getMessage();
+ if (message instanceof ParameterVisitable) {
+ final ParameterVisitable parameterVisitable = (ParameterVisitable) message;
+ resolve(parameterVisitable, jsonWriter);
+ return;
+ }
+
// Short-circuit if there are no parameters.
- final Object[] parameters = logEvent.getMessage().getParameters();
- if (parameters.length == 0) {
+ final Object[] parameters = message.getParameters();
+ if (parameters == null || parameters.length == 0) {
jsonWriter.writeNull();
return;
}
@@ -128,4 +146,60 @@ final class MessageParameterResolver implements EventResolver {
}
+ /**
+ * Perform a garbage-free resolution via {@link ParameterVisitable} interface.
+ */
+ private void resolve(
+ final ParameterVisitable parameterVisitable,
+ final JsonWriter jsonWriter) {
+ final ParameterConsumerState parameterConsumerState =
+ parameterConsumerStateRecycler.acquire();
+ try {
+ final boolean arrayNeeded = index < 0;
+ if (arrayNeeded) {
+ jsonWriter.writeArrayStart();
+ }
+ parameterConsumerState.resolver = this;
+ parameterConsumerState.jsonWriter = jsonWriter;
+ parameterVisitable.forEachParameter(
+ PARAMETER_CONSUMER, parameterConsumerState);
+ if (arrayNeeded) {
+ jsonWriter.writeArrayEnd();
+ }
+ } finally {
+ parameterConsumerStateRecycler.release(parameterConsumerState);
+ }
+ }
+
+ private static final class ParameterConsumerState {
+
+ private MessageParameterResolver resolver;
+
+ private JsonWriter jsonWriter;
+
+ private ParameterConsumerState() {}
+
+ }
+
+ private static final ParameterConsumer<ParameterConsumerState> PARAMETER_CONSUMER =
+ (final Object parameter, final int index, final ParameterConsumerState state) -> {
+
+ // Write the separator, if needed.
+ final boolean arrayNeeded = state.resolver.index < 0;
+ if (arrayNeeded && index > 0) {
+ state.jsonWriter.writeSeparator();
+ }
+
+ // Write the value.
+ if (arrayNeeded || state.resolver.index == index) {
+ if (state.resolver.stringified) {
+ final String stringifiedParameter = String.valueOf(parameter);
+ state.jsonWriter.writeString(stringifiedParameter);
+ } else {
+ state.jsonWriter.writeValue(parameter);
+ }
+ }
+
+ };
+
}
diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/MessageParameterResolverFactory.java b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/MessageParameterResolverFactory.java
index db1c369..055071c 100644
--- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/MessageParameterResolverFactory.java
+++ b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/MessageParameterResolverFactory.java
@@ -35,7 +35,7 @@ final class MessageParameterResolverFactory implements EventResolverFactory<Mess
public MessageParameterResolver create(
final EventResolverContext context,
final TemplateResolverConfig config) {
- return new MessageParameterResolver(config);
+ return new MessageParameterResolver(context, config);
}
}
diff --git a/log4j-layout-template-json/src/test/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutTest.java b/log4j-layout-template-json/src/test/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutTest.java
index 782db2d..2da177e 100644
--- a/log4j-layout-template-json/src/test/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutTest.java
+++ b/log4j-layout-template-json/src/test/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutTest.java
@@ -39,8 +39,10 @@ import org.apache.logging.log4j.layout.template.json.util.JsonReader;
import org.apache.logging.log4j.layout.template.json.util.JsonWriter;
import org.apache.logging.log4j.layout.template.json.util.MapAccessor;
import org.apache.logging.log4j.message.Message;
+import org.apache.logging.log4j.message.MessageFactory;
import org.apache.logging.log4j.message.ObjectMessage;
-import org.apache.logging.log4j.message.ParameterizedMessage;
+import org.apache.logging.log4j.message.ParameterizedMessageFactory;
+import org.apache.logging.log4j.message.ReusableMessageFactory;
import org.apache.logging.log4j.message.SimpleMessage;
import org.apache.logging.log4j.message.StringMapMessage;
import org.apache.logging.log4j.test.AvailablePortFinder;
@@ -1787,7 +1789,16 @@ public class JsonTemplateLayoutTest {
}
@Test
- public void test_MessageParameterResolver() {
+ public void test_MessageParameterResolver_with_ParameterizedMessageFactory() {
+ testMessageParameterResolver(ParameterizedMessageFactory.INSTANCE);
+ }
+
+ @Test
+ public void test_MessageParameterResolver_with_ReusableMessageFactory() {
+ testMessageParameterResolver(ReusableMessageFactory.INSTANCE);
+ }
+
+ private void testMessageParameterResolver(MessageFactory messageFactory) {
// Create the event template.
final String eventTemplate = writeJson(Map(
@@ -1813,7 +1824,7 @@ public class JsonTemplateLayoutTest {
// Create the log event.
final Object[] parameters = {1L + (long) Integer.MAX_VALUE, "foo", 56};
- final Message message = new ParameterizedMessage("foo", parameters);
+ final Message message = messageFactory.newMessage("foo", parameters);
final Level level = Level.FATAL;
final LogEvent logEvent = Log4jLogEvent
.newBuilder()
diff --git a/src/site/asciidoc/manual/json-template-layout.adoc.vm b/src/site/asciidoc/manual/json-template-layout.adoc.vm
index 2bc7e44..d90f607 100644
--- a/src/site/asciidoc/manual/json-template-layout.adoc.vm
+++ b/src/site/asciidoc/manual/json-template-layout.adoc.vm
@@ -14,6 +14,7 @@
See the License for the specific language governing permissions and
limitations under the License.
////
+#set($dollar = '$')
= JSON Template Layout
Volkan Yazıcı <vy...@apache.org>
@@ -814,7 +815,9 @@ index = "index" -> number
----
| `logEvent.getMessage().getParameters()`
| `stringified` flag translates to `String.valueOf(value)`, hence mind
- not-`String`-typed values.
+ not-`String`-typed values. Further, `logEvent.getMessage()` is expected to
+ implement `ParameterVisitable` interface, which is the case if
+ `log4j2.enableThreadlocals` property set to true.
a|
Resolve the message parameters into an array: