Spring Boot 是否有办法记录虚拟客户端的响应时间

vlf7wbxs  于 2023-01-05  发布在  Spring
关注(0)|答案(4)|浏览(118)
@FeignClient(...)
public interface SomeClient {
@RequestMapping(value = "/someUrl", method = POST, consumes = "application/json")
    ResponseEntity<String> createItem(...);

}

有没有办法找到createItem API调用的响应时间?我们使用了 Spring Boot ,执行器,普罗米修斯。

yyyllmsg

yyyllmsg1#

我们有直接的和定制的方法来记录伪客户机的请求和响应(包括响应时间),我们必须注入feign.logger.level bean,就是这样。
1.* * 默认/直接方式**

@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日志记录包/指定显式日志记录器类,否则它将不工作。

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);
    }
}

我们还必须注入customFeignLogger类bean

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

如果您自己构建FeignClient,那么您可以使用定制的日志记录器来构建它:

Feign.builder().logger(new customFeignLogger()).logLevel(Level.BASIC).target(SomeFeignClient.class,"http://localhost:8080");
qmelpv7a

qmelpv7a2#

将以下注解添加到项目中。

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();

                }
            }
        }
    }
}

然后用@DebugTracking注解您要在@FeignClient中跟踪的方法。

cld4siwp

cld4siwp3#

我正在使用以下代码(与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");
    }
}
ih99xse1

ih99xse14#

正确的方法是使用上面提到的自定义记录器。使用@Aspect是错误的。使用它可以在服务周围创建额外的 Package 器。Feign已经记录了这个指标。请从Feign获取该指标。

相关问题