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 12:44:55 UTC
[logging-log4j2] 07/07: LOG4J2-2936 Add message parameter resolver
to JSON template layout.
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
commit 51278468e49ff1b4548225a6a38f060061694547
Author: Volkan Yazici <vo...@gmail.com>
AuthorDate: Fri Nov 6 13:30:39 2020 +0100
LOG4J2-2936 Add message parameter resolver to JSON template layout.
---
.../json/resolver/EventResolverFactories.java | 1 +
.../template/json/resolver/LevelResolver.java | 2 +-
.../json/resolver/MessageParameterResolver.java | 131 +++++++++++++++++++++
.../resolver/MessageParameterResolverFactory.java | 41 +++++++
.../template/json/JsonTemplateLayoutTest.java | 51 ++++++++
.../asciidoc/manual/json-template-layout.adoc.vm | 52 ++++++++
6 files changed, 277 insertions(+), 1 deletion(-)
diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/EventResolverFactories.java b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/EventResolverFactories.java
index 07fe97b..b4b4f49 100644
--- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/EventResolverFactories.java
+++ b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/EventResolverFactories.java
@@ -44,6 +44,7 @@ enum EventResolverFactories {;
MapResolverFactory.getInstance(),
MarkerResolverFactory.getInstance(),
MessageResolverFactory.getInstance(),
+ MessageParameterResolverFactory.getInstance(),
PatternResolverFactory.getInstance(),
SourceResolverFactory.getInstance(),
ThreadResolverFactory.getInstance(),
diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/LevelResolver.java b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/LevelResolver.java
index 89de7e0..2952eb4 100644
--- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/LevelResolver.java
+++ b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/LevelResolver.java
@@ -27,7 +27,7 @@ import java.util.function.Function;
import java.util.stream.Collectors;
/**
- * Level resolver.
+ * {@link Level} resolver.
*
* <h3>Configuration</h3>
*
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
new file mode 100644
index 0000000..a21dff6
--- /dev/null
+++ b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/MessageParameterResolver.java
@@ -0,0 +1,131 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+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.message.Message;
+
+/**
+ * {@link Message} parameter (i.e., {@link Message#getParameters()}) resolver.
+ *
+ * <h3>Configuration</h3>
+ *
+ * <pre>
+ * config = [ stringified ] , [ index ]
+ * stringified = "stringified" -> boolean
+ * index = "index" -> number
+ * </pre>
+ *
+ * <h3>Examples</h3>
+ *
+ * Resolve the message parameters into an array:
+ *
+ * <pre>
+ * {
+ * "$resolver": "messageParameter"
+ * }
+ * </pre>
+ *
+ * Resolve the string representation of all message parameters into an array:
+ *
+ * <pre>
+ * {
+ * "$resolver": "messageParameter",
+ * "stringified": true
+ * }
+ * </pre>
+ *
+ * Resolve the first message parameter:
+ *
+ * <pre>
+ * {
+ * "$resolver": "messageParameter",
+ * "index": 0
+ * }
+ *
+ * Resolve the string representation of the first message parameter:
+ *
+ * <pre>
+ * {
+ * "$resolver": "messageParameter",
+ * "index": 0,
+ * "stringified": true
+ * }
+ * </pre>
+ */
+final class MessageParameterResolver implements EventResolver {
+
+ private final boolean stringified;
+
+ private final int index;
+
+ MessageParameterResolver(final TemplateResolverConfig config) {
+ this.stringified = config.getBoolean("stringified", false);
+ final Integer index = config.getInteger("index");
+ if (index != null && index < 0) {
+ throw new IllegalArgumentException("was expecting a positive index: " + config);
+ }
+ this.index = index == null ? -1 : index;
+ }
+
+ static String getName() {
+ return "messageParameter";
+ }
+
+ @Override
+ public void resolve(final LogEvent logEvent, final JsonWriter jsonWriter) {
+
+ // Short-circuit if there are no parameters.
+ final Object[] parameters = logEvent.getMessage().getParameters();
+ if (parameters.length == 0) {
+ jsonWriter.writeNull();
+ return;
+ }
+
+ // Resolve all parameters.
+ if (index < 0) {
+ jsonWriter.writeArrayStart();
+ for (int i = 0; i < parameters.length; i++) {
+ if (i > 0) {
+ jsonWriter.writeSeparator();
+ }
+ final Object parameter = parameters[i];
+ if (stringified) {
+ final String stringifiedParameter = String.valueOf(parameter);
+ jsonWriter.writeString(stringifiedParameter);
+ } else {
+ jsonWriter.writeValue(parameter);
+ }
+ }
+ jsonWriter.writeArrayEnd();
+ }
+
+ // Resolve a single parameter.
+ else {
+ final Object parameter = parameters[index];
+ if (stringified) {
+ final String stringifiedParameter = String.valueOf(parameter);
+ jsonWriter.writeString(stringifiedParameter);
+ } else {
+ 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
new file mode 100644
index 0000000..db1c369
--- /dev/null
+++ b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/MessageParameterResolverFactory.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.layout.template.json.resolver;
+
+final class MessageParameterResolverFactory implements EventResolverFactory<MessageParameterResolver> {
+
+ private static final MessageParameterResolverFactory INSTANCE = new MessageParameterResolverFactory();
+
+ private MessageParameterResolverFactory() {}
+
+ static MessageParameterResolverFactory getInstance() {
+ return INSTANCE;
+ }
+
+ @Override
+ public String getName() {
+ return MessageParameterResolver.getName();
+ }
+
+ @Override
+ public MessageParameterResolver create(
+ final EventResolverContext context,
+ final TemplateResolverConfig config) {
+ return new MessageParameterResolver(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 9de4d87..782db2d 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
@@ -40,6 +40,7 @@ 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.ObjectMessage;
+import org.apache.logging.log4j.message.ParameterizedMessage;
import org.apache.logging.log4j.message.SimpleMessage;
import org.apache.logging.log4j.message.StringMapMessage;
import org.apache.logging.log4j.test.AvailablePortFinder;
@@ -1786,6 +1787,56 @@ public class JsonTemplateLayoutTest {
}
@Test
+ public void test_MessageParameterResolver() {
+
+ // Create the event template.
+ final String eventTemplate = writeJson(Map(
+ "po*", Map(
+ "$resolver", "messageParameter"),
+ "ps*", Map(
+ "$resolver", "messageParameter",
+ "stringified", true),
+ "po2", Map(
+ "$resolver", "messageParameter",
+ "index", 2),
+ "ps2", Map(
+ "$resolver", "messageParameter",
+ "index", 2,
+ "stringified", true)));
+
+ // Create the layout.
+ final JsonTemplateLayout layout = JsonTemplateLayout
+ .newBuilder()
+ .setConfiguration(CONFIGURATION)
+ .setEventTemplate(eventTemplate)
+ .build();
+
+ // Create the log event.
+ final Object[] parameters = {1L + (long) Integer.MAX_VALUE, "foo", 56};
+ final Message message = new ParameterizedMessage("foo", parameters);
+ final Level level = Level.FATAL;
+ final LogEvent logEvent = Log4jLogEvent
+ .newBuilder()
+ .setLoggerName(LOGGER_NAME)
+ .setMessage(message)
+ .setLevel(level)
+ .build();
+
+ // Check the serialized event.
+ usingSerializedLogEventAccessor(layout, logEvent, accessor -> {
+ assertThat(accessor.getObject("po*")).isEqualTo(Arrays.asList(parameters));
+ List<String> stringifiedParameters = Arrays
+ .stream(parameters)
+ .map(String::valueOf)
+ .collect(Collectors.toList());
+ assertThat(accessor.getObject("ps*")).isEqualTo(stringifiedParameters);
+ assertThat(accessor.getObject("po2")).isEqualTo(parameters[2]);
+ assertThat(accessor.getString("ps2")).isEqualTo(stringifiedParameters.get(2));
+ });
+
+ }
+
+ @Test
public void test_unresolvable_nested_fields_are_skipped() {
// Create the event template.
diff --git a/src/site/asciidoc/manual/json-template-layout.adoc.vm b/src/site/asciidoc/manual/json-template-layout.adoc.vm
index 1c370ca..2bc7e44 100644
--- a/src/site/asciidoc/manual/json-template-layout.adoc.vm
+++ b/src/site/asciidoc/manual/json-template-layout.adoc.vm
@@ -804,6 +804,58 @@ Using this configuration, a `SimpleMessage` will generate a
`{"action": "login", "sessionId": "87asd97a"}`. Note that both emitted JSONs are
of type `object` and have no type-conflicting fields.
+| messageParameter
+a|
+[source]
+----
+config = [ stringified ] , [ index ]
+stringified = "stringified" -> boolean
+index = "index" -> number
+----
+| `logEvent.getMessage().getParameters()`
+| `stringified` flag translates to `String.valueOf(value)`, hence mind
+ not-`String`-typed values.
+a|
+Resolve the message parameters into an array:
+
+[source,json]
+----
+{
+ "$resolver": "messageParameter"
+}
+----
+
+Resolve the string representation of all message parameters into an array:
+
+[source,json]
+----
+{
+ "$resolver": "messageParameter",
+ "stringified": true
+}
+----
+
+Resolve the first message parameter:
+
+[source,json]
+----
+{
+ "$resolver": "messageParameter",
+ "index": 0
+}
+----
+
+Resolve the string representation of the first message parameter:
+
+[source,json]
+----
+{
+ "$resolver": "messageParameter",
+ "index": 0,
+ "stringified": true
+}
+----
+
| ndc
a|
[source]