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       * Escape prefix.
38       */
39      PREFIX("\u001b["),
40      /**
41       * Escape suffix.
42       */
43      SUFFIX("m"),
44  
45      /**
46       * Escape separator.
47       */
48      SEPARATOR(";"),
49  
50      /**
51       * Normal general attribute.
52       */
53      NORMAL("0"),
54  
55      /**
56       * Bright general attribute.
57       */
58      BRIGHT("1"),
59  
60      /**
61       * Dim general attribute.
62       */
63      DIM("2"),
64  
65      /**
66       * Underline general attribute.
67       */
68      UNDERLINE("3"),
69  
70      /**
71       * Blink general attribute.
72       */
73      BLINK("5"),
74  
75      /**
76       * Reverse general attribute.
77       */
78      REVERSE("7"),
79  
80      /**
81       * Normal general attribute.
82       */
83      HIDDEN("8"),
84  
85      /**
86       * Black foreground color.
87       */
88      BLACK("30"),
89  
90      /**
91       * Black foreground color.
92       */
93      FG_BLACK("30"),
94  
95      /**
96       * Red foreground color.
97       */
98      RED("31"),
99  
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 }