/* * 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.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.Arrays; 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; import org.apache.logging.log4j.util.PerformanceSensitive; /** * Style pattern converter. Adds ANSI color styling to the result of the enclosed pattern. */ public abstract class AbstractStyleNameConverter extends LogEventPatternConverter /*TODO: implements AnsiConverter*/ { private final List<PatternFormatter> formatters; private final String style; /** * Constructs the converter. * * @param formatters The PatternFormatters to generate the text to manipulate. * @param styling The styling that should encapsulate the pattern. */ protected AbstractStyleNameConverter(final String name, final List<PatternFormatter> formatters, final String styling) { super(name, "style"); this.formatters = formatters; this.style = styling; } /** * Black style pattern converter. Adds ANSI color styling to the result of the enclosed pattern. */ @Plugin(name = Black.NAME, category = "Converter") @ConverterKeys(Black.NAME) public static final class Black extends AbstractStyleNameConverter { /** Black */ protected static final String NAME = "black"; /** * Constructs the converter. This constructor must be public. * * @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); } /** * Gets an instance of the class (called via reflection). * * @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. * @return new instance of class or null */ public static Black newInstance(final Configuration config, final String[] options) { return newInstance(Black.class, NAME, config, options); } } /** * Blue style pattern converter. Adds ANSI color styling to the result of the enclosed pattern. */ @Plugin(name = Blue.NAME, category = "Converter") @ConverterKeys(Blue.NAME) public static final class Blue extends AbstractStyleNameConverter { /** Blue */ protected static final String NAME = "blue"; /** * Constructs the converter. This constructor must be public. * * @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); } /** * Gets an instance of the class (called via reflection). * * @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. * @return new instance of class or null */ public static Blue newInstance(final Configuration config, final String[] options) { return newInstance(Blue.class, NAME, config, options); } } /** * Cyan style pattern converter. Adds ANSI color styling to the result of the enclosed pattern. */ @Plugin(name = Cyan.NAME, category = "Converter") @ConverterKeys(Cyan.NAME) public static final class Cyan extends AbstractStyleNameConverter { /** Cyan */ protected static final String NAME = "cyan"; /** * Constructs the converter. This constructor must be public. * * @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); } /** * Gets an instance of the class (called via reflection). * * @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. * @return new instance of class or null */ public static Cyan newInstance(final Configuration config, final String[] options) { return newInstance(Cyan.class, NAME, config, options); } } /** * Green style pattern converter. Adds ANSI color styling to the result of the enclosed pattern. */ @Plugin(name = Green.NAME, category = "Converter") @ConverterKeys(Green.NAME) public static final class Green extends AbstractStyleNameConverter { /** Green */ protected static final String NAME = "green"; /** * Constructs the converter. This constructor must be public. * * @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); } /** * Gets an instance of the class (called via reflection). * * @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. * @return new instance of class or null */ public static Green newInstance(final Configuration config, final String[] options) { return newInstance(Green.class, NAME, config, options); } } /** * Magenta style pattern converter. Adds ANSI color styling to the result of the enclosed pattern. */ @Plugin(name = Magenta.NAME, category = "Converter") @ConverterKeys(Magenta.NAME) public static final class Magenta extends AbstractStyleNameConverter { /** Magenta */ protected static final String NAME = "magenta"; /** * Constructs the converter. This constructor must be public. * * @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); } /** * Gets an instance of the class (called via reflection). * * @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. * @return new instance of class or null */ public static Magenta newInstance(final Configuration config, final String[] options) { return newInstance(Magenta.class, NAME, config, options); } } /** * Red style pattern converter. Adds ANSI color styling to the result of the enclosed pattern. */ @Plugin(name = Red.NAME, category = "Converter") @ConverterKeys(Red.NAME) public static final class Red extends AbstractStyleNameConverter { /** Red */ protected static final String NAME = "red"; /** * Constructs the converter. This constructor must be public. * * @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); } /** * Gets an instance of the class (called via reflection). * * @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. * @return new instance of class or null */ public static Red newInstance(final Configuration config, final String[] options) { return newInstance(Red.class, NAME, config, options); } } /** * White style pattern converter. Adds ANSI color styling to the result of the enclosed pattern. */ @Plugin(name = White.NAME, category = "Converter") @ConverterKeys(White.NAME) public static final class White extends AbstractStyleNameConverter { /** White */ protected static final String NAME = "white"; /** * Constructs the converter. This constructor must be public. * * @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); } /** * Gets an instance of the class (called via reflection). * * @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. * @return new instance of class or null */ public static White newInstance(final Configuration config, final String[] options) { return newInstance(White.class, NAME, config, options); } } /** * Yellow style pattern converter. Adds ANSI color styling to the result of the enclosed pattern. */ @Plugin(name = Yellow.NAME, category = "Converter") @ConverterKeys(Yellow.NAME) public static final class Yellow extends AbstractStyleNameConverter { /** Yellow */ protected static final String NAME = "yellow"; /** * Constructs the converter. This constructor must be public. * * @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); } /** * Gets an instance of the class (called via reflection). * * @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. * @return new instance of class or null */ public static Yellow newInstance(final Configuration config, final String[] options) { return newInstance(Yellow.class, NAME, config, options); } } /** * Gets an instance of the class (called via reflection). * * @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. * @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 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)); } catch (final SecurityException e) { LOGGER.error(e.toString(), e); } catch (final NoSuchMethodException e) { LOGGER.error(e.toString(), e); } catch (final IllegalArgumentException e) { LOGGER.error(e.toString(), e); } catch (final InstantiationException e) { LOGGER.error(e.toString(), e); } catch (final IllegalAccessException e) { LOGGER.error(e.toString(), e); } catch (final InvocationTargetException e) { LOGGER.error(e.toString(), e); } return null; } /** * Creates a list of PatternFormatter from the given configuration and options or null if no pattern is supplied. * * @param config A configuration. * @param options pattern options. * @return a list of PatternFormatter from the given configuration and options or null if no pattern is supplied. */ private static List<PatternFormatter> toPatternFormatterList(final Configuration config, final String[] options) { if (options.length == 0 || options[0] == null) { LOGGER.error("No pattern supplied on style for config=" + config); return null; } final PatternParser parser = PatternLayout.createPatternParser(config); if (parser == null) { LOGGER.error("No PatternParser created for config=" + config + ", options=" + Arrays.toString(options)); return null; } return parser.parse(options[0]); } /** * {@inheritDoc} */ @Override @PerformanceSensitive("allocation") public void format(final LogEvent event, final StringBuilder toAppendTo) { final int start = toAppendTo.length(); for (int i = 0; i < formatters.size(); i++) { final PatternFormatter formatter = formatters.get(i); formatter.format(event, toAppendTo); } if (toAppendTo.length() > start) { toAppendTo.insert(start, style); toAppendTo.append(AnsiEscape.getDefaultStyle()); } } }