50

I am using the Apache CXF Framework. Inside my client program, I need to log CXF SOAP Requests and SOAP Responses. When I used

JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setAddress(host);
factory.setServiceClass(MyService.class);
factory.getInInterceptors().add(new LoggingInInterceptor());
factory.getOutInterceptors().add(new LoggingOutInterceptor());

I got these SOAP Request and SOAP Responses in the console:

Nov 9, 2011 6:48:01 PM org.apache.cxf.interceptor.LoggingOutInterceptor$LoggingCallback onClose
INFO: Outbound Message
---------------------------
ID: 2
Encoding: UTF-8
Content-Type: text/xml
Headers: {}
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns4:MYResponse
--------------------------------------

But my actual requirement is, instead of printing them to the server console, I need to have them inside the log file.

When I used log4j directly as shown

log4j(factory.getInInterceptors().add(new LoggingInInterceptor()));
log4j(factory.getOutInterceptors().add(new LoggingOutInterceptor()));

It is only printing true and true inside the log file.

Could anybody please let me know how to configure this?

Sagar Zala
  • 4,854
  • 9
  • 34
  • 62
Pawan
  • 31,545
  • 102
  • 256
  • 434
  • The same problem was discussed here: http://stackoverflow.com/questions/4592422/logging-request-response-with-apache-cxf-as-xml/17962979#17962979 – Mike Jul 31 '13 at 06:27

11 Answers11

74

You need to create a file named org.apache.cxf.Logger (that is: org.apache.cxf file with Logger extension) under /META-INF/cxf/ with the following contents:

org.apache.cxf.common.logging.Log4jLogger

Reference: Using Log4j Instead of java.util.logging.

Also if you replace standard:

<cxf:bus>
  <cxf:features>
    <cxf:logging/>
  </cxf:features>
</cxf:bus>

with much more verbose:

<bean id="abstractLoggingInterceptor" abstract="true">
    <property name="prettyLogging" value="true"/>
</bean>
<bean id="loggingInInterceptor" class="org.apache.cxf.interceptor.LoggingInInterceptor" parent="abstractLoggingInterceptor"/>
<bean id="loggingOutInterceptor" class="org.apache.cxf.interceptor.LoggingOutInterceptor" parent="abstractLoggingInterceptor"/>

<cxf:bus>
    <cxf:inInterceptors>
        <ref bean="loggingInInterceptor"/>
    </cxf:inInterceptors>
    <cxf:outInterceptors>
        <ref bean="loggingOutInterceptor"/>
    </cxf:outInterceptors>
    <cxf:outFaultInterceptors>
        <ref bean="loggingOutInterceptor"/>
    </cxf:outFaultInterceptors>
    <cxf:inFaultInterceptors>
        <ref bean="loggingInInterceptor"/>
    </cxf:inFaultInterceptors>
</cxf:bus>

Apache CXF will pretty print XML messages formatting them with proper indentation and line breaks. Very useful. More about it here.

Łukasz K
  • 562
  • 6
  • 10
