Есть ли способ записать время отклика фиктивного клиента

@FeignClient(...)
public interface SomeClient {
@RequestMapping(value = "/someUrl", method = POST, consumes = "application/json")
    ResponseEntity<String> createItem(...);

}

Есть ли способ найти время отклика для вызова API createItem? Мы используем пружинный ботинок, актуатор, прометей.


person Lavy    schedule 15.05.2019    source источник
comment
Есть множество способов, я думаю, вам нужен перехватчик запросов. Существует множество руководств, таких как baeldung.com/spring-mvc-handlerinterceptor. Или вы можете использовать pointcut для любых методов, которые соответствуют шаблону, это может быть труднее заставить работать, когда вы определяете интерфейс только с помощью Feign baeldung.com/spring-performance-logging. Кроме того, вы можете подключиться к JMX для мониторинга, github.com/iyzico/boot-mon один инструмент, но есть и другие.   -  person DCTID    schedule 15.05.2019
comment
@Lavy, так как ответ stackoverflow.com/questions/56140774/ был принят многими, не могли бы вы попробовать на своей стороне, а затем принять мой ответ   -  person Prasanth Rajendran    schedule 04.08.2020


Ответы (3)


У нас есть прямой, а также индивидуальный способ регистрации запросов и ответов фиктивных клиентов (включая время ответа). Мы должны внедрить bean-компонент feign.Logger.Level, вот и все.

  1. СПОСОБ ПО УМОЛЧАНИЮ/ПРЯМОЙ СПОСОБ
@Bean
Logger.Level feignLoggerLevel() {
  return Logger.Level.BASIC;
}

доступны уровни ведения журнала BASIC,FULL,HEADERS,NONE (по умолчанию) подробнее

Вышеупомянутая инъекция bean-компонента даст вам регистрацию запроса и ответа feign в следующем формате:

ЗАПРОС:

ссылка

log(configKey, "---> %s %s HTTP/1.1", request.httpMethod().name(), request.url());

ex:2019-09-26 12:50:12.163 [DEBUG] [http-nio-4200-exec-5] [com.sample.FeignClient:72] [FeignClient#getUser] ---> END HTTP (0-byte body)

где configkey означает FeignClientClassName#FeignClientCallingMethodName например: ApiClient#apiMethod.

ОТВЕТ

ссылка

log(configKey, "<--- HTTP/1.1 %s%s (%sms)", status, reason, elapsedTime);

ex:2019-09-26 12:50:12.163 [DEBUG] [http-nio-4200-exec-5] [com.sample.FeignClient:72] [FeignClient#getUser] <--- HTTP/1.1 200 OK (341ms)

elapsedTime — это время ответа на вызов API.

ПРИМЕЧАНИЕ. Если вы предпочитаете способ ведения журнала фиктивного клиента по умолчанию, то мы также должны учитывать базовый уровень ведения журнала приложения, поскольку ведение журнала класса feign.Slf4jLogger с фиктивным запросом и подробностями ответа с уровнем DEBUG (ссылка) . Если базовый уровень ведения журнала выше DEBUG, вам может потребоваться указать явный регистратор для пакета/класса ведения журнала feign, иначе он не будет работать.

  1. ПОЛЬЗОВАТЕЛЬСКИЙ СПОСОБ Если вы предпочитаете ведение журнала в собственном формате, вы можете расширить класс feign.Logger и настроить ведение журнала. Для типичного примера, если я хочу регистрировать сведения о заголовке запроса и ответа в одной строке в виде списка (по умолчанию Logger.Level.HEADERS печатает заголовок в несколько строк):
package com.test.logging.feign;

import feign.Logger;
import feign.Request;
import feign.Response;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;

import static feign.Logger.Level.HEADERS;

@Slf4j
public class customFeignLogger extends Logger {

    @Override
    protected void logRequest(String configKey, Level logLevel, Request request) {

        if (logLevel.ordinal() >= HEADERS.ordinal()) {
            super.logRequest(configKey, logLevel, request);
        } else {
            int bodyLength = 0;
            if (request.requestBody().asBytes() != null) {
                bodyLength = request.requestBody().asBytes().length;
            }
            log(configKey, "---> %s %s HTTP/1.1 (%s-byte body) %s", request.httpMethod().name(), request.url(), bodyLength, request.headers());
        }
    }

    @Override
    protected Response logAndRebufferResponse(String configKey, Level logLevel, Response response, long elapsedTime)
            throws IOException {
        if (logLevel.ordinal() >= HEADERS.ordinal()) {
            super.logAndRebufferResponse(configKey, logLevel, response, elapsedTime);
        } else {
            int status = response.status();
            Request request = response.request();
            log(configKey, "<--- %s %s HTTP/1.1 %s (%sms) %s", request.httpMethod().name(), request.url(), status, elapsedTime, response.headers());
        }
        return response;
    }


    @Override
    protected void log(String configKey, String format, Object... args) {
        log.debug(format(configKey, format, args));
    }

    protected String format(String configKey, String format, Object... args) {
        return String.format(methodTag(configKey) + format, args);
    }
}

также мы должны внедрить bean-компонент класса customFeignLogger

  @Bean
    public customFeignLogger customFeignLogging() {
        return new customFeignLogger();
    }

Если вы собираете FeignClient самостоятельно, вы можете собрать его с помощью настроенного регистратора:

 Feign.builder().logger(new customFeignLogger()).logLevel(Level.BASIC).target(SomeFeignClient.class,"http://localhost:8080");
person Prasanth Rajendran    schedule 29.09.2019

Добавьте следующую аннотацию в свой проект.

package com.example.annotation

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DebugTracking {
    @Aspect
    @Component
    public static class DebugTrackingAspect {
        @Around("@annotation(com.example.annotation.DebugTracking)")
        public Object trackExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
            StopWatch stopWatch = new StopWatch();
            stopWatch.start(joinPoint.toShortString());

            Exception exceptionThrown = null;

            try {
                // Execute the joint point as usual
                return joinPoint.proceed();

            } catch (Exception ex) {
                exceptionThrown = ex;
                throw ex;

            } finally {
                stopWatch.stop();

                System.out.println(String.format("%s took %dms.", stopWatch.getLastTaskName(), stopWatch.getLastTaskTimeMillis()));

                if (exceptionThrown != null) {
                    System.out.println(String.format("Exception thrown: %s", exceptionThrown.getMessage()));
                    exceptionThrown.printStackTrace();

                }
            }
        }
    }
}

Затем аннотируйте методы, которые вы хотите отслеживать, в @FeignClient с помощью @DebugTracking.

person Mr.J4mes    schedule 15.05.2019
comment
аннотация к методу feignclient не вызывается. Я попытался использовать @Around(value = execute(* com.xxx.VerbClient+.*(..))) без аннотации и теперь работает. stackoverflow.com/questions/51914315 / - person Lavy; 15.05.2019

Я использую следующее (с Spring и Lombok):

@Configuration // from Spring
@Slf4j // from Lombok
public class MyFeignConfiguration {
    @Bean // from Spring
    public MyFeignClient myFeignClient() {
        return Feign.builder()
            .logger(new Logger() {
                @Override
                protected void log(String configKey, String format, Object... args) {
                    LOG.info( String.format(methodTag(configKey) + format, args)); // LOG is the Lombok Slf4j object
                }
            })
            .logLevel(Logger.Level.BASIC) // see https://cloud.spring.io/spring-cloud-netflix/multi/multi_spring-cloud-feign.html#_feign_logging
            .target(MyFeignClient.class,"http://localhost:8080");
    }
}
person Julien Kronegg    schedule 20.04.2021