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