障害が発生した場合に備えて、いくつかの情報をログに記録したいと思います。特に、サーバーに接続しているクライアントの IP アドレスとポート、セキュリティが有効な場合はユーザー名、そして可能であれば着信メッセージもログに記録したいと思います。
エンドポイントの getOutFaultInterceptors チェーンにインターセプターを追加しましたが、handleMessage で使用できるプロパティがわかりません。
いくつかのアイデア?
ありがとうございました
エンドポイント 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
}
}
また、このスレッドを見てください。
私はこの方法で解決しました
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」プロパティを見つけ、そこに元のメッセージ (およびユーザー名を取得できます) と、ホストとポートを取得した「要求」を見つけました。
ありがとうございました。
障害を処理するときは、リクエスト入力ストリームを消費済みとして表示する必要があると思います。
受信メッセージを常にログに記録し、ある種のメッセージ相関 ID (ユーザー名など) を抽出することをお勧めします。メッセージヘッダーとして保持します。
障害ログには、入力要求の確認に限定された障害インターセプターを使用します。
通常の + 障害ログをメッセージ相関 ID と結び付けます。
ペイロードだけでなく、SOAP リクエスト全体をログに記録します。SOAP リクエストには、本文に加えてヘッダーが含まれる場合があります。
通常のロギングについては、この質問を参照してください。さらに、次のような出力障害インターセプターを追加してください。
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 です。