Log incoming and outgoing SOAP messages

Often it is nice to see what requests are sent to the service and what the anwer is. Even when the request is not a valid SOAP request. This can be done with interceptors and annotating the service

Annotations

@InInterceptors(interceptors = { "com.company.interceptors.LoggingInInterceptor" })
@OutInterceptors(interceptors = { "com.company.interceptors.LoggingOutInterceptor" })

LoggingInInterceptor

public class LoggingInInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
    private static final int MAXINLOGSIZE = 5000;

    public LoggingInInterceptor() {
        super(Phase.RECEIVE);
        log.debug("linking to {}", getPhase());
    }

    @Override
    public void handleMessage(SoapMessage message) throws Fault {
        // See "org.apache.cxf.interceptor.LoggingInInterceptor" for an example
        
        try {
            // use the appropriate input stream and restore it later
            InputStream is = message.getContent(InputStream.class);
            InputStream bis = is instanceof DelegatingInputStream?((DelegatingInputStream)is).getInputStream():is;

            // only copy up to the limit since that's all we need to log we can stream the rest
            CachedOutputStream cos = new CachedOutputStream();
            IOUtils.copyAtLeast(bis, cos, MAXINLOGSIZE);
            cos.flush();
            bis = new SequenceInputStream(cos.getInputStream(), bis);

            // restore the delegating input stream or the input stream
            if (is instanceof DelegatingInputStream) {
                ((DelegatingInputStream)is).setInputStream(bis);
            } else {
                message.setContent(InputStream.class, bis);
            }
            
            String body = IOUtils.toString(cos.getInputStream());
            log.debug("request: '{}'", body);
            cos.close();
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
    }
}

LoggingOutInterceptor

public class LoggingOutInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
    public LoggingOutInterceptor() {
        super(Phase.PRE_STREAM);
    }

    @Override
    public void handleMessage(SoapMessage message) throws Fault {
        OutputStream os = message.getContent(OutputStream.class);
        CacheAndWriteOutputStream cwos = new CacheAndWriteOutputStream(os);
        message.setContent(OutputStream.class, cwos);
        cwos.registerCallback(new LoggingOutCallBack());
    }

    class LoggingOutCallBack implements CachedOutputStreamCallback {
        // See "org.apache.cxf.interceptor.LoggingOutInterceptor" for an example
        
        private static final int MAXOUTLOGSIZE = 5000;

        @Override
        public void onClose(CachedOutputStream cos) {
            try {
                StringBuilder builder = new StringBuilder();
                cos.writeCacheTo(builder);
                String body = builder.toString();
                body = StringUtils.left(body, MAXOUTLOGSIZE);
                log.debug("response: '{}'", body);
                
                //empty out the cache
                cos.lockOutputStream();
                cos.resetOut(null, false);
            } catch (IOException e) {
                log.error(e.getMessage());
            }
        }

        @Override
        public void onFlush(CachedOutputStream cos) {}
    }
}