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 */ 017package org.apache.logging.log4j.core.pattern; 018 019import java.lang.reflect.Constructor; 020import java.lang.reflect.InvocationTargetException; 021import java.util.Arrays; 022import java.util.List; 023 024import org.apache.logging.log4j.core.LogEvent; 025import org.apache.logging.log4j.core.config.Configuration; 026import org.apache.logging.log4j.core.config.plugins.Plugin; 027import org.apache.logging.log4j.core.layout.PatternLayout; 028import org.apache.logging.log4j.util.PerformanceSensitive; 029 030/** 031 * Style pattern converter. Adds ANSI color styling to the result of the enclosed pattern. 032 */ 033public abstract class AbstractStyleNameConverter extends LogEventPatternConverter /*TODO: implements AnsiConverter*/ { 034 035 private final List<PatternFormatter> formatters; 036 037 private final String style; 038 039 /** 040 * Constructs the converter. 041 * 042 * @param formatters The PatternFormatters to generate the text to manipulate. 043 * @param styling The styling that should encapsulate the pattern. 044 */ 045 protected AbstractStyleNameConverter(final String name, final List<PatternFormatter> formatters, 046 final String styling) { 047 super(name, "style"); 048 this.formatters = formatters; 049 this.style = styling; 050 } 051 052 /** 053 * Black style pattern converter. Adds ANSI color styling to the result of the enclosed pattern. 054 */ 055 @Plugin(name = Black.NAME, category = "Converter") 056 @ConverterKeys(Black.NAME) 057 public static final class Black extends AbstractStyleNameConverter { 058 059 /** Black */ 060 protected static final String NAME = "black"; 061 062 /** 063 * Constructs the converter. This constructor must be public. 064 * 065 * @param formatters The PatternFormatters to generate the text to manipulate. 066 * @param styling The styling that should encapsulate the pattern. 067 */ 068 public Black(final List<PatternFormatter> formatters, final String styling) { 069 super(NAME, formatters, styling); 070 } 071 072 /** 073 * Gets an instance of the class (called via reflection). 074 * 075 * @param config The current Configuration. 076 * @param options The pattern options, may be null. If the first element is "short", only the first line of the 077 * throwable will be formatted. 078 * @return new instance of class or null 079 */ 080 public static Black newInstance(final Configuration config, final String[] options) { 081 return newInstance(Black.class, NAME, config, options); 082 } 083 } 084 085 /** 086 * Blue style pattern converter. Adds ANSI color styling to the result of the enclosed pattern. 087 */ 088 @Plugin(name = Blue.NAME, category = "Converter") 089 @ConverterKeys(Blue.NAME) 090 public static final class Blue extends AbstractStyleNameConverter { 091 092 /** Blue */ 093 protected static final String NAME = "blue"; 094 095 /** 096 * Constructs the converter. This constructor must be public. 097 * 098 * @param formatters The PatternFormatters to generate the text to manipulate. 099 * @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}