使用 Apache CXF 将请求/响应记录为 XML
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4592422/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Logging request/response with Apache CXF as XML
提问by irishguy
Is it possible to log the request/response as XML using CXF, ideally to a separate file so I can monitor what an application is doing?
是否可以使用 CXF 将请求/响应记录为 XML,理想情况下可以记录到单独的文件中,以便我可以监视应用程序在做什么?
采纳答案by BPS
Add the following to your endpoints and clients:
将以下内容添加到您的端点和客户端:
<jaxws:features>
<bean class="org.apache.cxf.feature.LoggingFeature" />
</jaxws:features>
This will log everything to the server log.
这会将所有内容记录到服务器日志中。
If you want to log them elsewhere, then look at the source code of the built-in CXF LoggingInInterceptor and LoggingOutInterceptor. You can follow the pattern they use to grab the messages on their way in/out and do with them what you like.
如果你想把它们记录在别处,那么看看内置的 CXF LoggingInInterceptor 和 LoggingOutInterceptor 的源代码。您可以按照他们用来在进/出的方式获取消息的模式,并随心所欲地处理它们。
Add your own interceptors to the chain with something like this:
将您自己的拦截器添加到链中,如下所示:
<jaxws:inInterceptors>
<ref bean="myLoggingInInterceptor" />
</jaxws:inInterceptors>
回答by Asturio
So, I tried a little more with this. To get the XML Request and Replies logged, and if you are using Log4J, you need to set the Log-level of CXF in the log4j.xmlfile like this (>= INFO):
所以,我尝试了更多。要记录 XML 请求和回复,如果您使用的是 Log4J,则需要在log4j.xml文件中设置 CXF 的日志级别,如下所示 (>= INFO):
<logger name="org.apache.cxf" >
<level value="INFO" />
</logger>
And the cxf.xmlfile should contains this:
而cxf.xml应提交包含此:
<cxf:bus>
<cxf:features>
<cxf:logging/>
</cxf:features>
</cxf:bus>
Both files should be in the CLASSPATH.
这两个文件都应该在 CLASSPATH 中。
To display the soap message add this to your code:
要显示肥皂消息,请将其添加到您的代码中:
Client client = ClientProxy.getClient(service);
client.getInInterceptors().add(new LoggingInInterceptor());
client.getOutInterceptors().add(new LoggingOutInterceptor());
回答by Asraful Haque
The request soap xml can be logged easily by an custom In interceptor. Say, we have an interceptor named "wsLoggingInInterceptor", So in the context file it will be like the following :
请求soap xml 可以通过自定义In 拦截器轻松记录。说,我们有一个名为“wsLoggingInInterceptor”的拦截器,所以在上下文文件中它会像下面这样:
<bean id="loggingInInterceptor" class="org.apache.cxf.interceptor.LoggingInInterceptor"/>
<bean id="logOutInterceptor" class="org.apache.cxf.interceptor.LoggingOutInterceptor"/>
<bean id="wsLoggingInInterceptor" class="org.jinouts.webservice.logging.WSLoggingInInterceptor"/>
<cxf:bus>
<cxf:inInterceptors>
<ref bean="loggingInInterceptor"/>
<ref bean="wsLoggingInInterceptor"/>
</cxf:inInterceptors>
<cxf:outInterceptors>
<ref bean="logOutInterceptor"/>
</cxf:outInterceptors>
</cxf:bus>
In the class we can get the request xml as follows:
在类中我们可以得到请求xml如下:
public class WSLoggingInInterceptor extends AbstractSoapInterceptor
{
public WSLoggingInInterceptor ()
{
super(Phase.RECEIVE);
}
@Override
public void handleMessage ( SoapMessage message ) throws Fault
{
//get the remote address
HttpServletRequest httpRequest = (HttpServletRequest) message.get ( AbstractHTTPDestination.HTTP_REQUEST );
System.out.println ("Request From the address : " + httpRequest.getRemoteAddr ( ) );
try
{
// now get the request xml
InputStream is = message.getContent ( InputStream.class );
CachedOutputStream os = new CachedOutputStream ( );
IOUtils.copy ( is, os );
os.flush ( );
message.setContent ( InputStream.class, os.getInputStream ( ) );
is.close ( );
System.out.println ("The request is: " + IOUtils.toString ( os.getInputStream ( ) ));
os.close ( );
}
catch ( Exception ex )
{
ex.printStackTrace ( );
}
}
}
Look, here I have also log the address from where the request is coming. You can also get some more information from the "HttpServletRequest" object. you can have more from : http://cxf.apache.org/docs/interceptors.html
看,这里我还记录了请求来自的地址。您还可以从“HttpServletRequest”对象中获取更多信息。你可以从:http: //cxf.apache.org/docs/interceptors.html获得更多
To log response xml you can have a look at this thread
要记录响应 xml,您可以查看 此线程
回答by jonashackt
If you are using Spring with it′s Java-Configuration, there are 2 easy ways to activate Logging of SOAP-Messages with Apache CXF:
如果您使用 Spring 及其 Java 配置,有两种简单的方法可以使用 Apache CXF 激活 SOAP 消息记录:
Directly on the SpringBus - that is usefull, if you want to log the Messages of all your CXF-Endpoints:
@Bean(name=Bus.DEFAULT_BUS_ID) public SpringBus springBus() { SpringBus springBus = new SpringBus(); LoggingFeature logFeature = new LoggingFeature(); logFeature.setPrettyLogging(true); logFeature.initialize(springBus); springBus.getFeatures().add(logFeature); return springBus; }Activate Logging seperately on every exposed CXF-Endpoint
@Bean public Endpoint endpoint() { EndpointImpl endpoint = new EndpointImpl(springBus(), weatherService()); endpoint.publish(SERVICE_NAME_URL_PATH); endpoint.setWsdlLocation("Weather1.0.wsdl"); LoggingFeature logFeature = new LoggingFeature(); logFeature.setPrettyLogging(true); logFeature.initialize(springBus()); endpoint.getFeatures().add(logFeature); return endpoint; }
直接在 SpringBus 上 - 如果您想记录所有 CXF 端点的消息,这很有用:
@Bean(name=Bus.DEFAULT_BUS_ID) public SpringBus springBus() { SpringBus springBus = new SpringBus(); LoggingFeature logFeature = new LoggingFeature(); logFeature.setPrettyLogging(true); logFeature.initialize(springBus); springBus.getFeatures().add(logFeature); return springBus; }在每个暴露的 CXF 端点上单独激活日志记录
@Bean public Endpoint endpoint() { EndpointImpl endpoint = new EndpointImpl(springBus(), weatherService()); endpoint.publish(SERVICE_NAME_URL_PATH); endpoint.setWsdlLocation("Weather1.0.wsdl"); LoggingFeature logFeature = new LoggingFeature(); logFeature.setPrettyLogging(true); logFeature.initialize(springBus()); endpoint.getFeatures().add(logFeature); return endpoint; }
Remind the LoggingFeature.setPrettyLogging(true); Method to see pretty printed SOAP-Messages and LoggingFeature.initialize(springBus()); - without the latter, the magic doesn′t happen. For cleaner Code, you could also separate the LoggingFeature as separate Bean and inject it either in your SpringBus or Endpoint-Bean.
提醒 LoggingFeature.setPrettyLogging(true); 查看漂亮打印的 SOAP 消息和 LoggingFeature.initialize(springBus()); - 没有后者,魔法就不会发生。为了使代码更简洁,您还可以将 LoggingFeature 分离为单独的 Bean,并将其注入您的 SpringBus 或 Endpoint-Bean。
回答by Mike
It's much more easier to add your own logger to the endpoint properties. In this case default logging interceptor will look for your logger in the endpoint properties and if it finds one it will use it otherwise it will create default. Here is my usage example:
将您自己的记录器添加到端点属性要容易得多。在这种情况下,默认日志拦截器将在端点属性中查找您的记录器,如果找到,它将使用它,否则它将创建默认值。这是我的使用示例:
<jaxws:endpoint
xmlns:client="http://service.info.client.diasoft.services.stream.integration.cib.sberbank.ru"
address="/diasoft/clientInfoWS"
serviceName="client:ClientWS"
implementor="#clientServiceImpl">
<jaxws:properties>
<entry key="MessageLogger" value-ref="logger"/>
</jaxws:properties>
<jaxws:features>
<bean class="org.apache.cxf.feature.LoggingFeature"/>
</jaxws:features>
</jaxws:endpoint>
<bean id="logger" class="org.apache.cxf.common.logging.LogUtils" factory-method="getLogger">
<constructor-arg value="ru.sberbank.cib.integration.stream.services.diasoft.client.info.service.ClientWSImpl"/>
</bean>
回答by Francisco M
In my case, I had to maintain a jaxb generated client. So I had found with the following situation in the applicationContext:
就我而言,我必须维护一个 jaxb 生成的客户端。所以我在applicationContext中发现了以下情况:
<jaxws:client id="aService"
serviceClass="org.xxx.ServiceClass"
address="${service.url}"
username="${service.username}"
password="${service.password}">
<jaxws:features>
<bean class="org.apache.cxf.feature.LoggingFeature" />
</jaxws:features>
</jaxws:client>
And I jus turned it into this:
我只是把它变成了这个:
<jaxws:client id="aService"
address="${service.url}"
username="${service.username}"
password="${service.password}">
<jaxws:features>
<bean class="org.apache.cxf.feature.LoggingFeature" />
</jaxws:features>
<jaxws:inInterceptors>
<bean class="com.blah.blah.SoapInInterceptor"/>
</jaxws:inInterceptors>
<jaxws:outInterceptors>
<bean class="com.blah.blah.SoapOutInterceptor"/>
</jaxws:outInterceptors>
<jaxws:inFaultInterceptors>
<bean class="com.blah.blah.SoapFaultInterceptor"/>
</jaxws:inFaultInterceptors>
</jaxws:client>
My SoapInInterceptor class:
我的 SoapInInterceptor 类:
public class SoapInInterceptor extends AbstractSoapInterceptor {
private static final Logger LOGGER = LoggerFactory.getLogger(SoapInInterceptor .class);
public SoapInInterceptor () {
super(Phase.RECEIVE);
}
@Override
public void handleMessage(SoapMessage message) throws Fault {
try {
InputStream is = message.getContent(InputStream.class);
CachedOutputStream os = new CachedOutputStream();
IOUtils.copy(is, os);
os.flush();
message.setContent(InputStream.class, os.getInputStream());
is.close();
LOGGER.debug("RESPONSE: {}", IOUtils.toString(os.getInputStream()));
os.close();
} catch (Exception ex) {
LOGGER.error("Error trying to log response", ex);
}
}
}
My SoapOutInterceptor class:
我的 SoapOutInterceptor 类:
public class SoapOutInterceptor extends AbstractSoapInterceptor {
private static final Logger LOGGER = LoggerFactory.getLogger(SoapOutInterceptor .class);
public SoapOutInterceptor () {
super(Phase.PRE_STREAM);
}
@Override
public void handleMessage(SoapMessage message) throws Fault {
CacheAndWriteOutputStream cwos = new CacheAndWriteOutputStream(message.getContent(OutputStream.class));
message.setContent(OutputStream.class, cwos);
cwos.registerCallback(new LoggingOutCallBack());
}
class LoggingOutCallBack implements CachedOutputStreamCallback {
@Override
public void onClose(CachedOutputStream cos) {
try {
if (cos != null) {
LOGGER.debug("REQUEST: {}", IOUtils.toString(cos.getInputStream()));
}
} catch (Exception e) {
LOGGER.error("Error trying to log request", e);
}
}
@Override
public void onFlush(CachedOutputStream arg0) {}
}
}
And my SoapFaultInterceptor class (almost equals to SoapInInterceptor):
而我的 SoapFaultInterceptor 类(几乎等于 SoapInInterceptor):
public class SoapFaultInterceptor extends AbstractSoapInterceptor{
private static final Logger LOGGER = LoggerFactory.getLogger(SoapFaultInterceptor.class);
public SoapFaultInterceptor() {
super(Phase.RECEIVE);
}
@Override
public void handleMessage(SoapMessage message) throws Fault {
try {
InputStream is = message.getContent(InputStream.class);
CachedOutputStream os = new CachedOutputStream();
IOUtils.copy(is, os);
os.flush();
message.setContent(InputStream.class, os.getInputStream());
is.close();
LOGGER.debug("FAULT: {}", IOUtils.toString(os.getInputStream()));
os.close();
} catch (Exception ex) {
LOGGER.error("Error trying to log fault", ex);
}
}
}
With the latter defined in the application, I only had to configure my logback.xml file like this:
在应用程序中定义后者后,我只需要像这样配置我的 logback.xml 文件:
<!—logger-->
<logger name="com.blah.blah">
<level value="DEBUG"/>
<appender-ref ref="aDailyRollingFileAppender"/>
</logger>
<!-- appender -->
<appender name="aDailyRollingFileAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/jboss-as-7.2.0.Final/standalone/log/soap-payloads.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>/jboss-as-7.2.0.Final/standalone/log/soap-payloads-%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>10</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{35} [%file:%line] - %msg %n</pattern>
</encoder>
</appender>
To make all the payloads be in the same file.
使所有有效载荷都在同一个文件中。
If you want to separate it, create different loggers/appenders by specifiying the complete class name of each Interceptor.
如果你想把它分开,通过指定每个拦截器的完整类名来创建不同的记录器/附加器。
For me, this solution fits perfectly for what I wanted.
对我来说,这个解决方案非常适合我想要的。
Hope this helps.
希望这可以帮助。
Regards.
问候。

