001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.camel.processor.interceptor;
018
019 import org.apache.camel.Exchange;
020 import org.apache.camel.Message;
021 import org.apache.camel.RouteNode;
022 import org.apache.camel.model.ProcessorDefinition;
023 import org.apache.camel.model.ProcessorDefinitionHelper;
024 import org.apache.camel.model.RouteDefinition;
025 import org.apache.camel.spi.TracedRouteNodes;
026 import org.apache.camel.util.MessageHelper;
027
028 /**
029 * @version $Revision: 885197 $
030 */
031 public class DefaultTraceFormatter implements TraceFormatter {
032 private int breadCrumbLength;
033 private int nodeLength;
034 private boolean showBreadCrumb = true;
035 private boolean showNode = true;
036 private boolean showExchangeId;
037 private boolean showShortExchangeId;
038 private boolean showExchangePattern = true;
039 private boolean showProperties;
040 private boolean showHeaders = true;
041 private boolean showBody = true;
042 private boolean showBodyType = true;
043 private boolean showOutHeaders;
044 private boolean showOutBody;
045 private boolean showOutBodyType;
046 private boolean showException = true;
047 private boolean showRouteId = true;
048 private int maxChars;
049
050 public Object format(final TraceInterceptor interceptor, final ProcessorDefinition<?> node, final Exchange exchange) {
051 Message in = exchange.getIn();
052 Message out = null;
053 if (exchange.hasOut()) {
054 out = exchange.getOut();
055 }
056
057 StringBuilder sb = new StringBuilder();
058 sb.append(extractBreadCrumb(interceptor, node, exchange));
059
060 if (showExchangePattern) {
061 sb.append(", Pattern:").append(exchange.getPattern());
062 }
063 // only show properties if we have any
064 if (showProperties && !exchange.getProperties().isEmpty()) {
065 sb.append(", Properties:").append(exchange.getProperties());
066 }
067 // only show headers if we have any
068 if (showHeaders && !in.getHeaders().isEmpty()) {
069 sb.append(", Headers:").append(in.getHeaders());
070 }
071 if (showBodyType) {
072 sb.append(", BodyType:").append(MessageHelper.getBodyTypeName(in));
073 }
074 if (showBody) {
075 sb.append(", Body:").append(MessageHelper.extractBodyAsString(in));
076 }
077 if (showOutHeaders && out != null) {
078 sb.append(", OutHeaders:").append(out.getHeaders());
079 }
080 if (showOutBodyType && out != null) {
081 sb.append(", OutBodyType:").append(MessageHelper.getBodyTypeName(out));
082 }
083 if (showOutBody && out != null) {
084 sb.append(", OutBody:").append(MessageHelper.extractBodyAsString(out));
085 }
086 if (showException && exchange.getException() != null) {
087 sb.append(", Exception:").append(exchange.getException());
088 }
089
090 // replace ugly <<<, with <<<
091 String s = sb.toString();
092 s = s.replaceFirst("<<<,", "<<<");
093
094 if (maxChars > 0) {
095 if (s.length() > maxChars) {
096 s = s.substring(0, maxChars) + "...";
097 }
098 return s;
099 } else {
100 return s;
101 }
102 }
103
104 public boolean isShowBody() {
105 return showBody;
106 }
107
108 public void setShowBody(boolean showBody) {
109 this.showBody = showBody;
110 }
111
112 public boolean isShowBodyType() {
113 return showBodyType;
114 }
115
116 public void setShowBodyType(boolean showBodyType) {
117 this.showBodyType = showBodyType;
118 }
119
120 public void setShowOutBody(boolean showOutBody) {
121 this.showOutBody = showOutBody;
122 }
123
124 public boolean isShowOutBody() {
125 return showOutBody;
126 }
127
128 public void setShowOutBodyType(boolean showOutBodyType) {
129 this.showOutBodyType = showOutBodyType;
130 }
131
132 public boolean isShowOutBodyType() {
133 return showOutBodyType;
134 }
135
136 public boolean isShowBreadCrumb() {
137 return showBreadCrumb;
138 }
139
140 public void setShowBreadCrumb(boolean showBreadCrumb) {
141 this.showBreadCrumb = showBreadCrumb;
142 }
143
144 public boolean isShowExchangeId() {
145 return showExchangeId;
146 }
147
148 public void setShowExchangeId(boolean showExchangeId) {
149 this.showExchangeId = showExchangeId;
150 }
151
152 public boolean isShowHeaders() {
153 return showHeaders;
154 }
155
156 public void setShowHeaders(boolean showHeaders) {
157 this.showHeaders = showHeaders;
158 }
159
160 public boolean isShowOutHeaders() {
161 return showOutHeaders;
162 }
163
164 public void setShowOutHeaders(boolean showOutHeaders) {
165 this.showOutHeaders = showOutHeaders;
166 }
167
168 public boolean isShowProperties() {
169 return showProperties;
170 }
171
172 public void setShowProperties(boolean showProperties) {
173 this.showProperties = showProperties;
174 }
175
176 public boolean isShowNode() {
177 return showNode;
178 }
179
180 public void setShowNode(boolean showNode) {
181 this.showNode = showNode;
182 }
183
184 public boolean isShowExchangePattern() {
185 return showExchangePattern;
186 }
187
188 public void setShowExchangePattern(boolean showExchangePattern) {
189 this.showExchangePattern = showExchangePattern;
190 }
191
192 public boolean isShowException() {
193 return showException;
194 }
195
196 public void setShowException(boolean showException) {
197 this.showException = showException;
198 }
199
200 public boolean isShowRouteId() {
201 return showRouteId;
202 }
203
204 public void setShowRouteId(boolean showRouteId) {
205 this.showRouteId = showRouteId;
206 }
207
208 public int getBreadCrumbLength() {
209 return breadCrumbLength;
210 }
211
212 public void setBreadCrumbLength(int breadCrumbLength) {
213 this.breadCrumbLength = breadCrumbLength;
214 }
215
216 public boolean isShowShortExchangeId() {
217 return showShortExchangeId;
218 }
219
220 public void setShowShortExchangeId(boolean showShortExchangeId) {
221 this.showShortExchangeId = showShortExchangeId;
222 }
223
224 public int getNodeLength() {
225 return nodeLength;
226 }
227
228 public void setNodeLength(int nodeLength) {
229 this.nodeLength = nodeLength;
230 }
231
232 public int getMaxChars() {
233 return maxChars;
234 }
235
236 public void setMaxChars(int maxChars) {
237 this.maxChars = maxChars;
238 }
239
240 // Implementation methods
241 //-------------------------------------------------------------------------
242
243 protected String extractRoute(ProcessorDefinition<?> node) {
244 RouteDefinition route = ProcessorDefinitionHelper.getRoute(node);
245 if (route != null) {
246 return route.getId();
247 } else {
248 return null;
249 }
250 }
251
252
253 protected Object getBreadCrumbID(Exchange exchange) {
254 return exchange.getExchangeId();
255 }
256
257 protected String getNodeMessage(RouteNode entry, Exchange exchange) {
258 String message = entry.getLabel(exchange);
259 if (nodeLength > 0) {
260 return String.format("%1$-" + nodeLength + "." + nodeLength + "s", message);
261 } else {
262 return message;
263 }
264 }
265
266 /**
267 * Creates the breadcrumb based on whether this was a trace of
268 * an exchange coming out of or into a processing step. For example,
269 * <br/><tt>transform(body) -> ID-mojo/39713-1225468755256/2-0</tt>
270 * <br/>or
271 * <br/><tt>ID-mojo/39713-1225468755256/2-0 -> transform(body)</tt>
272 */
273 protected String extractBreadCrumb(TraceInterceptor interceptor, ProcessorDefinition<?> currentNode, Exchange exchange) {
274 String id = "";
275 String result;
276
277 if (!showBreadCrumb && !showExchangeId && !showShortExchangeId && !showNode) {
278 return "";
279 }
280
281 // compute breadcrumb id
282 if (showBreadCrumb) {
283 id = getBreadCrumbID(exchange).toString();
284 } else if (showExchangeId || showShortExchangeId) {
285 id = getBreadCrumbID(exchange).toString();
286 if (showShortExchangeId) {
287 // only output last part of id
288 id = id.substring(id.lastIndexOf('-') + 1);
289 }
290 }
291
292 // compute from, to and route
293 String from = "";
294 String to = "";
295 String route = "";
296 if (showNode || showRouteId) {
297 TracedRouteNodes traced = exchange.getUnitOfWork().getTracedRouteNodes();
298
299 RouteNode traceFrom = traced.getSecondLastNode();
300 if (traceFrom != null) {
301 from = getNodeMessage(traceFrom, exchange);
302 } else if (exchange.getFromEndpoint() != null) {
303 from = "from(" + exchange.getFromEndpoint().getEndpointUri() + ")";
304 }
305
306 RouteNode traceTo = traced.getLastNode();
307 if (traceTo != null) {
308 to = getNodeMessage(traceTo, exchange);
309 // if its an abstract dummy holder then we have to get the 2nd last so we can get the real node that has
310 // information which route it belongs to
311 if (traceTo.isAbstract() && traceTo.getProcessorDefinition() == null) {
312 traceTo = traced.getSecondLastNode();
313 }
314 if (traceTo != null) {
315 route = extractRoute(traceTo.getProcessorDefinition());
316 }
317 }
318 }
319
320 // assemble result with and without the to/from
321 if (showNode) {
322 if (showRouteId && route != null) {
323 result = id.trim() + " >>> (" + route + ") " + from + " --> " + to.trim() + " <<< ";
324 } else {
325 result = id.trim() + " >>> " + from + " --> " + to.trim() + " <<< ";
326 }
327
328 if (interceptor.shouldTraceOutExchanges() && exchange.hasOut()) {
329 result += " (OUT) ";
330 }
331 } else {
332 result = id;
333 }
334
335 if (breadCrumbLength > 0) {
336 // we want to ensure text coming after this is aligned for readability
337 return String.format("%1$-" + breadCrumbLength + "." + breadCrumbLength + "s", result.trim());
338 } else {
339 return result.trim();
340 }
341 }
342
343 }