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.util.Arrays; 020import java.util.HashMap; 021import java.util.Locale; 022import java.util.Map; 023 024import org.apache.logging.log4j.core.util.Patterns; 025import org.apache.logging.log4j.util.EnglishEnums; 026import org.apache.logging.log4j.util.Strings; 027 028/** 029 * Converts text into ANSI escape sequences. 030 * <p> 031 * The names for colors and attributes are standard, but the exact shade/hue/value of colors are not, and depend on the 032 * device used to display them. 033 * </p> 034 */ 035public enum AnsiEscape { 036 037 /** 038 * The Control Sequence Introducer (or Control Sequence Initiator). 039 * <p> 040 * Most sequences are more than two characters and start with the characters ESC and [ (the left bracket). 041 * </p> 042 */ 043 CSI("\u001b["), 044 045 /** 046 * Escape suffix. 047 */ 048 SUFFIX("m"), 049 050 /** 051 * Escape separator. 052 */ 053 SEPARATOR(";"), 054 055 /** 056 * Normal general attribute. 057 */ 058 NORMAL("0"), 059 060 /** 061 * Bright general attribute. 062 */ 063 BRIGHT("1"), 064 065 /** 066 * Dim general attribute. 067 */ 068 DIM("2"), 069 070 /** 071 * Underline general attribute. 072 */ 073 UNDERLINE("3"), 074 075 /** 076 * Blink general attribute. 077 */ 078 BLINK("5"), 079 080 /** 081 * Reverse general attribute. 082 */ 083 REVERSE("7"), 084 085 /** 086 * Normal general attribute. 087 */ 088 HIDDEN("8"), 089 090 /** 091 * Black foreground color. 092 */ 093 BLACK("30"), 094 095 /** 096 * Black foreground color. 097 */ 098 FG_BLACK("30"), 099 100 /** 101 * Red foreground color. 102 */ 103 RED("31"), 104 105 /** 106 * Red foreground color. 107 */ 108 FG_RED("31"), 109 110 /** 111 * Green foreground color. 112 */ 113 GREEN("32"), 114 115 /** 116 * Green foreground color. 117 */ 118 FG_GREEN("32"), 119 120 /** 121 * Yellow foreground color. 122 */ 123 YELLOW("33"), 124 125 /** 126 * Yellow foreground color. 127 */ 128 FG_YELLOW("33"), 129 130 /** 131 * Blue foreground color. 132 */ 133 BLUE("34"), 134 135 /** 136 * Blue foreground color. 137 */ 138 FG_BLUE("34"), 139 140 /** 141 * Magenta foreground color. 142 */ 143 MAGENTA("35"), 144 145 /** 146 * Magenta foreground color. 147 */ 148 FG_MAGENTA("35"), 149 150 /** 151 * Cyan foreground color. 152 */ 153 CYAN("36"), 154 155 /** 156 * Cyan foreground color. 157 */ 158 FG_CYAN("36"), 159 160 /** 161 * White foreground color. 162 */ 163 WHITE("37"), 164 165 /** 166 * White foreground color. 167 */ 168 FG_WHITE("37"), 169 170 /** 171 * Default foreground color. 172 */ 173 DEFAULT("39"), 174 175 /** 176 * Default foreground color. 177 */ 178 FG_DEFAULT("39"), 179 180 /** 181 * Black background color. 182 */ 183 BG_BLACK("40"), 184 185 /** 186 * Red background color. 187 */ 188 BG_RED("41"), 189 190 /** 191 * Green background color. 192 */ 193 BG_GREEN("42"), 194 195 /** 196 * Yellow background color. 197 */ 198 BG_YELLOW("43"), 199 200 /** 201 * Blue background color. 202 */ 203 BG_BLUE("44"), 204 205 /** 206 * Magenta background color. 207 */ 208 BG_MAGENTA("45"), 209 210 /** 211 * Cyan background color. 212 */ 213 BG_CYAN("46"), 214 215 /** 216 * White background color. 217 */ 218 BG_WHITE("47"); 219 220 private static final String DEFAULT_STYLE = CSI.getCode() + SUFFIX.getCode(); 221 222 private final String code; 223 224 AnsiEscape(final String code) { 225 this.code = code; 226 } 227 228 /** 229 * Gets the default style. 230 * 231 * @return the default style 232 */ 233 public static String getDefaultStyle() { 234 return DEFAULT_STYLE; 235 } 236 237 /** 238 * Gets the escape code. 239 * 240 * @return the escape code. 241 */ 242 public String getCode() { 243 return code; 244 } 245 246 /** 247 * Creates a Map from a source array where values are ANSI escape sequences. The format is: 248 * 249 * <pre> 250 * Key1=Value, Key2=Value, ... 251 * </pre> 252 * 253 * For example: 254 * 255 * <pre> 256 * ERROR=red bold, WARN=yellow bold, INFO=green, ... 257 * </pre> 258 * 259 * You can use whitespace around the comma and equal sign. The names in values MUST come from the 260 * {@linkplain AnsiEscape} enum, case is normalized to upper-case internally. 261 * 262 * @param values the source string to parse. 263 * @param dontEscapeKeys do not escape these keys, leave the values as is in the map 264 * @return a new map 265 */ 266 public static Map<String, String> createMap(final String values, final String[] dontEscapeKeys) { 267 return createMap(values.split(Patterns.COMMA_SEPARATOR), dontEscapeKeys); 268 } 269 270 /** 271 * Creates a Map from a source array where values are ANSI escape sequences. Each array entry must be in the format: 272 * 273 * <pre> 274 * Key1 = Value 275 * </pre> 276 * 277 * For example: 278 * 279 * <pre> 280 * ERROR=red bold 281 * </pre> 282 * 283 * You can use whitespace around the equal sign and between the value elements. The names in values MUST come from 284 * the {@linkplain AnsiEscape} enum, case is normalized to upper-case internally. 285 * 286 * @param values 287 * the source array to parse. 288 * @param dontEscapeKeys 289 * do not escape these keys, leave the values as is in the map 290 * @return a new map 291 */ 292 public static Map<String, String> createMap(final String[] values, final String[] dontEscapeKeys) { 293 final String[] sortedIgnoreKeys = dontEscapeKeys != null ? dontEscapeKeys.clone() : Strings.EMPTY_ARRAY; 294 Arrays.sort(sortedIgnoreKeys); 295 final Map<String, String> map = new HashMap<>(); 296 for (final String string : values) { 297 final String[] keyValue = string.split(Patterns.toWhitespaceSeparator("=")); 298 if (keyValue.length > 1) { 299 final String key = keyValue[0].toUpperCase(Locale.ENGLISH); 300 final String value = keyValue[1]; 301 final boolean escape = Arrays.binarySearch(sortedIgnoreKeys, key) < 0; 302 map.put(key, escape ? createSequence(value.split("\\s")) : value); 303 } 304 } 305 return map; 306 } 307 308 /** 309 * Creates an ANSI escape sequence from the given {@linkplain AnsiEscape} names. 310 * 311 * @param names 312 * {@linkplain AnsiEscape} names. 313 * @return An ANSI escape sequence. 314 */ 315 public static String createSequence(final String... names) { 316 if (names == null) { 317 return getDefaultStyle(); 318 } 319 final StringBuilder sb = new StringBuilder(AnsiEscape.CSI.getCode()); 320 boolean first = true; 321 for (final String name : names) { 322 try { 323 final AnsiEscape escape = EnglishEnums.valueOf(AnsiEscape.class, name.trim()); 324 if (!first) { 325 sb.append(AnsiEscape.SEPARATOR.getCode()); 326 } 327 first = false; 328 sb.append(escape.getCode()); 329 } catch (final Exception ex) { 330 // Ignore the error. 331 } 332 } 333 sb.append(AnsiEscape.SUFFIX.getCode()); 334 return sb.toString(); 335 } 336 337}