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 static final String DEFAULT_STYLE = CSI.getCode() + SUFFIX.getCode();
220 
221     private final String code;
222 
223     AnsiEscape(final String code) {
224         this.code = code;
225     }
226 
227     /**
228      * Gets the default style.
229      *
230      * @return the default style
231      */
232     public static String getDefaultStyle() {
233         return DEFAULT_STYLE;
234     }
235 
236     /**
237      * Gets the escape code.
238      *
239      * @return the escape code.
240      */
241     public String getCode() {
242         return code;
243     }
244 
245     /**
246      * Creates a Map from a source array where values are ANSI escape sequences. The format is:
247      *
248      * <pre>
249      * Key1=Value, Key2=Value, ...
250      * </pre>
251      *
252      * For example:
253      *
254      * <pre>
255      * ERROR=red bold, WARN=yellow bold, INFO=green, ...
256      * </pre>
257      *
258      * You can use whitespace around the comma and equal sign. The names in values MUST come from the
259      * {@linkplain AnsiEscape} enum, case is normalized to upper-case internally.
260      *
261      * @param values the source string to parse.
262      * @param dontEscapeKeys do not escape these keys, leave the values as is in the map
263      * @return a new map
264      */
265     public static Map<String, String> createMap(final String values, final String[] dontEscapeKeys) {
266         return createMap(values.split(Patterns.COMMA_SEPARATOR), dontEscapeKeys);
267     }
268 
269     /**
270      * Creates a Map from a source array where values are ANSI escape sequences. Each array entry must be in the format:
271      *
272      * <pre>
273      * Key1 = Value
274      * </pre>
275      *
276      * For example:
277      *
278      * <pre>
279      * ERROR=red bold
280      * </pre>
281      *
282      * You can use whitespace around the equal sign and between the value elements. The names in values MUST come from
283      * the {@linkplain AnsiEscape} enum, case is normalized to upper-case internally.
284      *
285      * @param values
286      *            the source array to parse.
287      * @param dontEscapeKeys
288      *            do not escape these keys, leave the values as is in the map
289      * @return a new map
290      */
291     public static Map<String, String> createMap(final String[] values, final String[] dontEscapeKeys) {
292         final String[] sortedIgnoreKeys = dontEscapeKeys != null ? dontEscapeKeys.clone() : new String[0];
293         Arrays.sort(sortedIgnoreKeys);
294         final Map<String, String> map = new HashMap<>();
295         for (final String string : values) {
296             final String[] keyValue = string.split(Patterns.toWhitespaceSeparator("="));
297             if (keyValue.length > 1) {
298                 final String key = keyValue[0].toUpperCase(Locale.ENGLISH);
299                 final String value = keyValue[1];
300                 final boolean escape = Arrays.binarySearch(sortedIgnoreKeys, key) < 0;
301                 map.put(key, escape ? createSequence(value.split("\\s")) : value);
302             }
303         }
304         return map;
305     }
306 
307     /**
308      * Creates an ANSI escape sequence from the given {@linkplain AnsiEscape} names.
309      *
310      * @param names
311      *            {@linkplain AnsiEscape} names.
312      * @return An ANSI escape sequence.
313      */
314     public static String createSequence(final String... names) {
315         if (names == null) {
316             return getDefaultStyle();
317         }
318         final StringBuilder sb = new StringBuilder(AnsiEscape.CSI.getCode());
319         boolean first = true;
320         for (final String name : names) {
321             try {
322                 final AnsiEscape escape = EnglishEnums.valueOf(AnsiEscape.class, name.trim());
323                 if (!first) {
324                     sb.append(AnsiEscape.SEPARATOR.getCode());
325                 }
326                 first = false;
327                 sb.append(escape.getCode());
328             } catch (final Exception ex) {
329                 // Ignore the error.
330             }
331         }
332         sb.append(AnsiEscape.SUFFIX.getCode());
333         return sb.toString();
334     }
335 
336 }