Запрос регистрации и ответ в одном месте с помощью JAX-RS

У меня есть веб-сервер RESTEasy с множеством методов. Я хочу реализовать logback для отслеживания всех запросов и ответов, но я не хочу добавлять log.info() к каждому методу.

Может быть, есть способ поймать запросы и ответы в одном месте и занести в журнал. Возможно, что-то вроде фильтра на цепочке запросов HTTP-запроса на RESTEasy.

@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());
        }
    }

    ...
}

Ответы

Ответ 1

Вы можете создавать фильтры и легко связывать их с конечными точками, которые вам нужно записывать, сохраняя конечные точки и ориентируясь на бизнес-логику.

Определение аннотации привязки имени

Чтобы привязать фильтры к вашим конечным точкам 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;

Его можно использовать для получения Method и Class, которые соответствуют запрошенному URL:

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

HttpServletRequest и HttpServletResponse также доступны для инъекций:

@Context
HttpServletRequest httpServletRequest;

@Context
HttpServletResponse httpServletResponse;

Обратитесь к этому answer для типов, которые могут быть введены @Context.