2012-06-29 90 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。