【问题标题】:CXF Fault interceptor: log useful informationCXF 故障拦截器:记录有用信息
【发布时间】:2016-02-18 11:01:00
【问题描述】:

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

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

一些想法?

谢谢

【问题讨论】:

    标签: cxf soapfault


    【解决方案1】:

    在您的端点 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 线程。

    【讨论】:

    • 但是.. 仅在故障拦截器中记录这些信息怎么样?
    【解决方案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】:

      我认为您应该在处理故障时将请求输入流视为已消耗。

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

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

      将常规 + 故障记录与消息相关 ID 结合在一起。

      记录完整的soap请求,而不仅仅是有效负载。除了正文之外,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 是相关性/面包屑 ID。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-10-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多