Подтвердить что ты не робот

Запрос/ответ на ведение журнала с Apache CXF в формате XML

Возможно ли зарегистрировать запрос/ответ как XML с использованием CXF, в идеале, в отдельный файл, чтобы я мог контролировать, что делает приложение?

4b9b3361

Ответ 1

Добавьте к своим конечным точкам и клиентам следующее:

<jaxws:features>
    <bean class="org.apache.cxf.feature.LoggingFeature" />
</jaxws:features>

Это будет записывать все в журнал сервера.

Если вы хотите зарегистрировать их в другом месте, посмотрите на исходный код встроенного CQF LoggingInInterceptor и LoggingOutInterceptor. Вы можете следить за шаблоном, который они используют, чтобы захватить сообщения на своем пути в/из и делать с ними то, что вам нравится.

Добавьте свои собственные перехватчики в цепочку с чем-то вроде этого:

<jaxws:inInterceptors>
    <ref bean="myLoggingInInterceptor" />
</jaxws:inInterceptors>

Ответ 2

Итак, я попробовал немного больше с этим. Чтобы получить запрос XML и ответы, и если вы используете Log4J, вам необходимо установить уровень журнала CXF в файле log4j.xml, подобном этому ( >= INFO):

<logger name="org.apache.cxf" >
    <level value="INFO" />
</logger>

И файл cxf.xml должен содержать следующее:

<cxf:bus>
    <cxf:features>
        <cxf:logging/>
    </cxf:features>
</cxf:bus> 

Оба файла должны быть в CLASSPATH.

Чтобы отобразить сообщение о мыле, добавьте его в свой код:

Client client = ClientProxy.getClient(service);
client.getInInterceptors().add(new LoggingInInterceptor());
client.getOutInterceptors().add(new LoggingOutInterceptor());

Ответ 3

Мыло xap запроса может быть легко зарегистрировано обычным в перехватчике. Скажем, у нас есть перехватчик с именем "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, вы можете посмотреть этот поток

Ответ 4

Если вы используете Spring с его Java-конфигурацией, есть 2 простых способа активировать ведение журнала SOAP-сообщений с Apache CXF:

  • Непосредственно на 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; }

Напомнить LoggingFeature.setPrettyLogging(true); Метод просмотра довольно печатных SOAP-сообщений и LoggingFeature.initialize(springBus()); - без последней магии не бывает. Для более чистого кода вы также можете отделить LoggingFeature как отдельный Bean и ввести его либо в свой SpringBus, либо в Endpoint- Bean.

Ответ 5

Намного проще добавить свой собственный регистратор в свойства конечной точки. В этом случае перехватчик регистрации по умолчанию будет искать ваш логгер в свойствах конечных точек, и если он найдет его, он будет использовать его, иначе он будет создавать по умолчанию. Вот мой пример использования:

<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>

Ответ 6

В моем случае я должен был поддерживать сгенерированный 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>

Чтобы все полезные данные были в одном файле.

Если вы хотите разделить его, создайте разные регистраторы/приложения, указав полное имя класса каждого перехватчика.

Для меня это решение идеально подходит для того, что я хотел.

Надеюсь, это поможет.

С уважением.