使用 JAX-RS 在一处记录请求和响应

问题描述 投票:0回答:4

我有一个 RESTEasy Web 服务器,有很多方法。我想实现 logback 来跟踪所有请求和响应,但我不想为每个方法添加

log.info()

也许有办法在一个地方捕获请求和响应并记录下来。也许类似于 RESTEasy 上 HTTP 请求处理链上的过滤器。

@Path("/rest")
@Produces("application/json")
public class CounterRestService {

    //Don't want use log in controler every method to track requests and responces
    static final Logger log = LoggerFactory.getLogger(CounterRestService.class); 

    @POST
    @Path("/create")
    public CounterResponce create(@QueryParam("name") String name) {
        log.info("create "+name)
        try {
            CounterService.getInstance().put(name);
            log.info("responce data"); // <- :((
            return new CounterResponce();
        } catch (Exception e){
            log.info("responce error data"); // <- :((
            return new CounterResponce("error", e.getMessage());
        }    
    }

    @POST
    @Path("/insert")
    public CounterResponce create(Counter counter) {
        try {
            CounterService.getInstance().put(counter);
            return new CounterResponce();
        } catch (Exception e){
            return new CounterResponce("error", e.getMessage());
        }
    }

    ...
}
java rest jax-rs resteasy
4个回答
109
投票

您可以创建过滤器并轻松将它们绑定到您需要记录的端点,保持端点精简并专注于业务逻辑。

定义名称绑定注释

为了将过滤器绑定到 REST 端点,JAX-RS 提供了元注释

@NameBinding
,它可以按以下方式使用:

@NameBinding
@Retention(RUNTIME)
@Target({TYPE, METHOD})
public @interface Logged { }

记录 HTTP 请求

@Logged
注解将用于装饰一个过滤器类,该类实现了
ContainerRequestFilter
,允许您处理请求:

@Logged
@Provider
public class RequestLoggingFilter implements ContainerRequestFilter {

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {
        // Use the ContainerRequestContext to extract information from the HTTP request
        // Information such as the URI, headers and HTTP entity are available
    }
}

@Provider
注释标记了扩展接口的实现,该扩展接口应该可以在提供者扫描阶段由 JAX-RS 运行时发现。

ContainerRequestContext
可帮助您从 HTTP 请求中提取信息。

以下是来自

ContainerRequestContext
API 的方法,用于从 HTTP 请求中获取对您的日志有用的信息:

记录 HTTP 响应

要记录响应,请考虑实施

ContainerResponseFilter
:

@Logged
@Provider
public class ResponseLoggingFilter implements ContainerResponseFilter {

    @Override
    public void filter(ContainerRequestContext requestContext, 
                       ContainerResponseContext responseContext) throws IOException {
        // Use the ContainerRequestContext to extract information from the HTTP request
        // Use the ContainerResponseContext to extract information from the HTTP response
    }
}

ContainerResponseContext
可帮助您从 HTTP 响应中提取信息。

以下是

ContainerResponseContext
API 中的一些方法,用于从 HTTP 响应中获取对您的日志有用的信息:

将过滤器绑定到您的端点

要将过滤器绑定到端点方法或类,请使用上面定义的

@Logged
注释对其进行注释。对于带注释的方法和/或类,将执行过滤器:

@Path("/")
public class MyEndpoint {

    @GET
    @Path("{id}")
    @Produces("application/json")
    public Response myMethod(@PathParam("id") Long id) {
        // This method is not annotated with @Logged
        // The logging filters won't be executed when invoking this method
        ...
    }

    @DELETE
    @Logged
    @Path("{id}")
    @Produces("application/json")
    public Response myLoggedMethod(@PathParam("id") Long id) {
        // This method is annotated with @Logged
        // The request logging filter will be executed before invoking this method
        // The response logging filter will be executed before invoking this method
        ...
    }
}

在上面的示例中,日志过滤器将仅针对

myLoggedMethod(Long)
执行,因为它带有
@Logged
注释。

附加信息

除了

ContainerRequestContext
ContainerResponseFilter
接口中可用的方法之外,您还可以使用
ResourceInfo
在过滤器中注入
@Context

@Context
ResourceInfo resourceInfo;

它可用于获取与请求的 URL 匹配的

Method
Class

Class<?> resourceClass = resourceInfo.getResourceClass();
Method resourceMethod = resourceInfo.getResourceMethod();

HttpServletRequest
HttpServletResponse
也可用于注射:

@Context
HttpServletRequest httpServletRequest;

@Context
HttpServletResponse httpServletResponse;

可以参考这个answer了解可以用

@Context
注入的类型。


1
投票

尝试拦截器(不仅仅是普通的 EJB 拦截器,您可以使用 CDI)。

他们的存在是为了实现跨领域关注点(方面)。


1
投票

对于其他使用 Jersey 并尝试解决相同问题的人,有 org.glassfish.jersey.logging.LoggingFeature 可以在客户端或服务器上使用。它将请求和响应记录到 java.util.logging.Logger。

如果需要,可以使用 org.slf4j.bridge.SLF4JBridgeHandler 将输出桥接到 slf4j。


0
投票

我制作了一个小型库来轻松记录请求和响应:JAX-RS Logging

可通过 Maven Central 获取:

<dependency>
    <groupId>com.chavaillaz</groupId>
    <artifactId>jaxrs-logging</artifactId>
</dependency>

并且可以与注释一起使用:

@Logged(requestBody = true, responseBody = true)

记录以下消息(包含许多 MDC 字段):

Processed [method] [URI] with status [status] in [duration]ms
© www.soinside.com 2019 - 2024. All rights reserved.