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 @Plugin(name = "highlight", category = PatternConverter.CATEGORY)
70 @ConverterKeys({ "highlight" })
71 public final class HighlightConverter extends LogEventPatternConverter implements AnsiConverter {
72
73 private static final Map<Level, String> DEFAULT_STYLES = new HashMap<Level, String>();
74
75 private static final Map<Level, String> LOGBACK_STYLES = new HashMap<Level, String>();
76
77 private static final String STYLE_KEY = "STYLE";
78
79 private static final String STYLE_KEY_DEFAULT = "DEFAULT";
80
81 private static final String STYLE_KEY_LOGBACK = "LOGBACK";
82
83 private static final Map<String, Map<Level, String>> STYLES = new HashMap<String, Map<Level, String>>();
84
85 static {
86
87 DEFAULT_STYLES.put(Level.FATAL, AnsiEscape.createSequence("BRIGHT", "RED"));
88 DEFAULT_STYLES.put(Level.ERROR, AnsiEscape.createSequence("BRIGHT", "RED"));
89 DEFAULT_STYLES.put(Level.WARN, AnsiEscape.createSequence("YELLOW"));
90 DEFAULT_STYLES.put(Level.INFO, AnsiEscape.createSequence("GREEN"));
91 DEFAULT_STYLES.put(Level.DEBUG, AnsiEscape.createSequence("CYAN"));
92 DEFAULT_STYLES.put(Level.TRACE, AnsiEscape.createSequence("BLACK"));
93
94 LOGBACK_STYLES.put(Level.FATAL, AnsiEscape.createSequence("BLINK", "BRIGHT", "RED"));
95 LOGBACK_STYLES.put(Level.ERROR, AnsiEscape.createSequence("BRIGHT", "RED"));
96 LOGBACK_STYLES.put(Level.WARN, AnsiEscape.createSequence("RED"));
97 LOGBACK_STYLES.put(Level.INFO, AnsiEscape.createSequence("BLUE"));
98 LOGBACK_STYLES.put(Level.DEBUG, AnsiEscape.createSequence((String[]) null));
99 LOGBACK_STYLES.put(Level.TRACE, AnsiEscape.createSequence((String[]) null));
100
101 STYLES.put(STYLE_KEY_DEFAULT, DEFAULT_STYLES);
102 STYLES.put(STYLE_KEY_LOGBACK, LOGBACK_STYLES);
103 }
104
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
132
133 private static Map<Level, String> createLevelStyleMap(final String[] options) {
134 if (options.length < 2) {
135 return DEFAULT_STYLES;
136 }
137
138 final String string = options[1].replaceAll(PatternParser.NO_CONSOLE_NO_ANSI + "=(true|false)", Strings.EMPTY);
139
140 final Map<String, String> styles = AnsiEscape.createMap(string, new String[] {STYLE_KEY});
141 final Map<Level, String> levelStyles = new HashMap<Level, String>(DEFAULT_STYLES);
142 for (final Map.Entry<String, String> entry : styles.entrySet()) {
143 final String key = entry.getKey().toUpperCase(Locale.ENGLISH);
144 final String value = entry.getValue();
145 if (STYLE_KEY.equalsIgnoreCase(key)) {
146 final Map<Level, String> enumMap = STYLES.get(value.toUpperCase(Locale.ENGLISH));
147 if (enumMap == null) {
148 LOGGER.error("Unknown level style: " + value + ". Use one of " +
149 Arrays.toString(STYLES.keySet().toArray()));
150 } else {
151 levelStyles.putAll(enumMap);
152 }
153 } else {
154 final Level level = Level.toLevel(key);
155 if (level == null) {
156 LOGGER.error("Unknown level name: " + key + ". Use one of " +
157 Arrays.toString(DEFAULT_STYLES.keySet().toArray()));
158 } else {
159 levelStyles.put(level, value);
160 }
161 }
162 }
163 return levelStyles;
164 }
165
166
167
168
169
170
171
172
173
174 public static HighlightConverter newInstance(final Configuration config, final String[] options) {
175 if (options.length < 1) {
176 LOGGER.error("Incorrect number of options on style. Expected at least 1, received " + options.length);
177 return null;
178 }
179 if (options[0] == null) {
180 LOGGER.error("No pattern supplied on style");
181 return null;
182 }
183 final PatternParser parser = PatternLayout.createPatternParser(config);
184 final List<PatternFormatter> formatters = parser.parse(options[0]);
185 return new HighlightConverter(formatters, createLevelStyleMap(options));
186 }
187
188 private final Map<Level, String> levelStyles;
189
190 private final List<PatternFormatter> patternFormatters;
191
192
193
194
195
196
197
198 private HighlightConverter(final List<PatternFormatter> patternFormatters, final Map<Level, String> levelStyles) {
199 super("style", "style");
200 this.patternFormatters = patternFormatters;
201 this.levelStyles = levelStyles;
202 }
203
204
205
206
207 @Override
208 public void format(final LogEvent event, final StringBuilder toAppendTo) {
209 final StringBuilder buf = new StringBuilder();
210 for (final PatternFormatter formatter : patternFormatters) {
211 formatter.format(event, buf);
212 }
213
214 if (buf.length() > 0) {
215 toAppendTo.append(levelStyles.get(event.getLevel())).append(buf.toString()).
216 append(AnsiEscape.getDefaultStyle());
217 }
218 }
219
220 @Override
221 public boolean handlesThrowable() {
222 for (final PatternFormatter formatter : patternFormatters) {
223 if (formatter .handlesThrowable()) {
224 return true;
225 }
226 }
227 return false;
228 }
229 }