Camel errorHandler doesn't log before or after sending message to the dead letter channel - apache-camel

We have a simple Camel route like below. But we have noticed that errorHandler log is not working. After some investigation, we understood that errorHandler has different log parameters then other logs(like in route or onException).
We haven't succeeded to use errorHandler log. Yes, there are so many options to log but we want to learn how to use this one. Our aim is to log some texts before or after sending messages to deadletter queue.
How can we use errorHandler log?
apache-camel : 3.19.0
spring-boot : 2.7.5
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:camel="http://camel.apache.org/schema/spring"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://camel.apache.org/schema/spring
http://camel.apache.org/schema/spring/camel-spring.xsd">
<bean id="mdcEnricher" class="com.mycompany.MDCEnricher"/>
<camel:camelContext id="mycontext" xmlns="http://camel.apache.org/schema/spring" useMDCLogging="true">
<camel:errorHandler id="myErrorHandler" type="DeadLetterChannel"
useOriginalBody="true"
deadLetterUri="jms:queue:mybackoutq">
<redeliveryPolicy
maximumRedeliveries="1"
redeliveryDelay="1"
retryAttemptedLogLevel="WARN"
retriesExhaustedLogLevel="ERROR"/>
<log id="logIncomingMsg" logName="com.mypackage"
loggingLevel="ERROR" message="Pushing to backout queue"/>
</camel:errorHandler>
<camel:route id="myRoute" errorHandlerRef="myErrorHandler">
<from uri="jms:queue:myinputq"/>
<bean ref="mdcEnricher" method="enrich"/>
<log message="Received exchange with message id: [${headers.JMSMessageID}], starting processing"/>
<process ref="#class:com.mycompany.processor.MyProcessor"/>
<to uri="jms:queue:myoutputq"/>
<log message="Finished the processing exchange with message id: [${headers.JMSMessageID}]"/>
</camel:route>
Try to change log configuration and loggingLevel to DEBUG but nothing changed.
<springProfile name="local">
<logger name="org.apache.camel" level="DEBUG"/>
<logger name="com.mycompany" level="DEBUG"/>
<root level="DEBUG">
<appender-ref ref="LocalConsole"/>
</root>
</springProfile>

Related

Camel exchange failed without an exception

After upgrading from Camel 2.1 to 2.17 and some code modification we are having some problems with the exception handling in Camel. We send message from app A to app B. The happy flow works fine, but the unhappy flow doesn't.
We send the message to cause an exception but it is not correctly handled in the onexception block.
Actually, we see the following tracelog: ProcessTaskEx - message received, but I don't see: ProcessTaskEx - exception
The exception we get from Camel is:
camel exchange failed without an exception: <SOAP-ENV:Fault xmlns:SOAP-ENV>
Our route looks like this, any idea what the problem could be? Thank you very much for your time community! :)
<?xml version="1.0" encoding="ASCII"?>
<routes xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="switchyard://ProcessTaskEx"/>
<log message="ProcessTaskEx - message received: ${body}" loggingLevel="DEBUG" logName="WebServiceQueues" />
<to uri="switchyard://RequestCapacity"/>
<onException>
<exception>java.lang.Exception</exception>
<exception>webservicequeues.utilities.WebServiceQueueException</exception>
<log message="ProcessTaskEx - exception" loggingLevel="DEBUG" logName="WebServiceQueues" />
<redeliveryPolicy maximumRedeliveries="2" redeliveryDelay="60000" maximumRedeliveryDelay="900000" retriesExhaustedLogLevel="INFO" retryAttemptedLogLevel="INFO"/>
<handled>
<constant>true</constant>
</handled>
<log message="Failed after Retry.Sending ProcessTask Request to Error Queue" loggingLevel="ERROR" logName="WebServiceQueues" />
<to uri="switchyard://ErrorProcessTaskExQueue"/>
</onException>
</route>
</routes>
As fas as I remember, faults are not handled by default. In order to enable this a property must be set: handleFault="true". It can be set for the whole Camel context or for individual routes.
Example for a route in XML:
<route handleFault="true">
...
</route

How to make Camel pattern="InOut" work with IBM MQ

