From 1116a4948f235d562946d5ef951ea9ef8007dbf5 Mon Sep 17 00:00:00 2001 From: Gerald Kritzinger Date: Fri, 27 Nov 2015 11:47:09 +0100 Subject: [PATCH] LOG4J2-1169 --- .../core/pattern/EqualsReplacementConverter.java | 236 ++++---- .../log4j/core/layout/PatternLayoutTest.java | 645 +++++++++++---------- .../pattern/EqualsReplacementConverterTest.java | 172 ++++-- 3 files changed, 577 insertions(+), 476 deletions(-) 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 index 2534b5d..5662911 100644 --- 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 @@ -1,101 +1,135 @@ -/* - * 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, an array of three elements: pattern, testString, and substitution. - * @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 formatters = parser.parse(options[0]); - return new EqualsReplacementConverter(formatters, p, options[2]); - } - - private final List 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 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); - } -} +/* + * 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.LoggerContext; +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, an array of three elements: pattern, testString, and substitution. + * @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 formatters = parser.parse(options[0]); + return new EqualsReplacementConverter(formatters, p, options[2]); + } + + private final List 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 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(); + + // if pattern equals test append substitution + if (testString.equals(string)) { + String substitutionString = parseSubstitution(event); + toAppendTo.append(substitutionString); + } + // if pattern equals not test append pattern + else { + toAppendTo.append(string); + } + } + + /** + * Returns the parsed substitution test. + * + * @param event + * the current log event + * @return the parsed substitution test + */ + protected String parseSubstitution(final LogEvent event) { + + StringBuilder substitutionBuffer = new StringBuilder(); + // check if substitution needs to be parsed + if (substitution.contains("%")) { + // parse substitution pattern + Configuration config = LoggerContext.getContext().getConfiguration(); + List substitutionFormatters = PatternLayout.createPatternParser(config).parse(substitution); + for (PatternFormatter formatter : substitutionFormatters) { + formatter.format(event, substitutionBuffer); + } + } else { + substitutionBuffer.append(substitution); + } + return substitutionBuffer.toString(); + } +} 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 5ac73a5..41a6a55 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 @@ -1,312 +1,333 @@ -/* - * 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 java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; - -import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.MarkerManager; -import org.apache.logging.log4j.ThreadContext; -import org.apache.logging.log4j.core.BasicConfigurationFactory; -import org.apache.logging.log4j.core.Layout; -import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.Logger; -import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.config.ConfigurationFactory; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; -import org.apache.logging.log4j.core.lookup.MainMapLookup; -import org.apache.logging.log4j.message.SimpleMessage; -import org.apache.logging.log4j.util.Strings; -import org.junit.After; -import org.junit.BeforeClass; -import org.junit.Test; - -import static org.junit.Assert.*; - -/** - * - */ -public class PatternLayoutTest { - static ConfigurationFactory cf = new BasicConfigurationFactory(); - static String msgPattern = "%m%n"; - static String OUTPUT_FILE = "target/output/PatternParser"; - static final String regexPattern = "%replace{%logger %msg}{\\.}{/}"; - static String WITNESS_FILE = "witness/PatternParser"; - - public static void cleanupClass() { - ConfigurationFactory.removeConfigurationFactory(cf); - } - - @BeforeClass - public static void setupClass() { - ConfigurationFactory.setConfigurationFactory(cf); - final LoggerContext ctx = LoggerContext.getContext(); - ctx.reconfigure(); - } - - LoggerContext ctx = LoggerContext.getContext(); - - Logger root = ctx.getLogger(""); - - @After - public void after() { - ThreadContext.clearMap(); - } - - @Test - public void testHeaderFooterJavaLookup() throws Exception { - // % does not work here. - final String pattern = "%d{UNIX} MyApp%n${java:version}%n${java:runtime}%n${java:vm}%n${java:os}%n${java:hw}"; - final PatternLayout layout = PatternLayout.newBuilder().withConfiguration(ctx.getConfiguration()) - .withHeader("Header: " + pattern).withFooter("Footer: " + pattern).build(); - final byte[] header = layout.getHeader(); - assertNotNull("No header", header); - final String headerStr = new String(header); - assertTrue(headerStr, headerStr.contains("Header: ")); - assertTrue(headerStr, headerStr.contains("Java version ")); - assertTrue(headerStr, headerStr.contains("(build ")); - assertTrue(headerStr, headerStr.contains(" from ")); - assertTrue(headerStr, headerStr.contains(" architecture: ")); - // - final byte[] footer = layout.getFooter(); - assertNotNull("No footer", footer); - final String footerStr = new String(footer); - assertTrue(footerStr, footerStr.contains("Footer: ")); - assertTrue(footerStr, footerStr.contains("Java version ")); - assertTrue(footerStr, footerStr.contains("(build ")); - assertTrue(footerStr, footerStr.contains(" from ")); - assertTrue(footerStr, footerStr.contains(" architecture: ")); - } - - /** - * Tests LOG4J2-962. - */ - @Test - public void testHeaderFooterMainLookup() { - MainMapLookup.setMainArguments("value0", "value1", "value2"); - final PatternLayout layout = PatternLayout.newBuilder().withConfiguration(ctx.getConfiguration()) - .withHeader("${main:0}").withFooter("${main:2}").build(); - final byte[] header = layout.getHeader(); - assertNotNull("No header", header); - final String headerStr = new String(header); - assertTrue(headerStr, headerStr.contains("value0")); - // - final byte[] footer = layout.getFooter(); - assertNotNull("No footer", footer); - final String footerStr = new String(footer); - assertTrue(footerStr, footerStr.contains("value2")); - } - - @Test - public void testHeaderFooterThreadContext() throws Exception { - final PatternLayout layout = PatternLayout.newBuilder().withPattern("%d{UNIX} %m") - .withConfiguration(ctx.getConfiguration()).withHeader("${ctx:header}").withFooter("${ctx:footer}") - .build(); - ThreadContext.put("header", "Hello world Header"); - ThreadContext.put("footer", "Hello world Footer"); - final byte[] header = layout.getHeader(); - assertNotNull("No header", header); - assertTrue("expected \"Hello world Header\", actual " + Strings.dquote(new String(header)), - new String(header).equals(new String("Hello world Header"))); - } - - private void testMdcPattern(final String patternStr, final String expectedStr, final boolean useThreadContext) - throws Exception { - final PatternLayout layout = PatternLayout.newBuilder().withPattern(patternStr) - .withConfiguration(ctx.getConfiguration()).build(); - if (useThreadContext) { - ThreadContext.put("key1", "value1"); - ThreadContext.put("key2", "value2"); - } - final LogEvent event = Log4jLogEvent.newBuilder() // - .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") // - .setLevel(Level.INFO) // - .setMessage(new SimpleMessage("Hello")).build(); - final byte[] result = layout.toByteArray(event); - assertEquals(expectedStr, new String(result)); - } - - @Test - public void testMdcPattern1() throws Exception { - testMdcPattern("%m : %X", "Hello : {}", false); - } - - @Test - public void testMdcPattern2() throws Exception { - testMdcPattern("%m : %X{key1}", "Hello : value1", true); - } - - @Test - public void testMdcPattern3() throws Exception { - testMdcPattern("%m : %X{key2}", "Hello : value2", true); - } - - @Test - public void testMdcPattern4() throws Exception { - testMdcPattern("%m : %X{key3}", "Hello : ", true); - } - - @Test - public void testMdcPattern5() throws Exception { - testMdcPattern("%m : %X{key1}, %X{key2}, %X{key3}", "Hello : value1, value2, ", true); - } - - @Test - public void testRegex() throws Exception { - final PatternLayout layout = PatternLayout.newBuilder().withPattern(regexPattern) - .withConfiguration(ctx.getConfiguration()).build(); - final LogEvent event = Log4jLogEvent.newBuilder() // - .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") // - .setLevel(Level.INFO) // - .setMessage(new SimpleMessage("Hello, world!")).build(); - final byte[] result = layout.toByteArray(event); - assertEquals("org/apache/logging/log4j/core/layout/PatternLayoutTest Hello, world!", new String(result)); - } - - @Test - public void testRegexEmptyMarker() throws Exception { - // replace "[]" with the empty string - final PatternLayout layout = PatternLayout.newBuilder().withPattern("[%logger]%replace{[%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 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(); - final LogEvent event = Log4jLogEvent.newBuilder() // - .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") // - .setLevel(Level.INFO) // - .setMessage(new SimpleMessage("Hello, world!")).build(); - final byte[] result = layout.toByteArray(event); - assertEquals("\\INFO\tHello, world!\n\torg.apache.logging.log4j.core.layout.PatternLayoutTest\r\n\f", - new String(result)); - } - - @Test - public void testUnixTime() throws Exception { - final PatternLayout layout = PatternLayout.newBuilder().withPattern("%d{UNIX} %m") - .withConfiguration(ctx.getConfiguration()).build(); - final LogEvent event1 = Log4jLogEvent.newBuilder() // - .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") // - .setLevel(Level.INFO) // - .setMessage(new SimpleMessage("Hello, world 1!")).build(); - final byte[] result1 = layout.toByteArray(event1); - assertEquals(event1.getTimeMillis() / 1000 + " Hello, world 1!", new String(result1)); - // System.out.println("event1=" + event1.getTimeMillis() / 1000); - final LogEvent event2 = Log4jLogEvent.newBuilder() // - .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") // - .setLevel(Level.INFO) // - .setMessage(new SimpleMessage("Hello, world 2!")).build(); - final byte[] result2 = layout.toByteArray(event2); - assertEquals(event2.getTimeMillis() / 1000 + " Hello, world 2!", new String(result2)); - // System.out.println("event2=" + event2.getTimeMillis() / 1000); - } - - @SuppressWarnings("unused") - private void testUnixTime(final String pattern) throws Exception { - final PatternLayout layout = PatternLayout.newBuilder().withPattern(pattern + " %m") - .withConfiguration(ctx.getConfiguration()).build(); - final LogEvent event1 = Log4jLogEvent.newBuilder() // - .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") // - .setLevel(Level.INFO) // - .setMessage(new SimpleMessage("Hello, world 1!")).build(); - final byte[] result1 = layout.toByteArray(event1); - assertEquals(event1.getTimeMillis() + " Hello, world 1!", new String(result1)); - // System.out.println("event1=" + event1.getMillis()); - final LogEvent event2 = Log4jLogEvent.newBuilder() // - .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") // - .setLevel(Level.INFO) // - .setMessage(new SimpleMessage("Hello, world 2!")).build(); - final byte[] result2 = layout.toByteArray(event2); - assertEquals(event2.getTimeMillis() + " Hello, world 2!", new String(result2)); - // System.out.println("event2=" + event2.getMillis()); - } - - @Test - public void testUnixTimeMillis() throws Exception { - final PatternLayout layout = PatternLayout.newBuilder().withPattern("%d{UNIX_MILLIS} %m") - .withConfiguration(ctx.getConfiguration()).build(); - final LogEvent event1 = Log4jLogEvent.newBuilder() // - .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") // - .setLevel(Level.INFO) // - .setMessage(new SimpleMessage("Hello, world 1!")).build(); - final byte[] result1 = layout.toByteArray(event1); - assertEquals(event1.getTimeMillis() + " Hello, world 1!", new String(result1)); - // System.out.println("event1=" + event1.getTimeMillis()); - final LogEvent event2 = Log4jLogEvent.newBuilder() // - .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") // - .setLevel(Level.INFO) // - .setMessage(new SimpleMessage("Hello, world 2!")).build(); - final byte[] result2 = layout.toByteArray(event2); - assertEquals(event2.getTimeMillis() + " Hello, world 2!", new String(result2)); - // System.out.println("event2=" + event2.getTimeMillis()); - } - - @Test - public void testUsePlatformDefaultIfNoCharset() throws Exception { - final PatternLayout layout = PatternLayout.newBuilder().withPattern("%m") - .withConfiguration(ctx.getConfiguration()).build(); - assertEquals(Charset.defaultCharset(), layout.getCharset()); - } - - @Test - public void testUseSpecifiedCharsetIfExists() throws Exception { - final PatternLayout layout = PatternLayout.newBuilder().withPattern("%m") - .withConfiguration(ctx.getConfiguration()).withCharset(StandardCharsets.UTF_8).build(); - assertEquals(StandardCharsets.UTF_8, layout.getCharset()); - } - -} +/* + * 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 java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.MarkerManager; +import org.apache.logging.log4j.ThreadContext; +import org.apache.logging.log4j.core.BasicConfigurationFactory; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.Logger; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.config.ConfigurationFactory; +import org.apache.logging.log4j.core.impl.Log4jLogEvent; +import org.apache.logging.log4j.core.lookup.MainMapLookup; +import org.apache.logging.log4j.message.SimpleMessage; +import org.apache.logging.log4j.util.Strings; +import org.junit.After; +import org.junit.BeforeClass; +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * + */ +public class PatternLayoutTest { + static ConfigurationFactory cf = new BasicConfigurationFactory(); + static String msgPattern = "%m%n"; + static String OUTPUT_FILE = "target/output/PatternParser"; + static final String regexPattern = "%replace{%logger %msg}{\\.}{/}"; + static String WITNESS_FILE = "witness/PatternParser"; + + public static void cleanupClass() { + ConfigurationFactory.removeConfigurationFactory(cf); + } + + @BeforeClass + public static void setupClass() { + ConfigurationFactory.setConfigurationFactory(cf); + final LoggerContext ctx = LoggerContext.getContext(); + ctx.reconfigure(); + } + + LoggerContext ctx = LoggerContext.getContext(); + + Logger root = ctx.getLogger(""); + + @After + public void after() { + ThreadContext.clearMap(); + } + + @Test + public void testHeaderFooterJavaLookup() throws Exception { + // % does not work here. + final String pattern = "%d{UNIX} MyApp%n${java:version}%n${java:runtime}%n${java:vm}%n${java:os}%n${java:hw}"; + final PatternLayout layout = PatternLayout.newBuilder().withConfiguration(ctx.getConfiguration()) + .withHeader("Header: " + pattern).withFooter("Footer: " + pattern).build(); + final byte[] header = layout.getHeader(); + assertNotNull("No header", header); + final String headerStr = new String(header); + assertTrue(headerStr, headerStr.contains("Header: ")); + assertTrue(headerStr, headerStr.contains("Java version ")); + assertTrue(headerStr, headerStr.contains("(build ")); + assertTrue(headerStr, headerStr.contains(" from ")); + assertTrue(headerStr, headerStr.contains(" architecture: ")); + // + final byte[] footer = layout.getFooter(); + assertNotNull("No footer", footer); + final String footerStr = new String(footer); + assertTrue(footerStr, footerStr.contains("Footer: ")); + assertTrue(footerStr, footerStr.contains("Java version ")); + assertTrue(footerStr, footerStr.contains("(build ")); + assertTrue(footerStr, footerStr.contains(" from ")); + assertTrue(footerStr, footerStr.contains(" architecture: ")); + } + + /** + * Tests LOG4J2-962. + */ + @Test + public void testHeaderFooterMainLookup() { + MainMapLookup.setMainArguments("value0", "value1", "value2"); + final PatternLayout layout = PatternLayout.newBuilder().withConfiguration(ctx.getConfiguration()) + .withHeader("${main:0}").withFooter("${main:2}").build(); + final byte[] header = layout.getHeader(); + assertNotNull("No header", header); + final String headerStr = new String(header); + assertTrue(headerStr, headerStr.contains("value0")); + // + final byte[] footer = layout.getFooter(); + assertNotNull("No footer", footer); + final String footerStr = new String(footer); + assertTrue(footerStr, footerStr.contains("value2")); + } + + @Test + public void testHeaderFooterThreadContext() throws Exception { + final PatternLayout layout = PatternLayout.newBuilder().withPattern("%d{UNIX} %m") + .withConfiguration(ctx.getConfiguration()).withHeader("${ctx:header}").withFooter("${ctx:footer}") + .build(); + ThreadContext.put("header", "Hello world Header"); + ThreadContext.put("footer", "Hello world Footer"); + final byte[] header = layout.getHeader(); + assertNotNull("No header", header); + assertTrue("expected \"Hello world Header\", actual " + Strings.dquote(new String(header)), + new String(header).equals(new String("Hello world Header"))); + } + + private void testMdcPattern(final String patternStr, final String expectedStr, final boolean useThreadContext) + throws Exception { + final PatternLayout layout = PatternLayout.newBuilder().withPattern(patternStr) + .withConfiguration(ctx.getConfiguration()).build(); + if (useThreadContext) { + ThreadContext.put("key1", "value1"); + ThreadContext.put("key2", "value2"); + } + final LogEvent event = Log4jLogEvent.newBuilder() // + .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") // + .setLevel(Level.INFO) // + .setMessage(new SimpleMessage("Hello")).build(); + final byte[] result = layout.toByteArray(event); + assertEquals(expectedStr, new String(result)); + } + + @Test + public void testMdcPattern1() throws Exception { + testMdcPattern("%m : %X", "Hello : {}", false); + } + + @Test + public void testMdcPattern2() throws Exception { + testMdcPattern("%m : %X{key1}", "Hello : value1", true); + } + + @Test + public void testMdcPattern3() throws Exception { + testMdcPattern("%m : %X{key2}", "Hello : value2", true); + } + + @Test + public void testMdcPattern4() throws Exception { + testMdcPattern("%m : %X{key3}", "Hello : ", true); + } + + @Test + public void testMdcPattern5() throws Exception { + testMdcPattern("%m : %X{key1}, %X{key2}, %X{key3}", "Hello : value1, value2, ", true); + } + + @Test + public void testRegex() throws Exception { + final PatternLayout layout = PatternLayout.newBuilder().withPattern(regexPattern) + .withConfiguration(ctx.getConfiguration()).build(); + final LogEvent event = Log4jLogEvent.newBuilder() // + .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") // + .setLevel(Level.INFO) // + .setMessage(new SimpleMessage("Hello, world!")).build(); + final byte[] result = layout.toByteArray(event); + assertEquals("org/apache/logging/log4j/core/layout/PatternLayoutTest Hello, world!", new String(result)); + } + + @Test + public void testRegexEmptyMarker() throws Exception { + // replace "[]" with the empty string + final PatternLayout layout = PatternLayout.newBuilder().withPattern("[%logger]%replace{[%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 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 testEqualsMarkerWithMessageSubstitution() 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]", 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(); + final LogEvent event = Log4jLogEvent.newBuilder() // + .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") // + .setLevel(Level.INFO) // + .setMessage(new SimpleMessage("Hello, world!")).build(); + final byte[] result = layout.toByteArray(event); + assertEquals("\\INFO\tHello, world!\n\torg.apache.logging.log4j.core.layout.PatternLayoutTest\r\n\f", + new String(result)); + } + + @Test + public void testUnixTime() throws Exception { + final PatternLayout layout = PatternLayout.newBuilder().withPattern("%d{UNIX} %m") + .withConfiguration(ctx.getConfiguration()).build(); + final LogEvent event1 = Log4jLogEvent.newBuilder() // + .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") // + .setLevel(Level.INFO) // + .setMessage(new SimpleMessage("Hello, world 1!")).build(); + final byte[] result1 = layout.toByteArray(event1); + assertEquals(event1.getTimeMillis() / 1000 + " Hello, world 1!", new String(result1)); + // System.out.println("event1=" + event1.getTimeMillis() / 1000); + final LogEvent event2 = Log4jLogEvent.newBuilder() // + .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") // + .setLevel(Level.INFO) // + .setMessage(new SimpleMessage("Hello, world 2!")).build(); + final byte[] result2 = layout.toByteArray(event2); + assertEquals(event2.getTimeMillis() / 1000 + " Hello, world 2!", new String(result2)); + // System.out.println("event2=" + event2.getTimeMillis() / 1000); + } + + @SuppressWarnings("unused") + private void testUnixTime(final String pattern) throws Exception { + final PatternLayout layout = PatternLayout.newBuilder().withPattern(pattern + " %m") + .withConfiguration(ctx.getConfiguration()).build(); + final LogEvent event1 = Log4jLogEvent.newBuilder() // + .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") // + .setLevel(Level.INFO) // + .setMessage(new SimpleMessage("Hello, world 1!")).build(); + final byte[] result1 = layout.toByteArray(event1); + assertEquals(event1.getTimeMillis() + " Hello, world 1!", new String(result1)); + // System.out.println("event1=" + event1.getMillis()); + final LogEvent event2 = Log4jLogEvent.newBuilder() // + .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") // + .setLevel(Level.INFO) // + .setMessage(new SimpleMessage("Hello, world 2!")).build(); + final byte[] result2 = layout.toByteArray(event2); + assertEquals(event2.getTimeMillis() + " Hello, world 2!", new String(result2)); + // System.out.println("event2=" + event2.getMillis()); + } + + @Test + public void testUnixTimeMillis() throws Exception { + final PatternLayout layout = PatternLayout.newBuilder().withPattern("%d{UNIX_MILLIS} %m") + .withConfiguration(ctx.getConfiguration()).build(); + final LogEvent event1 = Log4jLogEvent.newBuilder() // + .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") // + .setLevel(Level.INFO) // + .setMessage(new SimpleMessage("Hello, world 1!")).build(); + final byte[] result1 = layout.toByteArray(event1); + assertEquals(event1.getTimeMillis() + " Hello, world 1!", new String(result1)); + // System.out.println("event1=" + event1.getTimeMillis()); + final LogEvent event2 = Log4jLogEvent.newBuilder() // + .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") // + .setLevel(Level.INFO) // + .setMessage(new SimpleMessage("Hello, world 2!")).build(); + final byte[] result2 = layout.toByteArray(event2); + assertEquals(event2.getTimeMillis() + " Hello, world 2!", new String(result2)); + // System.out.println("event2=" + event2.getTimeMillis()); + } + + @Test + public void testUsePlatformDefaultIfNoCharset() throws Exception { + final PatternLayout layout = PatternLayout.newBuilder().withPattern("%m") + .withConfiguration(ctx.getConfiguration()).build(); + assertEquals(Charset.defaultCharset(), layout.getCharset()); + } + + @Test + public void testUseSpecifiedCharsetIfExists() throws Exception { + final PatternLayout layout = PatternLayout.newBuilder().withPattern("%m") + .withConfiguration(ctx.getConfiguration()).withCharset(StandardCharsets.UTF_8).build(); + assertEquals(StandardCharsets.UTF_8, layout.getCharset()); + } + +} 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 index 5534662..19778bd 100644 --- 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 @@ -1,63 +1,109 @@ -/* - * 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()); - } -} +/* + * 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 { + + private String testMessage = "This is a test"; + + @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() + "]"); + } + + @Test + public void testMarkerReplacementWithMessage() { + testReplacement(testMessage, new String[]{ "[%marker]", "[]", "%msg"}); + } + + private void testReplacement(String tag, String expectedValue) { + + final String[] options = new String[] { "[" + tag + "]", "[]", expectedValue }; + testReplacement(expectedValue, options); + } + + private void testReplacement(String expectedValue, String[] options) { + final LogEvent event = Log4jLogEvent.newBuilder() // + .setLoggerName(EqualsReplacementConverterTest.class.getName()) // + .setLevel(Level.DEBUG) // + .setMessage(new SimpleMessage(testMessage)) // + .build(); + final StringBuilder sb = new StringBuilder(); + final LoggerContext ctx = LoggerContext.getContext(); + final EqualsReplacementConverter converter = EqualsReplacementConverter.newInstance(ctx.getConfiguration(), + options); + converter.format(event, sb); + assertEquals(expectedValue, sb.toString()); + } + + @Test + public void testParseSubstitutionWithPattern() { + testParseSubstitution("%msg", testMessage); + } + + @Test + public void testParseSubstitutionWithoutPattern() { + String substitution = "test"; + testParseSubstitution(substitution, substitution); + } + + @Test + public void testParseSubstitutionEmpty() { + testParseSubstitution("", ""); + } + + @Test + public void testParseSubstitutionWithWhiteSpaces() { + testParseSubstitution(" ", " "); + } + + private void testParseSubstitution(String substititon, String expected) { + + final LogEvent event = Log4jLogEvent.newBuilder() // + .setLoggerName(EqualsReplacementConverterTest.class.getName()) // + .setLevel(Level.DEBUG) // + .setMessage(new SimpleMessage(testMessage)) // + .build(); + final LoggerContext ctx = LoggerContext.getContext(); + final EqualsReplacementConverter converter = EqualsReplacementConverter.newInstance(ctx.getConfiguration(), new String[] { "[%marker]", "[]", substititon }); + String actual = converter.parseSubstitution(event); + assertEquals(expected, actual); + } +} -- 2.6.3.windows.1