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