As described here:
setting ReplyToQ attribute of MQMD of IBM MQ request message with Camel
I managed to set ReplyToQ in MQMD of request properly in Camel Route, but I can't get the response in the same Route, with the IBM MQ Endpoint ("to") that I would like to use both for output (of request) and for input (of response), because it is matching wrong Correlation ID, like this:
The OUT message was not received within: 20000 millis due reply message with correlationID: Camel-ID-MYPC-62418-1518179436629-0-5 not received on destination: queue:///REPLYQ. Exchange[ID-MYPC-62418-1518179436629-0-4]
Namely, responding application sets CorrelationID (in MQMD) to the MessageID (from MQMD of the received request). How to make this scenario work?
I tried with useMessageIDAsCorrelationID, but this doesn't change much the result (responses are not consumed). Another try was to set MessageID of request to some fixed value (that would not be final solution), but I can't even do that. I added this:
<setHeader headerName="JMSMessageID" id="_setHeader2">
<constant>abcdefg</constant>
</setHeader>
<setHeader headerName="JMSCorrelationID" id="_setHeader3">
<constant>abcdefg</constant>
</setHeader>
but this only sets CorrelationID, and I still get such things:
The OUT message was not received within: 20000 millis due reply message with correlationID: abcdefg not received on destination: queue:///REPLYQ. Exchange[ID-MYPC-65151-1518190285422-0-3]
Complete route definition:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:camel="http://camel.apache.org/schema/spring"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
<bean class="org.apache.camel.component.jms.JmsComponent" id="websphere">
<property name="connectionFactory">
<bean class="com.ibm.mq.jms.MQConnectionFactory">
<property name="transportType" value="1"/>
<property name="hostName" value="hostname"/>
<property name="port" value="port"/>
<property name="queueManager" value="qmgr_name"/>
<property name="channel" value="channel_name"/>
</bean>
</property>
</bean>
<!-- Define a traditional camel context here -->
<camelContext id="camel" useBreadcrumb="false" xmlns="http://camel.apache.org/schema/spring">
<route id="simple-route">
<from id="request-file" uri="file://C:/mqdocuments/?fileName=request.txt"/>
<log id="route-log" message=">>> ${body}"/>
<setHeader headerName="CamelJmsDestinationName" id="_setHeader1">
<constant>queue://QM_TEST/INPUTQ?targetClient=1&mdWriteEnabled=true&mdReadEnabled=true</constant>
</setHeader>
<setHeader headerName="JMSMessageID" id="_setHeader2">
<constant>abcdefg</constant>
</setHeader>
<setHeader headerName="JMSCorrelationID" id="_setHeader3">
<constant>abcdefg</constant>
</setHeader>
<to id="_to1" pattern="InOut" uri="websphere:queue:SYSTEM.DEFAULT.LOCAL.QUEUE?replyTo=REPLYQ"/>
</route>
</camelContext>
</beans>
OK, this simple code actually works as explained here:
http://camel.apache.org/correlation-identifier.html
<route id="simple-route">
<from id="request-file" uri="file://C:/mqdocuments/?fileName=request464.txt"/>
<log id="route-log-request" message="request: ${body}"/>
<setHeader headerName="CamelJmsDestinationName" id="_setHeader1">
<constant>queue://QM_TEST/INPUTQ?targetClient=1</constant>
</setHeader>
<to id="_to1" pattern="InOut" uri="websphere:queue:SYSTEM.DEFAULT.LOCAL.QUEUE?useMessageIDAsCorrelationID=true&replyTo=REPLYQ"/>
<log id="route-log-response" message="response: ${body}"/>
</route>
It prints out neatly response body to console output.
I don't know why I was under impression that it doesn't work when I first tried it. So, to summarize both questions, the catch is in using useMessageIDAsCorrelationID and replyTo parameters in uri of a queue, as well as pattern="InOut" parameter of <to> endpoint.

If route threw exception and handled is set to true, only first processor in doFinally is executed

