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