CXF Fault拦截器:记录有用的信息

时间:2012-06-29 15:39:22

标签: cxf soapfault

我想在出现故障时记录一些信息。 特别是我想记录联系服务器的客户端的IP地址和端口,如果安全性处于活动状态,则记录用户名,如果可能,还记录传入消息。

我在端点的getOutFaultInterceptors链中添加了一个拦截器,但是在handleMessage中我不知道我可以使用哪些属性。

一些想法?

谢谢

3 个答案:

答案 0 :(得分:3)

在端点xml定义中,您可以添加以下内容来记录传入消息:

<bean id="logInInterceptor" 
    class="org.apache.cxf.interceptor.LoggingInInterceptor" />
<jaxws:inInterceptors>
    <ref bean="logInInterceptor"/>
</jaxws:inInterceptors>

然后使用总线限制要记录的字符数:

<cxf:bus>
    <cxf:features>
        <cxf:logging limit="102400"/>
    </cxf:features>
<cxf:bus>

您尚未提及您的身份验证方法,因此,如果您使用UsernameTokenValidator的实现,则可以在此处记录传入的用户名。

要记录客户端的IP地址和端口等详细信息,请展开LoggingInInterceptor,然后在handleMessage()中使用以下代码:

handleMessage() {
    HttpServletRequest request =
            (HttpServletRequest)message.get(AbstractHTTPDestination.HTTP_REQUEST);
    if (null != request) {              
        String clientAddress = request.getRemoteAddr();
        int remotePort = request.getRemotePort();
        // log them
    }
}

另请查看this主题。

答案 1 :(得分:2)

我以这种方式解决了

public FaultInterceptor() {
    super(Phase.MARSHAL);
}

public void handleMessage(SoapMessage message) throws Fault {
    Fault fault = (Fault) message.getContent(Exception.class);
    Message inMessage = message.getExchange().getInMessage();
    if (inMessage == null) return;

    String xmlMessage = null;
    InputStream is = inMessage.getContent(InputStream.class);
    String rawXml = null;
    if (is != null) {
        rawXml = is.toString();
    }

    String username = null;
    if (rawXml != null && rawXml.length() > 0) {
        try {
            XPath xpath = XPathFactory.newInstance().newXPath();
            XPathExpression xpathExpression;

            xpathExpression = xpath.compile("//*[local-name()=\'Envelope\']/*[local-name()=\'Header\']/*[local-name()=\'Security\']" +
                    "/*[local-name()=\'UsernameToken\']/*[local-name()=\'Username\']");

            InputSource source = new InputSource(new StringReader(rawXml));

            username = xpathExpression.evaluate(source);
        } catch (XPathExpressionException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        xmlMessage = XMLUtils.prittyPrinter(is.toString());
    }

    String clientAddress = "<unknown>";
    int clientPort = -1;
    HttpServletRequest request = (HttpServletRequest)inMessage.get(AbstractHTTPDestination.HTTP_REQUEST); 
    if (null != request) {               
        clientAddress = request.getRemoteAddr(); 
        clientPort = request.getRemotePort();
    }

    logger.warn("User: " + username + " [" + clientAddress + ":" + clientPort + "] caused fault: " + fault +
            "\nMessage received: \n" + xmlMessage);



}

我找到了“inMessage”属性并在其上找到了原始消息(我可以检索用户名)和“请求”,我从中检索了主机和端口。

谢谢。

答案 2 :(得分:0)

我认为您应该在处理故障时查看请求输入流。

我建议您始终记录传入的消息,并提取某种消息相关ID - 例如用户名。将其保留为消息标题。

对于故障记录,请使用仅限于查看输入请求的故障拦截器。

将常规+故障记录与消息关联ID绑定在一起。

记录完整的soap请求,而不仅仅是有效负载。除了正文之外,肥皂请求可能还有标题。

有关常规日志记录,请参阅this question,另外添加一个输出故障拦截器,如下所示:

public class SoapFaultLoggingOutInterceptor extends AbstractPhaseInterceptor<Message> {

    private static final String LOCAL_NAME = "MessageID";

    private static final int PROPERTIES_SIZE = 128;

    private String name = "<interceptor name not set>";

    protected Logger logger = null;
    protected Level level;

    public SoapFaultLoggingOutInterceptor() {
        this(LogUtils.getLogger(SoapFaultLoggingOutInterceptor.class), Level.WARNING);
    }

    public SoapFaultLoggingOutInterceptor(Logger logger, Level reformatSuccessLevel) {
        super(Phase.MARSHAL);
        this.logger = logger;
        this.level = reformatSuccessLevel;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void handleMessage(Message message) throws Fault {
        if (!logger.isLoggable(level)) {
            return;
        }

        StringBuilder buffer = new StringBuilder(PROPERTIES_SIZE);

        // perform local logging - to the buffer 
        buffer.append(name);

        logProperties(buffer, message);

        logger.log(level, buffer.toString());
    }


    /**
     * Gets theMessageID header in the list of headers.
     *
     */
    protected String getIdHeader(Message message) {
        return getHeader(message, LOCAL_NAME);
    }

    protected String getHeader(Message message, String name) {
        List<Header> headers = (List<Header>) message.get(Header.HEADER_LIST);

        if(headers != null) {
            for(Header header:headers) {
                if(header.getName().getLocalPart().equalsIgnoreCase(name)) {
                    return header.getObject().toString();
                }
            }
        }
        return null;
    }        

    protected void logProperties(StringBuilder buffer, Message message) {
        final String messageId = getIdHeader(message);
        if(messageId != null) {
            buffer.append(" MessageId=");
            buffer.append(messageId);
        }

        Message inMessage = message.getExchange().getInMessage();

        HttpServletRequest request = (HttpServletRequest)inMessage.get(AbstractHTTPDestination.HTTP_REQUEST); 

        buffer.append(" RemoteAddr=");
        buffer.append(request.getRemoteAddr());
    }

    public Logger getLogger() {
        return logger;
    }

    public String getName() {
        return name;
    }

    public void setLogger(Logger logger) {
        this.logger = logger;
    }


}    

其中MessageID是相关/ breadcrumb id。