I've got a Camel Blueprint definition with two Camel contexts containing one route each.
First contexts route is invoked and in turn calls the route of the second context. Now if in the second route an Exception is thrown and the onException sets handled=true, in the first routes doFinally block only the first processor is invoked.
Here is my Blueprint definition:
<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:camel="http://camel.apache.org/schema/blueprint"
xsi:schemaLocation="
http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
http://camel.apache.org/schema/blueprint http://camel.apache.org/schema/blueprint/camel-blueprint.xsd">
<bean id="myException" class="java.lang.RuntimeException">
<argument value="Booom" />
</bean>
<camelContext id="firstContext" trace="false" xmlns="http://camel.apache.org/schema/blueprint">
<route id="firstRoute">
<from uri="direct-vm:start"/>
<doTry>
<to uri="log:FIRST_TRY"/>
<to uri="direct-vm:generateException"/>
<to uri="log:SECOND_TRY"/>
<doFinally>
<to uri="log:FIRST_FINALLY"/>
<to uri="log:SECOND_FINALLY"/>
</doFinally>
</doTry>
<log message="The message contains ${body}"/>
<to uri="mock:result"/>
</route>
</camelContext>
<camelContext id="secondContext" trace="false" xmlns="http://camel.apache.org/schema/blueprint">
<onException>
<exception>java.lang.Exception</exception>
<handled>
<constant>true</constant>
</handled>
</onException>
<route id="secondRoute">
<from uri="direct-vm:generateException"/>
<throwException ref="myException"/>
</route>
</camelContext>
</blueprint>
Only the <to uri="log:FIRST_FINALLY"/> gets printed out. I cannot see the <to uri="log:SECOND_FINALLY"/>. Am I missing something here? Any help is appreciated.
I am using Camel 2.10.6 inside Apache Servicemix 4.5.2.
Regards
Dominik
You can consider using multicast [1] as a workaround for this issue.
<doFinally>
<multicast>
<to uri="log:FIRST_FINALLY"/>
<to uri="log:SECOND_FINALLY"/>
</multicast>
</doFinally>
This is not the same as pipeline processing of course, but in some cases doFinally block can just send two messages independently.
[1] http://camel.apache.org/multicast

Camel Multicast issue

We are using the below configuration to send a file from single source to multiple remote destinations.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:camel="http://camel.apache.org/schema/spring"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
<routeContext id="gcgRatesOutbound" xmlns="http://camel.apache.org/schema/spring">
<route id="gcgRatesFileOut">
<from uri="file:{{nas.root}}/{{gcg.out.prices.dir}}?delay={{poll.delay}}&initialDelay={{initial.delay}}&readLock=rename&scheduledExecutorService=#scheduledExecutorService" />
<multicast stopOnException="true">
<to uri="scp://{{gcg.ste.Client1_User_Name}}#{{gcg.ste.Host_Name}}:{{gcg.ste.Port_Number}}/{{gcg.ste.Destination_Client1}}?knownHostsFile={{ssh.knownHosts}}&privateKeyFile={{ssh.privateKey}}" />
<to uri="scp://{{gcg.ste.Client2_User_Name}}#{{gcg.ste.Host_Name}}:{{gcg.ste.Port_Number}}/{{gcg.ste.Destination_Client2}}?knownHostsFile={{ssh.knownHosts}}&privateKeyFile={{ssh.privateKey}}" />
<to uri="scp://{{gcg.ste.Client3_User_Name}}#{{gcg.ste.Host_Name}}:{{gcg.ste.Port_Number}}/{{gcg.ste.Destination_Client3}}?knownHostsFile={{ssh.knownHosts}}&privateKeyFile={{ssh.privateKey}}" />
</multicast>
</route>
</routeContext>
</beans>
Using the above confirguration the file reaches the remote destinations, which confirmed that the connection to all the remote destinations were successfull.
We need that the file should be moved to the archive folder after the file has been successfully transfered to all the remote destinations.
And should move to error folder incase of any error.
However, when I add the archival code ( element) as child element to the multicast element in the above configuration and use the and the tag to move the file to error folder incase of an error. The file does not reach the remote destinations.
<doTry>
<multicast stopOnException="true" parallelProcessing="true">
<to uri="scp://{{gcg.ste.Client1_User_Name}}#{{gcg.ste.Host_Name}}:{{gcg.ste.Port_Number}}/{{gcg.ste.Destination_Client1}}?knownHostsFile={{ssh.knownHosts}}&privateKeyFile={{ssh.privateKey}}" />
<to uri="scp://{{gcg.ste.Client2_User_Name}}#{{gcg.ste.Host_Name}}:{{gcg.ste.Port_Number}}/{{gcg.ste.Destination_Client2}}?knownHostsFile={{ssh.knownHosts}}&privateKeyFile={{ssh.privateKey}}" />
<to uri="scp://{{gcg.ste.Client3_User_Name}}#{{gcg.ste.Host_Name}}:{{gcg.ste.Port_Number}}/{{gcg.ste.Destination_Client3}}?knownHostsFile={{ssh.knownHosts}}&privateKeyFile={{ssh.privateKey}}" />
<to uri="file://{{nas.root}}/{{gcg.out.prices.dir}}?fileName={{archive.dir}}" />
</multicast>
<doCatch>
<exception>java.lang.Exception</exception>
<handled>
<constant>true</constant>
</handled>
<to uri="file://{{nas.root}}/{{gcg.out.prices.dir}}?fileName={{error.dir}}" />
</doCatch>
</doTry>
The file does not reach the remote destinations nor does it produce any log and the file is moved to archive folder.
I tried placing the remote destinations, the archival code and the move to error code in seperate routes and have its reference in a single multicast as below
<to uri="direct:Client1FileOut" />
<to uri="direct:Client2FileOut" />
<to uri="direct:Client3FileOut" />
<to uri="direct:MoveToArchive" />
<route id="gcgFileOut1">
<from uri="direct:Client1FileOut" />
<doTry>
<to uri="scp://{{gcg.ste.Client1_User_Name}}#{{gcg.ste.Host_Name}}:{{gcg.ste.Port_Number}}/{{gcg.ste.Destination_Client1}}?knownHostsFile={{ssh.knownHosts}}&privateKeyFile={{ssh.privateKey}}" />
<doCatch>
<exception>java.lang.Exception</exception>
<handled>
<constant>true</constant>
</handled>
<to uri="direct:gcgError" />
</doCatch>
</doTry>
</route>
However, The file does not reach the remote destinations nor does it produce any log and the file is moved to archive folder.
I am new to camel.
I tried using the shareUnitOfWork attribute as below
<multicast shareUnitOfWork="true">
However, the file moved to archive folder along with Test_2_19082013_3.txt.camelLock file
Not sure why this file is also moved to archive when the file dropped was Test_2_19082013_3.txt
Also there is folder named "ARCHIV~1" created in the drop location.
Something might went wrong when moving the file to archive. You have stopOnException="true" parallelProcessing="true" and the local file is probably done first as it should be the fastest.
You probably want to print the error somewhere. Now, you catch the exception and mark the error as handled. Still you expect logs. Use the log component and output some log statements manually. Not only in case or error but also in case of success. You can log in the debug level so that you can manually enable log outprint in case you need it - like now.
Another option for you to figure out what's going on is to enable trace which will make you less "blind".
That said about debugging on your own -
You are archiving and storeing error messages in the input directory. The lock file you see is when Camel is reading. This is likely what's casuing your application to malfunction.
{{nas.root}}/{{gcg.out.prices.dir}}
The fileName=... is the filename, not another sub directory.
So: file://{{nas.root}}/{{gcg.out.prices.dir}}/{{archive.dir}} should do it (likewise for the error path).

Want to build a route which will check contents of Soap request and pass the request to appropriate URI

I am Ashish from Mumbai and very new to Apache Camel.
Currently I am building a route in XML which will scan the SOAP request and will redirect the request to appropriate URI.
My Soap request isn as follows:
<service xmlns="http://ws.madcomum.comprova.com">
<request>
<keysValues>
<item>
<bytesValue
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
<dateValue
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
<doubleValue
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
<key>validatesOriginIntegrity</key>
<longValue
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
<stringValue>z4x/FOOR+EPQ0vD9+itPSCBeNR4=</stringValue>
</item>
</keysValues>
<actionId>1</actionId>
<clientId>ARGO</clientId>
</request>
</service>
From this SOAP envelope, I want to parse out value of actionId tag using Camel Route.
If actionId has value of 1 then route must be redirected to callService else to another service.
I developed logic of route as folows:
<route>
<from uri="cxf:bean:comprovaWS?dataFormat=MESSAGE" />
<when>
<xpath>//actionId=1</xpath>
<to uri="log:input" />
<to ref="callService" />
<to uri="log:output" />
</when>
<otherwise>
<to uri="log:input" />
<to ref="otherService"/>
<to uri="log:output" />
</otherwise>
</choice>
</route>
But this logic is not working.
Is there any error in my route?
Though I am Java guy, I don't want to use Java here. I want to rely on Camel itself.
Please help me ASAP.
Regards,
Ashish
When you use xpath then 95% of the times when people have trouble its often due to namespaces. Your SOAP message is defined using a namespace - "http://ws.madcomum.comprova.com". The xpath expression must use this namespace to make it work.
See more details at: http://camel.apache.org/xpath, there is an example at the section Using XML configuration
Also as you use CXF in MESSAGE mode, then read about stream caching as the message is stream based: http://camel.apache.org/stream-caching.html

Resources