使用JAX-RS在一个位置记录请求和响应

时间:2015-11-12 07:39:59

标签: java rest jax-rs resteasy

我有一个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());
        }
    }

    ...
}

2 个答案:

答案 0 :(得分:66)

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

定义名称绑定注释

要将过滤器绑定到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进行了注释。

其他信息

除了ContainerRequestContextContainerResponseFilter界面中提供的方法外,您还可以使用ResourceInfo在过滤器中注入@Context

@Context
ResourceInfo resourceInfo;

它可用于获取与请求的网址匹配的MethodClass

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

HttpServletRequestHttpServletResponse也可以注射:

@Context
HttpServletRequest httpServletRequest;

@Context
HttpServletResponse httpServletResponse;

有关可以使用answer注入的类型,请参阅此@Context

答案 1 :(得分:0)

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

他们在那里执行交叉切割问题(方面)。