Search code examples
javaspringspring-ws

Spring: Logging outgoing HTTP requests


I am trying to log all the outgoing Http requests in my spring based web application. Is there is interceptor for this purpose? I want to log all outgoing the contents and headers before it leaves the application. I am using spring-ws to send SOAP requests. So basically, I want to log not only the SOAP request xml (as mentioned here How can I make Spring WebServices log all SOAP requests?) but the http request as a whole.


Solution

  • Intercept the request/response using a ClientInterceptor on the WebServiceGatewaySupport:

    // soapClient extends WebServiceGatewaySupport
    soapClient.setInterceptors(new ClientInterceptor[]{new ClientInterceptor() {
            @Override
            public boolean handleRequest(MessageContext messageContext) throws WebServiceClientException {
                ByteArrayOutputStream os = new ByteArrayOutputStream();
                try {
                    messageContext.getRequest().writeTo(os);
                } catch (IOException e) {
                    throw new WebServiceIOException(e.getMessage(), e);
                }
    
                String request = new String(os.toByteArray());
                logger.trace("Request Envelope: " + request);
                return true;
            }
    
            @Override
            public boolean handleResponse(MessageContext messageContext) throws WebServiceClientException {
                ByteArrayOutputStream os = new ByteArrayOutputStream();
                try {
                    messageContext.getResponse().writeTo(os);
                } catch (IOException e) {
                    throw new WebServiceIOException(e.getMessage(), e);
                }
    
                String response = new String(os.toByteArray());
                logger.trace("Response Envelope: " + response);
                return true;
            }
            ...
    

    To get the headers as well you need an instance of TransportOutputStream. Unfortunately the class is abstract, so you need to subclass is. Here's how it might look:

    class ByteArrayTransportOutputStream extends TransportOutputStream {
    
        private ByteArrayOutputStream outputStream;
    
        @Override
        public void addHeader(String name, String value) throws IOException {
            createOutputStream();
            String header = name + ": " + value + "\n";
            outputStream.write(header.getBytes());
        }
    
        public byte[] toByteArray() {
             return outputStream.toByteArray();
        }
    
        @Override
        protected OutputStream createOutputStream() throws IOException {
            if (outputStream == null) {
                outputStream = new ByteArrayOutputStream();
            }
            return outputStream;
        }
    }