http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08386d0e/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/AbstractStyleNameConverter.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/AbstractStyleNameConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/AbstractStyleNameConverter.java index c15c9fc..5a86560 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/AbstractStyleNameConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/AbstractStyleNameConverter.java @@ -18,6 +18,7 @@ package org.apache.logging.log4j.core.pattern; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; +import java.nio.charset.Charset; import java.util.Arrays; import java.util.List; @@ -29,7 +30,7 @@ import org.apache.logging.log4j.core.layout.PatternLayout; /** * Style pattern converter. Adds ANSI color styling to the result of the enclosed pattern. */ -public abstract class AbstractStyleNameConverter extends LogEventPatternConverter /*TODO: implements AnsiConverter*/ { +public abstract class AbstractStyleNameConverter extends LogEventPatternConverter /* TODO: implements AnsiConverter */{ private final List<PatternFormatter> formatters; @@ -42,8 +43,8 @@ public abstract class AbstractStyleNameConverter extends LogEventPatternConverte * @param styling The styling that should encapsulate the pattern. */ protected AbstractStyleNameConverter(final String name, final List<PatternFormatter> formatters, - final String styling) { - super(name, "style"); + final String styling, final FormattingInfo formattingInfo) { + super(name, "style", formattingInfo); this.formatters = formatters; this.style = styling; } @@ -64,8 +65,8 @@ public abstract class AbstractStyleNameConverter extends LogEventPatternConverte * @param formatters The PatternFormatters to generate the text to manipulate. * @param styling The styling that should encapsulate the pattern. */ - public Black(final List<PatternFormatter> formatters, final String styling) { - super(NAME, formatters, styling); + public Black(final List<PatternFormatter> formatters, final String styling, final FormattingInfo formattingInfo) { + super(NAME, formatters, styling, formattingInfo); } /** @@ -76,8 +77,9 @@ public abstract class AbstractStyleNameConverter extends LogEventPatternConverte * throwable will be formatted. * @return new instance of class or null */ - public static Black newInstance(final Configuration config, final String[] options) { - return newInstance(Black.class, NAME, config, options); + public static Black newInstance(final Configuration config, final String[] options, + final FormattingInfo formattingInfo) { + return newInstance(Black.class, NAME, config, options, formattingInfo); } } @@ -97,8 +99,8 @@ public abstract class AbstractStyleNameConverter extends LogEventPatternConverte * @param formatters The PatternFormatters to generate the text to manipulate. * @param styling The styling that should encapsulate the pattern. */ - public Blue(final List<PatternFormatter> formatters, final String styling) { - super(NAME, formatters, styling); + public Blue(final List<PatternFormatter> formatters, final String styling, final FormattingInfo formattingInfo) { + super(NAME, formatters, styling, formattingInfo); } /** @@ -106,11 +108,12 @@ public abstract class AbstractStyleNameConverter extends LogEventPatternConverte * * @param config The current Configuration. * @param options The pattern options, may be null. If the first element is "short", only the first line of the - * throwable will be formatted. + * throwable will be formatted. * @return new instance of class or null */ - public static Blue newInstance(final Configuration config, final String[] options) { - return newInstance(Blue.class, NAME, config, options); + public static Blue newInstance(final Configuration config, final String[] options, + final FormattingInfo formattingInfo) { + return newInstance(Blue.class, NAME, config, options, formattingInfo); } } @@ -130,8 +133,8 @@ public abstract class AbstractStyleNameConverter extends LogEventPatternConverte * @param formatters The PatternFormatters to generate the text to manipulate. * @param styling The styling that should encapsulate the pattern. */ - public Cyan(final List<PatternFormatter> formatters, final String styling) { - super(NAME, formatters, styling); + public Cyan(final List<PatternFormatter> formatters, final String styling, final FormattingInfo formattingInfo) { + super(NAME, formatters, styling, formattingInfo); } /** @@ -139,11 +142,12 @@ public abstract class AbstractStyleNameConverter extends LogEventPatternConverte * * @param config The current Configuration. * @param options The pattern options, may be null. If the first element is "short", only the first line of the - * throwable will be formatted. + * throwable will be formatted. * @return new instance of class or null */ - public static Cyan newInstance(final Configuration config, final String[] options) { - return newInstance(Cyan.class, NAME, config, options); + public static Cyan newInstance(final Configuration config, final String[] options, + final FormattingInfo formattingInfo) { + return newInstance(Cyan.class, NAME, config, options, formattingInfo); } } @@ -163,8 +167,8 @@ public abstract class AbstractStyleNameConverter extends LogEventPatternConverte * @param formatters The PatternFormatters to generate the text to manipulate. * @param styling The styling that should encapsulate the pattern. */ - public Green(final List<PatternFormatter> formatters, final String styling) { - super(NAME, formatters, styling); + public Green(final List<PatternFormatter> formatters, final String styling, final FormattingInfo formattingInfo) { + super(NAME, formatters, styling, formattingInfo); } /** @@ -172,11 +176,12 @@ public abstract class AbstractStyleNameConverter extends LogEventPatternConverte * * @param config The current Configuration. * @param options The pattern options, may be null. If the first element is "short", only the first line of the - * throwable will be formatted. + * throwable will be formatted. * @return new instance of class or null */ - public static Green newInstance(final Configuration config, final String[] options) { - return newInstance(Green.class, NAME, config, options); + public static Green newInstance(final Configuration config, final String[] options, + final FormattingInfo formattingInfo) { + return newInstance(Green.class, NAME, config, options, formattingInfo); } } @@ -196,8 +201,9 @@ public abstract class AbstractStyleNameConverter extends LogEventPatternConverte * @param formatters The PatternFormatters to generate the text to manipulate. * @param styling The styling that should encapsulate the pattern. */ - public Magenta(final List<PatternFormatter> formatters, final String styling) { - super(NAME, formatters, styling); + public Magenta(final List<PatternFormatter> formatters, final String styling, + final FormattingInfo formattingInfo) { + super(NAME, formatters, styling, formattingInfo); } /** @@ -205,11 +211,12 @@ public abstract class AbstractStyleNameConverter extends LogEventPatternConverte * * @param config The current Configuration. * @param options The pattern options, may be null. If the first element is "short", only the first line of the - * throwable will be formatted. + * throwable will be formatted. * @return new instance of class or null */ - public static Magenta newInstance(final Configuration config, final String[] options) { - return newInstance(Magenta.class, NAME, config, options); + public static Magenta newInstance(final Configuration config, final String[] options, + final FormattingInfo formattingInfo) { + return newInstance(Magenta.class, NAME, config, options, formattingInfo); } } @@ -229,8 +236,8 @@ public abstract class AbstractStyleNameConverter extends LogEventPatternConverte * @param formatters The PatternFormatters to generate the text to manipulate. * @param styling The styling that should encapsulate the pattern. */ - public Red(final List<PatternFormatter> formatters, final String styling) { - super(NAME, formatters, styling); + public Red(final List<PatternFormatter> formatters, final String styling, final FormattingInfo formattingInfo) { + super(NAME, formatters, styling, formattingInfo); } /** @@ -238,11 +245,12 @@ public abstract class AbstractStyleNameConverter extends LogEventPatternConverte * * @param config The current Configuration. * @param options The pattern options, may be null. If the first element is "short", only the first line of the - * throwable will be formatted. + * throwable will be formatted. * @return new instance of class or null */ - public static Red newInstance(final Configuration config, final String[] options) { - return newInstance(Red.class, NAME, config, options); + public static Red newInstance(final Configuration config, final String[] options, + final FormattingInfo formattingInfo) { + return newInstance(Red.class, NAME, config, options, formattingInfo); } } @@ -262,8 +270,8 @@ public abstract class AbstractStyleNameConverter extends LogEventPatternConverte * @param formatters The PatternFormatters to generate the text to manipulate. * @param styling The styling that should encapsulate the pattern. */ - public White(final List<PatternFormatter> formatters, final String styling) { - super(NAME, formatters, styling); + public White(final List<PatternFormatter> formatters, final String styling, final FormattingInfo formattingInfo) { + super(NAME, formatters, styling, formattingInfo); } /** @@ -271,11 +279,12 @@ public abstract class AbstractStyleNameConverter extends LogEventPatternConverte * * @param config The current Configuration. * @param options The pattern options, may be null. If the first element is "short", only the first line of the - * throwable will be formatted. + * throwable will be formatted. * @return new instance of class or null */ - public static White newInstance(final Configuration config, final String[] options) { - return newInstance(White.class, NAME, config, options); + public static White newInstance(final Configuration config, final String[] options, + final FormattingInfo formattingInfo) { + return newInstance(White.class, NAME, config, options, formattingInfo); } } @@ -295,8 +304,8 @@ public abstract class AbstractStyleNameConverter extends LogEventPatternConverte * @param formatters The PatternFormatters to generate the text to manipulate. * @param styling The styling that should encapsulate the pattern. */ - public Yellow(final List<PatternFormatter> formatters, final String styling) { - super(NAME, formatters, styling); + public Yellow(final List<PatternFormatter> formatters, final String styling, final FormattingInfo formattingInfo) { + super(NAME, formatters, styling, formattingInfo); } /** @@ -304,11 +313,12 @@ public abstract class AbstractStyleNameConverter extends LogEventPatternConverte * * @param config The current Configuration. * @param options The pattern options, may be null. If the first element is "short", only the first line of the - * throwable will be formatted. + * throwable will be formatted. * @return new instance of class or null */ - public static Yellow newInstance(final Configuration config, final String[] options) { - return newInstance(Yellow.class, NAME, config, options); + public static Yellow newInstance(final Configuration config, final String[] options, + final FormattingInfo formattingInfo) { + return newInstance(Yellow.class, NAME, config, options, formattingInfo); } } @@ -317,19 +327,18 @@ public abstract class AbstractStyleNameConverter extends LogEventPatternConverte * * @param config The current Configuration. * @param options The pattern options, may be null. If the first element is "short", only the first line of the - * throwable will be formatted. + * throwable will be formatted. * @return new instance of class or null */ protected static <T extends AbstractStyleNameConverter> T newInstance(final Class<T> asnConverterClass, - final String name, final Configuration config, - final String[] options) { + final String name, final Configuration config, final String[] options, final FormattingInfo formattingInfo) { final List<PatternFormatter> formatters = toPatternFormatterList(config, options); if (formatters == null) { return null; } try { final Constructor<T> constructor = asnConverterClass.getConstructor(List.class, String.class); - return constructor.newInstance(formatters, AnsiEscape.createSequence(name)); + return constructor.newInstance(formatters, AnsiEscape.createSequence(name), formattingInfo); } catch (final SecurityException e) { LOGGER.error(e.toString(), e); } catch (final NoSuchMethodException e) { @@ -370,13 +379,27 @@ public abstract class AbstractStyleNameConverter extends LogEventPatternConverte * {@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); - } - if (buf.length() > 0) { - toAppendTo.append(style).append(buf.toString()).append(AnsiEscape.getDefaultStyle()); + public void format(final LogEvent event, final TextBuffer toAppendTo) { + format0(event, toAppendTo, null); + } + + /** + * {@inheritDoc} + */ + @Override + public void format(final LogEvent event, final BinaryBuffer toAppendTo, final Charset charset) { + format0(event, toAppendTo, charset); + } + + private void format0(final LogEvent event, final Buffer toAppendTo, final Charset charset) { + StyleConverter.formatNested(event, toAppendTo, charset, false, formatters, style, AnsiEscape.getDefaultStyle()); + } + + @Override + public void setCharset(final Charset charset) { + super.setCharset(charset); + for (PatternFormatter paf : formatters) { + paf.getConverter().setCharset(charset); } } }
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08386d0e/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ArrayPatternConverter.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ArrayPatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ArrayPatternConverter.java index c571b45..b731390 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ArrayPatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ArrayPatternConverter.java @@ -23,8 +23,8 @@ public interface ArrayPatternConverter extends PatternConverter { /** * Formats an array of Objects. - * @param toAppendTo The StringBuilder to add the content to. + * @param toAppendTo The Buffer to add the content to. * @param objects The Object array. */ - void format(final StringBuilder toAppendTo, Object... objects); + void format(final Buffer toAppendTo, Object... objects); } http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08386d0e/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ClassNamePatternConverter.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ClassNamePatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ClassNamePatternConverter.java index a2e0f2a..1d17139 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ClassNamePatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ClassNamePatternConverter.java @@ -16,10 +16,11 @@ */ package org.apache.logging.log4j.core.pattern; +import java.nio.charset.Charset; + import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.plugins.Plugin; - /** * Formats the class name of the site of the logging request. */ @@ -27,16 +28,15 @@ import org.apache.logging.log4j.core.config.plugins.Plugin; @ConverterKeys({ "C", "class" }) public final class ClassNamePatternConverter extends NamePatternConverter { - private static final String NA = "?"; + private static final char NA = '?'; /** * Private constructor. * * @param options options, may be null. */ - private ClassNamePatternConverter( - final String[] options) { - super("Class Name", "class name", options); + private ClassNamePatternConverter(final String[] options, final FormattingInfo formattingInfo) { + super("Class Name", "class name", options, formattingInfo); } /** @@ -45,18 +45,18 @@ public final class ClassNamePatternConverter extends NamePatternConverter { * @param options options, may be null. * @return instance of pattern converter. */ - public static ClassNamePatternConverter newInstance(final String[] options) { - return new ClassNamePatternConverter(options); + public static ClassNamePatternConverter newInstance(final String[] options, final FormattingInfo formattingInfo) { + return new ClassNamePatternConverter(options, formattingInfo); } /** * Format a logging event. * - * @param event event to format. - * @param toAppendTo string buffer to which class name will be appended. + * @param event event to format. + * @param toAppendTo buffer to which class name will be appended. */ @Override - public void format(final LogEvent event, final StringBuilder toAppendTo) { + public void format(final LogEvent event, final TextBuffer toAppendTo) { final StackTraceElement element = event.getSource(); if (element == null) { toAppendTo.append(NA); @@ -64,4 +64,20 @@ public final class ClassNamePatternConverter extends NamePatternConverter { toAppendTo.append(abbreviate(element.getClassName())); } } + + /** + * Format a logging event. + * + * @param event event to format. + * @param toAppendTo buffer to which class name will be appended. + */ + @Override + public void format(final LogEvent event, final BinaryBuffer toAppendTo, final Charset charset) { + final StackTraceElement element = event.getSource(); + if (element == null) { + toAppendTo.append((byte) NA); + } else { + toAppendTo.append(abbreviateToBinary(element.getClassName(), charset)); + } + } } http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08386d0e/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/DatePatternConverter.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/DatePatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/DatePatternConverter.java index 4e34d50..6415abd 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/DatePatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/DatePatternConverter.java @@ -16,12 +16,14 @@ */ package org.apache.logging.log4j.core.pattern; +import java.nio.charset.Charset; import java.text.SimpleDateFormat; import java.util.Date; import java.util.TimeZone; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.plugins.Plugin; +import org.apache.logging.log4j.core.util.Assert; /** * Convert and format the event's date in a StringBuilder. @@ -30,48 +32,112 @@ import org.apache.logging.log4j.core.config.plugins.Plugin; @ConverterKeys({ "d", "date" }) public final class DatePatternConverter extends LogEventPatternConverter implements ArrayPatternConverter { - private abstract static class Formatter { - abstract String format(long time); + /** + * ADT for formatter helpers. + */ + public abstract static interface Formatter { + void format(long time, Buffer buffer); - public String toPattern() { - return null; - } + void format(Date time, Buffer buffer); + + void format(long timestamp, BinaryBuffer output, Charset charset); + + String toPattern(); } - private static class PatternFormatter extends Formatter { - private final SimpleDateFormat simpleDateFormat; + private static class PatternFormatter implements Formatter { + private ThreadLocal<SimpleDateFormat> simpleDateFormat = new ThreadLocal<SimpleDateFormat>() { + @Override + protected SimpleDateFormat initialValue() { + final SimpleDateFormat result = new SimpleDateFormat(pattern); + if (timeZone != null) { + result.setTimeZone(timeZone); + } + return result; + } + }; + private final String pattern; + private final TimeZone timeZone; + private final boolean useFastFormat; + + PatternFormatter(final String pattern, final TimeZone timeZone) { + this.pattern = Assert.requireNonNull(pattern, "pattern is null"); + this.timeZone = timeZone; + this.useFastFormat = ABSOLUTE_TIME_PATTERN.equals(pattern); + } - PatternFormatter(final SimpleDateFormat simpleDateFormat) { - this.simpleDateFormat = simpleDateFormat; + @Override + public void format(final long time, final Buffer buffer) { + format(new Date(time), buffer); } @Override - String format(final long time) { - return simpleDateFormat.format(Long.valueOf(time)); + public void format(final Date time, final Buffer buffer) { + if (useFastFormat) { + + } else { + final String formatted = simpleDateFormat.get().format(time); + buffer.append(formatted); + } + } + + @Override + public void format(final long timestamp, final BinaryBuffer output, final Charset charset) { + if (useFastFormat) { + + } else { + format(new Date(timestamp), output); // use SimpleDateFormat + } } @Override public String toPattern() { - return simpleDateFormat.toPattern(); + return pattern; } } - private static class UnixFormatter extends Formatter { + private static class UnixFormatter implements Formatter { + @Override + public void format(final long time, final Buffer buffer) { + buffer.append(time / 1000); + } @Override - String format(final long time) { - return Long.toString(time / 1000); + public void format(final Date time, final Buffer buffer) { + format(time.getTime(), buffer); } + @Override + public void format(final long timestamp, final BinaryBuffer output, final Charset charset) { + output.append(timestamp / 1000); + } + + @Override + public String toPattern() { + return null; + } } - private static class UnixMillisFormatter extends Formatter { + private static class UnixMillisFormatter implements Formatter { + @Override + public void format(final long time, final Buffer buffer) { + buffer.append(time); + } + + @Override + public void format(final Date time, final Buffer buffer) { + format(time.getTime(), buffer); + } @Override - String format(final long time) { - return Long.toString(time); + public void format(final long timestamp, final BinaryBuffer output, final Charset charset) { + output.append(timestamp); } + @Override + public String toPattern() { + return null; + } } /** @@ -82,7 +148,7 @@ public final class DatePatternConverter extends LogEventPatternConverter impleme /** * SimpleTimePattern for ABSOLUTE. */ - private static final String ABSOLUTE_TIME_PATTERN = "HH:mm:ss,SSS"; + static final String ABSOLUTE_TIME_PATTERN = "HH:mm:ss,SSS"; /** * COMPACT string literal. @@ -150,31 +216,22 @@ public final class DatePatternConverter extends LogEventPatternConverter impleme /** * Obtains an instance of pattern converter. * - * @param options - * options, may be null. + * @param options options, may be null. * @return instance of pattern converter. */ - public static DatePatternConverter newInstance(final String[] options) { - return new DatePatternConverter(options); + public static DatePatternConverter newInstance(final String[] options, final FormattingInfo formattingInfo) { + return new DatePatternConverter(options, formattingInfo); } - /** - * Date format. - */ - private String cachedDateString; - - private final Formatter formatter; - - private long lastTimestamp; + private Formatter formatter; /** * Private constructor. * - * @param options - * options, may be null. + * @param options options, may be null. */ - private DatePatternConverter(final String[] options) { - super("Date", "date"); + private DatePatternConverter(final String[] options, final FormattingInfo formattingInfo) { + super("Date", "date", formattingInfo); // null patternOption is OK. final String patternOption = options != null && options.length > 0 ? options[0] : null; @@ -203,62 +260,66 @@ public final class DatePatternConverter extends LogEventPatternConverter impleme } if (pattern != null) { - SimpleDateFormat tempFormat; - try { - tempFormat = new SimpleDateFormat(pattern); + new SimpleDateFormat(pattern); } catch (final IllegalArgumentException e) { LOGGER.warn("Could not instantiate SimpleDateFormat with pattern " + patternOption, e); // default to the DEFAULT format - tempFormat = new SimpleDateFormat(DEFAULT_PATTERN); + pattern = DEFAULT_PATTERN; } // if the option list contains a TZ option, then set it. - if (options != null && options.length > 1) { - final TimeZone tz = TimeZone.getTimeZone(options[1]); - tempFormat.setTimeZone(tz); - } - tempFormatter = new PatternFormatter(tempFormat); + final TimeZone tz = (options != null && options.length > 1) ? TimeZone.getTimeZone(options[1]) : null; + tempFormatter = new PatternFormatter(pattern, tz); } formatter = tempFormatter; } + @Override + public void setCharset(Charset charset) { + super.setCharset(charset); + if (formatter instanceof PatternFormatter) { + PatternFormatter paf = (PatternFormatter) formatter; + + // FastTimeFormat does not support time zones + if (paf.timeZone == null && paf.pattern.endsWith(ABSOLUTE_TIME_PATTERN)) { + formatter = new FastTimeFormatter(paf.pattern, charset); + } + } + } + /** * Append formatted date to string buffer. * - * @param date - * date - * @param toAppendTo - * buffer to which formatted date is appended. + * @param date date + * @param toAppendTo buffer to which formatted date is appended. */ - public void format(final Date date, final StringBuilder toAppendTo) { - synchronized (this) { - toAppendTo.append(formatter.format(date.getTime())); - } + public void format(final Date date, final Buffer toAppendTo) { + formatter.format(date, toAppendTo); } /** * {@inheritDoc} */ @Override - public void format(final LogEvent event, final StringBuilder output) { - final long timestamp = event.getTimeMillis(); + public void format(final LogEvent event, final TextBuffer output) { + formatter.format(event.getTimeMillis(), output); + } - synchronized (this) { - if (timestamp != lastTimestamp) { - lastTimestamp = timestamp; - cachedDateString = formatter.format(timestamp); - } - } - output.append(cachedDateString); + /** + * {@inheritDoc} + */ + @Override + public void format(final LogEvent event, final BinaryBuffer output, final Charset charset) { + formatter.format(event.getTimeMillis(), output, charset); } /** * {@inheritDoc} */ @Override - public void format(final Object obj, final StringBuilder output) { + public void format(final Object obj, final Buffer output) { if (obj instanceof Date) { format((Date) obj, output); } @@ -266,7 +327,7 @@ public final class DatePatternConverter extends LogEventPatternConverter impleme } @Override - public void format(final StringBuilder toAppendTo, final Object... objects) { + public void format(final Buffer toAppendTo, final Object... objects) { for (final Object obj : objects) { if (obj instanceof Date) { format(obj, toAppendTo); http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08386d0e/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/EncodingPatternConverter.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/EncodingPatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/EncodingPatternConverter.java index b437309..64ecf9f 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/EncodingPatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/EncodingPatternConverter.java @@ -16,6 +16,7 @@ */ package org.apache.logging.log4j.core.pattern; +import java.nio.charset.Charset; import java.util.List; import org.apache.logging.log4j.core.LogEvent; @@ -37,8 +38,8 @@ public final class EncodingPatternConverter extends LogEventPatternConverter { * * @param formatters The PatternFormatters to generate the text to manipulate. */ - private EncodingPatternConverter(final List<PatternFormatter> formatters) { - super("encode", "encode"); + private EncodingPatternConverter(final List<PatternFormatter> formatters, final FormattingInfo formattingInfo) { + super("encode", "encode", formattingInfo); this.formatters = formatters; } @@ -49,7 +50,7 @@ public final class EncodingPatternConverter extends LogEventPatternConverter { * @param options options, may be null. * @return instance of pattern converter. */ - public static EncodingPatternConverter newInstance(final Configuration config, final String[] options) { + public static EncodingPatternConverter newInstance(final Configuration config, final String[] options, final FormattingInfo formattingInfo) { if (options.length != 1) { LOGGER.error("Incorrect number of options on escape. Expected 1, received " + options.length); return null; @@ -60,49 +61,73 @@ public final class EncodingPatternConverter extends LogEventPatternConverter { } final PatternParser parser = PatternLayout.createPatternParser(config); final List<PatternFormatter> formatters = parser.parse(options[0]); - return new EncodingPatternConverter(formatters); + return new EncodingPatternConverter(formatters, formattingInfo); } /** * {@inheritDoc} */ @Override - public void format(final LogEvent event, final StringBuilder toAppendTo) { - final StringBuilder buf = new StringBuilder(); + public void format(final LogEvent event, final TextBuffer toAppendTo) { + replaceAndAppend(event, toAppendTo); + } + + /** + * {@inheritDoc} + */ + @Override + public void format(final LogEvent event, final BinaryBuffer toAppendTo, final Charset charset) { + replaceAndAppend(event, toAppendTo); + } + + private void replaceAndAppend(final LogEvent event, final Buffer toAppendTo) { + final TextBuffer buf = new TextBuffer(); for (final PatternFormatter formatter : formatters) { formatter.format(event, buf); } for (int i = 0; i < buf.length(); i++) { final char c = buf.charAt(i); - switch (c) { - case '\r': - toAppendTo.append("\\r"); - break; - case '\n': - toAppendTo.append("\\n"); - break; - case '&': - toAppendTo.append("&"); - break; - case '<': - toAppendTo.append("<"); - break; - case '>': - toAppendTo.append(">"); - break; - case '"': - toAppendTo.append("""); - break; - case '\'': - toAppendTo.append("'"); - break; - case '/': - toAppendTo.append("/"); - break; - default: - toAppendTo.append(c); - break; - } + replace(c, toAppendTo); + } + } + + private void replace(final char c, final Buffer toAppendTo) { + switch (c) { + case '\r': + toAppendTo.append("\\r"); + break; + case '\n': + toAppendTo.append("\\n"); + break; + case '&': + toAppendTo.append("&"); + break; + case '<': + toAppendTo.append("<"); + break; + case '>': + toAppendTo.append(">"); + break; + case '"': + toAppendTo.append("""); + break; + case '\'': + toAppendTo.append("'"); + break; + case '/': + toAppendTo.append("/"); + break; + default: + toAppendTo.append(c); + break; + } + } + + @Override + public void setCharset(final Charset charset) { + super.setCharset(charset); + for (PatternFormatter paf : formatters) { + paf.getConverter().setCharset(charset); } } } http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08386d0e/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverter.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverter.java index cf6f764..5224042 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/ExtendedThrowablePatternConverter.java @@ -16,6 +16,8 @@ */ package org.apache.logging.log4j.core.pattern; +import java.nio.charset.Charset; + import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.plugins.Plugin; import org.apache.logging.log4j.core.impl.Log4jLogEvent; @@ -23,12 +25,11 @@ import org.apache.logging.log4j.core.impl.ThrowableProxy; import org.apache.logging.log4j.core.util.Constants; /** - * Outputs the Throwable portion of the LoggingEvent as a full stacktrace - * unless this converter's option is 'short', where it just outputs the first line of the trace, or if - * the number of lines to print is explicitly specified. + * Outputs the Throwable portion of the LoggingEvent as a full stacktrace unless this converter's option is 'short', + * where it just outputs the first line of the trace, or if the number of lines to print is explicitly specified. * <p> - * The extended stack trace will also include the location of where the class was loaded from and the - * version of the jar if available. + * The extended stack trace will also include the location of where the class was loaded from and the version of the jar + * if available. */ @Plugin(name = "ExtendedThrowablePatternConverter", category = PatternConverter.CATEGORY) @ConverterKeys({ "xEx", "xThrowable", "xException" }) @@ -39,26 +40,40 @@ public final class ExtendedThrowablePatternConverter extends ThrowablePatternCon * * @param options options, may be null. */ - private ExtendedThrowablePatternConverter(final String[] options) { - super("ExtendedThrowable", "throwable", options); + private ExtendedThrowablePatternConverter(final String[] options, final FormattingInfo formattingInfo) { + super("ExtendedThrowable", "throwable", options, formattingInfo); } /** * Gets an instance of the class. * - * @param options pattern options, may be null. If first element is "short", - * only the first line of the throwable will be formatted. + * @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 ExtendedThrowablePatternConverter newInstance(final String[] options) { - return new ExtendedThrowablePatternConverter(options); + public static ExtendedThrowablePatternConverter newInstance(final String[] options, + final FormattingInfo formattingInfo) { + return new ExtendedThrowablePatternConverter(options, formattingInfo); + } + + + /** + * {@inheritDoc} + */ + @Override + public void format(final LogEvent event, final TextBuffer toAppendTo) { + handle(event, toAppendTo); } /** * {@inheritDoc} */ @Override - public void format(final LogEvent event, final StringBuilder toAppendTo) { + public void format(final LogEvent event, final BinaryBuffer toAppendTo, final Charset charset) { + handle(event, toAppendTo); + } + + private void handle(final LogEvent event, final Buffer toAppendTo) { ThrowableProxy proxy = null; if (event instanceof Log4jLogEvent) { proxy = ((Log4jLogEvent) event).getThrownProxy(); @@ -70,13 +85,12 @@ public final class ExtendedThrowablePatternConverter extends ThrowablePatternCon return; } final String trace = proxy.getExtendedStackTraceAsString(options.getPackages()); - final int len = toAppendTo.length(); - if (len > 0 && !Character.isWhitespace(toAppendTo.charAt(len - 1))) { + if (!toAppendTo.hasTrailingWhitespace()) { toAppendTo.append(' '); } if (!options.allLines() || !Constants.LINE_SEPARATOR.equals(options.getSeparator())) { - final StringBuilder sb = new StringBuilder(); final String[] array = trace.split(Constants.LINE_SEPARATOR); + final StringBuilder sb = new StringBuilder(array.length << 7); // *128: estimate 128 chars per line final int limit = options.minLines(array.length) - 1; for (int i = 0; i <= limit; ++i) { sb.append(array[i]); http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08386d0e/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/FileDatePatternConverter.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/FileDatePatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/FileDatePatternConverter.java index 7a83d78..a6fb361 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/FileDatePatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/FileDatePatternConverter.java @@ -19,9 +19,8 @@ package org.apache.logging.log4j.core.pattern; import org.apache.logging.log4j.core.config.plugins.Plugin; /** - * Formats a date by delegating to {@link DatePatternConverter}. The default - * date pattern for a %d specifier in a file name is different than - * the %d pattern in pattern layout. + * Formats a date by delegating to {@link DatePatternConverter}. The default date pattern for a %d specifier in a file + * name is different than the %d pattern in pattern layout. */ @Plugin(name = "FileDatePatternConverter", category = "FileConverter") @ConverterKeys({ "d", "date" }) @@ -38,14 +37,11 @@ public final class FileDatePatternConverter { * @param options options, may be null. * @return instance of pattern converter. */ - public static PatternConverter newInstance(final String[] options) { + public static PatternConverter newInstance(final String[] options, final FormattingInfo formattingInfo) { if (options == null || options.length == 0) { - return DatePatternConverter.newInstance( - new String[]{ - "yyyy-MM-dd" - }); + return DatePatternConverter.newInstance(new String[] { "yyyy-MM-dd" }, formattingInfo); } - return DatePatternConverter.newInstance(options); + return DatePatternConverter.newInstance(options, formattingInfo); } } http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08386d0e/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/FileLocationPatternConverter.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/FileLocationPatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/FileLocationPatternConverter.java index 7fcd33d..5a7a9af 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/FileLocationPatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/FileLocationPatternConverter.java @@ -16,27 +16,23 @@ */ package org.apache.logging.log4j.core.pattern; +import java.nio.charset.Charset; + import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.plugins.Plugin; - /** * Returns the event's line location information in a StringBuilder. */ @Plugin(name = "FileLocationPatternConverter", category = PatternConverter.CATEGORY) @ConverterKeys({ "F", "file" }) public final class FileLocationPatternConverter extends LogEventPatternConverter { - /** - * Singleton. - */ - private static final FileLocationPatternConverter INSTANCE = - new FileLocationPatternConverter(); /** * Private constructor. */ - private FileLocationPatternConverter() { - super("File Location", "file"); + private FileLocationPatternConverter(final FormattingInfo formattingInfo) { + super("File Location", "file", formattingInfo); } /** @@ -45,19 +41,29 @@ public final class FileLocationPatternConverter extends LogEventPatternConverter * @param options options, may be null. * @return instance of pattern converter. */ - public static FileLocationPatternConverter newInstance(final String[] options) { - return INSTANCE; + public static FileLocationPatternConverter newInstance(final String[] options, final FormattingInfo formattingInfo) { + return new FileLocationPatternConverter(formattingInfo); } /** * {@inheritDoc} */ @Override - public void format(final LogEvent event, final StringBuilder output) { + public void format(final LogEvent event, final TextBuffer output) { final StackTraceElement element = event.getSource(); + if (element != null) { + output.append(getCachedFormattedString(element.getFileName())); + } + } + /** + * {@inheritDoc} + */ + @Override + public void format(final LogEvent event, final BinaryBuffer toAppendTo, final Charset charset) { + final StackTraceElement element = event.getSource(); if (element != null) { - output.append(element.getFileName()); + toAppendTo.append(getCachedFormattedBytes(element.getFileName(), charset)); } } } http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08386d0e/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/FormattingInfo.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/FormattingInfo.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/FormattingInfo.java index 950a7d5..a02c2fc 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/FormattingInfo.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/FormattingInfo.java @@ -17,6 +17,9 @@ package org.apache.logging.log4j.core.pattern; +import java.nio.ByteBuffer; +import java.util.Arrays; + /** * Modifies the output of a pattern converter for a specified minimum and maximum width and alignment. */ @@ -24,7 +27,14 @@ public final class FormattingInfo { /** * Array of spaces. */ - private static final char[] SPACES = new char[] { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' }; + private static final char[] SPACES = new char[128]; + static { + Arrays.fill(SPACES, ' '); + } + private static final byte[] SPACEBYTES = new byte[128]; + static { + Arrays.fill(SPACEBYTES, (byte) ' '); + } /** * Default instance. @@ -49,14 +59,22 @@ public final class FormattingInfo { /** * Creates new instance. * - * @param leftAlign - * left align if true. - * @param minLength - * minimum length. - * @param maxLength - * maximum length. + * @param leftAlign left align if true. + * @param minLength minimum length (must be non-negative and not exceed maxLength). + * @param maxLength maximum length (must be non-negative). */ public FormattingInfo(final boolean leftAlign, final int minLength, final int maxLength) { + if (minLength < 0) { + throw new IllegalArgumentException("MinLength must be at least 0 but was " + minLength); + } + if (maxLength < 0) { + throw new IllegalArgumentException("MaxLength must be at least 0 but was " + maxLength); + } + // Note: I'd like to assert that min <= max, but this breaks the PatternParser unit tests (and perhaps user + // code) + // if (minLength > maxLength) { + // throw new IllegalArgumentException("MinLength " + minLength + " exceeds MaxLength " + maxLength); + // } this.leftAlign = leftAlign; this.minLength = minLength; this.maxLength = maxLength; @@ -101,12 +119,13 @@ public final class FormattingInfo { /** * Adjust the content of the buffer based on the specified lengths and alignment. * - * @param fieldStart - * start of field in buffer. - * @param buffer - * buffer to be modified. + * @param fieldStart start of field in buffer. + * @param buffer buffer to be modified. */ public void format(final int fieldStart, final StringBuilder buffer) { + if (this == DEFAULT) { + return; // no formatting + } final int rawLength = buffer.length() - fieldStart; if (rawLength > maxLength) { @@ -150,4 +169,49 @@ public final class FormattingInfo { return sb.toString(); } + /** + * Adjust the content of the buffer based on the specified lengths and alignment. + * + * @param fieldStart start of field in buffer. + * @param buffer buffer to be modified. + */ + public void format(int fieldStart, ByteBuffer buffer) { + if (this == DEFAULT) { + return; // no formatting + } + final int rawLength = buffer.position() - fieldStart; + + if (rawLength > maxLength) { + buffer.position(buffer.position() - maxLength); + final ByteBuffer src = buffer.slice(); + src.limit(maxLength); + buffer.position(fieldStart); + buffer.put(src); + } else if (rawLength < minLength) { + if (leftAlign) { + final int fieldEnd = buffer.position(); + buffer.position(fieldStart + minLength); + + for (int i = fieldEnd; i < buffer.position(); i++) { + buffer.put(i, (byte) ' '); + } + } else { + int old = buffer.position(); + int padLength = minLength - rawLength; + + buffer.position(fieldStart); + final ByteBuffer src = buffer.slice(); + src.limit(old - fieldStart); + buffer.position(fieldStart + padLength); + buffer.put(src); + + buffer.position(fieldStart); + for (; padLength > SPACES.length; padLength -= SPACES.length) { + buffer.put(SPACEBYTES, 0, padLength); + } + buffer.put(SPACEBYTES, 0, padLength); + buffer.position(minLength + fieldStart); + } + } + } } http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08386d0e/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/FullLocationPatternConverter.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/FullLocationPatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/FullLocationPatternConverter.java index 120a671..e6c43ef 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/FullLocationPatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/FullLocationPatternConverter.java @@ -16,6 +16,8 @@ */ package org.apache.logging.log4j.core.pattern; +import java.nio.charset.Charset; + import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.plugins.Plugin; @@ -26,17 +28,12 @@ import org.apache.logging.log4j.core.config.plugins.Plugin; @Plugin(name = "FullLocationPatternConverter", category = PatternConverter.CATEGORY) @ConverterKeys({ "l", "location" }) public final class FullLocationPatternConverter extends LogEventPatternConverter { - /** - * Singleton. - */ - private static final FullLocationPatternConverter INSTANCE = - new FullLocationPatternConverter(); /** * Private constructor. */ - private FullLocationPatternConverter() { - super("Full Location", "fullLocation"); + private FullLocationPatternConverter(final FormattingInfo formattingInfo) { + super("Full Location", "fullLocation", formattingInfo); } /** @@ -45,19 +42,29 @@ public final class FullLocationPatternConverter extends LogEventPatternConverter * @param options options, may be null. * @return instance of pattern converter. */ - public static FullLocationPatternConverter newInstance(final String[] options) { - return INSTANCE; + public static FullLocationPatternConverter newInstance(final String[] options, final FormattingInfo formattingInfo) { + return new FullLocationPatternConverter(formattingInfo); } /** * {@inheritDoc} */ @Override - public void format(final LogEvent event, final StringBuilder output) { + public void format(final LogEvent event, final TextBuffer output) { final StackTraceElement element = event.getSource(); + if (element != null) { + output.append(getCachedFormattedString(element)); + } + } + /** + * {@inheritDoc} + */ + @Override + public void format(final LogEvent event, final BinaryBuffer toAppendTo, final Charset charset) { + final StackTraceElement element = event.getSource(); if (element != null) { - output.append(element.toString()); + toAppendTo.append(getCachedFormattedBytes(element, charset)); } } } http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08386d0e/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/HighlightConverter.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/HighlightConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/HighlightConverter.java index 3fc0ef0..473f8d2 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/HighlightConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/HighlightConverter.java @@ -1,229 +1,243 @@ -/* - * 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.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; - -import org.apache.logging.log4j.Level; -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; -import org.apache.logging.log4j.util.Strings; - -/** - * Highlight pattern converter. Formats the result of a pattern using a color appropriate for the Level in the LogEvent. - * <p> - * For example: - * </p> - * - * <pre> - * %highlight{%d{ ISO8601 } [%t] %-5level: %msg%n%throwable} - * </pre> - * <p> - * You can define custom colors for each Level: - * </p> - * - * <pre> - * %highlight{%d{ ISO8601 } [%t] %-5level: %msg%n%throwable}{FATAL=red, ERROR=red, WARN=yellow, INFO=green, DEBUG=cyan, - * TRACE=black} - * </pre> - * <p> - * You can use a predefined style: - * </p> - * - * <pre> - * %highlight{%d{ ISO8601 } [%t] %-5level: %msg%n%throwable}{STYLE=Log4j} - * </pre> - * <p> - * The available predefined styles are: - * </p> - * <ul> - * <li>{@code Default}</li> - * <li>{@code Log4j} - The same as {@code Default}</li> - * <li>{@code Logback}</li> - * </ul> - * <p> - * You can use whitespace around the comma and equal sign. The names in values MUST come from the - * {@linkplain AnsiEscape} enum, case is normalized to upper-case internally. - * </p> - */ -@Plugin(name = "highlight", category = PatternConverter.CATEGORY) -@ConverterKeys({ "highlight" }) -public final class HighlightConverter extends LogEventPatternConverter implements AnsiConverter { - - private static final Map<Level, String> DEFAULT_STYLES = new HashMap<Level, String>(); - - private static final Map<Level, String> LOGBACK_STYLES = new HashMap<Level, String>(); - - private static final String STYLE_KEY = "STYLE"; - - private static final String STYLE_KEY_DEFAULT = "DEFAULT"; - - private static final String STYLE_KEY_LOGBACK = "LOGBACK"; - - private static final Map<String, Map<Level, String>> STYLES = new HashMap<String, Map<Level, String>>(); - - static { - // Default styles: - DEFAULT_STYLES.put(Level.FATAL, AnsiEscape.createSequence("BRIGHT", "RED")); - DEFAULT_STYLES.put(Level.ERROR, AnsiEscape.createSequence("BRIGHT", "RED")); - DEFAULT_STYLES.put(Level.WARN, AnsiEscape.createSequence("YELLOW")); - DEFAULT_STYLES.put(Level.INFO, AnsiEscape.createSequence("GREEN")); - DEFAULT_STYLES.put(Level.DEBUG, AnsiEscape.createSequence("CYAN")); - DEFAULT_STYLES.put(Level.TRACE, AnsiEscape.createSequence("BLACK")); - // Logback styles: - LOGBACK_STYLES.put(Level.FATAL, AnsiEscape.createSequence("BLINK", "BRIGHT", "RED")); - LOGBACK_STYLES.put(Level.ERROR, AnsiEscape.createSequence("BRIGHT", "RED")); - LOGBACK_STYLES.put(Level.WARN, AnsiEscape.createSequence("RED")); - LOGBACK_STYLES.put(Level.INFO, AnsiEscape.createSequence("BLUE")); - LOGBACK_STYLES.put(Level.DEBUG, AnsiEscape.createSequence((String[]) null)); - LOGBACK_STYLES.put(Level.TRACE, AnsiEscape.createSequence((String[]) null)); - // Style map: - STYLES.put(STYLE_KEY_DEFAULT, DEFAULT_STYLES); - STYLES.put(STYLE_KEY_LOGBACK, LOGBACK_STYLES); - } - - /** - * Creates a level style map where values are ANSI escape sequences given configuration options in {@code option[1]} - * . - * <p> - * The format of the option string in {@code option[1]} is: - * </p> - * - * <pre> - * Level1=Value, Level2=Value, ... - * </pre> - * - * <p> - * For example: - * </p> - * - * <pre> - * ERROR=red bold, WARN=yellow bold, INFO=green, ... - * </pre> - * - * <p> - * You can use whitespace around the comma and equal sign. The names in values MUST come from the - * {@linkplain AnsiEscape} enum, case is normalized to upper-case internally. - * </p> - * - * @param options - * The second slot can optionally contain the style map. - * @return a new map - */ - private static Map<Level, String> createLevelStyleMap(final String[] options) { - if (options.length < 2) { - return DEFAULT_STYLES; - } - // Feels like a hack. Should String[] options change to a Map<String,String>? - final String string = options[1].replaceAll(PatternParser.NO_CONSOLE_NO_ANSI + "=(true|false)", Strings.EMPTY); - // - final Map<String, String> styles = AnsiEscape.createMap(string, new String[] {STYLE_KEY}); - final Map<Level, String> levelStyles = new HashMap<Level, String>(DEFAULT_STYLES); - for (final Map.Entry<String, String> entry : styles.entrySet()) { - final String key = entry.getKey().toUpperCase(Locale.ENGLISH); - final String value = entry.getValue(); - if (STYLE_KEY.equalsIgnoreCase(key)) { - final Map<Level, String> enumMap = STYLES.get(value.toUpperCase(Locale.ENGLISH)); - if (enumMap == null) { - LOGGER.error("Unknown level style: " + value + ". Use one of " + - Arrays.toString(STYLES.keySet().toArray())); - } else { - levelStyles.putAll(enumMap); - } - } else { - final Level level = Level.toLevel(key); - if (level == null) { - LOGGER.error("Unknown level name: " + key + ". Use one of " + - Arrays.toString(DEFAULT_STYLES.keySet().toArray())); - } else { - levelStyles.put(level, value); - } - } - } - return levelStyles; - } - - /** - * 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 HighlightConverter newInstance(final Configuration config, final String[] options) { - if (options.length < 1) { - LOGGER.error("Incorrect number of options on style. Expected at least 1, received " + options.length); - return null; - } - if (options[0] == null) { - LOGGER.error("No pattern supplied on style"); - return null; - } - final PatternParser parser = PatternLayout.createPatternParser(config); - final List<PatternFormatter> formatters = parser.parse(options[0]); - return new HighlightConverter(formatters, createLevelStyleMap(options)); - } - - private final Map<Level, String> levelStyles; - - private final List<PatternFormatter> patternFormatters; - - /** - * Construct the converter. - * - * @param patternFormatters - * The PatternFormatters to generate the text to manipulate. - */ - private HighlightConverter(final List<PatternFormatter> patternFormatters, final Map<Level, String> levelStyles) { - super("style", "style"); - this.patternFormatters = patternFormatters; - this.levelStyles = levelStyles; - } - - /** - * {@inheritDoc} - */ - @Override - public void format(final LogEvent event, final StringBuilder toAppendTo) { - final StringBuilder buf = new StringBuilder(); - for (final PatternFormatter formatter : patternFormatters) { - formatter.format(event, buf); - } - - if (buf.length() > 0) { - toAppendTo.append(levelStyles.get(event.getLevel())).append(buf.toString()). - append(AnsiEscape.getDefaultStyle()); - } - } - - @Override - public boolean handlesThrowable() { - for (final PatternFormatter formatter : patternFormatters) { - if (formatter .handlesThrowable()) { - return true; - } - } - return false; - } -} +/* + * 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.nio.charset.Charset; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import org.apache.logging.log4j.Level; +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; +import org.apache.logging.log4j.util.Strings; + +/** + * Highlight pattern converter. Formats the result of a pattern using a color appropriate for the Level in the LogEvent. + * <p> + * For example: + * </p> + * + * <pre> + * %highlight{%d{ ISO8601 } [%t] %-5level: %msg%n%throwable} + * </pre> + * <p> + * You can define custom colors for each Level: + * </p> + * + * <pre> + * %highlight{%d{ ISO8601 } [%t] %-5level: %msg%n%throwable}{FATAL=red, ERROR=red, WARN=yellow, INFO=green, DEBUG=cyan, + * TRACE=black} + * </pre> + * <p> + * You can use a predefined style: + * </p> + * + * <pre> + * %highlight{%d{ ISO8601 } [%t] %-5level: %msg%n%throwable}{STYLE=Log4j} + * </pre> + * <p> + * The available predefined styles are: + * </p> + * <ul> + * <li>{@code Default}</li> + * <li>{@code Log4j} - The same as {@code Default}</li> + * <li>{@code Logback}</li> + * </ul> + * <p> + * You can use whitespace around the comma and equal sign. The names in values MUST come from the + * {@linkplain AnsiEscape} enum, case is normalized to upper-case internally. + * </p> + */ +@Plugin(name = "highlight", category = PatternConverter.CATEGORY) +@ConverterKeys({ "highlight" }) +public final class HighlightConverter extends LogEventPatternConverter implements AnsiConverter { + + private static final Map<Level, String> DEFAULT_STYLES = new HashMap<Level, String>(); + + private static final Map<Level, String> LOGBACK_STYLES = new HashMap<Level, String>(); + + private static final String STYLE_KEY = "STYLE"; + + private static final String STYLE_KEY_DEFAULT = "DEFAULT"; + + private static final String STYLE_KEY_LOGBACK = "LOGBACK"; + + private static final Map<String, Map<Level, String>> STYLES = new HashMap<String, Map<Level, String>>(); + + static { + // Default styles: + DEFAULT_STYLES.put(Level.FATAL, AnsiEscape.createSequence("BRIGHT", "RED")); + DEFAULT_STYLES.put(Level.ERROR, AnsiEscape.createSequence("BRIGHT", "RED")); + DEFAULT_STYLES.put(Level.WARN, AnsiEscape.createSequence("YELLOW")); + DEFAULT_STYLES.put(Level.INFO, AnsiEscape.createSequence("GREEN")); + DEFAULT_STYLES.put(Level.DEBUG, AnsiEscape.createSequence("CYAN")); + DEFAULT_STYLES.put(Level.TRACE, AnsiEscape.createSequence("BLACK")); + // Logback styles: + LOGBACK_STYLES.put(Level.FATAL, AnsiEscape.createSequence("BLINK", "BRIGHT", "RED")); + LOGBACK_STYLES.put(Level.ERROR, AnsiEscape.createSequence("BRIGHT", "RED")); + LOGBACK_STYLES.put(Level.WARN, AnsiEscape.createSequence("RED")); + LOGBACK_STYLES.put(Level.INFO, AnsiEscape.createSequence("BLUE")); + LOGBACK_STYLES.put(Level.DEBUG, AnsiEscape.createSequence((String[]) null)); + LOGBACK_STYLES.put(Level.TRACE, AnsiEscape.createSequence((String[]) null)); + // Style map: + STYLES.put(STYLE_KEY_DEFAULT, DEFAULT_STYLES); + STYLES.put(STYLE_KEY_LOGBACK, LOGBACK_STYLES); + } + + /** + * Creates a level style map where values are ANSI escape sequences given configuration options in {@code option[1]} + * . + * <p> + * The format of the option string in {@code option[1]} is: + * </p> + * + * <pre> + * Level1=Value, Level2=Value, ... + * </pre> + * + * <p> + * For example: + * </p> + * + * <pre> + * ERROR=red bold, WARN=yellow bold, INFO=green, ... + * </pre> + * + * <p> + * You can use whitespace around the comma and equal sign. The names in values MUST come from the + * {@linkplain AnsiEscape} enum, case is normalized to upper-case internally. + * </p> + * + * @param options The second slot can optionally contain the style map. + * @return a new map + */ + private static Map<Level, String> createLevelStyleMap(final String[] options) { + if (options.length < 2) { + return DEFAULT_STYLES; + } + // Feels like a hack. Should String[] options change to a Map<String,String>? + final String string = options[1].replaceAll(PatternParser.NO_CONSOLE_NO_ANSI + "=(true|false)", Strings.EMPTY); + // + final Map<String, String> styles = AnsiEscape.createMap(string, new String[] { STYLE_KEY }); + final Map<Level, String> levelStyles = new HashMap<Level, String>(DEFAULT_STYLES); + for (final Map.Entry<String, String> entry : styles.entrySet()) { + final String key = entry.getKey().toUpperCase(Locale.ENGLISH); + final String value = entry.getValue(); + if (STYLE_KEY.equalsIgnoreCase(key)) { + final Map<Level, String> enumMap = STYLES.get(value.toUpperCase(Locale.ENGLISH)); + if (enumMap == null) { + LOGGER.error("Unknown level style: " + value + ". Use one of " + + Arrays.toString(STYLES.keySet().toArray())); + } else { + levelStyles.putAll(enumMap); + } + } else { + final Level level = Level.toLevel(key); + if (level == null) { + LOGGER.error("Unknown level name: " + key + ". Use one of " + + Arrays.toString(DEFAULT_STYLES.keySet().toArray())); + } else { + levelStyles.put(level, value); + } + } + } + return levelStyles; + } + + /** + * 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 HighlightConverter newInstance(final Configuration config, final String[] options, + final FormattingInfo formattingInfo) { + if (options.length < 1) { + LOGGER.error("Incorrect number of options on style. Expected at least 1, received " + options.length); + return null; + } + if (options[0] == null) { + LOGGER.error("No pattern supplied on style"); + return null; + } + final PatternParser parser = PatternLayout.createPatternParser(config); + final List<PatternFormatter> formatters = parser.parse(options[0]); + return new HighlightConverter(formatters, createLevelStyleMap(options), formattingInfo); + } + + private final Map<Level, String> levelStyles; + + private final List<PatternFormatter> patternFormatters; + + /** + * Construct the converter. + * + * @param patternFormatters The PatternFormatters to generate the text to manipulate. + */ + private HighlightConverter(final List<PatternFormatter> patternFormatters, final Map<Level, String> levelStyles, + final FormattingInfo formattingInfo) { + super("style", "style", formattingInfo); + this.patternFormatters = patternFormatters; + this.levelStyles = levelStyles; + } + + /** + * {@inheritDoc} + */ + @Override + public void format(final LogEvent event, final TextBuffer toAppendTo) { + format0(event, toAppendTo, null); + } + + /** + * {@inheritDoc} + */ + @Override + public void format(final LogEvent event, final BinaryBuffer toAppendTo, final Charset charset) { + format0(event, toAppendTo, charset); + } + + private void format0(final LogEvent event, final Buffer toAppendTo, final Charset charset) { + StyleConverter.formatNested(event, toAppendTo, charset, false, patternFormatters, + levelStyles.get(event.getLevel()), AnsiEscape.getDefaultStyle()); + } + + @Override + public boolean handlesThrowable() { + for (final PatternFormatter formatter : patternFormatters) { + if (formatter.handlesThrowable()) { + return true; + } + } + return false; + } + + @Override + public void setCharset(final Charset charset) { + super.setCharset(charset); + for (PatternFormatter paf : patternFormatters) { + paf.getConverter().setCharset(charset); + } + } +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08386d0e/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/IntegerPatternConverter.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/IntegerPatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/IntegerPatternConverter.java index 5380d45..c352cac 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/IntegerPatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/IntegerPatternConverter.java @@ -20,24 +20,18 @@ import java.util.Date; import org.apache.logging.log4j.core.config.plugins.Plugin; - /** * Formats an integer. */ @Plugin(name = "IntegerPatternConverter", category = "FileConverter") @ConverterKeys({ "i", "index" }) public final class IntegerPatternConverter extends AbstractPatternConverter implements ArrayPatternConverter { - - /** - * Singleton. - */ - private static final IntegerPatternConverter INSTANCE = new IntegerPatternConverter(); /** * Private constructor. */ - private IntegerPatternConverter() { - super("Integer", "integer"); + private IntegerPatternConverter(final FormattingInfo formattingInfo) { + super("Integer", "integer", formattingInfo); } /** @@ -46,13 +40,12 @@ public final class IntegerPatternConverter extends AbstractPatternConverter impl * @param options options, may be null. * @return instance of pattern converter. */ - public static IntegerPatternConverter newInstance( - final String[] options) { - return INSTANCE; + public static IntegerPatternConverter newInstance(final String[] options, final FormattingInfo formattingInfo) { + return new IntegerPatternConverter(formattingInfo); } @Override - public void format(final StringBuilder toAppendTo, final Object... objects) { + public void format(final Buffer toAppendTo, final Object... objects) { for (final Object obj : objects) { if (obj instanceof Integer) { format(obj, toAppendTo); @@ -65,7 +58,7 @@ public final class IntegerPatternConverter extends AbstractPatternConverter impl * {@inheritDoc} */ @Override - public void format(final Object obj, final StringBuilder toAppendTo) { + public void format(final Object obj, final Buffer toAppendTo) { if (obj instanceof Integer) { toAppendTo.append(obj.toString()); } else if (obj instanceof Date) { http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08386d0e/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/LevelPatternConverter.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/LevelPatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/LevelPatternConverter.java index 1975fcf..7d31fc8 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/LevelPatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/LevelPatternConverter.java @@ -16,6 +16,7 @@ */ package org.apache.logging.log4j.core.pattern; +import java.nio.charset.Charset; import java.util.HashMap; import java.util.Locale; import java.util.Map; @@ -23,6 +24,7 @@ import java.util.Map; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.plugins.Plugin; +import org.apache.logging.log4j.core.util.Charsets; import org.apache.logging.log4j.core.util.Patterns; /** @@ -34,33 +36,29 @@ public final class LevelPatternConverter extends LogEventPatternConverter { private static final String OPTION_LENGTH = "length"; private static final String OPTION_LOWER = "lowerCase"; - /** - * Singleton. - */ - private static final LevelPatternConverter INSTANCE = new LevelPatternConverter(null); - - private final Map<Level, String> levelMap; + private final Map<Level, String> levelTextMap; + private final Map<Level, byte[]> levelBinaryMap = new HashMap<Level, byte[]>(); /** * Private constructor. */ - private LevelPatternConverter(final Map<Level, String> map) { - super("Level", "level"); - this.levelMap = map; + private LevelPatternConverter(final Map<Level, String> map, final FormattingInfo formattingInfo) { + super("Level", "level", formattingInfo); + this.levelTextMap = map; } /** * Obtains an instance of pattern converter. * - * @param options - * options, may be null. May contain a list of level names and The value that should be displayed for the - * Level. + * @param options options, may be null. May contain a list of level names and The value that should be displayed for + * the Level. * @return instance of pattern converter. */ - public static LevelPatternConverter newInstance(final String[] options) { + public static LevelPatternConverter newInstance(final String[] options, final FormattingInfo formattingInfo) { if (options == null || options.length == 0) { - return INSTANCE; + return createDefaultLevelPatternConverter(formattingInfo); } + final StringBuilder sb = new StringBuilder(64); final Map<Level, String> levelMap = new HashMap<Level, String>(); int length = Integer.MAX_VALUE; // More than the longest level name. boolean lowerCase = false; @@ -82,29 +80,63 @@ public final class LevelPatternConverter extends LogEventPatternConverter { if (level == null) { LOGGER.error("Invalid Level {}", key); } else { - levelMap.put(level, value); + levelMap.put(level, format(formattingInfo, sb, value)); } } } if (levelMap.isEmpty() && length == Integer.MAX_VALUE && !lowerCase) { - return INSTANCE; + return createDefaultLevelPatternConverter(formattingInfo); } for (final Level level : Level.values()) { if (!levelMap.containsKey(level)) { final String left = left(level, length); - levelMap.put(level, lowerCase ? left.toLowerCase(Locale.US) : left); + final String value = lowerCase ? left.toLowerCase(Locale.US) : left; + levelMap.put(level, format(formattingInfo, sb, value)); } } - return new LevelPatternConverter(levelMap); + return new LevelPatternConverter(levelMap, formattingInfo); + } + + private static LevelPatternConverter createDefaultLevelPatternConverter(final FormattingInfo formattingInfo) { + final FormattingInfo fi = formattingInfo; + return new LevelPatternConverter(createTextLevelMap(fi), fi); + } + + private static Map<Level, String> createTextLevelMap(final FormattingInfo formattingInfo) { + if (formattingInfo == null || formattingInfo == FormattingInfo.getDefault()) { + return null; // indicates no formatting + } + final Map<Level, String> result = new HashMap<Level, String>(); + final StringBuilder sb = new StringBuilder(64); + for (final Level level : Level.values()) { + final String formatted = format(formattingInfo, sb, level.name()); + result.put(level, formatted); + } + return result; + } + + private static Map<Level, byte[]> createBinaryLevelMap(final FormattingInfo formattingInfo, final Charset charset) { + final Map<Level, byte[]> result = new HashMap<Level, byte[]>(); + final StringBuilder sb = new StringBuilder(64); + for (final Level level : Level.values()) { + final String formatted = format(formattingInfo, sb, level.name()); + result.put(level, Charsets.getBytes(formatted, charset)); + } + return result; + } + + private static String format(final FormattingInfo formattingInfo, final StringBuilder sb, final String raw) { + sb.setLength(0); + sb.append(raw); + formattingInfo.format(0, sb); + return sb.toString(); } /** * Returns the leftmost chars of the level name for the given level. * - * @param level - * The level - * @param length - * How many chars to return + * @param level The level + * @param length How many chars to return * @return The abbreviated level name, or the whole level name if the {@code length} is greater than the level name * length, */ @@ -115,13 +147,34 @@ public final class LevelPatternConverter extends LogEventPatternConverter { } return string.substring(0, length); } + + @Override + public void setCharset(final Charset charset) { + super.setCharset(charset); + if (this.levelTextMap == null) { + this.levelBinaryMap.putAll(createBinaryLevelMap(getFormattingInfo(), charset)); + } else { + for (final Level level : levelTextMap.keySet()) { + final String value = levelTextMap.get(level); + levelBinaryMap.put(level, Charsets.getBytes(value, charset)); + } + } + } /** * {@inheritDoc} */ @Override - public void format(final LogEvent event, final StringBuilder output) { - output.append(levelMap == null ? event.getLevel().toString() : levelMap.get(event.getLevel())); + public void format(final LogEvent event, final TextBuffer output) { + output.append(levelTextMap == null ? event.getLevel().toString() : levelTextMap.get(event.getLevel())); + } + + /** + * {@inheritDoc} + */ + @Override + public void format(final LogEvent event, final BinaryBuffer output, final Charset charset) { + output.append(levelBinaryMap.get(event.getLevel())); } /** @@ -132,7 +185,6 @@ public final class LevelPatternConverter extends LogEventPatternConverter { if (e instanceof LogEvent) { return "level " + ((LogEvent) e).getLevel().name().toLowerCase(Locale.ENGLISH); } - return "level"; } } http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/08386d0e/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/LineLocationPatternConverter.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/LineLocationPatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/LineLocationPatternConverter.java index 2b912d7..64ac2c9 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/LineLocationPatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/LineLocationPatternConverter.java @@ -16,6 +16,8 @@ */ package org.apache.logging.log4j.core.pattern; +import java.nio.charset.Charset; + import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.plugins.Plugin; @@ -25,17 +27,12 @@ import org.apache.logging.log4j.core.config.plugins.Plugin; @Plugin(name = "LineLocationPatternConverter", category = PatternConverter.CATEGORY) @ConverterKeys({ "L", "line" }) public final class LineLocationPatternConverter extends LogEventPatternConverter { - /** - * Singleton. - */ - private static final LineLocationPatternConverter INSTANCE = - new LineLocationPatternConverter(); /** * Private constructor. */ - private LineLocationPatternConverter() { - super("Line", "line"); + private LineLocationPatternConverter(final FormattingInfo formattingInfo) { + super("Line", "line", formattingInfo); } /** @@ -44,20 +41,42 @@ public final class LineLocationPatternConverter extends LogEventPatternConverter * @param options options, may be null. * @return instance of pattern converter. */ - public static LineLocationPatternConverter newInstance( - final String[] options) { - return INSTANCE; + public static LineLocationPatternConverter newInstance(final String[] options, final FormattingInfo formattingInfo) { + return new LineLocationPatternConverter(formattingInfo); + } + + @Override + public String convert(final Object element) { + return String.valueOf(((StackTraceElement) element).getLineNumber()); } /** * {@inheritDoc} */ @Override - public void format(final LogEvent event, final StringBuilder output) { + public void format(final LogEvent event, final TextBuffer output) { final StackTraceElement element = event.getSource(); + if (element != null) { + if (hasFormattingInfo) { + output.append(getCachedFormattedString(element)); + } else { + output.append(element.getLineNumber()); + } + } + } + /** + * {@inheritDoc} + */ + @Override + public void format(final LogEvent event, final BinaryBuffer toAppendTo, final Charset charset) { + final StackTraceElement element = event.getSource(); if (element != null) { - output.append(element.getLineNumber()); + if (hasFormattingInfo) { + toAppendTo.append(getCachedFormattedBytes(element, charset)); + } else { + toAppendTo.append(element.getLineNumber()); + } } } }
