I have a RESTEasy web server with lot of methods. I want implement logback to track all requests and responses, but I don't want add log.info()
to every methods.
Maybe there's way to catch requests and responses in one place and log it. Maybe something like a filter on HTTP request process chain on 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());
}
}
...
}
You can create filters and easily bind them to the endpoints you need to log, keeping your endpoints lean and focused on the business logic.
Defining a name binding annotation
To bind filters to your REST endpoints, JAX-RS provides the meta-annotation
@NameBinding
and it can be used as following:Logging the HTTP request
The
@Logged
annotation will be used to decorate a filter class, which implementsContainerRequestFilter
, allowing you to handle the request:The
@Provider
annotation marks an implementation of an extension interface that should be discoverable by JAX-RS runtime during a provider scanning phase.The
ContainerRequestContext
helps you to extract information from the HTTP request.Here are methods from the
ContainerRequestContext
API to get information from the HTTP request that can be useful for your logs:ContainerRequestContext#getMethod()
: Get the HTTP method from the request.ContainerRequestContext#getUriInfo()
: Get URI information from the HTTP request.ContainerRequestContext#getHeaders()
: Get the headers from the HTTP request.ContainerRequestContext#getMediaType()
: Get the media type of the entity.ContainerRequestContext#getEntityStream()
: Get the entity input stream.Logging the HTTP response
For logging the response, consider implementing a
ContainerResponseFilter
:The
ContainerResponseContext
helps you to extract information from the HTTP response.Here are some methods from the
ContainerResponseContext
API to get information from the HTTP response that can be useful for your logs:ContainerResponseContext#getStatus()
: Get the status code from the HTTP response.ContainerResponseContext#getHeaders()
: Get the headers from the HTTP response.ContainerResponseContext#getEntityStream()
: Get the entity output stream.Binding the filters to your endpoints
To bind the filter to your endpoints methods or classes, annotate them with the
@Logged
annotation defined above. For the methods and/or classes which are annotated, the filters will be executed:In the example above, the logging filters will be executed only for
myLoggedMethod(Long)
because it's annotated with@Logged
.Additional information
Besides the methods available in
ContainerRequestContext
andContainerResponseFilter
interfaces, you can injectResourceInfo
in your filters using@Context
:It can be used to get the
Method
and theClass
which match with the requested URL:HttpServletRequest
andHttpServletResponse
are also available for injection:Refer to this answer for the types that can be injected with
@Context
.Try Interceptors(not just vanilla EJB interceptors you can use CDI with that).
They are there for implementing Cross Cutting Concerns(aspects).