Index: src/site/xdoc/manual/layouts.xml.vm =================================================================== --- src/site/xdoc/manual/layouts.xml.vm (revision 1605237) +++ src/site/xdoc/manual/layouts.xml.vm (working copy) @@ -142,7 +142,9 @@ A conversion pattern is composed of literal text and format control expressions called conversion specifiers.

-

Note that any literal text may be included in the conversion pattern. +

Note that any literal text, including Special Characters, may be included in the conversion + pattern. Special Characters include \t, \n, \r, \f. Use \\ to + insert a single backslash into the output.

Each conversion specifier starts with a percent sign (%) and is followed by optional format modifiers and a conversion character. The conversion character specifies the type of Index: log4j-core/src/test/java/org/apache/logging/log4j/core/layout/PatternLayoutTest.java =================================================================== --- log4j-core/src/test/java/org/apache/logging/log4j/core/layout/PatternLayoutTest.java (revision 1605237) +++ log4j-core/src/test/java/org/apache/logging/log4j/core/layout/PatternLayoutTest.java (working copy) @@ -237,5 +237,16 @@ assertTrue("expected \"Hello world Header\", actual \"" + new String(header) + '"', new String(header).equals(new String("Hello world Header"))); } - + @Test + public void testSpecialChars() throws Exception { + final LoggerContext ctx = (LoggerContext) LogManager.getContext(); + final PatternLayout layout = PatternLayout.newBuilder() + .withPattern("%level\\t%msg\\n\\t%logger\\n") + .withConfiguration(ctx.getConfiguration()) + .build(); + final LogEvent event = new Log4jLogEvent(this.getClass().getName(), null, + "org.apache.logging.log4j.core.Logger", Level.INFO, new SimpleMessage("Hello, world!"), null); + final byte[] result = layout.toByteArray(event); + assertEquals("INFO\tHello, world!\n\torg.apache.logging.log4j.core.layout.PatternLayoutTest\n", new String(result)); + } } Index: log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternLayout.java =================================================================== --- log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternLayout.java (revision 1605237) +++ log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternLayout.java (working copy) @@ -36,7 +36,6 @@ import org.apache.logging.log4j.core.pattern.PatternParser; import org.apache.logging.log4j.core.pattern.RegexReplacement; import org.apache.logging.log4j.core.util.Charsets; -import org.apache.logging.log4j.core.util.OptionConverter; /** *

A flexible layout configurable with pattern string. The goal of this class @@ -85,7 +84,7 @@ /** * Conversion pattern. */ - private final String conversionPattern; + private String conversionPattern; /** @@ -166,12 +165,12 @@ * @param conversionPattern conversion pattern. */ public void setConversionPattern(final String conversionPattern) { - final String pattern = OptionConverter.convertSpecialChars(conversionPattern); - if (pattern == null) { + if (conversionPattern == null) { return; } + this.conversionPattern = conversionPattern; final PatternParser parser = createPatternParser(this.config); - formatters = parser.parse(pattern, this.alwaysWriteExceptions, this.noConsoleNoAnsi); + formatters = parser.parse(conversionPattern, this.alwaysWriteExceptions, this.noConsoleNoAnsi); } /** Index: log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/LiteralPatternConverter.java =================================================================== --- log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/LiteralPatternConverter.java (revision 1605237) +++ log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/LiteralPatternConverter.java (working copy) @@ -18,6 +18,7 @@ import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.util.OptionConverter; /** @@ -41,7 +42,7 @@ */ public LiteralPatternConverter(final Configuration config, final String literal) { super("Literal", "literal"); - this.literal = literal; + this.literal = OptionConverter.convertSpecialChars(literal); this.config = config; substitute = config != null && literal.contains("${"); }