View Javadoc
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.util.Arrays;
20  import java.util.HashMap;
21  import java.util.Locale;
22  import java.util.Map;
23  
24  import org.apache.logging.log4j.core.util.Patterns;
25  import org.apache.logging.log4j.util.EnglishEnums;
26  
27  /**
28   * Converts text into ANSI escape sequences.
29   * <p>
30   * The names for colors and attributes are standard, but the exact shade/hue/value of colors are not, and depend on the
31   * device used to display them.
32   * </p>
33   */
34  public enum AnsiEscape {
35  
36      /**
37       * The Control Sequence Introducer (or Control Sequence Initiator).
38       * <p>
39       * Most sequences are more than two characters and start with the characters ESC and [ (the left bracket).
40       * </p>
41       */
42      CSI("\u001b["),
43      
44      /**
45       * Escape suffix.
46       */
47      SUFFIX("m"),
48  
49      /**
50       * Escape separator.
51       */
52      SEPARATOR(";"),
53  
54      /**
55       * Normal general attribute.
56       */
57      NORMAL("0"),
58  
59      /**
60       * Bright general attribute.
61       */
62      BRIGHT("1"),
63  
64      /**
65       * Dim general attribute.
66       */
67      DIM("2"),
68  
69      /**
70       * Underline general attribute.
71       */
72      UNDERLINE("3"),
73  
74      /**
75       * Blink general attribute.
76       */
77      BLINK("5"),
78  
79      /**
80       * Reverse general attribute.
81       */
82      REVERSE("7"),
83  
84      /**
85       * Normal general attribute.
86       */
87      HIDDEN("8"),
88  
89      /**
90       * Black foreground color.
91       */
92      BLACK("30"),
93  
94      /**
95       * Black foreground color.
96       */
97      FG_BLACK("30"),
98  
99      /**
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 }