我有一个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());
}
}
...
}
答案 0 :(得分:66)
您可以创建过滤器并轻松将它们绑定到您需要记录的端点,使您的端点保持精简并专注于业务逻辑。
要将过滤器绑定到REST端点,JAX-RS提供了元注释@NameBinding
,可以按如下方式使用:
@NameBinding
@Retention(RUNTIME)
@Target({TYPE, METHOD})
public @interface Logged { }
@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请求中获取可能对您的日志有用的信息:
ContainerRequestContext#getMethod()
:从请求中获取HTTP方法。ContainerRequestContext#getUriInfo()
:从HTTP请求中获取URI信息。ContainerRequestContext#getHeaders()
:从HTTP请求中获取标头。ContainerRequestContext#getMediaType()
:获取实体的媒体类型。ContainerRequestContext#getEntityStream()
:获取实体输入流。要记录响应,请考虑实施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响应中获取可能对您的日志有用的信息:
ContainerResponseContext#getStatus()
:从HTTP响应中获取状态代码。ContainerResponseContext#getHeaders()
:从HTTP响应中获取标头。ContainerResponseContext#getEntityStream()
:获取实体输出流。要将过滤器绑定到端点方法或类,请使用上面定义的@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;
Class<?> resourceClass = resourceInfo.getResourceClass();
Method resourceMethod = resourceInfo.getResourceMethod();
HttpServletRequest
和HttpServletResponse
也可以注射:
@Context
HttpServletRequest httpServletRequest;
@Context
HttpServletResponse httpServletResponse;
答案 1 :(得分:0)
尝试使用拦截器(不仅仅是可以使用CDI的普通EJB拦截器)。
他们在那里执行交叉切割问题(方面)。