如何在JAX-RS过滤器中记录请求处理时间

时间:2020-05-05 19:00:11

标签: jax-rs quarkus

我有JAX-RS Web应用程序,我想记录从获取请求到响应的时间。在Spring Boot中使用servlet过滤器很容易。但是我的应用程序中的过滤器无法正常运行:

@Provider
public class RequestLogFilter implements ContainerRequestFilter, ContainerResponseFilter {

    private long requestStartTime;

    @Override
    public void filter(ContainerRequestContext requestContext) {
        requestStartTime = System.currentTimeMillis();
    }

    @Override
    public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) {
        long requestFinishTime = System.currentTimeMillis();
        System.out.println(requestFinishTime - requestStartTime);
    }

}

在第一种方法中工作正常,当前时间戳记写在requestStartTime中。但是,似乎第二个方法拥有自己的requestStartTime变量副本,因为第二个方法始终等于零。所以我不能计算变量之间的差异。我该怎么办才能记录请求处理时间?

2 个答案:

答案 0 :(得分:3)

由于您是在同一类中同时实现ContainerRequestFilterContainerResponseFilter,因此似乎创建了两个不同的实例,因此变量requestStartTime在两个实例之间是不同的。

此问题已在Eclipse Jersey项目上报告,并认为是错误,已解决,请参见https://github.com/eclipse-ee4j/jersey/issues/3796

这里是整个讨论区:https://github.com/eclipse-ee4j/jaxrs-api/issues/605

有论据认为此行为不符合JAX-RS规范(第4.1节):

默认情况下,每个提供程序类的单个实例都被实例化 每个JAX-RS应用程序

但是Quarkus使用RESTEasy,所以我猜它不包含该修补程序。

无论如何,即使创建了一个实例(例如,使用注释@Singleton),您仍不应使用实例变量来保留开始时间,因为并发请求会覆盖它(感谢@areus指出这一点)。

相反,您可以将开始时间保存在ContainerRequestContextContainerRequestFilter.filter()的属性中,然后在ContainerResponseFilter.filter()上获取并使用它:

@Provider
public class RequestLogFilter implements ContainerRequestFilter, ContainerResponseFilter {

    @Override
    public void filter(ContainerRequestContext requestContext) {
        long requestStartTime = System.nanoTime();
        requestContext.setProperty("requestStartTime", requestStartTime);
    }

    @Override
    public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) {
        long requestStartTime = (long) requestContext.getProperty("requestStartTime");
        long requestFinishTime = System.nanoTime();
        long duration = requestFinishTime - requestStartTime;
        System.out.println("duration: " + TimeUnit.NANOSECONDS.toMillis(duration) + " ms");
    }
}

答案 1 :(得分:2)

实际上,由于MicroProfile Metrics API,Quarkus内置了类似的东西:

  1. 将SmallRye Metrics扩展名(quarkus-smallrye-metrics)添加到pom.xml

  2. 默认情况下应启用此功能,但可以通过在application.properties中添加以下内容来显式启用RestEasy / JAX-RS度量标准进行注册:

    quarkus.smallrye-metrics.extensions.enabled = true

度量标准(#次调用,每个过程花费的时间)将添加到/ metrics端点。一旦调用端点,指标就会显示出来。

相关问题