LOG4J2-3041 - Allow GelfLayout to use PatternSelectors
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/GelfLayout.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/GelfLayout.java
index 14e71e1..38254f6 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/GelfLayout.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/GelfLayout.java
@@ -144,6 +144,9 @@
@PluginBuilderAttribute
private String messagePattern = null;
+ @PluginElement("PatternSelector")
+ private PatternSelector patternSelector = null;
+
public Builder() {
super();
setCharset(StandardCharsets.UTF_8);
@@ -176,12 +179,23 @@
checker = ListChecker.NOOP_CHECKER;
}
PatternLayout patternLayout = null;
+ if (messagePattern != null && patternSelector != null) {
+ LOGGER.error("A message pattern and PatternSelector cannot both be specified on GelfLayout, "
+ + "ignoring message pattern");
+ messagePattern = null;
+ }
if (messagePattern != null) {
patternLayout = PatternLayout.newBuilder().setPattern(messagePattern)
.setAlwaysWriteExceptions(includeStacktrace)
.setConfiguration(getConfiguration())
.build();
}
+ if (patternSelector != null) {
+ patternLayout = PatternLayout.newBuilder().setPatternSelector(patternSelector)
+ .setAlwaysWriteExceptions(includeStacktrace)
+ .setConfiguration(getConfiguration())
+ .build();
+ }
return new GelfLayout(getConfiguration(), host, additionalFields, compressionType, compressionThreshold,
includeStacktrace, includeThreadContext, includeNullDelimiter, includeNewLineDelimiter, checker,
patternLayout);
@@ -310,6 +324,16 @@
}
/**
+ * The PatternSelector to use to format the message.
+ * @param patternSelector the PatternSelector.
+ * @return this builder
+ */
+ public B setPatternSelector(final PatternSelector patternSelector) {
+ this.patternSelector = patternSelector;
+ return asBuilder();
+ }
+
+ /**
* A comma separated list of thread context keys to include;
* @param mdcIncludes the list of keys.
* @return this builder
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/GelfLayoutTest2.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/GelfLayout2Test.java
similarity index 96%
rename from log4j-core/src/test/java/org/apache/logging/log4j/core/layout/GelfLayoutTest2.java
rename to log4j-core/src/test/java/org/apache/logging/log4j/core/layout/GelfLayout2Test.java
index 2b3f429..f9f44f7 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/GelfLayoutTest2.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/GelfLayout2Test.java
@@ -30,8 +30,8 @@
import static org.junit.jupiter.api.Assertions.*;
-@LoggerContextSource("GelfLayoutTest2.xml")
-public class GelfLayoutTest2 {
+@LoggerContextSource("GelfLayout2Test.xml")
+public class GelfLayout2Test {
@Test
public void gelfLayout(final LoggerContext context, @Named final ListAppender list) throws IOException {
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/GelfLayoutTest3.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/GelfLayout3Test.java
similarity index 94%
rename from log4j-core/src/test/java/org/apache/logging/log4j/core/layout/GelfLayoutTest3.java
rename to log4j-core/src/test/java/org/apache/logging/log4j/core/layout/GelfLayout3Test.java
index fc9a404..6ebd27c 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/GelfLayoutTest3.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/GelfLayout3Test.java
@@ -32,10 +32,10 @@
import static org.junit.jupiter.api.Assertions.*;
-@LoggerContextSource("GelfLayoutTest3.xml")
+@LoggerContextSource("GelfLayout3Test.xml")
@UsingAnyThreadContext
@Tag("json")
-public class GelfLayoutTest3 {
+public class GelfLayout3Test {
@Test
public void gelfLayout(final LoggerContext context, @Named final ListAppender list) throws IOException {
@@ -55,7 +55,7 @@
assertNull(json.get("_requestId"));
String message = json.get("full_message").asText();
assertTrue(message.contains("loginId=rgoers"));
- assertTrue(message.contains("GelfLayoutTest3"));
+ assertTrue(message.contains("GelfLayout3Test"));
}
}
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/GelfLayoutTest3.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/GelfLayoutPatternSelectorTest.java
similarity index 62%
copy from log4j-core/src/test/java/org/apache/logging/log4j/core/layout/GelfLayoutTest3.java
copy to log4j-core/src/test/java/org/apache/logging/log4j/core/layout/GelfLayoutPatternSelectorTest.java
index fc9a404..f3f5712 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/GelfLayoutTest3.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/GelfLayoutPatternSelectorTest.java
@@ -16,26 +16,32 @@
*/
package org.apache.logging.log4j.core.layout;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
+import java.io.IOException;
+
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.ThreadContext;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.junit.LoggerContextSource;
import org.apache.logging.log4j.junit.Named;
import org.apache.logging.log4j.junit.UsingAnyThreadContext;
+import org.apache.logging.log4j.spi.AbstractLogger;
import org.apache.logging.log4j.test.appender.ListAppender;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
-import java.io.IOException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
-import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
-@LoggerContextSource("GelfLayoutTest3.xml")
+@LoggerContextSource("GelfLayoutPatternSelectorTest.xml")
@UsingAnyThreadContext
@Tag("json")
-public class GelfLayoutTest3 {
+public class GelfLayoutPatternSelectorTest {
@Test
public void gelfLayout(final LoggerContext context, @Named final ListAppender list) throws IOException {
@@ -44,9 +50,10 @@
ThreadContext.put("loginId", "rgoers");
ThreadContext.put("internalId", "12345");
logger.info("My Test Message");
- final String gelf = list.getMessages().get(0);
+ logger.info(AbstractLogger.FLOW_MARKER, "My Test Message");
+ String gelf = list.getMessages().get(0);
final ObjectMapper mapper = new ObjectMapper();
- final JsonNode json = mapper.readTree(gelf);
+ JsonNode json = mapper.readTree(gelf);
assertEquals("My Test Message", json.get("short_message").asText());
assertEquals("myhost", json.get("host").asText());
assertNotNull(json.get("_loginId"));
@@ -54,8 +61,21 @@
assertNull(json.get("_internalId"));
assertNull(json.get("_requestId"));
String message = json.get("full_message").asText();
+ assertFalse(message.contains("====="));
assertTrue(message.contains("loginId=rgoers"));
- assertTrue(message.contains("GelfLayoutTest3"));
+ assertTrue(message.contains("GelfLayoutPatternSelectorTest"));
+ gelf = list.getMessages().get(1);
+ json = mapper.readTree(gelf);
+ assertEquals("My Test Message", json.get("short_message").asText());
+ assertEquals("myhost", json.get("host").asText());
+ assertNotNull(json.get("_loginId"));
+ assertEquals("rgoers", json.get("_loginId").asText());
+ assertNull(json.get("_internalId"));
+ assertNull(json.get("_requestId"));
+ message = json.get("full_message").asText();
+ assertTrue(message.contains("====="));
+ assertTrue(message.contains("loginId=rgoers"));
+ assertTrue(message.contains("GelfLayoutPatternSelectorTest"));
}
}
diff --git a/log4j-core/src/test/resources/GelfLayoutTest2.xml b/log4j-core/src/test/resources/GelfLayout2Test.xml
similarity index 100%
rename from log4j-core/src/test/resources/GelfLayoutTest2.xml
rename to log4j-core/src/test/resources/GelfLayout2Test.xml
diff --git a/log4j-core/src/test/resources/GelfLayoutTest3.xml b/log4j-core/src/test/resources/GelfLayout3Test.xml
similarity index 100%
rename from log4j-core/src/test/resources/GelfLayoutTest3.xml
rename to log4j-core/src/test/resources/GelfLayout3Test.xml
diff --git a/log4j-core/src/test/resources/GelfLayoutPatternSelectorTest.xml b/log4j-core/src/test/resources/GelfLayoutPatternSelectorTest.xml
new file mode 100644
index 0000000..7fe50f6
--- /dev/null
+++ b/log4j-core/src/test/resources/GelfLayoutPatternSelectorTest.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+
+-->
+<Configuration status="WARN" name="GelfLayoutPatternSelectorTest">
+ <Appenders>
+ <List name="list">
+ <GelfLayout host="myhost" includeThreadContext="true" threadContextIncludes="requestId,loginId">
+ <MarkerPatternSelector defaultPattern="%d [%t] %-5p %X{requestId, loginId} %C{1.}.%M:%L - %m%n">
+ <PatternMatch key="FLOW" pattern="[%-5level] %X{requestId, loginId} ====== %C{1.}.%M:%L %msg ======%n"/>
+ </MarkerPatternSelector>
+ <KeyValuePair key="foo" value="FOO"/>
+ <KeyValuePair key="runtime" value="$${java:runtime}"/>
+ </GelfLayout>
+ </List>
+ </Appenders>
+
+ <Loggers>
+ <Root level="info">
+ <AppenderRef ref="list"/>
+ </Root>
+ </Loggers>
+</Configuration>
\ No newline at end of file
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index f4fb31d..3a01186 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -169,7 +169,9 @@
</action>
</release>
<release version="2.15.0" date="2021-MM-DD" description="GA Release 2.15.0">
-
+ <action issue="LOG4J2-3041" dev="rgoers" type="update">
+ Allow a PatternSelector to be specified on GelfLayout.
+ </action>
</release>
<release version="2.14.1" date="2021-03-06" description="GA Release 2.14.1">
<!-- FIXES -->
diff --git a/src/site/asciidoc/manual/layouts.adoc b/src/site/asciidoc/manual/layouts.adoc
index 44d2580..0ac0d78 100644
--- a/src/site/asciidoc/manual/layouts.adoc
+++ b/src/site/asciidoc/manual/layouts.adoc
@@ -228,9 +228,20 @@
|messagePattern
|String
-|The pattern to use to format the String. If not supplied only the text derived from the logging
-message will be used. See <<PatternLayout>> for information on the pattern
-strings
+|The pattern to use to format the String. A messagePattern and patternSelector cannot both be
+specified. If both are present the message pattern will be ignored and an error will be logged.
+If not supplied only the text derived from the logging message will be used. See
+link:#PatternLayout[PatternLayout] for information on the pattern strings.
+
+|patternSelector
+|PatternSelector
+|The PatternSelector to use to format the String. A messagePattern and patternSelector cannot both be
+specified. If both are present the message pattern will be ignored and an error will be logged.
+If not supplied only the text derived from the logging message will be used.
+See link:#PatternSelectors[Pattern Selectors] for information on how to specify a
+PatternSelector.
+See link:#PatternLayout[PatternLayout] for information on the pattern strings.
+
|threadContextExcludes
|String
@@ -1785,6 +1796,7 @@
</PatternLayout>
----
+[#PatternSelectors]
=== Pattern Selectors
The PatternLayout can be configured with a PatternSelector to allow it