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.io.Serializable;
20 import java.util.Arrays;
21 import java.util.HashMap;
22 import java.util.HashSet;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.Set;
26 import java.util.Stack;
27
28 import org.apache.logging.log4j.core.pattern.PlainTextRenderer;
29 import org.apache.logging.log4j.core.pattern.TextRenderer;
30 import org.apache.logging.log4j.util.StackLocatorUtil;
31 import org.apache.logging.log4j.util.Strings;
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49 public class ThrowableProxy implements Serializable {
50
51 private static final char EOL = '\n';
52
53 private static final String EOL_STR = String.valueOf(EOL);
54
55 private static final long serialVersionUID = -2752771578252251910L;
56
57 private final ThrowableProxy causeProxy;
58
59 private int commonElementCount;
60
61 private final ExtendedStackTraceElement[] extendedStackTrace;
62
63 private final String localizedMessage;
64
65 private final String message;
66
67 private final String name;
68
69 private final ThrowableProxy[] suppressedProxies;
70
71 private final transient Throwable throwable;
72
73
74
75
76 @SuppressWarnings("unused")
77 private ThrowableProxy() {
78 this.throwable = null;
79 this.name = null;
80 this.extendedStackTrace = null;
81 this.causeProxy = null;
82 this.message = null;
83 this.localizedMessage = null;
84 this.suppressedProxies = ThrowableProxyHelper.EMPTY_THROWABLE_PROXY_ARRAY;
85 }
86
87
88
89
90
91
92 public ThrowableProxy(final Throwable throwable) {
93 this(throwable, null);
94 }
95
96
97
98
99
100
101
102 ThrowableProxy(final Throwable throwable, final Set<Throwable> visited) {
103 this.throwable = throwable;
104 this.name = throwable.getClass().getName();
105 this.message = throwable.getMessage();
106 this.localizedMessage = throwable.getLocalizedMessage();
107 final Map<String, ThrowableProxyHelper.CacheEntry> map = new HashMap<>();
108 final Stack<Class<?>> stack = StackLocatorUtil.getCurrentStackTrace();
109 this.extendedStackTrace = ThrowableProxyHelper.toExtendedStackTrace(this, stack, map, null, throwable.getStackTrace());
110 final Throwable throwableCause = throwable.getCause();
111 final Set<Throwable> causeVisited = new HashSet<>(1);
112 this.causeProxy = throwableCause == null ? null : new ThrowableProxy(throwable, stack, map, throwableCause,
113 visited, causeVisited);
114 this.suppressedProxies = ThrowableProxyHelper.toSuppressedProxies(throwable, visited);
115 }
116
117
118
119
120
121
122
123
124
125
126
127 private ThrowableProxy(final Throwable parent, final Stack<Class<?>> stack,
128 final Map<String, ThrowableProxyHelper.CacheEntry> map,
129 final Throwable cause, final Set<Throwable> suppressedVisited,
130 final Set<Throwable> causeVisited) {
131 causeVisited.add(cause);
132 this.throwable = cause;
133 this.name = cause.getClass().getName();
134 this.message = this.throwable.getMessage();
135 this.localizedMessage = this.throwable.getLocalizedMessage();
136 this.extendedStackTrace = ThrowableProxyHelper.toExtendedStackTrace(this, stack, map, parent.getStackTrace(), cause.getStackTrace());
137 final Throwable causeCause = cause.getCause();
138 this.causeProxy = causeCause == null || causeVisited.contains(causeCause) ? null : new ThrowableProxy(parent,
139 stack, map, causeCause, suppressedVisited, causeVisited);
140 this.suppressedProxies = ThrowableProxyHelper.toSuppressedProxies(cause, suppressedVisited);
141 }
142
143 @Override
144 public boolean equals(final Object obj) {
145 if (this == obj) {
146 return true;
147 }
148 if (obj == null) {
149 return false;
150 }
151 if (this.getClass() != obj.getClass()) {
152 return false;
153 }
154 final ThrowableProxy other = (ThrowableProxy) obj;
155 if (this.causeProxy == null) {
156 if (other.causeProxy != null) {
157 return false;
158 }
159 } else if (!this.causeProxy.equals(other.causeProxy)) {
160 return false;
161 }
162 if (this.commonElementCount != other.commonElementCount) {
163 return false;
164 }
165 if (this.name == null) {
166 if (other.name != null) {
167 return false;
168 }
169 } else if (!this.name.equals(other.name)) {
170 return false;
171 }
172 if (!Arrays.equals(this.extendedStackTrace, other.extendedStackTrace)) {
173 return false;
174 }
175 if (!Arrays.equals(this.suppressedProxies, other.suppressedProxies)) {
176 return false;
177 }
178 return true;
179 }
180
181
182
183
184
185
186
187 public void formatWrapper(final StringBuilder sb, final ThrowableProxy cause, final String suffix) {
188 this.formatWrapper(sb, cause, null, PlainTextRenderer.getInstance(), suffix);
189 }
190
191
192
193
194
195
196
197
198 @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
199 public void formatWrapper(final StringBuilder sb, final ThrowableProxy cause, final List<String> ignorePackages, final String suffix) {
200 this.formatWrapper(sb, cause, ignorePackages, PlainTextRenderer.getInstance(), suffix);
201 }
202
203
204
205
206
207
208
209
210
211 @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
212 public void formatWrapper(final StringBuilder sb, final ThrowableProxy cause, final List<String> ignorePackages,
213 final TextRenderer textRenderer, final String suffix) {
214 formatWrapper(sb, cause, ignorePackages, textRenderer, suffix, EOL_STR);
215 }
216
217
218
219
220
221
222
223
224
225
226 @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
227 public void formatWrapper(final StringBuilder sb, final ThrowableProxy cause, final List<String> ignorePackages,
228 final TextRenderer textRenderer, final String suffix, final String lineSeparator) {
229 ThrowableProxyRenderer.formatWrapper(sb, cause, ignorePackages, textRenderer, suffix, lineSeparator);
230 }
231
232 public ThrowableProxy getCauseProxy() {
233 return this.causeProxy;
234 }
235
236
237
238
239
240
241
242 public String getCauseStackTraceAsString(final String suffix) {
243 return this.getCauseStackTraceAsString(null, PlainTextRenderer.getInstance(), suffix, EOL_STR);
244 }
245
246
247
248
249
250
251
252
253 public String getCauseStackTraceAsString(final List<String> packages, final String suffix) {
254 return getCauseStackTraceAsString(packages, PlainTextRenderer.getInstance(), suffix, EOL_STR);
255 }
256
257
258
259
260
261
262
263
264
265 public String getCauseStackTraceAsString(final List<String> ignorePackages, final TextRenderer textRenderer, final String suffix) {
266 return getCauseStackTraceAsString(ignorePackages, textRenderer, suffix, EOL_STR);
267 }
268
269
270
271
272
273
274
275
276
277
278 public String getCauseStackTraceAsString(final List<String> ignorePackages, final TextRenderer textRenderer, final String suffix, final String lineSeparator) {
279 final StringBuilder sb = new StringBuilder();
280 ThrowableProxyRenderer.formatCauseStackTrace(this, sb, ignorePackages, textRenderer, suffix, lineSeparator);
281 return sb.toString();
282 }
283
284
285
286
287
288
289
290 public int getCommonElementCount() {
291 return this.commonElementCount;
292 }
293
294
295
296
297
298
299
300
301 void setCommonElementCount(final int value) {
302 this.commonElementCount = value;
303 }
304
305
306
307
308
309
310 public ExtendedStackTraceElement[] getExtendedStackTrace() {
311 return this.extendedStackTrace;
312 }
313
314
315
316
317
318
319 public String getExtendedStackTraceAsString() {
320 return this.getExtendedStackTraceAsString(null, PlainTextRenderer.getInstance(), Strings.EMPTY, EOL_STR);
321 }
322
323
324
325
326
327
328
329 public String getExtendedStackTraceAsString(final String suffix) {
330 return this.getExtendedStackTraceAsString(null, PlainTextRenderer.getInstance(), suffix, EOL_STR);
331 }
332
333
334
335
336
337
338
339
340 public String getExtendedStackTraceAsString(final List<String> ignorePackages, final String suffix) {
341 return getExtendedStackTraceAsString(ignorePackages, PlainTextRenderer.getInstance(), suffix, EOL_STR);
342 }
343
344
345
346
347
348
349
350
351
352 public String getExtendedStackTraceAsString(final List<String> ignorePackages, final TextRenderer textRenderer, final String suffix) {
353 return getExtendedStackTraceAsString(ignorePackages, textRenderer, suffix, EOL_STR);
354 }
355
356
357
358
359
360
361
362
363
364
365 public String getExtendedStackTraceAsString(final List<String> ignorePackages, final TextRenderer textRenderer, final String suffix, final String lineSeparator) {
366 final StringBuilder sb = new StringBuilder(1024);
367 formatExtendedStackTraceTo(sb, ignorePackages, textRenderer, suffix, lineSeparator);
368 return sb.toString();
369 }
370
371
372
373
374
375
376
377
378
379
380 public void formatExtendedStackTraceTo(final StringBuilder sb, final List<String> ignorePackages, final TextRenderer textRenderer, final String suffix, final String lineSeparator) {
381 ThrowableProxyRenderer.formatExtendedStackTraceTo(this, sb, ignorePackages, textRenderer, suffix, lineSeparator);
382 }
383
384 public String getLocalizedMessage() {
385 return this.localizedMessage;
386 }
387
388 public String getMessage() {
389 return this.message;
390 }
391
392
393
394
395
396
397 public String getName() {
398 return this.name;
399 }
400
401 public StackTraceElement[] getStackTrace() {
402 return this.throwable == null ? null : this.throwable.getStackTrace();
403 }
404
405
406
407
408
409
410 public ThrowableProxy[] getSuppressedProxies() {
411 return this.suppressedProxies;
412 }
413
414
415
416
417
418
419
420 public String getSuppressedStackTrace(final String suffix) {
421 final ThrowableProxy[] suppressed = this.getSuppressedProxies();
422 if (suppressed == null || suppressed.length == 0) {
423 return Strings.EMPTY;
424 }
425 final StringBuilder sb = new StringBuilder("Suppressed Stack Trace Elements:").append(EOL);
426 for (final ThrowableProxy proxy : suppressed) {
427 sb.append(proxy.getExtendedStackTraceAsString(suffix));
428 }
429 return sb.toString();
430 }
431
432
433
434
435
436
437 public Throwable getThrowable() {
438 return this.throwable;
439 }
440
441 @Override
442 public int hashCode() {
443 final int prime = 31;
444 int result = 1;
445 result = prime * result + (this.causeProxy == null ? 0 : this.causeProxy.hashCode());
446 result = prime * result + this.commonElementCount;
447 result = prime * result + (this.extendedStackTrace == null ? 0 : Arrays.hashCode(this.extendedStackTrace));
448 result = prime * result + (this.suppressedProxies == null ? 0 : Arrays.hashCode(this.suppressedProxies));
449 result = prime * result + (this.name == null ? 0 : this.name.hashCode());
450 return result;
451 }
452
453 @Override
454 public String toString() {
455 final String msg = this.message;
456 return msg != null ? this.name + ": " + msg : this.name;
457 }
458 }