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 String STYLE_KEY_DEFAULT = "DEFAULT";
76
77 private static final String STYLE_KEY_LOGBACK = "LOGBACK";
78
79 private static final String STYLE_KEY = "STYLE";
80
81 private static final EnumMap<Level, String> DEFAULT_STYLES = new EnumMap<Level, String>(Level.class);
82
83 private static final EnumMap<Level, String> LOGBACK_STYLES = new EnumMap<Level, String>(Level.class);
84
85 private static final Map<String, EnumMap<Level, String>> STYLES = new HashMap<String, EnumMap<Level, String>>();
86
87 private final List<PatternFormatter> formatters;
88
89 private final EnumMap<Level, String> levelStyles;
90
91 static {
92
93 DEFAULT_STYLES.put(Level.FATAL, AnsiEscape.createSequence("BRIGHT", "RED"));
94 DEFAULT_STYLES.put(Level.ERROR, AnsiEscape.createSequence("BRIGHT", "RED"));
95 DEFAULT_STYLES.put(Level.WARN, AnsiEscape.createSequence("YELLOW"));
96 DEFAULT_STYLES.put(Level.INFO, AnsiEscape.createSequence("GREEN"));
97 DEFAULT_STYLES.put(Level.DEBUG, AnsiEscape.createSequence("CYAN"));
98 DEFAULT_STYLES.put(Level.TRACE, AnsiEscape.createSequence("BLACK"));
99
100 LOGBACK_STYLES.put(Level.FATAL, AnsiEscape.createSequence("BLINK", "BRIGHT", "RED"));
101 LOGBACK_STYLES.put(Level.ERROR, AnsiEscape.createSequence("BRIGHT", "RED"));
102 LOGBACK_STYLES.put(Level.WARN, AnsiEscape.createSequence("RED"));
103 LOGBACK_STYLES.put(Level.INFO, AnsiEscape.createSequence("BLUE"));
104 LOGBACK_STYLES.put(Level.DEBUG, AnsiEscape.createSequence((String[]) null));
105 LOGBACK_STYLES.put(Level.TRACE, AnsiEscape.createSequence((String[]) null));
106
107 STYLES.put(STYLE_KEY_DEFAULT, DEFAULT_STYLES);
108 STYLES.put(STYLE_KEY_LOGBACK, LOGBACK_STYLES);
109 }
110
111
112
113
114
115
116
117 private HighlightConverter(final List<PatternFormatter> formatters, final EnumMap<Level, String> levelStyles) {
118 super("style", "style");
119 this.formatters = formatters;
120 this.levelStyles = levelStyles;
121 }
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147 private static EnumMap<Level, String> createLevelStyleMap(final String[] options) {
148 if (options.length < 2) {
149 return DEFAULT_STYLES;
150 }
151 final Map<String, String> styles = AnsiEscape.createMap(options[1], new String[] {STYLE_KEY});
152 final EnumMap<Level, String> levelStyles = new EnumMap<Level, String>(DEFAULT_STYLES);
153 for (final Map.Entry<String, String> entry : styles.entrySet()) {
154 final String key = entry.getKey().toUpperCase(Locale.ENGLISH);
155 final String value = entry.getValue();
156 if (STYLE_KEY.equalsIgnoreCase(key)) {
157 final EnumMap<Level, String> enumMap = STYLES.get(value.toUpperCase(Locale.ENGLISH));
158 if (enumMap == null) {
159 LOGGER.error("Unknown level style: " + value + ". Use one of " +
160 Arrays.toString(STYLES.keySet().toArray()));
161 } else {
162 levelStyles.putAll(enumMap);
163 }
164 } else {
165 final Level level = Level.valueOf(key);
166 if (level == null) {
167 LOGGER.error("Unknown level name: " + key + ". Use one of " +
168 Arrays.toString(DEFAULT_STYLES.keySet().toArray()));
169 } else {
170 levelStyles.put(level, value);
171 }
172 }
173 }
174 return levelStyles;
175 }
176
177
178
179
180
181
182
183
184
185 public static HighlightConverter newInstance(final Configuration config, final String[] options) {
186 if (options.length < 1) {
187 LOGGER.error("Incorrect number of options on style. Expected at least 1, received " + options.length);
188 return null;
189 }
190 if (options[0] == null) {
191 LOGGER.error("No pattern supplied on style");
192 return null;
193 }
194 final PatternParser parser = PatternLayout.createPatternParser(config);
195 final List<PatternFormatter> formatters = parser.parse(options[0]);
196 return new HighlightConverter(formatters, createLevelStyleMap(options));
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 : formatters) {
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 }