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