Ich habe einen RESTEasy-Webserver mit vielen Methoden. Ich möchte Logback implementieren, um alle Anforderungen und Antworten zu verfolgen, aber ich möchte nicht, dass log.info()
zu jeder Methode hinzugefügt wird.
Vielleicht gibt es eine Möglichkeit, Anfragen und Antworten an einem Ort abzufangen und zu protokollieren. Vielleicht so etwas wie ein Filter für die HTTP-Request-Prozesskette für 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());
}
}
...
}
Sie können Filter erstellen und diese einfach an die Endpunkte binden, die Sie für die Protokollierung benötigen. So bleiben Ihre Endpunkte schlank und konzentrieren sich auf die Geschäftslogik.
Um Filter an Ihre REST -Endpunkte zu binden, stellt JAX-RS die Meta-Annotation @NameBinding
bereit und kann wie folgt verwendet werden:
@NameBinding
@Retention(RUNTIME)
@Target({TYPE, METHOD})
public @interface Logged { }
Die Annotation @Logged
wird zum Dekorieren einer Filterklasse verwendet, die ContainerRequestFilter
implementiert, sodass Sie die Anfrage bearbeiten können:
@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
}
}
Die Annotation @Provider
/ kennzeichnet eine Implementierung einer Erweiterungsschnittstelle, die während einer Provider-Scan-Phase von der JAX-RS-Laufzeit erkannt werden kann.
Die ContainerRequestContext
hilft Ihnen, Informationen aus der HTTP-Anfrage zu extrahieren.
Hier sind Methoden aus der ContainerRequestContext
-API , um Informationen aus der HTTP-Anforderung abzurufen, die für Ihre Protokolle nützlich sein können:
ContainerRequestContext#getMethod()
: Ruft die HTTP-Methode aus der Anforderung ab.ContainerRequestContext#getUriInfo()
: Ruft URI-Informationen von der HTTP-Anforderung ab.ContainerRequestContext#getHeaders()
: Ruft die Header von der HTTP-Anfrage ab.ContainerRequestContext#getMediaType()
: Ruft den Medientyp der Entität ab.ContainerRequestContext#getEntityStream()
: Ruft den Entitätseingangsstrom ab.Erwägen Sie zum Protokollieren der Antwort die Implementierung einer 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
}
}
Die ContainerResponseContext
hilft Ihnen, Informationen aus der HTTP-Antwort zu extrahieren.
Hier sind einige Methoden aus der ContainerResponseContext
-API , um Informationen aus der HTTP-Antwort zu erhalten, die für Ihre Protokolle nützlich sein können:
ContainerResponseContext#getStatus()
: Ruft den Statuscode aus der HTTP-Antwort ab.ContainerResponseContext#getHeaders()
: Ruft die Header aus der HTTP-Antwort ab.ContainerResponseContext#getEntityStream()
: Ruft den Entitätsausgabestrom ab.Um den Filter an Ihre Endpunktmethoden oder -klassen zu binden, kommentieren Sie sie mit der oben definierten @Logged
-Annotation. Für die Methoden und/oder Klassen, die mit Anmerkungen versehen sind, werden die Filter ausgeführt:
@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
...
}
}
Im obigen Beispiel werden die Protokollierungsfilter nur für myLoggedMethod(Long)
ausgeführt, da sie mit @Logged
kommentiert sind.
Neben den in ContainerRequestContext
und ContainerResponseFilter
schnittstellen verfügbaren Methoden können Sie ResourceInfo
in Ihre Filter einfügen, indem Sie @Context
verwenden:
@Context
ResourceInfo resourceInfo;
Es kann verwendet werden, um die Method
und die Class
zu erhalten, die mit der angeforderten URL übereinstimmen:
Class<?> resourceClass = resourceInfo.getResourceClass();
Method resourceMethod = resourceInfo.getResourceMethod();
HttpServletRequest
und HttpServletResponse
sind auch für die Injektion verfügbar:
@Context
HttpServletRequest httpServletRequest;
@Context
HttpServletResponse httpServletResponse;
In diesem answer finden Sie die Typen, die mit @Context
injiziert werden können.
Probieren Sie Interceptors aus (nicht nur Vanilla EJB-Interceptors, sondern auch CDI).
Sie sind für die Umsetzung von Cross Cutting Concerns (Aspekten) da.