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.PlainTextRenderer;
25 import org.apache.logging.log4j.core.pattern.TextRenderer;
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 private final String suffix;
74
75
76
77
78 private final List<String> ignorePackages;
79
80 public static final String CLASS_NAME = "short.className";
81 public static final String METHOD_NAME = "short.methodName";
82 public static final String LINE_NUMBER = "short.lineNumber";
83 public static final String FILE_NAME = "short.fileName";
84 public static final String MESSAGE = "short.message";
85 public static final String LOCALIZED_MESSAGE = "short.localizedMessage";
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100 protected ThrowableFormatOptions(final int lines, final String separator, final List<String> ignorePackages,
101 final TextRenderer textRenderer, final String suffix) {
102 this.lines = lines;
103 this.separator = separator == null ? Strings.LINE_SEPARATOR : separator;
104 this.ignorePackages = ignorePackages;
105 this.textRenderer = textRenderer == null ? PlainTextRenderer.getInstance() : textRenderer;
106 this.suffix = suffix;
107 }
108
109
110
111
112
113
114
115 protected ThrowableFormatOptions(final List<String> packages) {
116 this(DEFAULT_LINES, null, packages, null, null);
117 }
118
119
120
121
122 protected ThrowableFormatOptions() {
123 this(DEFAULT_LINES, null, null, null, null);
124 }
125
126
127
128
129
130
131 public int getLines() {
132 return this.lines;
133 }
134
135
136
137
138
139
140 public String getSeparator() {
141 return this.separator;
142 }
143
144
145
146
147
148
149 public TextRenderer getTextRenderer() {
150 return textRenderer;
151 }
152
153
154
155
156
157
158 public List<String> getIgnorePackages() {
159 return this.ignorePackages;
160 }
161
162
163
164
165
166
167 public boolean allLines() {
168 return this.lines == DEFAULT_LINES;
169 }
170
171
172
173
174
175
176 public boolean anyLines() {
177 return this.lines > 0;
178 }
179
180
181
182
183
184
185
186
187 public int minLines(final int maxLines) {
188 return this.lines > maxLines ? maxLines : this.lines;
189 }
190
191
192
193
194
195
196 public boolean hasPackages() {
197 return this.ignorePackages != null && !this.ignorePackages.isEmpty();
198 }
199
200
201
202
203 @Override
204 public String toString() {
205 final StringBuilder s = new StringBuilder();
206 s.append('{')
207 .append(allLines() ? FULL : this.lines == 2 ? SHORT : anyLines() ? String.valueOf(this.lines) : NONE)
208 .append('}');
209 s.append("{separator(").append(this.separator).append(")}");
210 if (hasPackages()) {
211 s.append("{filters(");
212 for (final String p : this.ignorePackages) {
213 s.append(p).append(',');
214 }
215 s.deleteCharAt(s.length() - 1);
216 s.append(")}");
217 }
218 return s.toString();
219 }
220
221
222
223
224
225
226
227
228 public static ThrowableFormatOptions newInstance(String[] options) {
229 if (options == null || options.length == 0) {
230 return DEFAULT;
231 }
232
233
234
235
236
237
238 if (options.length == 1 && Strings.isNotEmpty(options[0])) {
239 final String[] opts = options[0].split(Patterns.COMMA_SEPARATOR, 2);
240 final String first = opts[0].trim();
241 try (final Scanner scanner = new Scanner(first)) {
242 if (opts.length > 1 && (first.equalsIgnoreCase(FULL) || first.equalsIgnoreCase(SHORT)
243 || first.equalsIgnoreCase(NONE) || scanner.hasNextInt())) {
244 options = new String[] { first, opts[1].trim() };
245 }
246 }
247 }
248
249 int lines = DEFAULT.lines;
250 String separator = DEFAULT.separator;
251 List<String> packages = DEFAULT.ignorePackages;
252 TextRenderer ansiRenderer = DEFAULT.textRenderer;
253 String suffix = DEFAULT.getSuffix();
254 for (final String rawOption : options) {
255 if (rawOption != null) {
256 final String option = rawOption.trim();
257 if (option.isEmpty()) {
258
259 } else if (option.startsWith("separator(") && option.endsWith(")")) {
260 separator = option.substring("separator(".length(), option.length() - 1);
261 } else if (option.startsWith("filters(") && option.endsWith(")")) {
262 final String filterStr = option.substring("filters(".length(), option.length() - 1);
263 if (filterStr.length() > 0) {
264 final String[] array = filterStr.split(Patterns.COMMA_SEPARATOR);
265 if (array.length > 0) {
266 packages = new ArrayList<>(array.length);
267 for (String token : array) {
268 token = token.trim();
269 if (token.length() > 0) {
270 packages.add(token);
271 }
272 }
273 }
274 }
275 } else if (option.equalsIgnoreCase(NONE)) {
276 lines = 0;
277 } else if (option.equalsIgnoreCase(SHORT) || option.equalsIgnoreCase(CLASS_NAME)
278 || option.equalsIgnoreCase(METHOD_NAME) || option.equalsIgnoreCase(LINE_NUMBER)
279 || option.equalsIgnoreCase(FILE_NAME) || option.equalsIgnoreCase(MESSAGE)
280 || option.equalsIgnoreCase(LOCALIZED_MESSAGE)) {
281 lines = 2;
282 } else if (option.startsWith("ansi(") && option.endsWith(")") || option.equals("ansi")) {
283 if (Loader.isJansiAvailable()) {
284 final String styleMapStr = option.equals("ansi") ? Strings.EMPTY
285 : option.substring("ansi(".length(), option.length() - 1);
286 ansiRenderer = new JAnsiTextRenderer(new String[] { null, styleMapStr },
287 JAnsiTextRenderer.DefaultExceptionStyleMap);
288 } else {
289 StatusLogger.getLogger().warn(
290 "You requested ANSI exception rendering but JANSI is not on the classpath. Please see https://logging.apache.org/log4j/2.x/runtime-dependencies.html");
291 }
292 } else if (option.startsWith("S(") && option.endsWith(")")){
293 suffix = option.substring("S(".length(), option.length() - 1);
294 } else if (option.startsWith("suffix(") && option.endsWith(")")){
295 suffix = option.substring("suffix(".length(), option.length() - 1);
296 } else if (!option.equalsIgnoreCase(FULL)) {
297 lines = Integer.parseInt(option);
298 }
299 }
300 }
301 return new ThrowableFormatOptions(lines, separator, packages, ansiRenderer, suffix);
302 }
303
304 public String getSuffix() {
305 return suffix;
306 }
307
308 }