71

I need all SOAP requests logged in the CommonLogFormat (see http://en.wikipedia.org/wiki/Common_Log_Format), plus the duration (the amount of time it takes to process the request).

What's the best way to do this? It looks like it's possible to configure log4j for Spring WebServices but will it log all the values I'm interested in? http://pijava.wordpress.com/2009/12/04/spring-webservice-soap-requestresponse-logging-with-log4j/

EDIT: We're actually using SLF4J, not Log4j. Also, it looks like it's possible to do this by configuring the PayloadLoggingInterceptor: http://static.springsource.org/spring-ws/site/reference/html/server.html#server-endpoint-interceptor

But I am not sure where the log messages will go. I added that interceptor to our interceptors and I don't see any log messages.

Arpit Aggarwal
  • 27,626
  • 16
  • 90
  • 108
Nate Reed
  • 6,761
  • 12
  • 53
  • 67

9 Answers9

100

For Spring Boot project adding below in application.properties worked for me:

logging.level.org.springframework.web=DEBUG
logging.level.org.springframework.ws.client.MessageTracing.sent=DEBUG
logging.level.org.springframework.ws.server.MessageTracing.sent=DEBUG
logging.level.org.springframework.ws.client.MessageTracing.received=TRACE
logging.level.org.springframework.ws.server.MessageTracing.received=TRACE
Arpit Aggarwal
  • 27,626
  • 16
  • 90
  • 108
  • 1
    Nice. Initially I was confused because Sent code flow was only using DEBUG and not TRACE so it did not print the complete SOAP message details for Request. But then I realised that the received message is in TRACE mode so it displays both the response and also the complete request message body to which the response is about – firstpostcommenter Nov 04 '20 at 15:16
57

You can use this to log the raw payload of incoming and outgoing web service calls.. I'm not sure how to log how long the webservice communication took.

   <!-- Spring Web Service Payload Logging-->
   <logger name="org.springframework.ws.client.MessageTracing">
    <level value="TRACE"/> 
   </logger>
   <logger name="org.springframework.ws.server.MessageTracing">
    <level value="TRACE"/> 
   </logger>

Additional details can be found at http://static.springsource.org/spring-ws/site/reference/html/common.html#logging

Jonas Geiregat
  • 5,214
  • 4
  • 41
  • 60
JustinKSU
  • 4,875
  • 2
  • 29
  • 51
  • I can't find these classes in spring-ws 1.5.9 – wytten Nov 15 '12 at 20:11
  • 6
    They aren't classes, they are categories that are logged to. See documentation at http://static.springsource.org/spring-ws/site/reference/html/common.html#logging – JustinKSU Nov 15 '12 at 21:54
  • PayloadLoggingInterceptor might also be helpful. Original poster added a link to it. – JustinKSU Nov 15 '12 at 22:03
  • I would think so. Try it out and let us know! – JustinKSU Nov 05 '15 at 15:40
  • 1
    Just a bit more concise syntax: – Ondrej Burkert Aug 18 '16 at 06:09
  • this just log message with http status 200 (OK). Is these some way to log message which end with other status like 400 ? – hudi Apr 27 '17 at 07:18
  • @hudi it depends. Some things logged like 404 may not make it down to the Spring level. It's a 500 error thrown by the application, I think it should get logged. I would suggest asking a separate question with a little more detail. – JustinKSU Apr 27 '17 at 13:44
  • I've added and now it logs to the file as well as console. How to make it log to the file only? – Mukhamedali Zhadigerov Aug 25 '19 at 17:33
  • Below is where the logger's set. `protected static final Log sentMessageTracingLogger = LogFactory.getLog("org.springframework.ws.client.MessageTracing.sent");` `protected static final Log receivedMessageTracingLogger = LogFactory.getLog("org.springframework.ws.client.MessageTracing.received");` – Olgun Kaya Feb 11 '20 at 08:28
30

If you have your own Logging system the following interceptor can be an alternative to log the SOAP messages.

    setInterceptors(new ClientInterceptor[]{new ClientInterceptor() {

        @Override
        public boolean handleResponse(MessageContext messageContext) throws WebServiceClientException {
            System.out.println("### SOAP RESPONSE ###");
            try {
                ByteArrayOutputStream buffer = new ByteArrayOutputStream();
                messageContext.getResponse().writeTo(buffer);
                String payload = buffer.toString(java.nio.charset.StandardCharsets.UTF_8.name());
                System.out.println(payload);
            } catch (IOException e) {
                throw new WebServiceClientException("Can not write the SOAP response into the out stream", e) {
                    private static final long serialVersionUID = -7118480620416458069L;
                };
            }

            return true;
        }

        @Override
        public boolean handleRequest(MessageContext messageContext) throws WebServiceClientException {

            System.out.println("### SOAP REQUEST ###");
            try {
                ByteArrayOutputStream buffer = new ByteArrayOutputStream();
                messageContext.getRequest().writeTo(buffer);
                String payload = buffer.toString(java.nio.charset.StandardCharsets.UTF_8.name());
                System.out.println(payload);
            } catch (IOException e) {
                throw new WebServiceClientException("Can not write the SOAP request into the out stream", e) {
                    private static final long serialVersionUID = -7118480620416458069L;
                };
            }

            return true;
        }

        @Override
        public boolean handleFault(MessageContext messageContext) throws WebServiceClientException {
            System.out.println("### SOAP FAULT ###");
            try {
                ByteArrayOutputStream buffer = new ByteArrayOutputStream();
                messageContext.getResponse().writeTo(buffer);
                String payload = buffer.toString(java.nio.charset.StandardCharsets.UTF_8.name());
                System.out.println(payload);
            } catch (IOException e) {
                throw new WebServiceClientException("Can not write the SOAP fault into the out stream", e) {
                    private static final long serialVersionUID = 3538336091916808141L;
                };
            }

            return true;
        }
    }});

In each handle method you can easily use payload to obtain raw soap messages.

Rman
  • 458
  • 4
  • 7
  • Finally an answer that isn't using hard coded property files or spring XML! – PeterS Sep 24 '19 at 08:06
  • 2
    Precisions, it could be obvious for some, but the method is exactly : `org.springframework.ws.client.core.support.WebServiceGatewaySupport#setInterceptors` and the implemented interface is `org.springframework.ws.client.support.interceptor.ClientInterceptor` for which you also need to implment an empty `afterCompletion` method. – pdem Aug 24 '21 at 09:38
25

This worked for me. It logs the request message sent and the response received. You could work out the total time taken from the log.

log4j.logger.org.springframework.ws.client.MessageTracing.sent=TRACE
log4j.logger.org.springframework.ws.client.MessageTracing.received=TRACE
aram063
  • 1,067
  • 13
  • 19
8

First, SLF4J is just a simple facade. It means you still need a logging framework(e.g. java.util.logging, logback, log4j).

Second, Spring-ws uses Commons Logging interface that is another simple facade like SLF4J.

Finally, you can use below setting to enable Spring-ws message logging functionality.

log4j.logger.org.springframework.ws.client.MessageTracing.sent=DEBUG
log4j.logger.org.springframework.ws.client.MessageTracing.received=TRACE

log4j.logger.org.springframework.ws.server.MessageTracing.sent=DEBUG
log4j.logger.org.springframework.ws.server.MessageTracing.received=TRACE
E.L.
  • 171
  • 2
  • 3
7

Include the following in the log4j.properties file...

  1. To log all server-side messages: log4j.logger.org.springframework.ws.server.MessageTracing=DEBUG
  2. To log all client-side messages: log4j.logger.org.springframework.ws.client.MessageTracing=TRACE

On the DEBUG level - only the payload root element is logged

On the TRACE level - the entire message content is logged

Lastly to log only the sent or received messages use the .sent or .received at the end of the configurations.

ex : log4j.logger.org.springframework.ws.server.MessageTracing.received=DEBUG logs the client-side received massages payload root element returning :

DEBUG WebServiceMessageReceiverHandlerAdapter:114 - Accepting incoming [org.springframework.ws.transport.http.HttpServletConnection@51ad62d9] to [http://localhost:8080/mock-platform/services]

For more info

1

Add a servlet filter to the spring ws (to move with org.springframework.web.servlet.DispatcherServlet) in web.xml

you can find a filter here https://web.archive.org/web/20160317123724/http://www.wetfeetblog.com/servlet-filer-to-log-request-and-response-details-and-payload/431

inside the filter you can log as you wish

Michał Stochmal
  • 5,895
  • 4
  • 36
  • 44
Supun Sameera
  • 2,683
  • 3
  • 17
  • 14
1
. . .
package com.example.Soap;

import org.springframework.ws.client.WebServiceClientException;
import org.springframework.ws.client.support.interceptor.ClientInterceptor;
import org.springframework.ws.context.MessageContext;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

public class LoggingVonfig  implements ClientInterceptor  {



        @Override
        public boolean handleResponse(MessageContext messageContext) throws WebServiceClientException {
            System.out.println("### SOAP RESPONSE ###");
            try {
                ByteArrayOutputStream buffer = new ByteArrayOutputStream();
                messageContext.getResponse().writeTo(buffer);
                String payload = buffer.toString(java.nio.charset.StandardCharsets.UTF_8.name());
                System.out.println(payload);
            } catch (IOException e) {
                throw new WebServiceClientException("Can not write the SOAP response into the out stream", e) {
                    private static final long serialVersionUID = -7118480620416458069L;
                };
            }

            return true;
        }

        @Override
        public boolean handleRequest(MessageContext messageContext) throws WebServiceClientException {

            System.out.println("### SOAP REQUEST ###");
            try {
                ByteArrayOutputStream buffer = new ByteArrayOutputStream();
                messageContext.getRequest().writeTo(buffer);
                String payload = buffer.toString(java.nio.charset.StandardCharsets.UTF_8.name());
                System.out.println(payload);
            } catch (IOException e) {
                throw new WebServiceClientException("Can not write the SOAP request into the out stream", e) {
                    private static final long serialVersionUID = -7118480620416458069L;
                };
            }

            return true;
        }

        @Override
        public boolean handleFault(MessageContext messageContext) throws WebServiceClientException {
            System.out.println("### SOAP FAULT ###");
            try {
                ByteArrayOutputStream buffer = new ByteArrayOutputStream();
                messageContext.getResponse().writeTo(buffer);
                String payload = buffer.toString(java.nio.charset.StandardCharsets.UTF_8.name());
                System.out.println(payload);
            } catch (IOException e) {
                throw new WebServiceClientException("Can not write the SOAP fault into the out stream", e) {
                    private static final long serialVersionUID = 3538336091916808141L;
                };
            }

            return true;
        }

    @Override
    public void afterCompletion(MessageContext messageContext, Exception e) throws WebServiceClientException {

    }

}

. . . 

This is logging Configuration class


. . . 
package com.example.Soap;

import com.example.Soap.com.example.Soap.Add;
import com.example.Soap.com.example.Soap.AddResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ws.client.core.support.WebServiceGatewaySupport;
import org.springframework.ws.client.support.interceptor.ClientInterceptor;
import org.springframework.ws.soap.client.core.SoapActionCallback;

public class CalculatorClient  extends WebServiceGatewaySupport {

    private static Logger log = LoggerFactory.getLogger(CalculatorClient.class);

    public com.example.Soap.com.example.Soap.AddResponse getaddition(com.example.Soap.com.example.Soap.Add addrequest){
        com.example.Soap.com.example.Soap.Add add = new com.example.Soap.com.example.Soap.Add();
        add.setIntB(addrequest.getIntB());
        add.setIntA(addrequest.getIntA());
        log.info("----------------------------------------------"+"Inbound Request"+"-----------------------");
        com.example.Soap.com.example.Soap.AddResponse addResponse = (com.example.Soap.com.example.Soap.AddResponse) getWebServiceTemplate().marshalSendAndReceive("http://www.dneonline.com/calculator.asmx?wsdl",add,new SoapActionCallback("http://tempuri.org/Add"));

        return addResponse;
    }
    public com.example.Soap.com.example.Soap.SubtractResponse getSubtract(com.example.Soap.com.example.Soap.Subtract subreq){
        com.example.Soap.com.example.Soap.Subtract subtract=new com.example.Soap.com.example.Soap.Subtract();
        subtract.setIntA(subreq.getIntA());
        subtract.setIntB(subreq.getIntB());
        com.example.Soap.com.example.Soap.SubtractResponse subtractResponse=(com.example.Soap.com.example.Soap.SubtractResponse) getWebServiceTemplate().marshalSendAndReceive("http://www.dneonline.com/calculator.asmx?wsdl",subtract,new SoapActionCallback("http://tempuri.org/Subtract"));
        return  subtractResponse;
    }
    public com.example.Soap.com.example.Soap.MultiplyResponse getMultiply(com.example.Soap.com.example.Soap.Multiply multiply)
    {
        com.example.Soap.com.example.Soap.Multiply multiply1=new com.example.Soap.com.example.Soap.Multiply();
        multiply1.setIntA(multiply.getIntA());
        multiply1.setIntB(multiply.getIntB());
        com.example.Soap.com.example.Soap.MultiplyResponse multiplyResponse=(com.example.Soap.com.example.Soap.MultiplyResponse) getWebServiceTemplate().marshalSendAndReceive("http://www.dneonline.com/calculator.asmx?wsdl",multiply1,new SoapActionCallback("http://tempuri.org/Multiply"));
        return  multiplyResponse;
    }
    public com.example.Soap.com.example.Soap.DivideResponse getDivide(com.example.Soap.com.example.Soap.Divide divide){
        com.example.Soap.com.example.Soap.Divide divide1=new com.example.Soap.com.example.Soap.Divide();
        divide1.setIntA(divide.getIntA());
        divide1.setIntB(divide.getIntB());
        com.example.Soap.com.example.Soap.DivideResponse divideResponse=(com.example.Soap.com.example.Soap.DivideResponse) getWebServiceTemplate().marshalSendAndReceive("http://www.dneonline.com/calculator.asmx?wsdl",divide1,new SoapActionCallback("http://tempuri.org/Divide"));
        return divideResponse;
    }

    public void MySoapClient() {
        this.setInterceptors(new ClientInterceptor[] { new LoggingVonfig() });

    }

}

. . . 
This is my client class

. . . 
package com.example.Soap;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.ws.client.core.WebServiceTemplate;

@Configuration
public class CalculatorConfig {

    @Bean
    public Jaxb2Marshaller marshaller(){
        Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
//        jaxb2Marshaller.setPackagesToScan("com.example.Soap.com.example.Soap");

        jaxb2Marshaller.setContextPath("com.example.Soap.com.example.Soap"); // this will serilaize and unserialize it
        return jaxb2Marshaller;
    }

    @Bean
    public CalculatorClient calculatorClient(Jaxb2Marshaller jaxb2Marshaller){
        WebServiceTemplate wsTemplate = new WebServiceTemplate();
        CalculatorClient calculatorClient = new CalculatorClient();
        calculatorClient.setDefaultUri("http://www.dneonline.com");
        calculatorClient.setMarshaller(jaxb2Marshaller);
        calculatorClient.setUnmarshaller(jaxb2Marshaller);


        return calculatorClient;
    }


}

. . .

configuration file

. . . 

package com.example.Soap;

import com.example.Soap.com.example.Soap.Add;
import com.example.Soap.com.example.Soap.AddResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
public class SoapApplication {

    @Autowired
    private CalculatorClient calculatorClient;

    @PostMapping(value = "/add")
    public com.example.Soap.com.example.Soap.AddResponse addelements(@RequestBody com.example.Soap.com.example.Soap.Add add){
        return calculatorClient.getaddition(add);
    }
    @PostMapping(value = "/subtract")
    public com.example.Soap.com.example.Soap.SubtractResponse addelements(@RequestBody com.example.Soap.com.example.Soap.Subtract subreq){
        return calculatorClient.getSubtract(subreq);
    }
    @PostMapping(value = "/multiply")
    public com.example.Soap.com.example.Soap.MultiplyResponse addelements(@RequestBody com.example.Soap.com.example.Soap.Multiply multiply){
        return  calculatorClient.getMultiply(multiply);
    }
    @PostMapping(value = "/divide")
    public com.example.Soap.com.example.Soap.DivideResponse addelements(@RequestBody com.example.Soap.com.example.Soap.Divide divide){
        return calculatorClient.getDivide(divide);
    }

    public static void main(String[] args) {
        SpringApplication.run(SoapApplication.class, args);
    }

}
.  . .

These are my classes but still, I can't able to log all requests and responses in my console. I'm not getting where I have done wrong. I implemented Client configuration too.

  • If you have a new question, please ask it by clicking the [Ask Question](https://stackoverflow.com/questions/ask) button. Include a link to this question if it helps provide context. - [From Review](/review/late-answers/30402983) – Procrastinator Nov 22 '21 at 13:54
  • Anyways ...just call your method MySoapClient() before client call – Anurag Yadav Apr 19 '22 at 18:56
1

An easiest way is adding attribute into your security config (securityPolicy.xml):

<xwss:SecurityConfiguration xmlns:xwss="http://java.sun.com/xml/ns/xwss/config" dumpMessages="true">

No additional settings inside application.properties required.

Check that link to understanding security policy file.