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; 018 019import java.io.PrintWriter; 020import java.io.StringWriter; 021import java.util.Map; 022import java.util.TreeMap; 023import java.util.concurrent.Future; 024 025import org.apache.camel.Exchange; 026import org.apache.camel.Message; 027import org.apache.camel.spi.ExchangeFormatter; 028import org.apache.camel.util.MessageHelper; 029import org.apache.camel.util.ObjectHelper; 030import org.apache.camel.util.StringHelper; 031 032/** 033 * Default {@link ExchangeFormatter} that have fine grained options to configure what to include in the output. 034 */ 035public class DefaultExchangeFormatter implements ExchangeFormatter { 036 037 protected static final String LS = System.getProperty("line.separator"); 038 private static final String SEPARATOR = "###REPLACE_ME###"; 039 040 public enum OutputStyle { Default, Tab, Fixed } 041 042 private boolean showExchangeId; 043 private boolean showExchangePattern = true; 044 private boolean showProperties; 045 private boolean showHeaders; 046 private boolean skipBodyLineSeparator = true; 047 private boolean showBodyType = true; 048 private boolean showBody = true; 049 private boolean showOut; 050 private boolean showException; 051 private boolean showCaughtException; 052 private boolean showStackTrace; 053 private boolean showAll; 054 private boolean multiline; 055 private boolean showFuture; 056 private boolean showStreams; 057 private boolean showFiles; 058 private int maxChars = 10000; 059 private OutputStyle style = OutputStyle.Default; 060 061 private String style(String label) { 062 if (style == OutputStyle.Default) { 063 return String.format(", %s: ", label); 064 } 065 if (style == OutputStyle.Tab) { 066 return String.format("\t%s: ", label); 067 } else { 068 return String.format("\t%-20s", label); 069 } 070 } 071 072 public String format(Exchange exchange) { 073 Message in = exchange.getIn(); 074 075 StringBuilder sb = new StringBuilder(); 076 if (showAll || showExchangeId) { 077 if (multiline) { 078 sb.append(SEPARATOR); 079 } 080 sb.append(style("Id")).append(exchange.getExchangeId()); 081 } 082 if (showAll || showExchangePattern) { 083 if (multiline) { 084 sb.append(SEPARATOR); 085 } 086 sb.append(style("ExchangePattern")).append(exchange.getPattern()); 087 } 088 089 if (showAll || showProperties) { 090 if (multiline) { 091 sb.append(SEPARATOR); 092 } 093 sb.append(style("Properties")).append(sortMap(exchange.getProperties())); 094 } 095 if (showAll || showHeaders) { 096 if (multiline) { 097 sb.append(SEPARATOR); 098 } 099 sb.append(style("Headers")).append(sortMap(in.getHeaders())); 100 } 101 if (showAll || showBodyType) { 102 if (multiline) { 103 sb.append(SEPARATOR); 104 } 105 sb.append(style("BodyType")).append(getBodyTypeAsString(in)); 106 } 107 if (showAll || showBody) { 108 if (multiline) { 109 sb.append(SEPARATOR); 110 } 111 String body = getBodyAsString(in); 112 if (skipBodyLineSeparator) { 113 body = StringHelper.replaceAll(body, LS, ""); 114 } 115 sb.append(style("Body")).append(body); 116 } 117 118 if (showAll || showException || showCaughtException) { 119 120 // try exception on exchange first 121 Exception exception = exchange.getException(); 122 boolean caught = false; 123 if ((showAll || showCaughtException) && exception == null) { 124 // fallback to caught exception 125 exception = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class); 126 caught = true; 127 } 128 129 if (exception != null) { 130 if (multiline) { 131 sb.append(SEPARATOR); 132 } 133 if (caught) { 134 sb.append(style("CaughtExceptionType")).append(exception.getClass().getCanonicalName()); 135 sb.append(style("CaughtExceptionMessage")).append(exception.getMessage()); 136 } else { 137 sb.append(style("ExceptionType")).append(exception.getClass().getCanonicalName()); 138 sb.append(style("ExceptionMessage")).append(exception.getMessage()); 139 } 140 if (showAll || showStackTrace) { 141 StringWriter sw = new StringWriter(); 142 exception.printStackTrace(new PrintWriter(sw)); 143 sb.append(style("StackTrace")).append(sw.toString()); 144 } 145 } 146 } 147 148 if (showAll || showOut) { 149 if (exchange.hasOut()) { 150 Message out = exchange.getOut(); 151 if (showAll || showHeaders) { 152 if (multiline) { 153 sb.append(SEPARATOR); 154 } 155 sb.append(style("OutHeaders")).append(sortMap(out.getHeaders())); 156 } 157 if (showAll || showBodyType) { 158 if (multiline) { 159 sb.append(SEPARATOR); 160 } 161 sb.append(style("OutBodyType")).append(getBodyTypeAsString(out)); 162 } 163 if (showAll || showBody) { 164 if (multiline) { 165 sb.append(SEPARATOR); 166 } 167 String body = getBodyAsString(out); 168 if (skipBodyLineSeparator) { 169 body = StringHelper.replaceAll(body, LS, ""); 170 } 171 sb.append(style("OutBody")).append(body); 172 } 173 } else { 174 if (multiline) { 175 sb.append(SEPARATOR); 176 } 177 sb.append(style("Out: null")); 178 } 179 } 180 181 if (maxChars > 0) { 182 StringBuilder answer = new StringBuilder(); 183 for (String s : sb.toString().split(SEPARATOR)) { 184 if (s != null) { 185 if (s.length() > maxChars) { 186 s = s.substring(0, maxChars); 187 answer.append(s).append("..."); 188 } else { 189 answer.append(s); 190 } 191 if (multiline) { 192 answer.append(LS); 193 } 194 } 195 } 196 197 // switch string buffer 198 sb = answer; 199 } 200 201 if (multiline) { 202 sb.insert(0, "Exchange["); 203 sb.append("]"); 204 return sb.toString(); 205 } else { 206 // get rid of the leading space comma if needed 207 if (sb.length() > 0 && sb.charAt(0) == ',' && sb.charAt(1) == ' ') { 208 sb.replace(0, 2, ""); 209 } 210 sb.insert(0, "Exchange["); 211 sb.append("]"); 212 213 return sb.toString(); 214 } 215 } 216 217 public boolean isShowExchangeId() { 218 return showExchangeId; 219 } 220 221 public void setShowExchangeId(boolean showExchangeId) { 222 this.showExchangeId = showExchangeId; 223 } 224 225 public boolean isShowProperties() { 226 return showProperties; 227 } 228 229 public void setShowProperties(boolean showProperties) { 230 this.showProperties = showProperties; 231 } 232 233 public boolean isShowHeaders() { 234 return showHeaders; 235 } 236 237 public void setShowHeaders(boolean showHeaders) { 238 this.showHeaders = showHeaders; 239 } 240 241 public boolean isSkipBodyLineSeparator() { 242 return skipBodyLineSeparator; 243 } 244 245 public void setSkipBodyLineSeparator(boolean skipBodyLineSeparator) { 246 this.skipBodyLineSeparator = skipBodyLineSeparator; 247 } 248 249 public boolean isShowBodyType() { 250 return showBodyType; 251 } 252 253 public void setShowBodyType(boolean showBodyType) { 254 this.showBodyType = showBodyType; 255 } 256 257 public boolean isShowBody() { 258 return showBody; 259 } 260 261 public void setShowBody(boolean showBody) { 262 this.showBody = showBody; 263 } 264 265 public boolean isShowOut() { 266 return showOut; 267 } 268 269 public void setShowOut(boolean showOut) { 270 this.showOut = showOut; 271 } 272 273 public boolean isShowAll() { 274 return showAll; 275 } 276 277 public void setShowAll(boolean showAll) { 278 this.showAll = showAll; 279 } 280 281 public boolean isShowException() { 282 return showException; 283 } 284 285 public void setShowException(boolean showException) { 286 this.showException = showException; 287 } 288 289 public boolean isShowStackTrace() { 290 return showStackTrace; 291 } 292 293 public void setShowStackTrace(boolean showStackTrace) { 294 this.showStackTrace = showStackTrace; 295 } 296 297 public boolean isShowCaughtException() { 298 return showCaughtException; 299 } 300 301 public void setShowCaughtException(boolean showCaughtException) { 302 this.showCaughtException = showCaughtException; 303 } 304 305 public boolean isMultiline() { 306 return multiline; 307 } 308 309 public int getMaxChars() { 310 return maxChars; 311 } 312 313 public void setMaxChars(int maxChars) { 314 this.maxChars = maxChars; 315 } 316 317 /** 318 * If enabled then each information is outputted on a newline. 319 */ 320 public void setMultiline(boolean multiline) { 321 this.multiline = multiline; 322 } 323 324 public boolean isShowFuture() { 325 return showFuture; 326 } 327 328 /** 329 * If enabled Camel will on Future objects wait for it to complete to obtain the payload to be logged. 330 * <p/> 331 * Is default disabled. 332 */ 333 public void setShowFuture(boolean showFuture) { 334 this.showFuture = showFuture; 335 } 336 337 public boolean isShowExchangePattern() { 338 return showExchangePattern; 339 } 340 341 public void setShowExchangePattern(boolean showExchangePattern) { 342 this.showExchangePattern = showExchangePattern; 343 } 344 345 public boolean isShowStreams() { 346 return showStreams; 347 } 348 349 /** 350 * If enabled Camel will output stream objects 351 * <p/> 352 * Is default disabled. 353 */ 354 public void setShowStreams(boolean showStreams) { 355 this.showStreams = showStreams; 356 } 357 358 public boolean isShowFiles() { 359 return showFiles; 360 } 361 362 /** 363 * If enabled Camel will output files 364 * <p/> 365 * Is default disabled. 366 */ 367 public void setShowFiles(boolean showFiles) { 368 this.showFiles = showFiles; 369 } 370 371 public OutputStyle getStyle() { 372 return style; 373 } 374 375 /** 376 * Sets the outputs style to use. 377 */ 378 public void setStyle(OutputStyle style) { 379 this.style = style; 380 } 381 382 // Implementation methods 383 //------------------------------------------------------------------------- 384 protected String getBodyAsString(Message message) { 385 if (message.getBody() instanceof Future) { 386 if (!isShowFuture()) { 387 // just use a to string of the future object 388 return message.getBody().toString(); 389 } 390 } 391 392 return MessageHelper.extractBodyForLogging(message, "", isShowStreams(), isShowFiles(), getMaxChars(message)); 393 } 394 395 private int getMaxChars(Message message) { 396 int maxChars = getMaxChars(); 397 if (message.getExchange() != null) { 398 String property = message.getExchange().getContext().getProperty(Exchange.LOG_DEBUG_BODY_MAX_CHARS); 399 if (property != null) { 400 maxChars = message.getExchange().getContext().getTypeConverter().convertTo(Integer.class, property); 401 } 402 } 403 return maxChars; 404 } 405 406 protected String getBodyTypeAsString(Message message) { 407 String answer = ObjectHelper.classCanonicalName(message.getBody()); 408 if (answer != null && answer.startsWith("java.lang.")) { 409 return answer.substring(10); 410 } 411 return answer; 412 } 413 414 private static Map<String, Object> sortMap(Map<String, Object> map) { 415 Map<String, Object> answer = new TreeMap<String, Object>(String.CASE_INSENSITIVE_ORDER); 416 answer.putAll(map); 417 return answer; 418 } 419 420}