Total Pageviews

Sunday 9 December 2012

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


Before going in details of logging apache-cxf soap request and response using log4j, lets discuss the concept of Bus in apache-cxf.
Bus: It's a main component of entire cxf architecture and embodies Spring based configuration files(usually called cxf.xml). It acts as an interceptor provider, which will be added to the respective inbound and outbound message and fault interceptor chains for all client and server endpoints created on the bus (in its context). These configurations are loaded on servlet initialization through SpringBusFactory. And this files defines a common context for all the endpoints. The SpringBusFactory searches for all bean configuration files in the META-INF/cxf directories on classpath, and builds an application context from them. The bean configuration files included in the application context construction are:
  • META-INF/cxf/cxf.xml (e.g., in cxf-rt-core only)
  • META-INF/cxf/cxf-extension.xml (e.g. in cxf-rt-bindings-soap)
  • META-INF/cxf/cxf-property-editors.xml (e.g. in cxf-rt-transports-http)
Enabling inbound and outbound soap messages in Apache-CXF
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 could be easily configured/enabled as:
<!-- Enabling Interceptors -->
<bean id="logInbound" class="org.apache.cxf.interceptor.LoggingInInterceptor"/>
<bean id="logOutbound" class="org.apache.cxf.interceptor.LoggingOutInterceptor"/>
<!-- Begin: 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>
<!-- End: Enabling Interceptors -->
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 Log4J logging instead. In the org.apache.cxf.common.logging package of the CXF api, there used to be a Log4JLogger class, which extends org.apache.cxf.common.logging.AbstractDelegatingLogger class, and could be used for delegating logging to a Log4J implementation.

Configuring Log4J in CXF

In the same package as Log4JLogger, there exists a class LogUtils, which CXF uses to obtain logger instances from. This class contains a static final string KEY, which is set to the value org.apache.cxf.Logger. And CXF uses this value, to bootstrap which logging API to use.
So, what all we have to do is to over ride this key value. And this could be achieved in any of the following ways:
  1. 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(Log4jLogger in our case) class, with no comments, on a single line as: org.apache.cxf.common.logging.Log4jLogger
(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.Log4jLogger (content of org.apache.cxf.Logger) )
  1. Supply a -Dorg.apache.cxf.Logger=org.apache.cxf.common.logging.Log4jLogger system property to code, when executing.
Following Spring Web Context Configuration file(spring-servlet.xml) could be considered for reference:
<?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 "
>
<!-- log 4j initialization -->
<bean id="log4jInitialization" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"
p:targetClass="org.springframework.util.Log4jConfigurer" p:targetMethod="initLogging"
p:arguments="${log4j.file.loc}"
/>
<!-- 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.

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