如何在 JAX-RS 过滤器中记录请求处理时间
How to log request processing time in JAX-RS filter
我有 JAX-RS 网络应用程序,我想记录从请求到响应的时间。在 Spring Boot with 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
变量副本,因为它始终等于零。所以我无法计算变量之间的差异。我可以做些什么来记录请求处理时间?
实际上,由于 MicroProfile Metrics API:
,Quarkus 内置了类似的东西
将 SmallRye Metrics 扩展 (quarkus-smallrye-metrics) 添加到您的 pom.xml
默认情况下应启用此功能,但您可以通过将以下内容添加到 application.properties:
来明确启用要注册的 RestEasy/JAX-RS 指标
quarkus.smallrye-metrics.extensions.enabled=true
指标(# 次调用,每次调用花费的时间)将添加到 /metrics 端点。一旦您调用端点,指标就会显示出来。
由于您在同一个 class 中实现 ContainerRequestFilter
和 ContainerResponseFilter
,似乎创建了 2 个不同的实例,因此变量 requestStartTime
是不同的2 个实例。
这个问题是在 Eclipse Jersey 项目上报告的,被认为是一个错误,已经解决,参见 https://github.com/eclipse-ee4j/jersey/issues/3796。
这里是整个讨论:https://github.com/eclipse-ee4j/jaxrs-api/issues/605。
争论的焦点是此行为不符合 JAX-RS 规范(第 4.1 节):
By default a single instance of each provider class is instantiated
for each JAX-RS application
但是 Quarkus 使用 RESTEasy,所以我猜它不包含该修复程序。
无论如何,即使创建了单个实例(例如使用注释 @Singleton
),您仍然不应该使用实例变量来保持开始时间,因为并发请求会覆盖它(感谢@ areus 指出了这一点)。
相反,您可以在 ContainerRequestFilter.filter()
上保存 ContainerRequestContext
属性的开始时间,然后获取它并在 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");
}
}
我有 JAX-RS 网络应用程序,我想记录从请求到响应的时间。在 Spring Boot with 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
变量副本,因为它始终等于零。所以我无法计算变量之间的差异。我可以做些什么来记录请求处理时间?
实际上,由于 MicroProfile Metrics API:
,Quarkus 内置了类似的东西将 SmallRye Metrics 扩展 (quarkus-smallrye-metrics) 添加到您的 pom.xml
默认情况下应启用此功能,但您可以通过将以下内容添加到 application.properties:
来明确启用要注册的 RestEasy/JAX-RS 指标quarkus.smallrye-metrics.extensions.enabled=true
指标(# 次调用,每次调用花费的时间)将添加到 /metrics 端点。一旦您调用端点,指标就会显示出来。
由于您在同一个 class 中实现 ContainerRequestFilter
和 ContainerResponseFilter
,似乎创建了 2 个不同的实例,因此变量 requestStartTime
是不同的2 个实例。
这个问题是在 Eclipse Jersey 项目上报告的,被认为是一个错误,已经解决,参见 https://github.com/eclipse-ee4j/jersey/issues/3796。
这里是整个讨论:https://github.com/eclipse-ee4j/jaxrs-api/issues/605。
争论的焦点是此行为不符合 JAX-RS 规范(第 4.1 节):
By default a single instance of each provider class is instantiated for each JAX-RS application
但是 Quarkus 使用 RESTEasy,所以我猜它不包含该修复程序。
无论如何,即使创建了单个实例(例如使用注释 @Singleton
),您仍然不应该使用实例变量来保持开始时间,因为并发请求会覆盖它(感谢@ areus 指出了这一点)。
相反,您可以在 ContainerRequestFilter.filter()
上保存 ContainerRequestContext
属性的开始时间,然后获取它并在 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");
}
}