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