J'ai un serveur Web RESTEasy avec beaucoup de méthodes. Je veux implémenter logback pour suivre toutes les demandes et réponses, mais je ne veux pas ajouter log.info()
à toutes les méthodes.
Peut-être qu’il ya un moyen d’attraper les demandes et les réponses au même endroit et de le consigner. Peut-être que quelque chose comme un filtre sur la chaîne de processus de requête HTTP sur 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());
}
}
...
}
Vous pouvez créer des filtres et les lier facilement aux points de terminaison que vous devez consigner, tout en maintenant vos points de terminaison minces et concentrés sur la logique métier.
Pour lier les filtres à vos points de terminaison REST, JAX-RS fournit la méta-annotation @NameBinding
et peut être utilisé comme suit:
@NameBinding
@Retention(RUNTIME)
@Target({TYPE, METHOD})
public @interface Logged { }
L'annotation @Logged
sera utilisée pour décorer une classe de filtre, qui implémente ContainerRequestFilter
, vous permettant de gérer la demande:
@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
}
}
L'annotation @Provider
marque l'implémentation d'une interface d'extension qui devrait être détectable par le moteur d'exécution JAX-RS au cours d'une phase d'analyse du fournisseur.
La variable ContainerRequestContext
vous aide à extraire des informations de la requête HTTP.
Voici les méthodes de l'API ContainerRequestContext
pour obtenir des informations de la requête HTTP qui peuvent être utiles pour vos journaux:
ContainerRequestContext#getMethod()
: Extrait la méthode HTTP de la requête.ContainerRequestContext#getUriInfo()
: Extrait les informations URI de la requête HTTP.ContainerRequestContext#getHeaders()
: récupère les en-têtes de la requête HTTP.ContainerRequestContext#getMediaType()
: Récupère le type de média de l'entité.ContainerRequestContext#getEntityStream()
: Récupère le flux d'entrée de l'entité.Pour consigner la réponse, envisagez de mettre en œuvre une 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
vous aide à extraire des informations de la réponse HTTP.
Voici quelques méthodes de l'API ContainerResponseContext
pour obtenir des informations de la réponse HTTP qui peuvent être utiles pour vos journaux:
ContainerResponseContext#getStatus()
: Extrait le code d'état de la réponse HTTP.ContainerResponseContext#getHeaders()
: récupère les en-têtes de la réponse HTTP.ContainerResponseContext#getEntityStream()
: récupère le flux de sortie de l'entité.Pour lier le filtre à vos méthodes ou classes de points de terminaison, annotez-les avec l'annotation @Logged
définie ci-dessus. Pour les méthodes et/ou les classes annotées, les filtres seront exécutés:
@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
...
}
}
Dans l'exemple ci-dessus, les filtres de journalisation ne seront exécutés que pour myLoggedMethod(Long)
car ils sont annotés avec @Logged
.
Outre les méthodes disponibles dans les interfaces ContainerRequestContext
et ContainerResponseFilter
, vous pouvez injecter ResourceInfo
dans vos filtres à l'aide de @Context
:
@Context
ResourceInfo resourceInfo;
Il peut être utilisé pour obtenir le Method
et le Class
qui correspondent à l'URL demandée:
Class<?> resourceClass = resourceInfo.getResourceClass();
Method resourceMethod = resourceInfo.getResourceMethod();
HttpServletRequest
et HttpServletResponse
sont également disponibles pour injection:
@Context
HttpServletRequest httpServletRequest;
@Context
HttpServletResponse httpServletResponse;
Reportez-vous à cette answer pour connaître les types pouvant être injectés avec @Context
.
Essayez les intercepteurs (pas seulement les intercepteurs Vanilla EJB, vous pouvez utiliser CDI avec cela).
Ils sont là pour mettre en œuvre les préoccupations transversales (aspects).