Добавление micrometer-метрик для взаимодействий по SOAP

от автора

Когда мы хотим знать, в каком состоянии находятся системы, с которыми наше приложение взаимодействует, мы используем механизм метрик. Самым распространенным механизмом работы с метриками в приложениях на Spring Boot является micrometer.

Для интеграций по HTTP с использованием REST очень удобно использовать spring-boot-starter-actuator. Актуатор уже из коробки предоставляет набор из http_client_requests и http_server_requests метрик с разбивкой по uri, method и результату.

Но остались еще проекты, которые взаимодействуют по протоколу SOAP. Хотя экосистема Spring (как и ванильная Java) предоставляют возможность собирать веб-сервисы и клиенты для протокола SOAP, но коробочного решения для снятия метрик с таких клиентов не существует.

Что такое SOAP

SOAP — это довольно старый и редко используемый протокол для обмена произвольными сообщениями в формате XML. Надеюсь вам повезет и вы никогда с ним не столкнетесь)

Представим, что появилось требование — реализовать механизм снятия метрик с клиентов, которые взаимодействуют по SOAP. Считать будем количество отправленных запросов и результат выполнения запроса с разбивкой по uri.

Для проектов на Java и Spring есть два способа построить веб-клиента для протокола SOAP — Spring WebService и JAX-WS. Рассмотрим решения под оба этих варианта, поскольку единый механизм создать не получится.

Снятие метрик для клиента с использованием Spring WebService

В модуле Spring WebService для создания клиента применяется класс WebServiceTemplate, который может быть расширен с помощью набора различных ClientInterceptor. Интерфейс ClientInterceptor предоставляет 4 метода.

Нам интересен

void afterCompletion(MessageContext messageContext, Exception ex),

поскольку он вызывается во всех случаях — отправки запроса, получения ответа (в том числе с Fault), выброса какого-либо исключения в процессе обмена.

Реализуем свою имплементацию интерфейса. В ней переопределяем только метод afterCompletion, и реагируем только на ответ (или исключение). Факт отправки запроса в метриках нам не интересен.

public class SpringWsMetricsInterceptor implements ClientInterceptor {     private static final Pattern pattern = Pattern.compile("^[^#]*?://.*?(?<pathGroup>/.*)$");      private final MeterRegistry meterRegistry;      public SpringWsMetricsInterceptor(MeterRegistry meterRegistry) {       this.meterRegistry = meterRegistry;     }      @Override     public boolean handleRequest(MessageContext messageContext) throws WebServiceClientException {         return true;     }      @Override     public boolean handleResponse(MessageContext messageContext) throws WebServiceClientException {         return true;     }      @Override     public boolean handleFault(MessageContext messageContext) throws WebServiceClientException {         return true;     }      @Override     public void afterCompletion(MessageContext messageContext, Exception e) throws WebServiceClientException {         if (messageContext.hasResponse() || e != null) {             //в метрики пишем либо успешный ответ, либо ошибку             TransportContext context = TransportContextHolder.getTransportContext();             String url = context.getConnection().getUri().getPath();             String outcome = e != null ? "SERVER_ERROR" : "SUCCESS";             String status = e != null ? e.getMessage() : "200";              Matcher matcher = pattern.matcher(url);             String uri = matcher.find() ? matcher.group("pathGroup") : url;             Counter.builder("soap.ws.client.requests")                     .tag("outcome", outcome)                     .tag("status", status)                     .tag("uri", uri)                     .register(meterRegistry)                     .increment();         }     } } 

В результате получаем набор метрик вида

soap_ws_client_requests_total{outcome="SUCCESS",status="200",uri="/path/to/service",}

Снятие метрик для клиента с использованием JAX-WS

Для клиентов, реализованных с использованием JAX-WS, к сожалению, нет возможности построить красивый и укладывающийся в парадигму Spring вариант снятия метрик.

Поскольку механизм JAX-WS предлагает только вызов метода интерфейса, сгенерированного плагином, и явно не имплементированного в коде, то остается только использовать аннотацию @Timed. Необходимо в клиенте реализовать набор методов, повторяющих методы JAX-WS интерфейса и проаннотировать их.

Допустим, есть wsdl-схема, из который будет сгенерирован интерфейс:

@WebService(name = "MyJaxWsInterface", targetNamespace = "urn:myJaxWs:interface") public interface MyJaxWsInterface {     @WebMethod(operationName = "Create")     @WebResult(name = "createResponse", targetNamespace = "urn:myJaxWs:types", partName = "result")     public CreateResponse create(         @WebParam(name = "createRequest", targetNamespace = "urn:myJaxWs:types", partName = "request")         CreateRequest request)         throws IllegalUsageException_Exception, InternalSystemErrorException_Exception     ; }

Нужно реализовать враппер, расширяющий SOAP интерфейс, методы которого проаннотированы @Timed.

public class JaxWsClientWrapper implements MyJaxWsInterface {     private MyJaxWsInterface myJaxWsInterface;          public JaxWsClientWrapper(MyJaxWsInterface myJaxWsInterface) {         this.myJaxWsInterface = myJaxWsInterface;     }      @Override     @Timed     public CreateResponse create(CreateRequest request){         return myJaxWsInterface.createRequest(request);     } }

В результате получаем набор стандартных метрик, где будет указано имя класса, имя вызываемого метода и наличие или отсутствие exception при вызове. К сожалению, при таком подходе нет возможности получить url и status ответов в метриках.


ссылка на оригинал статьи https://habr.com/ru/articles/774456/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *