I wrote a custom CXF interceptor to log all the SOAP request and responses into the database and it seems to be working fine with positive test cases and server errors.
But when a SOAP Fault occurs it just neglects my interceptor and nothing is logged.
Custom CXF interceptors.
public class DbLogOutInterceptor extends AbstractSoapInterceptor {
public void handleMessage(SoapMessage message) {
logger.info("Handling outbound request");
String transaction = MDC.get(mdcKey);
logger.info("OutBound Transaction ID : {} ", transaction);
//code to log the SOAP message in database
.......
}
}
I am not seeing the log statements from this method instead I see
11:56:34,102 INFO [Soap12FaultOutInterceptor] class org.apache.cxf.binding.soap.interceptor.Soap12FaultOutInterceptor$Soap12FaultOutInterceptor Internalapplication/soap+xml
11:56:34,103 INFO [EligibilityInfo] Outbound Message
---------------------------
ID: 2
Response-Code: 500
Encoding: UTF-8
Content-Type: application/soap+xml
Headers: {}
Payload :
What I have to do in order to capture the SOAP fault erros in my custom interceptors.
The Best way is to implement the Fault listener and use org.slf4j.Logger to log the error message instead of using java logging.
It would be wise to override the LoggingInInterceptor and write ur custome interceptor to get the request payload.
public class CxfInputFaultInterceptor extends AbstractLoggingInterceptor {
private static final Logger LOG = LogUtils.getLogger(CxfInputFaultInterceptor.class);
public CxfInputFaultInterceptor() {
super(Phase.RECEIVE);
}
Step 1: cxf-beans.xml
<cxf:bus>
<cxf:inInterceptors>
<ref bean="cxfInputFaultInterceptor"/>
</cxf:inInterceptors>
<cxf:inFaultInterceptors>
<ref bean="cxfInputFaultInterceptor"/>
</cxf:inFaultInterceptors>
<cxf:properties>
<entry key="org.apache.cxf.logging.FaultListener">
<bean id="cxfFaultListener" class="pkg.common.ws.interceptor.CxfFaultListenerImpl" >
<property name="loggedUser" ref="loggedUser"/>
</bean>
</entry>
</cxf:properties>
</cxf:bus>
Step 2 : your listener which should implements org.apache.cxf.logging.FaultListener
import java.io.InputStream;
import org.apache.cxf.interceptor.LoggingMessage;
import org.apache.cxf.logging.FaultListener;
import org.apache.cxf.message.Message;
import org.apache.cxf.service.model.EndpointInfo;
import org.apache.cxf.service.model.InterfaceInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/*
* Listener to faults on the processing of messages by CXF intercepter chain. Here we override
* java.util.logging.Logger and use org.slf4j.Logger to print error to console.
*/
public class CxfFaultListenerImpl implements FaultListener{
private static final Logger logger = LoggerFactory.getLogger(CxfFaultListenerImpl.class);
private static final String NEWLINE="\n";
public boolean faultOccurred(final Exception exception,final String description,final Message message) {
createErrorLog(message);
logger.error(" --------------------------------------------------------------------------------------------------");
logger.error(" Stack Trace : ");
logger.error(" --------------------------------------------------------------------------------------------------");
logger.error(NEWLINE,exception);
logger.error(" --------------------------------------------------------------------------------------------------");
return true;
}
private void createErrorLog(final Message message){
final Message inMessage = message.getExchange().getInMessage();
final InputStream is = inMessage.getContent(InputStream.class);
final EndpointInfo endpoint = message.getExchange().getEndpoint().getEndpointInfo();
String logName=null;
if(endpoint!=null && endpoint.getService()!=null){
final String serviceName = endpoint.getService().getName().getLocalPart();
final InterfaceInfo iface = endpoint.getService().getInterface();
final String portName = endpoint.getName().getLocalPart();
final String portTypeName = iface.getName().getLocalPart();
logName = serviceName + "." + portName + "." + portTypeName;
}
final LoggingMessage buffer
= new LoggingMessage("Error occured on Service Call : "+NEWLINE +"----------------------------", logName);
final Integer responseCode = (Integer)message.get(Message.RESPONSE_CODE);
if (responseCode != null) {
buffer.getResponseCode().append(responseCode);
}
final String encoding = (String)message.get(Message.ENCODING);
if (encoding != null) {
buffer.getEncoding().append(encoding);
}
final String httpMethod = (String)message.get(Message.HTTP_REQUEST_METHOD);
if (httpMethod != null) {
buffer.getHttpMethod().append(httpMethod);
}
final String ct = (String)message.get(Message.CONTENT_TYPE);
if (ct != null) {
buffer.getContentType().append(ct);
}
final Object headers = message.get(Message.PROTOCOL_HEADERS);
if (headers != null) {
buffer.getHeader().append(headers);
}
final String uri = (String)message.get(Message.REQUEST_URL);
if (uri != null) {
buffer.getAddress().append(uri);
final String query = (String)message.get(Message.QUERY_STRING);
if (query != null) {
buffer.getAddress().append("?").append(query);
}
}
final String requestXml= is.toString();
if(requestXml !=null){
buffer.getMessage().append("LoggedIn User: ");
buffer.getMessage().append(getCurrentUsername()+NEWLINE);
buffer.getMessage().append("Request payload : "+NEWLINE);
buffer.getMessage().append(requestXml);
}else{
buffer.getMessage().append("LoggedIn User: ");
buffer.getMessage().append(getCurrentUsername()+NEWLINE);
buffer.getMessage().append("No inbound request message to append.");
}
logger.error(buffer.toString());
}
}
Hope that helps someone who just wants the stack trace and payload only when an error occurs on the service call and thus avoid huge log files.
So in my custom interceptor I write the following code:
Fault fault = new Fault(message.getContent(Exception.class));
Now this is in some legacy code that was throwing exceptions from Java and letting the framework convert it to a fault. I won't get into my feelings on that, but this will get you the fault that is generated.
Now if you are throwing a fault from your service method, do
Fault fault = message.getContect(Fault.class);
Hopefully this will help you get the answer to what you want. Make sure you register the interceptor like below
<jaxws:endpoint
id="fooService" implementor="com.bar.FooService" address="/FooServices">
<jaxws:outFaultInterceptors>
<ref class="com.bar.interceptor.DbLogOutInterceptor"/>
</jaxws:outFaultInterceptors>
</jaxws:endpoint>
<jaxws:endpoint
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With