我想在出现故障时记录一些信息。 特别是我想记录与服务器联系的客户端的IP地址和端口,用户名(如果安全处于活动状态,并且如果可能的话还有传入消息)。CXF故障拦截器:记录有用信息
我在端点的getOutFaultInterceptors链中添加了一个拦截器,但在handleMessage中我不知道可以使用哪些属性。
有些想法?
谢谢
我想在出现故障时记录一些信息。 特别是我想记录与服务器联系的客户端的IP地址和端口,用户名(如果安全处于活动状态,并且如果可能的话还有传入消息)。CXF故障拦截器:记录有用信息
我在端点的getOutFaultInterceptors链中添加了一个拦截器,但在handleMessage中我不知道可以使用哪些属性。
有些想法?
谢谢
我解决这样
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”属性并在其上我发现原始消息(我可以检索用户名)和从其中我检索到的主机的“请求”和端口。
谢谢。
在您的端点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线程。
我想你应该查看处理故障时消耗的请求输入流。
我建议你总是记录传入的消息,并提取某种消息关联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。
但是..那么只有在故障拦截器中记录这些信息呢? – Francesco