Wednesday, February 12, 2014

Logging request/response messages with Apache CXF

Today I would llike to give a short introduction in How-To log request/response messages of your Apache CXF JAX-WS service.

I assume that you know how to setup a JAX WS service with Apache CXF. The final steps to make logging of the request/response message happen are:

(1) Add LoggingInInterceptor/LoggingOutInterceptor to your Server/Client class

You can plug in provided LoggingInterceptors that will log the request/response messages. The following snippet of a Spring Bean Server configuration shows how to do this:

    @Bean
    org.apache.cxf.endpoint.Server calculatorService() {
        JaxWsServerFactoryBean svrFactory = new JaxWsServerFactoryBean();
        svrFactory.setServiceClass(Calculator.class);
        svrFactory.setAddress("http://localhost:9000/CalculatorService");
        svrFactory.setServiceBean(new CalculatorImpl());
        svrFactory.getInInterceptors().add(new LoggingInInterceptor());
        svrFactory.getOutInterceptors().add(new LoggingOutInterceptor());

        return svrFactory.create();
    }


(2) tell Apache CXF to use the logging framework of your choice

Apache CXF by default uses java.util.logging. That is propably - in most cases - not the framework that you use in your application. You have to change this, which can be easily done by setting the system property

    org.apache.cxf.Logger

E.g. to change the logging framework to log4j you need to set the system property like this (for example as '-D' java option):

    -Dorg.apache.cxf.Logger=org.apache.cxf.common.logging.Log4jLogger

(3) configure the logging

The most hidden information for me was to find out which logger I need to configure for the logging. A small notice on the Apache CXF 2.5 migration guide gave the needed information
"The Logging interceptors now log using service specific categories/loggers instead of just LoggingInInterceptor/LoggingOutInterceptor. The names of the logger that is used is org.apache.cxf.services.ServiceName.PortName.PortTypeName. This allows the user to configure specific per service filters and formatters in their logging configuration."
Given this information and the WSDL parts of your service like, e.g.

 ....
    <wsdl:portType name="calculator">
 ....
    <wsdl:service name="CalculatorService">
        <wsdl:port binding="tns:CalculatorServiceSoapBinding" name="calculatorPort">
            <soap:address location="http://localhost:9000/CalculatorService"/>
        </wsdl:port>
    </wsdl:service>
....

your logger configuration in log4j would look like this:

    <logger name="org.apache.cxf.services.CalculatorService.calculatorPort.calculator">
        <level value="info" />
        <appender-ref ref="<some appender>" />
    </logger>



All these things done you should see the request/response messages like this ;-)



2 comments:

  1. Nice presentation. I've seen other places (including the Apache CXF site: http://cxf.apache.org/docs/configuration.html) that state how simple it is to log the requests. And it definitely is if you are not using message-level encryption. If you are (I am), then using this approach will only show the encrypted payload and not the decrypted message.

    Fortunately, there are some approaches to consider when getting over that hurdle:

    http://gleefultomatoes.blogspot.com/2014/05/getting-decrypted-payload-from-cxf.html

    ReplyDelete
  2. Nice post. I've recently put up a more feature-rich logger feature for CXF you might be interested in: https://github.com/greenbird/xml-formatter-components/tree/master/cxf

    ReplyDelete