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 org.apache.logging.log4j.core.pattern.TextRenderer;
20 import org.apache.logging.log4j.util.Strings;
21
22 import java.util.List;
23
24
25
26
27
28 class ThrowableProxyRenderer {
29
30 private static final String TAB = "\t";
31 private static final String CAUSED_BY_LABEL = "Caused by: ";
32 private static final String SUPPRESSED_LABEL = "Suppressed: ";
33 private static final String WRAPPED_BY_LABEL = "Wrapped by: ";
34
35 private ThrowableProxyRenderer() {
36
37 }
38
39 @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
40 static void formatWrapper(final StringBuilder sb, final ThrowableProxy cause, final List<String> ignorePackages,
41 final TextRenderer textRenderer, final String suffix, final String lineSeparator) {
42 final Throwable caused = cause.getCauseProxy() != null ? cause.getCauseProxy().getThrowable() : null;
43 if (caused != null) {
44 formatWrapper(sb, cause.getCauseProxy(), ignorePackages, textRenderer, suffix, lineSeparator);
45 sb.append(WRAPPED_BY_LABEL);
46 renderSuffix(suffix, sb, textRenderer);
47 }
48 renderOn(cause, sb, textRenderer);
49 renderSuffix(suffix, sb, textRenderer);
50 textRenderer.render(lineSeparator, sb, "Text");
51 formatElements(sb, Strings.EMPTY, cause.getCommonElementCount(),
52 cause.getThrowable().getStackTrace(), cause.getExtendedStackTrace(), ignorePackages, textRenderer, suffix, lineSeparator);
53 }
54
55 private static void formatCause(final StringBuilder sb, final String prefix, final ThrowableProxy cause,
56 final List<String> ignorePackages, final TextRenderer textRenderer, final String suffix, final String lineSeparator) {
57 formatThrowableProxy(sb, prefix, CAUSED_BY_LABEL, cause, ignorePackages, textRenderer, suffix, lineSeparator);
58 }
59
60 private static void formatThrowableProxy(final StringBuilder sb, final String prefix, final String causeLabel,
61 final ThrowableProxy throwableProxy, final List<String> ignorePackages,
62 final TextRenderer textRenderer, final String suffix, final String lineSeparator) {
63 if (throwableProxy == null) {
64 return;
65 }
66 textRenderer.render(prefix, sb, "Prefix");
67 textRenderer.render(causeLabel, sb, "CauseLabel");
68 renderOn(throwableProxy, sb, textRenderer);
69 renderSuffix(suffix, sb, textRenderer);
70 textRenderer.render(lineSeparator, sb, "Text");
71 formatElements(sb, prefix, throwableProxy.getCommonElementCount(),
72 throwableProxy.getStackTrace(), throwableProxy.getExtendedStackTrace(), ignorePackages, textRenderer, suffix, lineSeparator);
73 formatSuppressed(sb, prefix + TAB, throwableProxy.getSuppressedProxies(), ignorePackages, textRenderer, suffix, lineSeparator);
74 formatCause(sb, prefix, throwableProxy.getCauseProxy(), ignorePackages, textRenderer, suffix, lineSeparator);
75 }
76
77 private static void formatSuppressed(final StringBuilder sb, final String prefix, final ThrowableProxy[] suppressedProxies,
78 final List<String> ignorePackages, final TextRenderer textRenderer, final String suffix, final String lineSeparator) {
79 if (suppressedProxies == null) {
80 return;
81 }
82 for (final ThrowableProxy suppressedProxy : suppressedProxies) {
83 formatThrowableProxy(sb, prefix, SUPPRESSED_LABEL, suppressedProxy, ignorePackages, textRenderer, suffix, lineSeparator);
84 }
85 }
86
87 private static void formatElements(final StringBuilder sb, final String prefix, final int commonCount,
88 final StackTraceElement[] causedTrace, final ExtendedStackTraceElement[] extStackTrace,
89 final List<String> ignorePackages, final TextRenderer textRenderer, final String suffix, final String lineSeparator) {
90 if (ignorePackages == null || ignorePackages.isEmpty()) {
91 for (final ExtendedStackTraceElement element : extStackTrace) {
92 formatEntry(element, sb, prefix, textRenderer, suffix, lineSeparator);
93 }
94 } else {
95 int count = 0;
96 for (int i = 0; i < extStackTrace.length; ++i) {
97 if (!ignoreElement(causedTrace[i], ignorePackages)) {
98 if (count > 0) {
99 appendSuppressedCount(sb, prefix, count, textRenderer, suffix, lineSeparator);
100 count = 0;
101 }
102 formatEntry(extStackTrace[i], sb, prefix, textRenderer, suffix, lineSeparator);
103 } else {
104 ++count;
105 }
106 }
107 if (count > 0) {
108 appendSuppressedCount(sb, prefix, count, textRenderer, suffix, lineSeparator);
109 }
110 }
111 if (commonCount != 0) {
112 textRenderer.render(prefix, sb, "Prefix");
113 textRenderer.render("\t... ", sb, "More");
114 textRenderer.render(Integer.toString(commonCount), sb, "More");
115 textRenderer.render(" more", sb, "More");
116 renderSuffix(suffix, sb, textRenderer);
117 textRenderer.render(lineSeparator, sb, "Text");
118 }
119 }
120
121 private static void renderSuffix(final String suffix, final StringBuilder sb, final TextRenderer textRenderer) {
122 if (!suffix.isEmpty()) {
123 textRenderer.render(" ", sb, "Suffix");
124 textRenderer.render(suffix, sb, "Suffix");
125 }
126 }
127
128 private static void appendSuppressedCount(final StringBuilder sb, final String prefix, final int count,
129 final TextRenderer textRenderer, final String suffix, final String lineSeparator) {
130 textRenderer.render(prefix, sb, "Prefix");
131 if (count == 1) {
132 textRenderer.render("\t... ", sb, "Suppressed");
133 } else {
134 textRenderer.render("\t... suppressed ", sb, "Suppressed");
135 textRenderer.render(Integer.toString(count), sb, "Suppressed");
136 textRenderer.render(" lines", sb, "Suppressed");
137 }
138 renderSuffix(suffix, sb, textRenderer);
139 textRenderer.render(lineSeparator, sb, "Text");
140 }
141
142 private static void formatEntry(final ExtendedStackTraceElement extStackTraceElement, final StringBuilder sb,
143 final String prefix, final TextRenderer textRenderer, final String suffix, final String lineSeparator) {
144 textRenderer.render(prefix, sb, "Prefix");
145 textRenderer.render("\tat ", sb, "At");
146 extStackTraceElement.renderOn(sb, textRenderer);
147 renderSuffix(suffix, sb, textRenderer);
148 textRenderer.render(lineSeparator, sb, "Text");
149 }
150
151 private static boolean ignoreElement(final StackTraceElement element, final List<String> ignorePackages) {
152 if (ignorePackages != null) {
153 final String className = element.getClassName();
154 for (final String pkg : ignorePackages) {
155 if (className.startsWith(pkg)) {
156 return true;
157 }
158 }
159 }
160 return false;
161 }
162
163
164
165
166
167
168
169
170
171
172
173 static void formatExtendedStackTraceTo(final ThrowableProxy src, final StringBuilder sb, final List<String> ignorePackages, final TextRenderer textRenderer, final String suffix, final String lineSeparator) {
174 textRenderer.render(src.getName(), sb, "Name");
175 textRenderer.render(": ", sb, "NameMessageSeparator");
176 textRenderer.render(src.getMessage(), sb, "Message");
177 renderSuffix(suffix, sb, textRenderer);
178 textRenderer.render(lineSeparator, sb, "Text");
179 final StackTraceElement[] causedTrace = src.getThrowable() != null ? src.getThrowable().getStackTrace() : null;
180 formatElements(sb, Strings.EMPTY, 0, causedTrace, src.getExtendedStackTrace(), ignorePackages, textRenderer, suffix, lineSeparator);
181 formatSuppressed(sb, TAB, src.getSuppressedProxies(), ignorePackages, textRenderer, suffix, lineSeparator);
182 formatCause(sb, Strings.EMPTY, src.getCauseProxy(), ignorePackages, textRenderer, suffix, lineSeparator);
183 }
184
185
186
187
188
189
190
191
192
193
194
195 static void formatCauseStackTrace(final ThrowableProxy src, final StringBuilder sb, final List<String> ignorePackages, final TextRenderer textRenderer, final String suffix, final String lineSeparator) {
196 final ThrowableProxy causeProxy = src.getCauseProxy();
197 if (causeProxy != null) {
198 formatWrapper(sb, causeProxy, ignorePackages, textRenderer, suffix, lineSeparator);
199 sb.append(WRAPPED_BY_LABEL);
200 ThrowableProxyRenderer.renderSuffix(suffix, sb, textRenderer);
201 }
202 renderOn(src, sb, textRenderer);
203 ThrowableProxyRenderer.renderSuffix(suffix, sb, textRenderer);
204 textRenderer.render(lineSeparator, sb, "Text");
205 ThrowableProxyRenderer.formatElements(sb, Strings.EMPTY, 0, src.getStackTrace(), src.getExtendedStackTrace(),
206 ignorePackages, textRenderer, suffix, lineSeparator);
207 }
208
209 private static void renderOn(final ThrowableProxy src, final StringBuilder output, final TextRenderer textRenderer) {
210 final String msg = src.getMessage();
211 textRenderer.render(src.getName(), output, "Name");
212 if (msg != null) {
213 textRenderer.render(": ", output, "NameMessageSeparator");
214 textRenderer.render(msg, output, "Message");
215 }
216 }
217 }