View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache license, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the license for the specific language governing permissions and
15   * limitations under the license.
16   */
17  package org.apache.logging.log4j.core.pattern;
18  
19  import java.lang.reflect.Constructor;
20  import java.lang.reflect.InvocationTargetException;
21  import java.util.Arrays;
22  import java.util.List;
23  
24  import org.apache.logging.log4j.core.LogEvent;
25  import org.apache.logging.log4j.core.config.Configuration;
26  import org.apache.logging.log4j.core.config.plugins.Plugin;
27  import org.apache.logging.log4j.core.layout.PatternLayout;
28  
29  /**
30   * Style pattern converter. Adds ANSI color styling to the result of the enclosed pattern.
31   */
32  public abstract class AbstractStyleNameConverter extends LogEventPatternConverter /*TODO: implements AnsiConverter*/ {
33  
34      private final List<PatternFormatter> formatters;
35  
36      private final String style;
37  
38      /**
39       * Constructs the converter.
40       *
41       * @param formatters The PatternFormatters to generate the text to manipulate.
42       * @param styling The styling that should encapsulate the pattern.
43       */
44      protected AbstractStyleNameConverter(final String name, final List<PatternFormatter> formatters,
45                                           final String styling) {
46          super(name, "style");
47          this.formatters = formatters;
48          this.style = styling;
49      }
50  
51      /**
52       * Black style pattern converter. Adds ANSI color styling to the result of the enclosed pattern.
53       */
54      @Plugin(name = Black.NAME, category = "Converter")
55      @ConverterKeys(Black.NAME)
56      public static final class Black extends AbstractStyleNameConverter {
57  
58          /** Black */
59          protected static final String NAME = "black";
60  
61          /**
62           * Constructs the converter. This constructor must be public.
63           *
64           * @param formatters The PatternFormatters to generate the text to manipulate.
65           * @param styling The styling that should encapsulate the pattern.
66           */
67          public Black(final List<PatternFormatter> formatters, final String styling) {
68              super(NAME, formatters, styling);
69          }
70  
71          /**
72           * Gets an instance of the class (called via reflection).
73           *
74           * @param config The current Configuration.
75           * @param options The pattern options, may be null. If the first element is "short", only the first line of the
76           *            throwable will be formatted.
77           * @return new instance of class or null
78           */
79          public static Black newInstance(final Configuration config, final String[] options) {
80              return newInstance(Black.class, NAME, config, options);
81          }
82      }
83  
84      /**
85       * Blue style pattern converter. Adds ANSI color styling to the result of the enclosed pattern.
86       */
87      @Plugin(name = Blue.NAME, category = "Converter")
88      @ConverterKeys(Blue.NAME)
89      public static final class Blue extends AbstractStyleNameConverter {
90  
91          /** Blue */
92          protected static final String NAME = "blue";
93  
94          /**
95           * Constructs the converter. This constructor must be public.
96           *
97           * @param formatters The PatternFormatters to generate the text to manipulate.
98           * @param styling The styling that should encapsulate the pattern.
99           */
100         public Blue(final List<PatternFormatter> formatters, final String styling) {
101             super(NAME, formatters, styling);
102         }
103 
104         /**
105          * Gets an instance of the class (called via reflection).
106          *
107          * @param config The current Configuration.
108          * @param options The pattern options, may be null. If the first element is "short", only the first line of the
109          *                throwable will be formatted.
110          * @return new instance of class or null
111          */
112         public static Blue newInstance(final Configuration config, final String[] options) {
113             return newInstance(Blue.class, NAME, config, options);
114         }
115     }
116 
117     /**
118      * Cyan style pattern converter. Adds ANSI color styling to the result of the enclosed pattern.
119      */
120     @Plugin(name = Cyan.NAME, category = "Converter")
121     @ConverterKeys(Cyan.NAME)
122     public static final class Cyan extends AbstractStyleNameConverter {
123 
124         /** Cyan */
125         protected static final String NAME = "cyan";
126 
127         /**
128          * Constructs the converter. This constructor must be public.
129          *
130          * @param formatters The PatternFormatters to generate the text to manipulate.
131          * @param styling The styling that should encapsulate the pattern.
132          */
133         public Cyan(final List<PatternFormatter> formatters, final String styling) {
134             super(NAME, formatters, styling);
135         }
136 
137         /**
138          * Gets an instance of the class (called via reflection).
139          *
140          * @param config The current Configuration.
141          * @param options The pattern options, may be null. If the first element is "short", only the first line of the
142          *                throwable will be formatted.
143          * @return new instance of class or null
144          */
145         public static Cyan newInstance(final Configuration config, final String[] options) {
146             return newInstance(Cyan.class, NAME, config, options);
147         }
148     }
149 
150     /**
151      * Green style pattern converter. Adds ANSI color styling to the result of the enclosed pattern.
152      */
153     @Plugin(name = Green.NAME, category = "Converter")
154     @ConverterKeys(Green.NAME)
155     public static final class Green extends AbstractStyleNameConverter {
156 
157         /** Green */
158         protected static final String NAME = "green";
159 
160         /**
161          * Constructs the converter. This constructor must be public.
162          *
163          * @param formatters The PatternFormatters to generate the text to manipulate.
164          * @param styling The styling that should encapsulate the pattern.
165          */
166         public Green(final List<PatternFormatter> formatters, final String styling) {
167             super(NAME, formatters, styling);
168         }
169 
170         /**
171          * Gets an instance of the class (called via reflection).
172          *
173          * @param config The current Configuration.
174          * @param options The pattern options, may be null. If the first element is "short", only the first line of the
175          *                throwable will be formatted.
176          * @return new instance of class or null
177          */
178         public static Green newInstance(final Configuration config, final String[] options) {
179             return newInstance(Green.class, NAME, config, options);
180         }
181     }
182 
183     /**
184      * Magenta style pattern converter. Adds ANSI color styling to the result of the enclosed pattern.
185      */
186     @Plugin(name = Magenta.NAME, category = "Converter")
187     @ConverterKeys(Magenta.NAME)
188     public static final class Magenta extends AbstractStyleNameConverter {
189 
190         /** Magenta */
191         protected static final String NAME = "magenta";
192 
193         /**
194          * Constructs the converter. This constructor must be public.
195          *
196          * @param formatters The PatternFormatters to generate the text to manipulate.
197          * @param styling The styling that should encapsulate the pattern.
198          */
199         public Magenta(final List<PatternFormatter> formatters, final String styling) {
200             super(NAME, formatters, styling);
201         }
202 
203         /**
204          * Gets an instance of the class (called via reflection).
205          *
206          * @param config The current Configuration.
207          * @param options The pattern options, may be null. If the first element is "short", only the first line of the
208          *                throwable will be formatted.
209          * @return new instance of class or null
210          */
211         public static Magenta newInstance(final Configuration config, final String[] options) {
212             return newInstance(Magenta.class, NAME, config, options);
213         }
214     }
215 
216     /**
217      * Red style pattern converter. Adds ANSI color styling to the result of the enclosed pattern.
218      */
219     @Plugin(name = Red.NAME, category = "Converter")
220     @ConverterKeys(Red.NAME)
221     public static final class Red extends AbstractStyleNameConverter {
222 
223         /** Red */
224         protected static final String NAME = "red";
225 
226         /**
227          * Constructs the converter. This constructor must be public.
228          *
229          * @param formatters The PatternFormatters to generate the text to manipulate.
230          * @param styling The styling that should encapsulate the pattern.
231          */
232         public Red(final List<PatternFormatter> formatters, final String styling) {
233             super(NAME, formatters, styling);
234         }
235 
236         /**
237          * Gets an instance of the class (called via reflection).
238          *
239          * @param config The current Configuration.
240          * @param options The pattern options, may be null. If the first element is "short", only the first line of the
241          *                throwable will be formatted.
242          * @return new instance of class or null
243          */
244         public static Red newInstance(final Configuration config, final String[] options) {
245             return newInstance(Red.class, NAME, config, options);
246         }
247     }
248 
249     /**
250      * White style pattern converter. Adds ANSI color styling to the result of the enclosed pattern.
251      */
252     @Plugin(name = White.NAME, category = "Converter")
253     @ConverterKeys(White.NAME)
254     public static final class White extends AbstractStyleNameConverter {
255 
256         /** White */
257         protected static final String NAME = "white";
258 
259         /**
260          * Constructs the converter. This constructor must be public.
261          *
262          * @param formatters The PatternFormatters to generate the text to manipulate.
263          * @param styling The styling that should encapsulate the pattern.
264          */
265         public White(final List<PatternFormatter> formatters, final String styling) {
266             super(NAME, formatters, styling);
267         }
268 
269         /**
270          * Gets an instance of the class (called via reflection).
271          *
272          * @param config The current Configuration.
273          * @param options The pattern options, may be null. If the first element is "short", only the first line of the
274          *                throwable will be formatted.
275          * @return new instance of class or null
276          */
277         public static White newInstance(final Configuration config, final String[] options) {
278             return newInstance(White.class, NAME, config, options);
279         }
280     }
281 
282     /**
283      * Yellow style pattern converter. Adds ANSI color styling to the result of the enclosed pattern.
284      */
285     @Plugin(name = Yellow.NAME, category = "Converter")
286     @ConverterKeys(Yellow.NAME)
287     public static final class Yellow extends AbstractStyleNameConverter {
288 
289         /** Yellow */
290         protected static final String NAME = "yellow";
291 
292         /**
293          * Constructs the converter. This constructor must be public.
294          *
295          * @param formatters The PatternFormatters to generate the text to manipulate.
296          * @param styling The styling that should encapsulate the pattern.
297          */
298         public Yellow(final List<PatternFormatter> formatters, final String styling) {
299             super(NAME, formatters, styling);
300         }
301 
302         /**
303          * Gets an instance of the class (called via reflection).
304          *
305          * @param config The current Configuration.
306          * @param options The pattern options, may be null. If the first element is "short", only the first line of the
307          *                throwable will be formatted.
308          * @return new instance of class or null
309          */
310         public static Yellow newInstance(final Configuration config, final String[] options) {
311             return newInstance(Yellow.class, NAME, config, options);
312         }
313     }
314 
315     /**
316      * Gets an instance of the class (called via reflection).
317      *
318      * @param config The current Configuration.
319      * @param options The pattern options, may be null. If the first element is "short", only the first line of the
320      *                throwable will be formatted.
321      * @return new instance of class or null
322      */
323     protected static <T extends AbstractStyleNameConverter> T newInstance(final Class<T> asnConverterClass,
324                                                                           final String name, final Configuration config,
325                                                                           final String[] options) {
326         final List<PatternFormatter> formatters = toPatternFormatterList(config, options);
327         if (formatters == null) {
328             return null;
329         }
330         try {
331             final Constructor<T> constructor = asnConverterClass.getConstructor(List.class, String.class);
332             return constructor.newInstance(formatters, AnsiEscape.createSequence(name));
333         } catch (final SecurityException e) {
334             LOGGER.error(e.toString(), e);
335         } catch (final NoSuchMethodException e) {
336             LOGGER.error(e.toString(), e);
337         } catch (final IllegalArgumentException e) {
338             LOGGER.error(e.toString(), e);
339         } catch (final InstantiationException e) {
340             LOGGER.error(e.toString(), e);
341         } catch (final IllegalAccessException e) {
342             LOGGER.error(e.toString(), e);
343         } catch (final InvocationTargetException e) {
344             LOGGER.error(e.toString(), e);
345         }
346         return null;
347     }
348 
349     /**
350      * Creates a list of PatternFormatter from the given configuration and options or null if no pattern is supplied.
351      *
352      * @param config A configuration.
353      * @param options pattern options.
354      * @return a list of PatternFormatter from the given configuration and options or null if no pattern is supplied.
355      */
356     private static List<PatternFormatter> toPatternFormatterList(final Configuration config, final String[] options) {
357         if (options.length == 0 || options[0] == null) {
358             LOGGER.error("No pattern supplied on style for config=" + config);
359             return null;
360         }
361         final PatternParser parser = PatternLayout.createPatternParser(config);
362         if (parser == null) {
363             LOGGER.error("No PatternParser created for config=" + config + ", options=" + Arrays.toString(options));
364             return null;
365         }
366         return parser.parse(options[0]);
367     }
368 
369     /**
370      * {@inheritDoc}
371      */
372     @Override
373     public void format(final LogEvent event, final StringBuilder toAppendTo) {
374         final StringBuilder buf = new StringBuilder();
375         for (final PatternFormatter formatter : formatters) {
376             formatter.format(event, buf);
377         }
378         if (buf.length() > 0) {
379             toAppendTo.append(style).append(buf.toString()).append(AnsiEscape.getDefaultStyle());
380         }
381     }
382 }