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 */
017package org.apache.camel.processor.interceptor;
018
019import org.apache.camel.Exchange;
020import org.apache.camel.Message;
021import org.apache.camel.RouteNode;
022import org.apache.camel.model.ProcessorDefinition;
023import org.apache.camel.model.ProcessorDefinitionHelper;
024import org.apache.camel.model.RouteDefinition;
025import org.apache.camel.spi.TracedRouteNodes;
026import org.apache.camel.util.MessageHelper;
027
028/**
029 * @version 
030 */
031@Deprecated
032public class DefaultTraceFormatter implements TraceFormatter {
033    
034    protected static final String LS = System.lineSeparator();
035    private static final String SEPARATOR = "###REPLACE_ME###";
036    
037    private int breadCrumbLength;
038    private int nodeLength;
039    private boolean showBreadCrumb = true;
040    private boolean showNode = true;
041    private boolean showExchangeId;
042    private boolean showShortExchangeId;
043    private boolean showExchangePattern = true;
044    private boolean showProperties;
045    private boolean showHeaders = true;
046    private boolean showBody = true;
047    private boolean showBodyType = true;
048    private boolean showOutHeaders;
049    private boolean showOutBody;
050    private boolean showOutBodyType;
051    private boolean showException = true;
052    private boolean showRouteId = true;
053    private boolean multiline;
054
055    private int maxChars = 10000;
056
057    public Object format(final TraceInterceptor interceptor, final ProcessorDefinition<?> node, final Exchange exchange) {
058        Message in = exchange.getIn();
059        Message out = null;
060        if (exchange.hasOut()) {
061            out = exchange.getOut();
062        }
063
064        StringBuilder sb = new StringBuilder();
065        if (multiline) {
066            sb.append(SEPARATOR);
067        }
068        sb.append(extractBreadCrumb(interceptor, node, exchange));
069        
070        if (showExchangePattern) {
071            if (multiline) {
072                sb.append(SEPARATOR);
073            }
074            sb.append(", Pattern:").append(exchange.getPattern());
075        }
076        // only show properties if we have any
077        if (showProperties && !exchange.getProperties().isEmpty()) {
078            if (multiline) {
079                sb.append(SEPARATOR);
080            }
081            sb.append(", Properties:").append(exchange.getProperties());
082        }
083        // only show headers if we have any
084        if (showHeaders && !in.getHeaders().isEmpty()) {
085            if (multiline) {
086                sb.append(SEPARATOR);
087            }
088            sb.append(", Headers:").append(in.getHeaders());
089        }
090        if (showBodyType) {
091            if (multiline) {
092                sb.append(SEPARATOR);
093            }
094            sb.append(", BodyType:").append(MessageHelper.getBodyTypeName(in));
095        }
096        if (showBody) {
097            if (multiline) {
098                sb.append(SEPARATOR);
099            }
100            sb.append(", Body:").append(MessageHelper.extractBodyForLogging(in, ""));
101        }
102        if (showOutHeaders && out != null) {
103            if (multiline) {
104                sb.append(SEPARATOR);
105            }
106            sb.append(", OutHeaders:").append(out.getHeaders());
107        }
108        if (showOutBodyType && out != null) {
109            if (multiline) {
110                sb.append(SEPARATOR);
111            }
112            sb.append(", OutBodyType:").append(MessageHelper.getBodyTypeName(out));
113        }
114        if (showOutBody && out != null) {
115            if (multiline) {
116                sb.append(SEPARATOR);
117            }
118            sb.append(", OutBody:").append(MessageHelper.extractBodyForLogging(out, ""));
119        }        
120        if (showException && exchange.getException() != null) {
121            if (multiline) {
122                sb.append(SEPARATOR);
123            }
124            sb.append(", Exception:").append(exchange.getException());
125        }
126
127        // replace ugly <<<, with <<<
128        sb = new StringBuilder(sb.toString().replaceFirst("<<<,", "<<<"));
129        
130        if (maxChars > 0) {
131            StringBuilder answer = new StringBuilder();
132            for (String s : sb.toString().split(SEPARATOR)) {
133                if (s != null) {
134                    if (s.length() > maxChars) {
135                        s = s.substring(0, maxChars);
136                        answer.append(s).append("...");
137                    } else {
138                        answer.append(s);
139                    }
140                    if (multiline) {
141                        answer.append(LS);
142                    }
143                }
144            }
145
146            // switch string buffer
147            sb = answer;
148        }
149
150        return sb.toString();
151    }
152
153    public boolean isShowBody() {
154        return showBody;
155    }
156
157    public void setShowBody(boolean showBody) {
158        this.showBody = showBody;
159    }
160
161    public boolean isShowBodyType() {
162        return showBodyType;
163    }
164
165    public void setShowBodyType(boolean showBodyType) {
166        this.showBodyType = showBodyType;
167    }
168
169    public void setShowOutBody(boolean showOutBody) {
170        this.showOutBody = showOutBody;
171    }
172
173    public boolean isShowOutBody() {
174        return showOutBody;
175    }    
176    
177    public void setShowOutBodyType(boolean showOutBodyType) {
178        this.showOutBodyType = showOutBodyType;
179    }
180
181    public boolean isShowOutBodyType() {
182        return showOutBodyType;
183    }    
184    
185    public boolean isShowBreadCrumb() {
186        return showBreadCrumb;
187    }
188
189    public void setShowBreadCrumb(boolean showBreadCrumb) {
190        this.showBreadCrumb = showBreadCrumb;
191    }
192
193    public boolean isShowExchangeId() {
194        return showExchangeId;
195    }
196
197    public void setShowExchangeId(boolean showExchangeId) {
198        this.showExchangeId = showExchangeId;
199    }
200
201    public boolean isShowHeaders() {
202        return showHeaders;
203    }
204
205    public void setShowHeaders(boolean showHeaders) {
206        this.showHeaders = showHeaders;
207    }
208
209    public boolean isShowOutHeaders() {
210        return showOutHeaders;
211    }
212
213    public void setShowOutHeaders(boolean showOutHeaders) {
214        this.showOutHeaders = showOutHeaders;
215    }
216
217    public boolean isShowProperties() {
218        return showProperties;
219    }
220
221    public void setShowProperties(boolean showProperties) {
222        this.showProperties = showProperties;
223    }
224
225    public boolean isShowNode() {
226        return showNode;
227    }
228
229    public void setShowNode(boolean showNode) {
230        this.showNode = showNode;
231    }
232
233    public boolean isShowExchangePattern() {
234        return showExchangePattern;
235    }
236
237    public void setShowExchangePattern(boolean showExchangePattern) {
238        this.showExchangePattern = showExchangePattern;
239    }
240
241    public boolean isShowException() {
242        return showException;
243    }
244
245    public void setShowException(boolean showException) {
246        this.showException = showException;
247    }
248
249    public boolean isShowRouteId() {
250        return showRouteId;
251    }
252
253    public void setShowRouteId(boolean showRouteId) {
254        this.showRouteId = showRouteId;
255    }
256
257    public boolean isMultiline() {
258        return multiline;
259    }
260
261    public void setMultiline(boolean multiline) {
262        this.multiline = multiline;
263    }
264
265    public int getBreadCrumbLength() {
266        return breadCrumbLength;
267    }
268
269    public void setBreadCrumbLength(int breadCrumbLength) {
270        this.breadCrumbLength = breadCrumbLength;
271    }
272
273    public boolean isShowShortExchangeId() {
274        return showShortExchangeId;
275    }
276
277    public void setShowShortExchangeId(boolean showShortExchangeId) {
278        this.showShortExchangeId = showShortExchangeId;
279    }
280
281    public int getNodeLength() {
282        return nodeLength;
283    }
284
285    public void setNodeLength(int nodeLength) {
286        this.nodeLength = nodeLength;
287    }
288
289    public int getMaxChars() {
290        return maxChars;
291    }
292
293    public void setMaxChars(int maxChars) {
294        this.maxChars = maxChars;
295    }
296
297    // Implementation methods
298    //-------------------------------------------------------------------------
299
300    protected String extractRoute(ProcessorDefinition<?> node) {
301        RouteDefinition route = ProcessorDefinitionHelper.getRoute(node);
302        if (route != null) {
303            return route.getId();
304        } else {
305            return null;
306        }
307    }
308
309    protected Object getBreadCrumbID(Exchange exchange) {
310        return exchange.getExchangeId();
311    }
312
313    protected String getNodeMessage(RouteNode entry, Exchange exchange) {
314        String message = entry.getLabel(exchange);
315        if (nodeLength > 0) {
316            return String.format("%1$-" + nodeLength + "." + nodeLength + "s", message);
317        } else {
318            return message;
319        }
320    }
321    
322    /**
323     * Creates the breadcrumb based on whether this was a trace of
324     * an exchange coming out of or into a processing step. For example, 
325     * <br/><tt>transform(body) -> ID-mojo/39713-1225468755256/2-0</tt>
326     * <br/>or
327     * <br/><tt>ID-mojo/39713-1225468755256/2-0 -> transform(body)</tt>
328     */
329    protected String extractBreadCrumb(TraceInterceptor interceptor, ProcessorDefinition<?> currentNode, Exchange exchange) {
330        String id = "";
331        String result;
332        
333        if (!showBreadCrumb && !showExchangeId && !showShortExchangeId && !showNode) {
334            return "";
335        }
336
337        // compute breadcrumb id
338        if (showBreadCrumb) {
339            id = getBreadCrumbID(exchange).toString();
340        } else if (showExchangeId || showShortExchangeId) {
341            id = getBreadCrumbID(exchange).toString();
342            if (showShortExchangeId) {
343                // only output last part of id
344                id = id.substring(id.lastIndexOf('-') + 1);
345            }
346        }
347
348        // compute from, to and route
349        String from = "";
350        String to = "";
351        String route = "";
352        if (showNode || showRouteId) {
353            if (exchange.getUnitOfWork() != null) {
354                TracedRouteNodes traced = exchange.getUnitOfWork().getTracedRouteNodes();
355                if (traced != null) {
356                    RouteNode traceFrom = traced.getSecondLastNode();
357                    if (traceFrom != null) {
358                        from = getNodeMessage(traceFrom, exchange);
359                    } else if (exchange.getFromEndpoint() != null) {
360                        from = "from(" + exchange.getFromEndpoint().getEndpointUri() + ")";
361                    }
362
363                    RouteNode traceTo = traced.getLastNode();
364                    if (traceTo != null) {
365                        to = getNodeMessage(traceTo, exchange);
366                        // if its an abstract dummy holder then we have to get the 2nd last so we can get the real node that has
367                        // information which route it belongs to
368                        if (traceTo.isAbstract() && traceTo.getProcessorDefinition() == null) {
369                            traceTo = traced.getSecondLastNode();
370                        }
371                        if (traceTo != null) {
372                            route = extractRoute(traceTo.getProcessorDefinition());
373                        }
374                    }
375                }
376            }
377        }
378
379        // assemble result with and without the to/from
380        if (showNode) {
381            if (showRouteId && route != null) {
382                result = id.trim() + " >>> (" + route + ") " + from + " --> " + to.trim() + " <<< ";
383            } else {
384                result = id.trim() + " >>> " + from + " --> " + to.trim() + " <<< ";
385            }
386
387            if (interceptor.shouldTraceOutExchanges() && exchange.hasOut()) {
388                result += " (OUT) ";
389            }
390        } else {
391            result = id;
392        }
393
394        if (breadCrumbLength > 0) {
395            // we want to ensure text coming after this is aligned for readability
396            return String.format("%1$-" + breadCrumbLength + "." + breadCrumbLength + "s", result.trim());
397        } else {
398            return result.trim();
399        }
400    }
401
402}