001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements. See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache license, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License. You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the license for the specific language governing permissions and
015     * limitations under the license.
016     */
017    package org.apache.logging.log4j.core.pattern;
018    
019    import java.lang.reflect.Constructor;
020    import java.lang.reflect.InvocationTargetException;
021    import java.util.List;
022    
023    import org.apache.logging.log4j.core.LogEvent;
024    import org.apache.logging.log4j.core.config.Configuration;
025    import org.apache.logging.log4j.core.config.plugins.Plugin;
026    import org.apache.logging.log4j.core.layout.PatternLayout;
027    
028    /**
029     * Style pattern converter. Adds ANSI color styling to the result of the enclosed pattern.
030     */
031    public abstract class AbstractStyleNameConverter extends LogEventPatternConverter {
032    
033        private final List<PatternFormatter> formatters;
034    
035        private final String style;
036    
037        /**
038         * Constructs the converter.
039         *
040         * @param formatters The PatternFormatters to generate the text to manipulate.
041         * @param styling The styling that should encapsulate the pattern.
042         */
043        protected AbstractStyleNameConverter(final String name, final List<PatternFormatter> formatters,
044                                             final String styling) {
045            super(name, "style");
046            this.formatters = formatters;
047            this.style = styling;
048        }
049    
050        /**
051         * Black style pattern converter. Adds ANSI color styling to the result of the enclosed pattern.
052         */
053        @Plugin(name = Black.NAME, type = "Converter")
054        @ConverterKeys(Black.NAME)
055        public static final class Black extends AbstractStyleNameConverter {
056    
057            /** Black */
058            protected static final String NAME = "black";
059    
060            /**
061             * Constructs the converter. This constructor must be public.
062             *
063             * @param formatters The PatternFormatters to generate the text to manipulate.
064             * @param styling The styling that should encapsulate the pattern.
065             */
066            public Black(final List<PatternFormatter> formatters, final String styling) {
067                super(NAME, formatters, styling);
068            }
069    
070            /**
071             * Gets an instance of the class (called via reflection).
072             *
073             * @param config The current Configuration.
074             * @param options The pattern options, may be null. If the first element is "short", only the first line of the
075             *            throwable will be formatted.
076             * @return new instance of class or null
077             */
078            public static Black newInstance(final Configuration config, final String[] options) {
079                return newInstance(Black.class, NAME, config, options);
080            }
081        }
082    
083        /**
084         * Blue style pattern converter. Adds ANSI color styling to the result of the enclosed pattern.
085         */
086        @Plugin(name = Blue.NAME, type = "Converter")
087        @ConverterKeys(Blue.NAME)
088        public static final class Blue extends AbstractStyleNameConverter {
089    
090            /** Blue */
091            protected static final String NAME = "blue";
092    
093            /**
094             * Constructs the converter. This constructor must be public.
095             *
096             * @param formatters The PatternFormatters to generate the text to manipulate.
097             * @param styling The styling that should encapsulate the pattern.
098             */
099            public Blue(final List<PatternFormatter> formatters, final String styling) {
100                super(NAME, formatters, styling);
101            }
102    
103            /**
104             * Gets an instance of the class (called via reflection).
105             *
106             * @param config The current Configuration.
107             * @param options The pattern options, may be null. If the first element is "short", only the first line of the
108             *                throwable will be formatted.
109             * @return new instance of class or null
110             */
111            public static Blue newInstance(final Configuration config, final String[] options) {
112                return newInstance(Blue.class, NAME, config, options);
113            }
114        }
115    
116        /**
117         * Cyan style pattern converter. Adds ANSI color styling to the result of the enclosed pattern.
118         */
119        @Plugin(name = Cyan.NAME, type = "Converter")
120        @ConverterKeys(Cyan.NAME)
121        public static final class Cyan extends AbstractStyleNameConverter {
122    
123            /** Cyan */
124            protected static final String NAME = "cyan";
125    
126            /**
127             * Constructs the converter. This constructor must be public.
128             *
129             * @param formatters The PatternFormatters to generate the text to manipulate.
130             * @param styling The styling that should encapsulate the pattern.
131             */
132            public Cyan(final List<PatternFormatter> formatters, final String styling) {
133                super(NAME, formatters, styling);
134            }
135    
136            /**
137             * Gets an instance of the class (called via reflection).
138             *
139             * @param config The current Configuration.
140             * @param options The pattern options, may be null. If the first element is "short", only the first line of the
141             *                throwable will be formatted.
142             * @return new instance of class or null
143             */
144            public static Cyan newInstance(final Configuration config, final String[] options) {
145                return newInstance(Cyan.class, NAME, config, options);
146            }
147        }
148    
149        /**
150         * Green style pattern converter. Adds ANSI color styling to the result of the enclosed pattern.
151         */
152        @Plugin(name = Green.NAME, type = "Converter")
153        @ConverterKeys(Green.NAME)
154        public static final class Green extends AbstractStyleNameConverter {
155    
156            /** Green */
157            protected static final String NAME = "green";
158    
159            /**
160             * Constructs the converter. This constructor must be public.
161             *
162             * @param formatters The PatternFormatters to generate the text to manipulate.
163             * @param styling The styling that should encapsulate the pattern.
164             */
165            public Green(final List<PatternFormatter> formatters, final String styling) {
166                super(NAME, formatters, styling);
167            }
168    
169            /**
170             * Gets an instance of the class (called via reflection).
171             *
172             * @param config The current Configuration.
173             * @param options The pattern options, may be null. If the first element is "short", only the first line of the
174             *                throwable will be formatted.
175             * @return new instance of class or null
176             */
177            public static Green newInstance(final Configuration config, final String[] options) {
178                return newInstance(Green.class, NAME, config, options);
179            }
180        }
181    
182        /**
183         * Magenta style pattern converter. Adds ANSI color styling to the result of the enclosed pattern.
184         */
185        @Plugin(name = Magenta.NAME, type = "Converter")
186        @ConverterKeys(Magenta.NAME)
187        public static final class Magenta extends AbstractStyleNameConverter {
188    
189            /** Magenta */
190            protected static final String NAME = "magenta";
191    
192            /**
193             * Constructs the converter. This constructor must be public.
194             *
195             * @param formatters The PatternFormatters to generate the text to manipulate.
196             * @param styling The styling that should encapsulate the pattern.
197             */
198            public Magenta(final List<PatternFormatter> formatters, final String styling) {
199                super(NAME, formatters, styling);
200            }
201    
202            /**
203             * Gets an instance of the class (called via reflection).
204             *
205             * @param config The current Configuration.
206             * @param options The pattern options, may be null. If the first element is "short", only the first line of the
207             *                throwable will be formatted.
208             * @return new instance of class or null
209             */
210            public static Magenta newInstance(final Configuration config, final String[] options) {
211                return newInstance(Magenta.class, NAME, config, options);
212            }
213        }
214    
215        /**
216         * Red style pattern converter. Adds ANSI color styling to the result of the enclosed pattern.
217         */
218        @Plugin(name = Red.NAME, type = "Converter")
219        @ConverterKeys(Red.NAME)
220        public static final class Red extends AbstractStyleNameConverter {
221    
222            /** Red */
223            protected static final String NAME = "red";
224    
225            /**
226             * Constructs the converter. This constructor must be public.
227             *
228             * @param formatters The PatternFormatters to generate the text to manipulate.
229             * @param styling The styling that should encapsulate the pattern.
230             */
231            public Red(final List<PatternFormatter> formatters, final String styling) {
232                super(NAME, formatters, styling);
233            }
234    
235            /**
236             * Gets an instance of the class (called via reflection).
237             *
238             * @param config The current Configuration.
239             * @param options The pattern options, may be null. If the first element is "short", only the first line of the
240             *                throwable will be formatted.
241             * @return new instance of class or null
242             */
243            public static Red newInstance(final Configuration config, final String[] options) {
244                return newInstance(Red.class, NAME, config, options);
245            }
246        }
247    
248        /**
249         * White style pattern converter. Adds ANSI color styling to the result of the enclosed pattern.
250         */
251        @Plugin(name = White.NAME, type = "Converter")
252        @ConverterKeys(White.NAME)
253        public static final class White extends AbstractStyleNameConverter {
254    
255            /** White */
256            protected static final String NAME = "white";
257    
258            /**
259             * Constructs the converter. This constructor must be public.
260             *
261             * @param formatters The PatternFormatters to generate the text to manipulate.
262             * @param styling The styling that should encapsulate the pattern.
263             */
264            public White(final List<PatternFormatter> formatters, final String styling) {
265                super(NAME, formatters, styling);
266            }
267    
268            /**
269             * Gets an instance of the class (called via reflection).
270             *
271             * @param config The current Configuration.
272             * @param options The pattern options, may be null. If the first element is "short", only the first line of the
273             *                throwable will be formatted.
274             * @return new instance of class or null
275             */
276            public static White newInstance(final Configuration config, final String[] options) {
277                return newInstance(White.class, NAME, config, options);
278            }
279        }
280    
281        /**
282         * Yellow style pattern converter. Adds ANSI color styling to the result of the enclosed pattern.
283         */
284        @Plugin(name = Yellow.NAME, type = "Converter")
285        @ConverterKeys(Yellow.NAME)
286        public static final class Yellow extends AbstractStyleNameConverter {
287    
288            /** Yellow */
289            protected static final String NAME = "yellow";
290    
291            /**
292             * Constructs the converter. This constructor must be public.
293             *
294             * @param formatters The PatternFormatters to generate the text to manipulate.
295             * @param styling The styling that should encapsulate the pattern.
296             */
297            public Yellow(final List<PatternFormatter> formatters, final String styling) {
298                super(NAME, formatters, styling);
299            }
300    
301            /**
302             * Gets an instance of the class (called via reflection).
303             *
304             * @param config The current Configuration.
305             * @param options The pattern options, may be null. If the first element is "short", only the first line of the
306             *                throwable will be formatted.
307             * @return new instance of class or null
308             */
309            public static Yellow newInstance(final Configuration config, final String[] options) {
310                return newInstance(Yellow.class, NAME, config, options);
311            }
312        }
313    
314        /**
315         * Gets an instance of the class (called via reflection).
316         *
317         * @param config The current Configuration.
318         * @param options The pattern options, may be null. If the first element is "short", only the first line of the
319         *                throwable will be formatted.
320         * @return new instance of class or null
321         */
322        protected static <T extends AbstractStyleNameConverter> T newInstance(final Class<T> asnConverterClass,
323                                                                              final String name, final Configuration config,
324                                                                              final String[] options) {
325            final List<PatternFormatter> formatters = toPatternFormatterList(config, options);
326            if (formatters == null) {
327                return null;
328            }
329            try {
330                final Constructor<T> constructor = asnConverterClass.getConstructor(List.class, String.class);
331                return constructor.newInstance(formatters, AnsiEscape.createSequence(name));
332            } catch (final SecurityException e) {
333                LOGGER.error(e.toString(), e);
334            } catch (final NoSuchMethodException e) {
335                LOGGER.error(e.toString(), e);
336            } catch (final IllegalArgumentException e) {
337                LOGGER.error(e.toString(), e);
338            } catch (final InstantiationException e) {
339                LOGGER.error(e.toString(), e);
340            } catch (final IllegalAccessException e) {
341                LOGGER.error(e.toString(), e);
342            } catch (final InvocationTargetException e) {
343                LOGGER.error(e.toString(), e);
344            }
345            return null;
346        }
347    
348        /**
349         * Creates a list of PatternFormatter from the given configuration and options or null if no pattern is supplied.
350         *
351         * @param config A configuration.
352         * @param options pattern options.
353         * @return a list of PatternFormatter from the given configuration and options or null if no pattern is supplied.
354         */
355        private static List<PatternFormatter> toPatternFormatterList(final Configuration config, final String[] options) {
356            if (options.length == 0 || options[0] == null) {
357                LOGGER.error("No pattern supplied on style for config=" + config);
358                return null;
359            }
360            final PatternParser parser = PatternLayout.createPatternParser(config);
361            if (parser == null) {
362                LOGGER.error("No PatternParser created for config=" + config + ", options=" + options);
363                return null;
364            }
365            return parser.parse(options[0]);
366        }
367    
368        /**
369         * {@inheritDoc}
370         */
371        @Override
372        public void format(final LogEvent event, final StringBuilder toAppendTo) {
373            final StringBuilder buf = new StringBuilder();
374            for (final PatternFormatter formatter : formatters) {
375                formatter.format(event, buf);
376            }
377            if (buf.length() > 0) {
378                toAppendTo.append(style).append(buf.toString()).append(AnsiEscape.getDefaultStyle());
379            }
380        }
381    }