1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core.pattern;
18
19 import java.util.Arrays;
20 import java.util.HashMap;
21 import java.util.List;
22 import java.util.Locale;
23 import java.util.Map;
24
25 import org.apache.logging.log4j.Level;
26 import org.apache.logging.log4j.core.LogEvent;
27 import org.apache.logging.log4j.core.config.Configuration;
28 import org.apache.logging.log4j.core.config.plugins.Plugin;
29 import org.apache.logging.log4j.core.layout.PatternLayout;
30 import org.apache.logging.log4j.util.Strings;
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71 @Plugin(name = "highlight", category = "Converter")
72 @ConverterKeys({ "highlight" })
73 public final class HighlightConverter extends LogEventPatternConverter implements AnsiConverter {
74
75 private static final Map<Level, String> DEFAULT_STYLES = new HashMap<Level, String>();
76
77 private static final Map<Level, String> LOGBACK_STYLES = new HashMap<Level, String>();
78
79 private static final String STYLE_KEY = "STYLE";
80
81 private static final String STYLE_KEY_DEFAULT = "DEFAULT";
82
83 private static final String STYLE_KEY_LOGBACK = "LOGBACK";
84
85 private static final Map<String, Map<Level, String>> STYLES = new HashMap<String, Map<Level, String>>();
86
87 static {
88
89 DEFAULT_STYLES.put(Level.FATAL, AnsiEscape.createSequence("BRIGHT", "RED"));
90 DEFAULT_STYLES.put(Level.ERROR, AnsiEscape.createSequence("BRIGHT", "RED"));
91 DEFAULT_STYLES.put(Level.WARN, AnsiEscape.createSequence("YELLOW"));
92 DEFAULT_STYLES.put(Level.INFO, AnsiEscape.createSequence("GREEN"));
93 DEFAULT_STYLES.put(Level.DEBUG, AnsiEscape.createSequence("CYAN"));
94 DEFAULT_STYLES.put(Level.TRACE, AnsiEscape.createSequence("BLACK"));
95
96 LOGBACK_STYLES.put(Level.FATAL, AnsiEscape.createSequence("BLINK", "BRIGHT", "RED"));
97 LOGBACK_STYLES.put(Level.ERROR, AnsiEscape.createSequence("BRIGHT", "RED"));
98 LOGBACK_STYLES.put(Level.WARN, AnsiEscape.createSequence("RED"));
99 LOGBACK_STYLES.put(Level.INFO, AnsiEscape.createSequence("BLUE"));
100 LOGBACK_STYLES.put(Level.DEBUG, AnsiEscape.createSequence((String[]) null));
101 LOGBACK_STYLES.put(Level.TRACE, AnsiEscape.createSequence((String[]) null));
102
103 STYLES.put(STYLE_KEY_DEFAULT, DEFAULT_STYLES);
104 STYLES.put(STYLE_KEY_LOGBACK, LOGBACK_STYLES);
105 }
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131 private static Map<Level, String> createLevelStyleMap(final String[] options) {
132 if (options.length < 2) {
133 return DEFAULT_STYLES;
134 }
135
136 final String string = options[1].replaceAll(PatternParser.NO_CONSOLE_NO_ANSI + "=(true|false)", Strings.EMPTY);
137
138 final Map<String, String> styles = AnsiEscape.createMap(string, new String[] {STYLE_KEY});
139 final Map<Level, String> levelStyles = new HashMap<Level, String>(DEFAULT_STYLES);
140 for (final Map.Entry<String, String> entry : styles.entrySet()) {
141 final String key = entry.getKey().toUpperCase(Locale.ENGLISH);
142 final String value = entry.getValue();
143 if (STYLE_KEY.equalsIgnoreCase(key)) {
144 final Map<Level, String> enumMap = STYLES.get(value.toUpperCase(Locale.ENGLISH));
145 if (enumMap == null) {
146 LOGGER.error("Unknown level style: " + value + ". Use one of " +
147 Arrays.toString(STYLES.keySet().toArray()));
148 } else {
149 levelStyles.putAll(enumMap);
150 }
151 } else {
152 final Level level = Level.toLevel(key);
153 if (level == null) {
154 LOGGER.error("Unknown level name: " + key + ". Use one of " +
155 Arrays.toString(DEFAULT_STYLES.keySet().toArray()));
156 } else {
157 levelStyles.put(level, value);
158 }
159 }
160 }
161 return levelStyles;
162 }
163
164
165
166
167
168
169
170
171
172 public static HighlightConverter newInstance(final Configuration config, final String[] options) {
173 if (options.length < 1) {
174 LOGGER.error("Incorrect number of options on style. Expected at least 1, received " + options.length);
175 return null;
176 }
177 if (options[0] == null) {
178 LOGGER.error("No pattern supplied on style");
179 return null;
180 }
181 final PatternParser parser = PatternLayout.createPatternParser(config);
182 final List<PatternFormatter> formatters = parser.parse(options[0]);
183 return new HighlightConverter(formatters, createLevelStyleMap(options));
184 }
185
186 private final Map<Level, String> levelStyles;
187
188 private final List<PatternFormatter> patternFormatters;
189
190
191
192
193
194
195
196 private HighlightConverter(final List<PatternFormatter> patternFormatters, final Map<Level, String> levelStyles) {
197 super("style", "style");
198 this.patternFormatters = patternFormatters;
199 this.levelStyles = levelStyles;
200 }
201
202
203
204
205 @Override
206 public void format(final LogEvent event, final StringBuilder toAppendTo) {
207 final StringBuilder buf = new StringBuilder();
208 for (final PatternFormatter formatter : patternFormatters) {
209 formatter.format(event, buf);
210 }
211
212 if (buf.length() > 0) {
213 toAppendTo.append(levelStyles.get(event.getLevel())).append(buf.toString()).
214 append(AnsiEscape.getDefaultStyle());
215 }
216 }
217
218 @Override
219 public boolean handlesThrowable() {
220 for (final PatternFormatter formatter : patternFormatters) {
221 if (formatter .handlesThrowable()) {
222 return true;
223 }
224 }
225 return false;
226 }
227 }