Total Pageviews

Wednesday 23 October 2013

Spring : Logging SOAP Request and Response from a Apache – Cxf client using Slf4j



Let's start with the three step process of delegating cxf logging through Slf4j:

1. Enable inbound and outbound soap messages of Apache-CXF in Spring Context

For logging soap messages we need to configure this cxf bus for inbound and outbound messages as by default, it contributes no interceptors(implies no logging of SOAP messages) but can be easily configured/enabled as:

<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:cxf="http://cxf.apache.org/core"
xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/util
http://www.springframework.org/schema/cache/spring-cache.xsd
http://www.springframework.org/schema/util/spring-util-2.0.xsd "
>
<!-- Enabling Interceptors -->
<bean id="logInbound" class="org.apache.cxf.interceptor.LoggingInInterceptor"/>
<bean id="logOutbound" class="org.apache.cxf.interceptor.LoggingOutInterceptor"/>
 

<!-- Enabling message logging using custom CXF bean elements -->
<cxf:bus>
    <cxf:inInterceptors>
            <ref bean="logInbound"/>
    </cxf:inInterceptors>
    <cxf:outInterceptors>
            <ref bean="logOutbound"/>
     </cxf:outInterceptors>
     <cxf:outFaultInterceptors>
            <ref bean="logOutbound"/>
     </cxf:outFaultInterceptors>
     <cxf:inFaultInterceptors>
            <ref bean="logInbound"/>
     </cxf:inFaultInterceptors>
</cxf:bus>
</beans>

Note: The configurable properties of the bus are defined in the bus configuration schema http://cxf.apache.org/schemas/core.xsd. Be sure to include the namespace - URI pair for this schema in the schemaLocation attribute of the <beans> element.



2. Configure CXF for using Slf4j

CXF by default uses Java SE Logging API for both client- and server-side logging of SOAP requests and responses, which results in logging of SOAP messages in server logs (i.e.catalina.out for tomcat) but we can configure CXF to use Slf4j logging instead.

In the org.apache.cxf.common.logging package of the CXF api, there used to be a Slf4jLogger class that extends org.apache.cxf.common.logging.AbstractDelegatingLogger class, and can be used for delegating logging to a Slf4j API implementations i.e. log4j, logback etc.

This is achieved through the use of configuration files. There are two options to bootstrapping CXF logging and each is listed below:

Create a file, in the classpath, named META-INF/cxf/org.apache.cxf.Logger. This file should contain the fully-qualified name of the logging(Slf4jLogger in our case) class, with no comments, on a single line as: org.apache.cxf.common.logging.Slf4jLogger

Hint: To achieve it create the following directory structure, form its jar with any name you like and then put it in lib directory of your project with other jars: |-META-INF (directory)
   |-cxf (directory)
       |- org.apache.cxf.Logger (file: with name as specified, no extention at all)
         |-org.apache.cxf.common.logging.Slf4jLogger (content of org.apache.cxf.Logger file)

or
Supply a -Dorg.apache.cxf.Logger=org.apache.cxf.common.logging.Slf4jLogger system property to code, when executing.

3. Define Custom configuration location for logback.xml file

As Spring does not provide any convenience class that features simple methods for custom logback configuration as it provides for Log4j (org.springframework.util.Log4jConfigurer)  for defining the custom configuration location or a refresh interval. Hence, therefore, we need to explicitly define a logback configuration listener and  logbackConfigLocation as context parameter in our applications web.xml as:

<listener>
        <listener-class>ch.qos.logback.ext.spring.web.LogbackConfigListener</listener-class>
</listener>
<context-param>
       <param-name>logbackConfigLocation</param-name>
       <param-value>/WEB-INF/conf/logback.xml</param-value>
</context-param>

Now that we are done with all the prerequisites, Apache cxf will now be delegating all its logs to Slf4j rather than to default Java SE logging.

But as Slf4j is simply a logging facade API not really a logging implementation, instead it's an abstraction layer, and hence required to be plugged in with any of its implementation such as logback (log4j or java.util.logging are also possible) which natively implements the Slf4j API. And the same can be achieved for logback implementation by merely adding following jars in your applications class path:

slf4j-api-<version>.jar
logback-classic-<version> .jar
logback-core-<version>.jar
logback-ext-spring-<version>.jar

And more on regarding slf4j dependencies can be read from SLF4J Manual.

Spring : Logging SOAP Request and Response from a Apache – Cxf client using log4j