1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core.impl;
18
19 import java.util.ArrayList;
20 import java.util.List;
21 import java.util.Scanner;
22
23 import org.apache.logging.log4j.core.pattern.JAnsiTextRenderer;
24 import org.apache.logging.log4j.core.pattern.TextRenderer;
25 import org.apache.logging.log4j.core.pattern.PlainTextRenderer;
26 import org.apache.logging.log4j.core.util.Loader;
27 import org.apache.logging.log4j.core.util.Patterns;
28 import org.apache.logging.log4j.status.StatusLogger;
29 import org.apache.logging.log4j.util.Strings;
30
31
32
33
34 public final class ThrowableFormatOptions {
35
36 private static final int DEFAULT_LINES = Integer.MAX_VALUE;
37
38
39
40
41 protected static final ThrowableFormatOptions DEFAULT = new ThrowableFormatOptions();
42
43
44
45
46 private static final String FULL = "full";
47
48
49
50
51 private static final String NONE = "none";
52
53
54
55
56 private static final String SHORT = "short";
57
58
59
60
61 private final TextRenderer textRenderer;
62
63
64
65
66 private final int lines;
67
68
69
70
71 private final String separator;
72
73
74
75
76 private final List<String> ignorePackages;
77
78 public static final String CLASS_NAME = "short.className";
79 public static final String METHOD_NAME = "short.methodName";
80 public static final String LINE_NUMBER = "short.lineNumber";
81 public static final String FILE_NAME = "short.fileName";
82 public static final String MESSAGE = "short.message";
83 public static final String LOCALIZED_MESSAGE = "short.localizedMessage";
84
85
86
87
88
89
90
91
92
93
94
95
96
97 protected ThrowableFormatOptions(final int lines, final String separator, final List<String> ignorePackages,
98 final TextRenderer textRenderer) {
99 this.lines = lines;
100 this.separator = separator == null ? Strings.LINE_SEPARATOR : separator;
101 this.ignorePackages = ignorePackages;
102 this.textRenderer = textRenderer == null ? PlainTextRenderer.getInstance() : textRenderer;
103 }
104
105
106
107
108
109
110
111 protected ThrowableFormatOptions(final List<String> packages) {
112 this(DEFAULT_LINES, null, packages, null);
113 }
114
115
116
117
118 protected ThrowableFormatOptions() {
119 this(DEFAULT_LINES, null, null, null);
120 }
121
122
123
124
125
126
127 public int getLines() {
128 return this.lines;
129 }
130
131
132
133
134
135
136 public String getSeparator() {
137 return this.separator;
138 }
139
140
141
142
143
144
145 public TextRenderer getTextRenderer() {
146 return textRenderer;
147 }
148
149
150
151
152
153
154 public List<String> getIgnorePackages() {
155 return this.ignorePackages;
156 }
157
158
159
160
161
162
163 public boolean allLines() {
164 return this.lines == DEFAULT_LINES;
165 }
166
167
168
169
170
171
172 public boolean anyLines() {
173 return this.lines > 0;
174 }
175
176
177
178
179
180
181
182
183 public int minLines(final int maxLines) {
184 return this.lines > maxLines ? maxLines : this.lines;
185 }
186
187
188
189
190
191
192 public boolean hasPackages() {
193 return this.ignorePackages != null && !this.ignorePackages.isEmpty();
194 }
195
196
197
198
199 @Override
200 public String toString() {
201 final StringBuilder s = new StringBuilder();
202 s.append('{')
203 .append(allLines() ? FULL : this.lines == 2 ? SHORT : anyLines() ? String.valueOf(this.lines) : NONE)
204 .append('}');
205 s.append("{separator(").append(this.separator).append(")}");
206 if (hasPackages()) {
207 s.append("{filters(");
208 for (final String p : this.ignorePackages) {
209 s.append(p).append(',');
210 }
211 s.deleteCharAt(s.length() - 1);
212 s.append(")}");
213 }
214 return s.toString();
215 }
216
217
218
219
220
221
222
223
224 public static ThrowableFormatOptions newInstance(String[] options) {
225 if (options == null || options.length == 0) {
226 return DEFAULT;
227 }
228
229
230
231
232
233
234 if (options.length == 1 && Strings.isNotEmpty(options[0])) {
235 final String[] opts = options[0].split(Patterns.COMMA_SEPARATOR, 2);
236 final String first = opts[0].trim();
237 try (final Scanner scanner = new Scanner(first)) {
238 if (opts.length > 1 && (first.equalsIgnoreCase(FULL) || first.equalsIgnoreCase(SHORT)
239 || first.equalsIgnoreCase(NONE) || scanner.hasNextInt())) {
240 options = new String[] { first, opts[1].trim() };
241 }
242 }
243 }
244
245 int lines = DEFAULT.lines;
246 String separator = DEFAULT.separator;
247 List<String> packages = DEFAULT.ignorePackages;
248 TextRenderer ansiRenderer = DEFAULT.textRenderer;
249 for (final String rawOption : options) {
250 if (rawOption != null) {
251 final String option = rawOption.trim();
252 if (option.isEmpty()) {
253
254 } else if (option.startsWith("separator(") && option.endsWith(")")) {
255 separator = option.substring("separator(".length(), option.length() - 1);
256 } else if (option.startsWith("filters(") && option.endsWith(")")) {
257 final String filterStr = option.substring("filters(".length(), option.length() - 1);
258 if (filterStr.length() > 0) {
259 final String[] array = filterStr.split(Patterns.COMMA_SEPARATOR);
260 if (array.length > 0) {
261 packages = new ArrayList<>(array.length);
262 for (String token : array) {
263 token = token.trim();
264 if (token.length() > 0) {
265 packages.add(token);
266 }
267 }
268 }
269 }
270 } else if (option.equalsIgnoreCase(NONE)) {
271 lines = 0;
272 } else if (option.equalsIgnoreCase(SHORT) || option.equalsIgnoreCase(CLASS_NAME)
273 || option.equalsIgnoreCase(METHOD_NAME) || option.equalsIgnoreCase(LINE_NUMBER)
274 || option.equalsIgnoreCase(FILE_NAME) || option.equalsIgnoreCase(MESSAGE)
275 || option.equalsIgnoreCase(LOCALIZED_MESSAGE)) {
276 lines = 2;
277 } else if (option.startsWith("ansi(") && option.endsWith(")") || option.equals("ansi")) {
278 if (Loader.isJansiAvailable()) {
279 final String styleMapStr = option.equals("ansi") ? Strings.EMPTY
280 : option.substring("ansi(".length(), option.length() - 1);
281 ansiRenderer = new JAnsiTextRenderer(new String[] { null, styleMapStr },
282 JAnsiTextRenderer.DefaultExceptionStyleMap);
283 } else {
284 StatusLogger.getLogger().warn(
285 "You requested ANSI exception rendering but JANSI is not on the classpath. Please see https://logging.apache.org/log4j/2.x/runtime-dependencies.html");
286 }
287 } else if (!option.equalsIgnoreCase(FULL)) {
288 lines = Integer.parseInt(option);
289 }
290 }
291 }
292 return new ThrowableFormatOptions(lines, separator, packages, ansiRenderer);
293 }
294
295 }