Есть ли способ записать время отклика симулированного клиента
@FeignClient(...)
public interface SomeClient {
@RequestMapping(value = "/someUrl", method = POST, consumes = "application/json")
ResponseEntity<String> createItem(...);
}
Есть ли способ найти время отклика для вызова API createItem? Мы используем пружинный чехол, привод, прометей.
4 ответа
У нас есть простой, а также индивидуальный способ регистрации запросов и ответов фиктивных клиентов (включая время ответа). Мы должны внедрить bean-компонент feign.Logger.Level, вот и все.
- ПО УМОЛЧАНИЮ / ПРЯМОЙ ПУТЬ
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.BASIC;
}
для более подробной информации доступны уровни ведения журнала BASIC,FULL,HEADERS,NONE(по умолчанию)
Вышеупомянутая инъекция bean-компонента даст вам регистрацию симулируемого запроса и ответа в следующем формате:
ЗАПРОС:
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
ведение журнала пакета / класса, иначе это не сработает.
- ИНДИВИДУАЛЬНЫЙ СПОСОБ
Если вы предпочитаете вести журнал в своем индивидуальном формате, вы можете расширить
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");
Добавьте следующую аннотацию к вашему проекту.
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
,
правильный способ сделать это - использовать пользовательский регистратор, как указано выше. Использование @Aspect неправильно. При этом вы создаете дополнительную оболочку вокруг сервиса. Feign уже записывает этот показатель. Получите эту метрику от притворства.
Я использую следующее (с 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");
}
}