2012-06-29 39 views
2

我想在出现故障时记录一些信息。 特别是我想记录与服务器联系的客户端的IP地址和端口,用户名(如果安全处于活动状态,并且如果可能的话还有传入消息)。CXF故障拦截器:记录有用信息

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

有些想法?

谢谢

回答

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”属性并在其上我发现原始消息(我可以检索用户名)和从其中我检索到的主机的“请求”和端口。

谢谢。

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线程。

+0

但是..那么只有在故障拦截器中记录这些信息呢? – Francesco

0

我想你应该查看处理故障时消耗的请求输入流。

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

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

将常规+错误日志与消息关联ID绑定在一起。

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

定期记录参见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是相关/面包屑的id。