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.EnumMap;
21 import java.util.HashMap;
22 import java.util.List;
23 import java.util.Locale;
24 import java.util.Map;
25
26 import org.apache.logging.log4j.Level;
27 import org.apache.logging.log4j.core.LogEvent;
28 import org.apache.logging.log4j.core.config.Configuration;
29 import org.apache.logging.log4j.core.config.plugins.Plugin;
30 import org.apache.logging.log4j.core.layout.PatternLayout;
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 {
74
75 private static final EnumMap<Level, String> DEFAULT_STYLES = new EnumMap<Level, String>(Level.class);
76
77 private static final EnumMap<Level, String> LOGBACK_STYLES = new EnumMap<Level, String>(Level.class);
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, EnumMap<Level, String>> STYLES = new HashMap<String, EnumMap<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 EnumMap<Level, String> createLevelStyleMap(final String[] options) {
132 if (options.length < 2) {
133 return DEFAULT_STYLES;
134 }
135 final Map<String, String> styles = AnsiEscape.createMap(options[1], new String[] {STYLE_KEY});
136 final EnumMap<Level, String> levelStyles = new EnumMap<Level, String>(DEFAULT_STYLES);
137 for (final Map.Entry<String, String> entry : styles.entrySet()) {
138 final String key = entry.getKey().toUpperCase(Locale.ENGLISH);
139 final String value = entry.getValue();
140 if (STYLE_KEY.equalsIgnoreCase(key)) {
141 final EnumMap<Level, String> enumMap = STYLES.get(value.toUpperCase(Locale.ENGLISH));
142 if (enumMap == null) {
143 LOGGER.error("Unknown level style: " + value + ". Use one of " +
144 Arrays.toString(STYLES.keySet().toArray()));
145 } else {
146 levelStyles.putAll(enumMap);
147 }
148 } else {
149 final Level level = Level.valueOf(key);
150 if (level == null) {
151 LOGGER.error("Unknown level name: " + key + ". Use one of " +
152 Arrays.toString(DEFAULT_STYLES.keySet().toArray()));
153 } else {
154 levelStyles.put(level, value);
155 }
156 }
157 }
158 return levelStyles;
159 }
160
161
162
163
164
165
166
167
168
169 public static HighlightConverter newInstance(final Configuration config, final String[] options) {
170 if (options.length < 1) {
171 LOGGER.error("Incorrect number of options on style. Expected at least 1, received " + options.length);
172 return null;
173 }
174 if (options[0] == null) {
175 LOGGER.error("No pattern supplied on style");
176 return null;
177 }
178 final PatternParser parser = PatternLayout.createPatternParser(config);
179 final List<PatternFormatter> formatters = parser.parse(options[0]);
180 return new HighlightConverter(formatters, createLevelStyleMap(options));
181 }
182
183 private final EnumMap<Level, String> levelStyles;
184
185 private final List<PatternFormatter> patternFormatters;
186
187
188
189
190
191
192
193 private HighlightConverter(final List<PatternFormatter> patternFormatters, final EnumMap<Level, String> levelStyles) {
194 super("style", "style");
195 this.patternFormatters = patternFormatters;
196 this.levelStyles = levelStyles;
197 }
198
199
200
201
202 @Override
203 public void format(final LogEvent event, final StringBuilder toAppendTo) {
204 final StringBuilder buf = new StringBuilder();
205 for (final PatternFormatter formatter : patternFormatters) {
206 formatter.format(event, buf);
207 }
208
209 if (buf.length() > 0) {
210 toAppendTo.append(levelStyles.get(event.getLevel())).append(buf.toString()).
211 append(AnsiEscape.getDefaultStyle());
212 }
213 }
214
215 @Override
216 public boolean handlesThrowable() {
217 for (final PatternFormatter formatter : patternFormatters) {
218 if (formatter .handlesThrowable()) {
219 return true;
220 }
221 }
222 return false;
223 }
224 }