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    }