ChatGPT解决这个技术问题 Extra ChatGPT

How can I make Spring WebServices log all SOAP requests?

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.


A
Arpit Aggarwal

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

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
J
Jonas Geiregat

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


I can't find these classes in spring-ws 1.5.9
They aren't classes, they are categories that are logged to. See documentation at static.springsource.org/spring-ws/site/reference/html/…
PayloadLoggingInterceptor might also be helpful. Original poster added a link to it.
I would think so. Try it out and let us know!
Just a bit more concise syntax:
a
aram063

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

Obviously, that should be added to your log4j.properties file.
R
Rman

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.


Finally an answer that isn't using hard coded property files or spring XML!
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.
E
E.L.

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

This worked for me. Thanks. Does anybody know how to pretty print the SOAP in the logs?
S
Shanaka Jayalath

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

To log all server-side messages: log4j.logger.org.springframework.ws.server.MessageTracing=DEBUG 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


S
Supun Sameera

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 http://www.wetfeetblog.com/servlet-filer-to-log-request-and-response-details-and-payload/431

inside the filter you can log as you wish


Link not valid anymore
n
naga sri sai
. . .
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 button. Include a link to this question if it helps provide context. - From Review
Anyways ...just call your method MySoapClient() before client call