CXF 3.1 wsdl2java 使用 Log4j2 进行日志记录
CXF 3.1 wsdl2java logging with Log4j2
我已经使用 CXF 3.1 wsdl2java 生成了我的服务,所以没有 cxf.xml。
我正在尝试将服务的请求和响应 XML 添加到我的 log4j2 设置中。由于版本更改等原因,存在很多冲突信息。我的 request/response xml CXF 日志文件始终为空。
这是最接近我的设置的:How to log CXF webservice requests with log4j2?
所以我的 log4j2.xml
中有以下内容
<logger name="org.apache.cxf" additivity="false" level="info">
<AppenderRef ref="APP_LOG_FILE"/>
</logger>
<logger name="org.apache.cxf.interceptor.LoggingInInterceptor" additivity="false" level="info">
<AppenderRef ref="WS_LOG_FILE" />
</logger>
<logger name="org.apache.cxf.interceptor.LoggingOutInterceptor" additivity="false" level="info">
<AppenderRef ref="WS_LOG_FILE" />
</logger>
没有显示 appender,但它们在那里,APP_LOG_FILE 已填充,但 WS_LOG_FILE appender 文件始终为空,同时正在交换消息。
我添加了一个包含此内容的 META-INF/cxf/org.apache.cxf.Logger 文件
org.apache.cxf.common.logging.Slf4jLogger
我还尝试在 运行 将我的 jar 作为 cxf.Logger 文件的替代方案时使用额外的命令行参数:
-Dorg.apache.cxf.Logger=org.apache.cxf.common.logging.Slf4jLogger
我添加了额外的依赖:
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.0</version>
</dependency>
我在日志记录拦截器(它们是必需的还是 log4j2.xml 中的配置的替代品?)和没有它们的情况下都尝试了以下操作,如当前注释掉的那样。
GetComparisonDecisionService equinitiComparisonService = new GetComparisonDecisionService();
GetComparisonDecisionInterface comparison = equinitiComparisonService.getGetComparisonDecision();
/*
Client client = ClientProxy.getClient(equinitiComparisonService.getPort(GetComparisonDecisionInterface.class));
client.getInInterceptors().add(new LoggingInInterceptor());
client.getOutInterceptors().add(new LoggingOutInterceptor());
*/
GetComparisonDecisionCallParameter comparisonDecisionCallParameter = new GetComparisonDecisionCallParameter();
comparisonDecisionCallParameter.setSecurityToken(token);
comparisonDecisionCallParameter.setComparisonApplication(equinitiApp);
GetComparisonDecisionResponseParameter eqDescn = comparison.getComparisonDecision(comparisonDecisionCallParameter);
我现在 运行 没主意了。 cxf 文档非常简洁。
查看 Frank 的评论,它解决了问题。
我注意到在 CXF 站点上查找信息的明显位置 - http://cxf.apache.org/docs/debugging-and-logging.html 没有提到此方法!?
作为答案的要求:对于 CXF < 3.1,建议按照您在最后一个代码片段中显示的方式设置 LoggingInterceptors。您应该像这样使用@Feature-Annotation:@Features(features = "org.apache.cxf.feature.LoggingFeature")
。
这是我想出的另一种解决方法,因为我无法使已接受的解决方案起作用。这个想法是为您的服务定义一个处理程序,并将记录 SOAP 信封的责任委托给该处理程序。我们有点重新发明轮子,因为这个功能显然已经存在,只需要激活,但如果你无法让它工作,你可能想试试这个。
定义自定义 class 实现 SOAPHandler 接口
public class LoggingMessageHandler implements SOAPHandler<SOAPMessageContext> {
// this is a static instance of Logback's LoggerFactory.getLogger
// exposed by the my.personal.package.logging.soap.SOAPMessageLogger class
// all SOAP envelopes are logged by this logger
private Logger logger = SOAPMessageLogger.getLogger();
@Override
public boolean handleMessage(SOAPMessageContext context) {
final StringWriter sw = new StringWriter();
try {
TransformerFactory.newInstance().newTransformer().transform(
new DOMSource(context.getMessage().getSOAPPart()),
new StreamResult(sw));
// I'm formatting the log output so that every request or response only takes a single row in the log file
// this way the file is easier to go through, weighs less, and SOAP messages are easier to copy-paste
String SOAPMessageString = sw.toString().replaceAll("[\n\t ]", "");
if((Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY)) {
logger.info("{} REQUEST:\n{}", new Object[]{(context.get(MessageContext.WSDL_OPERATION)), SOAPMessageString});
}
else {
logger.info("{} RESPONSE:\n{}", new Object[]{(context.get(MessageContext.WSDL_OPERATION)), SOAPMessageString});
}
} catch (Exception e) {
logger.warn("Could not log SOAP envelope: " + e.getMessage());
}
return true;
}
@Override
public boolean handleFault(SOAPMessageContext context) {
logger.warn("handleFault handler was fired, will attempt to retrieve and log message details...");
final StringWriter sw = new StringWriter();
try {
TransformerFactory.newInstance().newTransformer().transform(
new DOMSource(context.getMessage().getSOAPPart()),
new StreamResult(sw));
logger.warn(sw.toString());
} catch (Exception e) {
logger.warn("Could not log SOAP envelope: " + e.getMessage());
}
return true;
}
@Override
public void close(MessageContext context) {
logger.trace("Closing!");
}
@Override
public Set<QName> getHeaders() {
return null;
}
}
定义自定义 class 实现 HandlerResolver 接口
public class LoggingMessageHandlerResolver implements HandlerResolver {
@Override
public List<Handler> getHandlerChain(PortInfo portInfo) {
return Collections.singletonList(new LoggingMessageHandler());
}
}
最后,当您实例化远程 SOAP Web 服务的代理时,将您的自定义 LoggingHandlerResolver 设置为其解析器:
public MyRemoteServicePort getServicePort() {
MyRemoteService myRemoteService = new MyRemoteService(new URL(webServicesBaseURL+myRemoteWsdlPath));
myRemoteService.setHandlerResolver(new LoggingMessageHandlerResolver());
return myRemoteService.getMyRemotePort();
}
这样,每次通过 MyRemoteServicePort 的消息 sent/received 都会被 handleMessage 方法拦截,并记录下来。您当然可以配置 Logback(或您想要使用的任何日志记录机制)以便根据您的喜好自定义日志输出。
我已经使用 CXF 3.1 wsdl2java 生成了我的服务,所以没有 cxf.xml。
我正在尝试将服务的请求和响应 XML 添加到我的 log4j2 设置中。由于版本更改等原因,存在很多冲突信息。我的 request/response xml CXF 日志文件始终为空。
这是最接近我的设置的:How to log CXF webservice requests with log4j2?
所以我的 log4j2.xml
中有以下内容 <logger name="org.apache.cxf" additivity="false" level="info">
<AppenderRef ref="APP_LOG_FILE"/>
</logger>
<logger name="org.apache.cxf.interceptor.LoggingInInterceptor" additivity="false" level="info">
<AppenderRef ref="WS_LOG_FILE" />
</logger>
<logger name="org.apache.cxf.interceptor.LoggingOutInterceptor" additivity="false" level="info">
<AppenderRef ref="WS_LOG_FILE" />
</logger>
没有显示 appender,但它们在那里,APP_LOG_FILE 已填充,但 WS_LOG_FILE appender 文件始终为空,同时正在交换消息。
我添加了一个包含此内容的 META-INF/cxf/org.apache.cxf.Logger 文件
org.apache.cxf.common.logging.Slf4jLogger
我还尝试在 运行 将我的 jar 作为 cxf.Logger 文件的替代方案时使用额外的命令行参数:
-Dorg.apache.cxf.Logger=org.apache.cxf.common.logging.Slf4jLogger
我添加了额外的依赖:
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.0</version>
</dependency>
我在日志记录拦截器(它们是必需的还是 log4j2.xml 中的配置的替代品?)和没有它们的情况下都尝试了以下操作,如当前注释掉的那样。
GetComparisonDecisionService equinitiComparisonService = new GetComparisonDecisionService();
GetComparisonDecisionInterface comparison = equinitiComparisonService.getGetComparisonDecision();
/*
Client client = ClientProxy.getClient(equinitiComparisonService.getPort(GetComparisonDecisionInterface.class));
client.getInInterceptors().add(new LoggingInInterceptor());
client.getOutInterceptors().add(new LoggingOutInterceptor());
*/
GetComparisonDecisionCallParameter comparisonDecisionCallParameter = new GetComparisonDecisionCallParameter();
comparisonDecisionCallParameter.setSecurityToken(token);
comparisonDecisionCallParameter.setComparisonApplication(equinitiApp);
GetComparisonDecisionResponseParameter eqDescn = comparison.getComparisonDecision(comparisonDecisionCallParameter);
我现在 运行 没主意了。 cxf 文档非常简洁。
查看 Frank 的评论,它解决了问题。
我注意到在 CXF 站点上查找信息的明显位置 - http://cxf.apache.org/docs/debugging-and-logging.html 没有提到此方法!?
作为答案的要求:对于 CXF < 3.1,建议按照您在最后一个代码片段中显示的方式设置 LoggingInterceptors。您应该像这样使用@Feature-Annotation:@Features(features = "org.apache.cxf.feature.LoggingFeature")
。
这是我想出的另一种解决方法,因为我无法使已接受的解决方案起作用。这个想法是为您的服务定义一个处理程序,并将记录 SOAP 信封的责任委托给该处理程序。我们有点重新发明轮子,因为这个功能显然已经存在,只需要激活,但如果你无法让它工作,你可能想试试这个。
定义自定义 class 实现 SOAPHandler 接口
public class LoggingMessageHandler implements SOAPHandler<SOAPMessageContext> {
// this is a static instance of Logback's LoggerFactory.getLogger
// exposed by the my.personal.package.logging.soap.SOAPMessageLogger class
// all SOAP envelopes are logged by this logger
private Logger logger = SOAPMessageLogger.getLogger();
@Override
public boolean handleMessage(SOAPMessageContext context) {
final StringWriter sw = new StringWriter();
try {
TransformerFactory.newInstance().newTransformer().transform(
new DOMSource(context.getMessage().getSOAPPart()),
new StreamResult(sw));
// I'm formatting the log output so that every request or response only takes a single row in the log file
// this way the file is easier to go through, weighs less, and SOAP messages are easier to copy-paste
String SOAPMessageString = sw.toString().replaceAll("[\n\t ]", "");
if((Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY)) {
logger.info("{} REQUEST:\n{}", new Object[]{(context.get(MessageContext.WSDL_OPERATION)), SOAPMessageString});
}
else {
logger.info("{} RESPONSE:\n{}", new Object[]{(context.get(MessageContext.WSDL_OPERATION)), SOAPMessageString});
}
} catch (Exception e) {
logger.warn("Could not log SOAP envelope: " + e.getMessage());
}
return true;
}
@Override
public boolean handleFault(SOAPMessageContext context) {
logger.warn("handleFault handler was fired, will attempt to retrieve and log message details...");
final StringWriter sw = new StringWriter();
try {
TransformerFactory.newInstance().newTransformer().transform(
new DOMSource(context.getMessage().getSOAPPart()),
new StreamResult(sw));
logger.warn(sw.toString());
} catch (Exception e) {
logger.warn("Could not log SOAP envelope: " + e.getMessage());
}
return true;
}
@Override
public void close(MessageContext context) {
logger.trace("Closing!");
}
@Override
public Set<QName> getHeaders() {
return null;
}
}
定义自定义 class 实现 HandlerResolver 接口
public class LoggingMessageHandlerResolver implements HandlerResolver {
@Override
public List<Handler> getHandlerChain(PortInfo portInfo) {
return Collections.singletonList(new LoggingMessageHandler());
}
}
最后,当您实例化远程 SOAP Web 服务的代理时,将您的自定义 LoggingHandlerResolver 设置为其解析器:
public MyRemoteServicePort getServicePort() {
MyRemoteService myRemoteService = new MyRemoteService(new URL(webServicesBaseURL+myRemoteWsdlPath));
myRemoteService.setHandlerResolver(new LoggingMessageHandlerResolver());
return myRemoteService.getMyRemotePort();
}
这样,每次通过 MyRemoteServicePort 的消息 sent/received 都会被 handleMessage 方法拦截,并记录下来。您当然可以配置 Logback(或您想要使用的任何日志记录机制)以便根据您的喜好自定义日志输出。