@FeignClient(...)
public interface SomeClient {
@RequestMapping(value = "/someUrl", method = POST, consumes = "application/json")
ResponseEntity<String> createItem(...);
}
有没有办法找到 createItem api 调用的响应时间?我们正在使用弹簧靴、执行器、普罗米修斯。
@FeignClient(...)
public interface SomeClient {
@RequestMapping(value = "/someUrl", method = POST, consumes = "application/json")
ResponseEntity<String> createItem(...);
}
有没有办法找到 createItem api 调用的响应时间?我们正在使用弹簧靴、执行器、普罗米修斯。
我们有直接和定制的方式来记录假装客户的请求和响应(包括响应时间)。我们必须注入 feign.Logger.Level bean,就是这样。
@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 客户端日志记录的默认方式,那么我们还必须考虑底层应用程序日志记录级别,因为feign.Slf4jLogger
带有 feign 请求的类日志记录和带有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);
}
}
我们还必须注入 customFeignLogger 类 bean
@Bean
public customFeignLogger customFeignLogging() {
return new customFeignLogger();
}
如果您自己构建 FeignClient,那么您可以使用自定义的 logger 构建它:
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
.
我正在使用以下(使用 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");
}
}