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 }