[LOG4J2-1145] Add %equals to PatternLayout to test and replace patterns with strings. Also split out a test method that relies on source code line numbers to be fixed.
Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/e72d2dc7 Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/e72d2dc7 Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/e72d2dc7 Branch: refs/heads/LOG4J2-1136 Commit: e72d2dc7f3d82a08e787688fae21706c1991505a Parents: 1e8f2cd Author: ggregory <[email protected]> Authored: Thu Oct 1 15:13:21 2015 -0700 Committer: Ralph Goers <[email protected]> Committed: Sat Oct 3 23:08:06 2015 -0700 ---------------------------------------------------------------------- .../pattern/EqualsReplacementConverter.java | 102 +++++++++++++++++++ .../log4j/core/layout/PatternLayoutTest.java | 52 ++++------ .../log4j/core/layout/PatternSelectorTest.java | 65 ++++++++++++ .../pattern/EqualsReplacementConverterTest.java | 63 ++++++++++++ src/changes/changes.xml | 3 + src/site/xdoc/manual/layouts.xml.vm | 15 ++- 6 files changed, 269 insertions(+), 31 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e72d2dc7/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/EqualsReplacementConverter.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/EqualsReplacementConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/EqualsReplacementConverter.java new file mode 100644 index 0000000..c564dc9 --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/EqualsReplacementConverter.java @@ -0,0 +1,102 @@ +/* + * 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.core.pattern; + +import java.util.List; + +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.plugins.Plugin; +import org.apache.logging.log4j.core.layout.PatternLayout; + +/** + * Equals pattern converter. + */ +@Plugin(name = "equals", category = PatternConverter.CATEGORY) +@ConverterKeys({ "equals" }) +public final class EqualsReplacementConverter extends LogEventPatternConverter { + + /** + * Gets an instance of the class. + * + * @param config + * The current Configuration. + * @param options + * pattern options, may be null. If first element is "short", + * only the first line of the throwable will be formatted. + * @return instance of class. + */ + public static EqualsReplacementConverter newInstance(final Configuration config, final String[] options) { + if (options.length != 3) { + LOGGER.error("Incorrect number of options on equals. Expected 3 received " + options.length); + return null; + } + if (options[0] == null) { + LOGGER.error("No pattern supplied on equals"); + return null; + } + if (options[1] == null) { + LOGGER.error("No test string supplied on equals"); + return null; + } + if (options[2] == null) { + LOGGER.error("No substitution supplied on equals"); + return null; + } + final String p = options[1]; + final PatternParser parser = PatternLayout.createPatternParser(config); + final List<PatternFormatter> formatters = parser.parse(options[0]); + return new EqualsReplacementConverter(formatters, p, options[2]); + } + + private final List<PatternFormatter> formatters; + + private final String substitution; + + private final String testString; + + /** + * Construct the converter. + * + * @param formatters + * The PatternFormatters to generate the text to manipulate. + * @param testString + * The test string. + * @param substitution + * The substitution string. + */ + private EqualsReplacementConverter(final List<PatternFormatter> formatters, final String testString, + final String substitution) { + super("equals", "equals"); + this.testString = testString; + this.substitution = substitution; + this.formatters = formatters; + } + + /** + * {@inheritDoc} + */ + @Override + public void format(final LogEvent event, final StringBuilder toAppendTo) { + final StringBuilder buf = new StringBuilder(); + for (final PatternFormatter formatter : formatters) { + formatter.format(event, buf); + } + final String string = buf.toString(); + toAppendTo.append(testString.equals(string) ? substitution : string); + } +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e72d2dc7/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/PatternLayoutTest.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/PatternLayoutTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/PatternLayoutTest.java index 664c469..5ac73a5 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/PatternLayoutTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/PatternLayoutTest.java @@ -201,6 +201,28 @@ public class PatternLayoutTest { } @Test + public void testEqualsEmptyMarker() throws Exception { + // replace "[]" with the empty string + final PatternLayout layout = PatternLayout.newBuilder().withPattern("[%logger]%equals{[%marker]}{[]}{} %msg") + .withConfiguration(ctx.getConfiguration()).build(); + // Not empty marker + final LogEvent event1 = Log4jLogEvent.newBuilder() // + .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") // + .setLevel(Level.INFO) // + .setMarker(MarkerManager.getMarker("TestMarker")) // + .setMessage(new SimpleMessage("Hello, world!")).build(); + final byte[] result1 = layout.toByteArray(event1); + assertEquals("[org.apache.logging.log4j.core.layout.PatternLayoutTest][TestMarker] Hello, world!", new String(result1)); + // empty marker + final LogEvent event2 = Log4jLogEvent.newBuilder() // + .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") // + .setLevel(Level.INFO) // + .setMessage(new SimpleMessage("Hello, world!")).build(); + final byte[] result2 = layout.toByteArray(event2); + assertEquals("[org.apache.logging.log4j.core.layout.PatternLayoutTest] Hello, world!", new String(result2)); + } + + @Test public void testSpecialChars() throws Exception { final PatternLayout layout = PatternLayout.newBuilder().withPattern("\\\\%level\\t%msg\\n\\t%logger\\r\\n\\f") .withConfiguration(ctx.getConfiguration()).build(); @@ -287,34 +309,4 @@ public class PatternLayoutTest { assertEquals(StandardCharsets.UTF_8, layout.getCharset()); } - @Test - public void testPatternSelector() throws Exception { - PatternMatch[] patterns = new PatternMatch[1]; - patterns[0] = new PatternMatch("FLOW", "%d %-5p [%t]: ====== %C{1}.%M:%L %m ======%n"); - PatternSelector selector = MarkerPatternSelector.createSelector(patterns, "%d %-5p [%t]: %m%n", true, true, ctx.getConfiguration()); - final PatternLayout layout = PatternLayout.newBuilder().withPatternSelector(selector) - .withConfiguration(ctx.getConfiguration()).build(); - final LogEvent event1 = Log4jLogEvent.newBuilder() // - .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.layout.PatternLayoutTest$FauxLogger") - .setMarker(MarkerManager.getMarker("FLOW")) - .setLevel(Level.TRACE) // - .setIncludeLocation(true) - .setMessage(new SimpleMessage("entry")).build(); - final String result1 = new FauxLogger().formatEvent(event1, layout); - final String expectSuffix1 = String.format("====== PatternLayoutTest.testPatternSelector:303 entry ======%n"); - assertTrue("Unexpected result: " + result1, result1.endsWith(expectSuffix1)); - final LogEvent event2 = Log4jLogEvent.newBuilder() // - .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") // - .setLevel(Level.INFO) // - .setMessage(new SimpleMessage("Hello, world 1!")).build(); - final String result2 = new String(layout.toByteArray(event2)); - final String expectSuffix2 = String.format("Hello, world 1!%n"); - assertTrue("Unexpected result: " + result2, result2.endsWith(expectSuffix2)); - } - - public class FauxLogger { - public String formatEvent(LogEvent event, Layout<?> layout) { - return new String(layout.toByteArray(event)); - } - } } http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e72d2dc7/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/PatternSelectorTest.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/PatternSelectorTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/PatternSelectorTest.java new file mode 100644 index 0000000..5fb0d74 --- /dev/null +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/PatternSelectorTest.java @@ -0,0 +1,65 @@ +/* + * 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.core.layout; + +import static org.junit.Assert.assertTrue; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.MarkerManager; +import org.apache.logging.log4j.core.Layout; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.impl.Log4jLogEvent; +import org.apache.logging.log4j.message.SimpleMessage; +import org.junit.Test; + +public class PatternSelectorTest { + + public class FauxLogger { + public String formatEvent(LogEvent event, Layout<?> layout) { + return new String(layout.toByteArray(event)); + } + } + + LoggerContext ctx = LoggerContext.getContext(); + + @Test + public void testPatternSelector() throws Exception { + PatternMatch[] patterns = new PatternMatch[1]; + patterns[0] = new PatternMatch("FLOW", "%d %-5p [%t]: ====== %C{1}.%M:%L %m ======%n"); + PatternSelector selector = MarkerPatternSelector.createSelector(patterns, "%d %-5p [%t]: %m%n", true, true, ctx.getConfiguration()); + final PatternLayout layout = PatternLayout.newBuilder().withPatternSelector(selector) + .withConfiguration(ctx.getConfiguration()).build(); + final LogEvent event1 = Log4jLogEvent.newBuilder() // + .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.layout.PatternSelectorTest$FauxLogger") + .setMarker(MarkerManager.getMarker("FLOW")) + .setLevel(Level.TRACE) // + .setIncludeLocation(true) + .setMessage(new SimpleMessage("entry")).build(); + final String result1 = new FauxLogger().formatEvent(event1, layout); + final String expectSuffix1 = String.format("====== PatternSelectorTest.testPatternSelector:53 entry ======%n"); + assertTrue("Unexpected result: " + result1, result1.endsWith(expectSuffix1)); + final LogEvent event2 = Log4jLogEvent.newBuilder() // + .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") // + .setLevel(Level.INFO) // + .setMessage(new SimpleMessage("Hello, world 1!")).build(); + final String result2 = new String(layout.toByteArray(event2)); + final String expectSuffix2 = String.format("Hello, world 1!%n"); + assertTrue("Unexpected result: " + result2, result2.endsWith(expectSuffix2)); + } + +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e72d2dc7/log4j-core/src/test/java/org/apache/logging/log4j/core/pattern/EqualsReplacementConverterTest.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/pattern/EqualsReplacementConverterTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/pattern/EqualsReplacementConverterTest.java new file mode 100644 index 0000000..5534662 --- /dev/null +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/pattern/EqualsReplacementConverterTest.java @@ -0,0 +1,63 @@ +/* + * 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.core.pattern; + +import static org.junit.Assert.assertEquals; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.impl.Log4jLogEvent; +import org.apache.logging.log4j.message.SimpleMessage; +import org.apache.logging.log4j.util.Strings; +import org.junit.Test; + +/** + * + */ +public class EqualsReplacementConverterTest { + + @Test + public void testMarkerReplacement() { + testReplacement("%marker", Strings.EMPTY); + } + + @Test + public void testMarkerSimpleNameReplacement() { + testReplacement("%markerSimpleName", Strings.EMPTY); + } + + @Test + public void testLoggerNameReplacement() { + testReplacement("%logger", "[" + EqualsReplacementConverterTest.class.getName() + "]"); + } + + private void testReplacement(String tag, String expectedValue) { + final LogEvent event = Log4jLogEvent.newBuilder() // + .setLoggerName(EqualsReplacementConverterTest.class.getName()) // + .setLevel(Level.DEBUG) // + .setMessage(new SimpleMessage("This is a test")) // + .build(); + final StringBuilder sb = new StringBuilder(); + final LoggerContext ctx = LoggerContext.getContext(); + final String[] options = new String[] { "[" + tag + "]", "[]", expectedValue }; + final EqualsReplacementConverter converter = EqualsReplacementConverter.newInstance(ctx.getConfiguration(), + options); + converter.format(event, sb); + assertEquals(expectedValue, sb.toString()); + } +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e72d2dc7/src/changes/changes.xml ---------------------------------------------------------------------- diff --git a/src/changes/changes.xml b/src/changes/changes.xml index ec10a83..db5fc73 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -27,6 +27,9 @@ <action issue="LOG4J2-1129" dev="rgoers" type="add"> Allow PatternLayout to select a pattern to use based on some selection criteria. </action> + <action issue="LOG4J2-1145" dev="ggregory" type="add"> + Add %equals to PatternLayout to test and replace patterns with strings. + </action> <action issue="LOG4J2-1020" dev="mikes" type="fix"> Possibility to set shutdown timeout on AsyncAppender </action> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e72d2dc7/src/site/xdoc/manual/layouts.xml.vm ---------------------------------------------------------------------- diff --git a/src/site/xdoc/manual/layouts.xml.vm b/src/site/xdoc/manual/layouts.xml.vm index dd7a0fb..f05827a 100644 --- a/src/site/xdoc/manual/layouts.xml.vm +++ b/src/site/xdoc/manual/layouts.xml.vm @@ -618,7 +618,7 @@ WARN [main]: Message 2</pre> <tr> <td align="center"> <b>enc</b>{pattern}<br /> - <b>encode</b>{pattern}</b> + <b>encode</b>{pattern} </td> <td> <p> @@ -652,6 +652,19 @@ WARN [main]: Message 2</pre> </tr> <tr> <td align="center"> + <b>equals</b>{pattern}{test}{substitution} + </td> + <td> + <p>Replaces occurrences of 'test', a string, with its replacement 'substitution' in the + string resulting from evaluation of the pattern. For example, "%equals{[%marker]}{[]}{}" will + replace '[]' strings produces by events without markers with an empty string. + </p> + <p>The pattern can be arbitrarily complex and in particular can contain multiple conversion keywords. + </p> + </td> + </tr> + <tr> + <td align="center"> <b>ex</b>|<b>exception</b>|<b>throwable</b><br /> {["none"<br /> |"full"<br />