Tomasz Nurkiewicz
  • 334,321
  • 69
  • 703
  • 674
  • Hi thomas , currently under META-INF folder , i have a file named MANIFEST.MF . Do you mean to add a cxf folder under META-INF ?? and please tell me how to create this file org.apache.cxf.Logger?? – Pawan Nov 09 '11 at 14:00
  • Yes, create `/cxf` folder in `/META-INF` and place a file named `org.apache.cxf` file with `Logger` extension there. Also see my updates. – Tomasz Nurkiewicz Nov 09 '11 at 14:13
  • please see the image http://tinypic.com/view.php?pic=adouue&s=5 , i have created the folders – Pawan Nov 09 '11 at 14:17
  • Just one staright question , you mean to create a folder struture as META-INF\cxf\org\apache\cxf\Logger , this is what you mean ?? – Pawan Nov 09 '11 at 14:24
  • 2
    The **file** must be named `org.apache.cxf` with `Logger` extension. As far as I can see you have created a file `\META-INF\cxf\org\apache\cxf\Logger.class` rather than `\META-INF\cxf\org.apache.cxf.Logger`. I have never said you need to create a directory structure of `\org\apache\cxf`. This is the file name (awkward, I must admit). – Tomasz Nurkiewicz Nov 09 '11 at 14:26
  • I dont know i should you this or not , but still , where can i find this file org.apache.cxf.Logger , because i am seeing files as org\apache\log4j – Pawan Nov 09 '11 at 14:33
  • 2
    OK, have a look at [Using Log4j Instead of java.util.logging](http://cxf.apache.org/docs/debugging-and-logging.html#DebuggingandLogging-UsingLog4jInsteadofjava.util.logging), this is really a matter of creating a one-line file in your project... – Tomasz Nurkiewicz Nov 09 '11 at 14:37
  • Thanks for the link , it helped get started , i have downloaded Log4jLogger from cxf jar . After creating the directory structure and pasting the file , Do i need to configure anything inside log4j.properties file ?? – Pawan Nov 09 '11 at 15:01
  • If nothing appears now on the console then yes, you need to configure `log4j.properties` file. But this is beyond the scope of this question. – Tomasz Nurkiewicz Nov 09 '11 at 15:06
  • I have already configured log4j , Actually , my other log debug startements are coming , but not this . any idea ?? – Pawan Nov 09 '11 at 15:07
  • 6
    Make sure `org.apache.cxf` logger is set to `ALL` or `DEBUG`. – Tomasz Nurkiewicz Nov 09 '11 at 15:13
  • I do not have `org.apache.cxf.Logger` file anywhere. And having only `` in my bean config prints messages with formatting (but I know that answer is 2 years old). – Betlista Oct 10 '13 at 13:03
  • See for additional pretty-printing options: https://github.com/greenbird/xml-formatter-components/tree/master/cxf – ThomasRS Apr 30 '15 at 10:59
19

Another easy way is to set the logger like this- ensure that you do it before you load the cxf web service related classes. You can use it in some static blocks.

YourClientConstructor() {

  LogUtils.setLoggerClass(org.apache.cxf.common.logging.Log4jLogger.class);

  URL wsdlURL = YOurURL;//

  //create the service
  YourService = new YourService(wsdlURL, SERVICE_NAME);
  port = yourService.getServicePort(); 

  Client client = ClientProxy.getClient(port);
  client.getInInterceptors().add(new LoggingInInterceptor());
  client.getOutInterceptors().add(new LoggingOutInterceptor());
}

Then the inbound and outbound messages will be printed to Log4j file instead of the console. Make sure your log4j is configured properly

Radek Postołowicz
  • 4,506
  • 2
  • 30
  • 47
Vins
  • 1,931
  • 16
  • 14
14

Simplest way to achieve pretty logging in Preethi Jain szenario:

LoggingInInterceptor loggingInInterceptor = new LoggingInInterceptor();
loggingInInterceptor.setPrettyLogging(true);
LoggingOutInterceptor loggingOutInterceptor = new LoggingOutInterceptor();
loggingOutInterceptor.setPrettyLogging(true);
factory.getInInterceptors().add(loggingInInterceptor);
factory.getOutInterceptors().add(loggingOutInterceptor);
Radek Postołowicz
  • 4,506
  • 2
  • 30
  • 47
dpa
  • 141
  • 1
  • 4
5

In your spring context configuring below would log the request and response soap messsage.

<bean id="loggingFeature" class="org.apache.cxf.feature.LoggingFeature">
    <property name="prettyLogging" value="true" />
</bean>

<cxf:bus>
    <cxf:features>
        <ref bean="loggingFeature" />
    </cxf:features>
</cxf:bus>
Manjunath
  • 141
  • 2
  • 7
5

This worked for me.

Setup log4j as normal. Then use this code:

    // LOGGING 
    LoggingOutInterceptor loi = new LoggingOutInterceptor(); 
    loi.setPrettyLogging(true); 
    LoggingInInterceptor lii = new LoggingInInterceptor(); 
    lii.setPrettyLogging(true); 

    org.apache.cxf.endpoint.Client client = org.apache.cxf.frontend.ClientProxy.getClient(isalesService); 
    org.apache.cxf.endpoint.Endpoint cxfEndpoint = client.getEndpoint(); 

    cxfEndpoint.getOutInterceptors().add(loi); 
    cxfEndpoint.getInInterceptors().add(lii);
Al Grant
  • 2,102
  • 1
  • 26
  • 49
2

Procedure for global setting of client/server logging of SOAP/REST requests/ responses with log4j logger. This way you set up logging for the whole application without having to change the code, war, jar files, etc.

  1. install file cxf-rt-features-logging-X.Y.Z.jar to your CLASS_PATH

  2. create file (path for example: /opt/cxf/cxf-logging.xml):

    <?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:cxf="http://cxf.apache.org/core" 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-2.0.xsd">
    <cxf:bus>
     <cxf:features>
     <bean class="org.apache.cxf.ext.logging.LoggingFeature">
     <property name="prettyLogging" value="true"/>
     </bean>
     </cxf:features>
     </cxf:bus>
     </beans>
    
  3. set logging for org.apache.cxf (log4j 1.x) log4j.logger.org.apache.cxf=INFO,YOUR_APPENDER

  4. set these properties on java start-up

java ... -Dcxf.config.file.url=file:///opt/cxf/cxf-logging.xml -Dorg.apache.cxf.Logger=org.apache.cxf.common.logging.Log4jLogger -Dcom.sun.xml.ws.transport.http.client.HttpTransportPipe.dump=true -Dcom.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.dump=true -Dcom.sun.xml.ws.transport.http.HttpAdapter.dump=true -Dcom.sun.xml.internal.ws.transport.http.HttpAdapter.dump=true ...

I don't know why, but it is necessary to set variables as well com.sun.xml.*

Richard Kotal
  • 179
  • 1
  • 8
1

When configuring log4j.properties, putting org.apache.cxf logging level to INFO is enough to see the plain SOAP messages:

log4j.logger.org.apache.cxf=INFO

DEBUG is too verbose.

dpinya
  • 542
  • 7
  • 16
  • Setting org.apache to TRACE was first thing I tried and SOAP messages are not logged. Only thing what is loaded is something like `TRACE [http-8080-1] [org.apache.cxf.service.invoker.AbstractInvoker] Invoking method ...` but this is too late, because when parsing fails request is not logged at all... – Betlista Oct 10 '13 at 12:25
1

cxf.xml

<cxf:bus>
    <cxf:ininterceptors>
        <ref bean="loggingInInterceptor" />
    </cxf:ininterceptors>
    <cxf:outinterceptors>
        <ref bean="logOutInterceptor" />
    </cxf:outinterceptors>
</cxf:bus>

org.apache.cxf.Logger

org.apache.cxf.common.logging.Log4jLogger

Please check screenshot here

Radek Postołowicz
  • 4,506
  • 2
  • 30
  • 47
Jose
  • 11
  • 1
1

Try this code:

EndpointImpl impl = (EndpointImpl)Endpoint.publish(address, implementor);
    impl.getServer().getEndpoint().getInInterceptors().add(new LoggingInInterceptor());
    impl.getServer().getEndpoint().getOutInterceptors().add(new LoggingOutInterceptor());

Inside the logback.xml you need to put the interface name for webservice:

<appender name="FILE" class="ch.qos.logback.classic.sift.SiftingAppender">
    <discriminator
        class="com.progressoft.ecc.integration.logging.ThreadNameDiscriminator">
        <key>threadName</key>
        <defaultValue>unknown</defaultValue>
    </discriminator>
    <filter class="ch.qos.logback.core.filter.EvaluatorFilter">
        <evaluator>
            <expression>logger.contains("InterfaceWebServiceSoap")</expression>
        </evaluator>
        <OnMismatch>DENY</OnMismatch>
        <OnMatch>NEUTRAL</OnMatch>
    </filter>
    <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
        <level>TRACE</level>
    </filter>
    <sift>
        <appender name="FILE-${threadName}"
            class="ch.qos.logback.core.rolling.RollingFileAppender">
            <File>${LOGGING_PATH}/${threadName}.log</File>
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <FileNamePattern>${ARCHIVING_PATH}/%d{yyyy-MM-dd}.${threadName}%i.log.zip
                </FileNamePattern>
                <MaxHistory>30</MaxHistory>
                <TimeBasedFileNamingAndTriggeringPolicy
                    class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                    <MaxFileSize>50MB</MaxFileSize>
                </TimeBasedFileNamingAndTriggeringPolicy>
            </rollingPolicy>
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <Pattern>%date{dd-MM-yyyy HH:mm:ss.SSS} | %5level | %-60([%logger{53}:%line]): %msg %ex{full} %n</Pattern>
            </encoder>
        </appender>
    </sift>
</appender>

<root>
    <level value="ALL" />
    <appender-ref ref="FILE" />
</root>
Radek Postołowicz
  • 4,506
  • 2
  • 30
  • 47
1

In case somebody wants to do this, using Play Framework (and using LogBack http://logback.qos.ch/), then you can configure the application-logger.xml with this line:

 <logger name="org.apache.cxf" level="DEBUG"/>

For me, it did the trick ;)

1

Old configuration options will not work for those who use Apache CXF version 3.1 or later. Check here. In my case, I used apache cxf 3.4.2 in spring boot (version 2.4.2) project.

To print logging properly, you need to add feature in your Bus object (in my case, it was SpringBus) like following -

  1. Create LoggingFeature -
LoggingFeature loggingFeature = new LoggingFeature();
loggingFeature.setPrettyLogging(true);
  1. Create/autowire Bus object, then set feature to bus
bus.setFeatures(Arrays.asList(loggingFeature));

In case if you need to check how will create bus in spring boot project, please check here.

arifng
  • 726
  • 1
  • 12
  • 22