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.Processor;
022 import org.apache.camel.RouteNode;
023 import org.apache.camel.model.ProcessorDefinition;
024 import org.apache.camel.processor.Traceable;
025 import org.apache.camel.spi.TraceableUnitOfWork;
026 import org.apache.camel.spi.UnitOfWork;
027 import org.apache.camel.util.MessageHelper;
028
029 /**
030 * @version $Revision: 795369 $
031 */
032 public class DefaultTraceFormatter implements TraceFormatter {
033 private int breadCrumbLength;
034 private int nodeLength;
035 private boolean showBreadCrumb = true;
036 private boolean showNode = true;
037 private boolean showExchangeId;
038 private boolean showShortExchangeId;
039 private boolean showExchangePattern = true;
040 private boolean showProperties;
041 private boolean showHeaders = true;
042 private boolean showBody = true;
043 private boolean showBodyType = true;
044 private boolean showOutHeaders;
045 private boolean showOutBody;
046 private boolean showOutBodyType;
047 private boolean showException = 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 if (maxChars > 0) {
091 String s = sb.toString();
092 if (s.length() > maxChars) {
093 s = s.substring(0, maxChars) + "...";
094 }
095 return s;
096 } else {
097 return sb.toString();
098 }
099 }
100
101 public boolean isShowBody() {
102 return showBody;
103 }
104
105 public void setShowBody(boolean showBody) {
106 this.showBody = showBody;
107 }
108
109 public boolean isShowBodyType() {
110 return showBodyType;
111 }
112
113 public void setShowBodyType(boolean showBodyType) {
114 this.showBodyType = showBodyType;
115 }
116
117 public void setShowOutBody(boolean showOutBody) {
118 this.showOutBody = showOutBody;
119 }
120
121 public boolean isShowOutBody() {
122 return showOutBody;
123 }
124
125 public void setShowOutBodyType(boolean showOutBodyType) {
126 this.showOutBodyType = showOutBodyType;
127 }
128
129 public boolean isShowOutBodyType() {
130 return showOutBodyType;
131 }
132
133 public boolean isShowBreadCrumb() {
134 return showBreadCrumb;
135 }
136
137 public void setShowBreadCrumb(boolean showBreadCrumb) {
138 this.showBreadCrumb = showBreadCrumb;
139 }
140
141 public boolean isShowExchangeId() {
142 return showExchangeId;
143 }
144
145 public void setShowExchangeId(boolean showExchangeId) {
146 this.showExchangeId = showExchangeId;
147 }
148
149 public boolean isShowHeaders() {
150 return showHeaders;
151 }
152
153 public void setShowHeaders(boolean showHeaders) {
154 this.showHeaders = showHeaders;
155 }
156
157 public boolean isShowOutHeaders() {
158 return showOutHeaders;
159 }
160
161 public void setShowOutHeaders(boolean showOutHeaders) {
162 this.showOutHeaders = showOutHeaders;
163 }
164
165 public boolean isShowProperties() {
166 return showProperties;
167 }
168
169 public void setShowProperties(boolean showProperties) {
170 this.showProperties = showProperties;
171 }
172
173 public boolean isShowNode() {
174 return showNode;
175 }
176
177 public void setShowNode(boolean showNode) {
178 this.showNode = showNode;
179 }
180
181 public boolean isShowExchangePattern() {
182 return showExchangePattern;
183 }
184
185 public void setShowExchangePattern(boolean showExchangePattern) {
186 this.showExchangePattern = showExchangePattern;
187 }
188
189 public boolean isShowException() {
190 return showException;
191 }
192
193 public void setShowException(boolean showException) {
194 this.showException = showException;
195 }
196
197 public int getBreadCrumbLength() {
198 return breadCrumbLength;
199 }
200
201 public void setBreadCrumbLength(int breadCrumbLength) {
202 this.breadCrumbLength = breadCrumbLength;
203 }
204
205 public boolean isShowShortExchangeId() {
206 return showShortExchangeId;
207 }
208
209 public void setShowShortExchangeId(boolean showShortExchangeId) {
210 this.showShortExchangeId = showShortExchangeId;
211 }
212
213 public int getNodeLength() {
214 return nodeLength;
215 }
216
217 public void setNodeLength(int nodeLength) {
218 this.nodeLength = nodeLength;
219 }
220
221 public int getMaxChars() {
222 return maxChars;
223 }
224
225 public void setMaxChars(int maxChars) {
226 this.maxChars = maxChars;
227 }
228
229 // Implementation methods
230 //-------------------------------------------------------------------------
231 protected Object getBreadCrumbID(Exchange exchange) {
232 return exchange.getExchangeId();
233 }
234
235 protected String getNodeMessage(RouteNode entry, Exchange exchange) {
236 String message = entry.getLabel(exchange);
237 if (nodeLength > 0) {
238 return String.format("%1$-" + nodeLength + "." + nodeLength + "s", message);
239 } else {
240 return message;
241 }
242 }
243
244 /**
245 * Creates the breadcrumb based on whether this was a trace of
246 * an exchange coming out of or into a processing step. For example,
247 * <br/><tt>transform(body) -> ID-mojo/39713-1225468755256/2-0</tt>
248 * <br/>or
249 * <br/><tt>ID-mojo/39713-1225468755256/2-0 -> transform(body)</tt>
250 */
251 protected String extractBreadCrumb(TraceInterceptor interceptor, ProcessorDefinition currentNode, Exchange exchange) {
252 String id = "";
253 String result;
254
255 if (!showBreadCrumb && !showExchangeId && !showShortExchangeId && !showNode) {
256 return "";
257 }
258
259 // compute breadcrumb id
260 if (showBreadCrumb) {
261 id = getBreadCrumbID(exchange).toString();
262 } else if (showExchangeId || showShortExchangeId) {
263 id = getBreadCrumbID(exchange).toString();
264 if (showShortExchangeId) {
265 // skip hostname for short exchange id
266 id = id.substring(id.indexOf('/') + 1);
267 }
268 }
269
270 // compute from and to
271 String from = "";
272 String to = "";
273 if (showNode && exchange.getUnitOfWork() instanceof TraceableUnitOfWork) {
274 TraceableUnitOfWork tuow = (TraceableUnitOfWork) exchange.getUnitOfWork();
275
276 RouteNode traceFrom = tuow.getSecondLastNode();
277 if (traceFrom != null) {
278 from = getNodeMessage(traceFrom, exchange);
279 } else if (exchange.getFromEndpoint() != null) {
280 from = "from(" + exchange.getFromEndpoint().getEndpointUri() + ")";
281 }
282
283 RouteNode traceTo = tuow.getLastNode();
284 if (traceTo != null) {
285 to = getNodeMessage(traceTo, exchange);
286 }
287 }
288
289 // assemble result with and without the to/from
290 if (showNode) {
291 result = id.trim() + " >>> " + from + " --> " + to.trim();
292 if (interceptor.shouldTraceOutExchanges() && exchange.hasOut()) {
293 result += " (OUT) ";
294 }
295 } else {
296 result = id;
297 }
298
299 if (breadCrumbLength > 0) {
300 // we want to ensure text coming after this is aligned for readability
301 return String.format("%1$-" + breadCrumbLength + "." + breadCrumbLength + "s", result.trim());
302 } else {
303 return result.trim();
304 }
305 }
306
307 }