Я использую CherryPy и лично и профессионально, и я чрезвычайно доволен им. Я даже делаю виды вещи, которую Вы описываете, такие как наличие кэшей глобального объекта, выполнение других потоков в фоновом режиме, и т.д. И это интегрируется хорошо с Apache; просто выполните CherryPy как автономный сервер, связанный с localhost, затем используйте Apache mod_proxy
, и mod_rewrite
для имения Apache прозрачно передают запросы к CherryPy.
веб-сайт CherryPy http://cherrypy.org/
Добавьте следующее к своим конечным точкам и клиентам:
<jaxws:features>
<bean class="org.apache.cxf.feature.LoggingFeature" />
</jaxws:features>
Это запишет все в журнал сервера.
Если вы хотите записать их в другом месте, посмотрите на исходный код встроенного CXF LoggingInInterceptor и LoggingOutInterceptor. Вы можете следовать шаблону, который они используют, чтобы захватывать сообщения при входе и выходе и делать с ними то, что вам нравится.
Добавьте свои собственные перехватчики в цепочку примерно так:
<jaxws:inInterceptors>
<ref bean="myLoggingInInterceptor" />
</jaxws:inInterceptors>
Запрос мыла 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>
В классе мы можем получить запрос 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 ( );
}
}
}
Послушайте, здесь у меня также есть лог адрес, откуда приходит запрос. Вы также можете получить дополнительную информацию из объекта "HttpServletRequest". Вы можете получить больше от: http://cxf.apache.org/docs/interceptors.html
Для регистрации XML-ответов вы можете посмотреть эту ветку
Гораздо проще добавить собственный регистратор в свойства конечной точки. В этом случае перехватчик регистрации по умолчанию будет искать ваш регистратор в свойствах конечной точки, и если он найдет его, он будет использовать его, в противном случае он создаст значение по умолчанию. Вот мой пример использования:
<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>
В моем случае я должен был поддержать сгенерированный клиент 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>
И я закон превратил его в это:
<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>
Мой класс 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);
}
}
}
Мой класс 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) {}
}
}
И мой класс 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);
}
}
}
С последним, определенным в приложении, я только должен был настроить свой файл 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>
, Чтобы заставить все полезные нагрузки быть в том же файле.
, Если Вы хотите разделить его, создайте другой loggers/appenders specifiying полное имя класса каждого Перехватчика.
Для меня, это решение соответствует отлично для того, что я хотел.
Hope это помогает.
Отношения.