You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@camel.apache.org by Peter Hilton <pe...@lunatech.com> on 2013/05/14 18:10:08 UTC

Logging cause of failure with deadLetterChannel error handler?

How should I approach the following scenario? I’m starting to suspect that I'm doing it wrong…

I'm using: Camel 2.11.0, Scala DSL, Scala 2.10.0, sbt 0.12.2, JDK 1.6.0_43, OSX 10.8.3


I have a route that takes a file, parses it and then sends JSON to a web service. If the Camel processor that parses the file throws a parse exception, the configured error handler moves the file to the dead letter endpoint. This much works.

	errorHandler(deadLetterChannel(failureEndpoint).disableRedelivery())

However, I *also* want to log an error with the parse exception that the parser throws. How should I do this?

First, I’m confused by the documentation and examples I’ve found: they suggest using a log or a file but not both. It isn’t weird to want to both move an invalid input file to a dead letter 'failure' directory and to log the cause of the failure. Should the error handler be doing both?

The following is as far as we got, adding our custom 'ErrorProcessor' so we could customise the log output:

	case class ErrorProcessor(implicit routeId: String) extends CamelProcessor {

	  def process(exchange: Exchange): Unit = {
	    val formatString = "Error [%s] while processing [%s]"
	    val exception = exchange.getProperty(Exchange.EXCEPTION_CAUGHT).asInstanceOf[Throwable]
	    val message = formatString.format(exception.getMessage, exchange.getIn.getHeaders.get("CamelFileNameOnly").asInstanceOf[String])
	    Logger.error(message, exception)
	  }
	}

	…

	val deadLetterErrorHandler = deadLetterChannel(failureEndpoint).disableRedelivery()
	deadLetterErrorHandler.setFailureProcessor(ErrorProcessor())
	errorHandler(deadLetterErrorHandler)

This is okay, but I would prefer to encapsulate all of the above in a single component that I can then give to errorHandler(…) for every route builder.

We tried to make a custom DeadLetterChannelBuilder, but it didn't work: we tried overriding getFailureProcessor to return our customer error processor, but its process method was never called.

What is the correct way to customise log output for DeadLetterChannelBuilder whose endpoint is a directory that the message (file) will be moved to?

How much of this can I do using standard Camel components and the Scala DSL?

Peter

Solved: Logging cause of failure with deadLetterChannel error handler?

Posted by Peter Hilton <pe...@lunatech.com>.
On 14 May 2013, at 18:10, Peter Hilton <pe...@lunatech.com> wrote:
> I have a route that takes a file, parses it and then sends JSON to a web service. If the Camel processor that parses the file throws a parse exception, the configured error handler moves the file to the dead letter endpoint. This much works.
> 
> 	errorHandler(deadLetterChannel(failureEndpoint).disableRedelivery())
> 
> However, I *also* want to log an error with the parse exception that the parser throws. How should I do this?

I now have something that works.

After reading enough of the Scala DSL unit tests, I added the following to my route builder:

	handle[Exception] {
	  log(LoggingLevel.ERROR, "${id} ${exception}")
	  to(failureEndpoint)
	}.handled

It doesn't appear to be necessary to call maximumRedeliveries(0) on handle, since I don't get retries when I do this.

This is not ideal because I would prefer this to be a single statement, e.g. using a custom component, to be able to customise the log output, and to include the stack trace. I may get to those things, but I've run out of time for now.

Peter

Re: Logging cause of failure with deadLetterChannel error handler?

Posted by Peter Hilton <pe...@lunatech.com>.
On 14 May 2013, at 18:10, Peter Hilton <pe...@lunatech.com> wrote:
> 	…
> 
> 	val deadLetterErrorHandler = deadLetterChannel(failureEndpoint).disableRedelivery()
> 	deadLetterErrorHandler.setFailureProcessor(ErrorProcessor())
> 	errorHandler(deadLetterErrorHandler)
> 
> This is okay, but I would prefer to encapsulate all of the above in a single component that I can then give to errorHandler(…) for every route builder.

Correction: this error handler doesn't work. The ErrorProcessor logs the failure as expected, but the message file is not moved to the dead letter failure endpoint :(

Perhaps it’s possible to use a dead letter endpoint and handle the exception separately logging…

	errorHandler(deadLetterChannel(failureEndpoint).disableRedelivery())

	…

	hanlde[Exception] {
		// Log error…
		…

Peter