简体   繁体   中英

How can I configure DropWizard to explain request failures?

If I send JSON without a request body:

POST /stuff
Content-Type: application/json
Content-Length: 0
                       <---- Body missing!

… to my DropWizard (Jersey) resource,

private class PostBody { public String a };

@POST
@Consumes(MediaType.APPLICATION_JSON)
public Response create(@Valid PostBody body)
{ … }

Right now, I only get one line in the log:

127.0.0.1 - - [04/May/2015:13:21:25 +0000] "POST /stuff HTTP/1.1" 422 370 232 232

HTTP 422 is not an unreasonable hint, but I must believe there was a more detailed message to be had here. Similarly, if a header is missing or path component doesn't match the provided format, I should like to see a log line like "Header ____ could not be parsed".

127.0.0.1 - - [04/May/2015:13:21:25 +0000] Received "POST /stuff HTTP/1.1"
127.0.0.1 - - [04/May/2015:13:21:25 +0000] Error: Body could not be parsed (Failure while deserializing field "a")
127.0.0.1 - - [04/May/2015:13:21:25 +0000] "POST /stuff HTTP/1.1" 422 370 232 232

Is such logging built into DropWizard? How can I enable it?

You'll need to override exception mappers in that case. In 422 case, you need to implement an exception mapper for ConstraintViolationException.

See this answer: Override DropWizard ConstraintViolation message

By default, Dropwizard/Jersey maps exceptions into responses (default exception mappers), and in some cases, logging is limited and thus not very useful; because of simplicity or simply to force the developer to do better logging by himself. For reference, a more complete description:

" Jersey, or should I say JAX-RS, exposes a mechanism that will allow you to map a thrown Exception or Throwable to a REST response, instead of being unhandled and being presented to the user as some stacktrace or error text. (This mechanism requires than you implement the generic ExceptionMapper interface and then register it.) This is excellent for REST APIs that like to return errors back to the client as part of using the API, like returning a JSON representation of an Exception that can be parsed and handled on the client. " ( source )

Programmatically, creating your own custom exception mappers can be accomplished by the steps that follow. Code is considering Dropwizard 0.9.x, and the specific case in your question; however, to tackle other cases/exceptions the process is analogous. Also some lines are omitted for simplicity):

  1. Disabling the default exception mappers:

    • via your Application subclass:

       AbstractServerFactory sf = (AbstractServerFactory) config.getServerFactory(); sf.setRegisterDefaultExceptionMappers( false ); 
    • via your application configuration:

       server: registerDefaultExceptionMappers: false 
  2. Creating your custom exception mappers that extend the original ones by adding logging (JSON and validation exceptions):

     public class CustomConstraintViolationExceptionMapper extends ConstraintViolationExceptionMapper { @Override public Response toResponse( ConstraintViolationException exception ) { Response superResponse = super.toResponse( exception ); ValidationErrorMessage validationErrorMessage = (ValidationErrorMessage) superResponse.getEntity(); log.error( String.format( "%s\\t%s", exception.getMessage(), String.join( ";", validationErrorMessage.getErrors() ) ) ); return superResponse; } } public class CustomJsonProcessingExceptionMapper extends JsonProcessingExceptionMapper { @Override public Response toResponse( JsonProcessingException exception ) { log.error( String.format( "%s", exception.getOriginalMessage() ) ); return super.toResponse( exception ); } } 
  3. Register your created custom exception mappers:

     environment.jersey().register( new CustomConstraintViolationExceptionMapper() ); environment.jersey().register( new CustomJsonProcessingExceptionMapper() ); 
  4. Don't forget to add back the other default exception mappers (if need be - check Dropwizard's code ):

     environment.jersey().register( new LoggingExceptionMapper<Throwable>(){} ); environment.jersey().register( new EarlyEofExceptionMapper() ); 
  5. The end result will be logging such as:

     ERROR [2016-07-05 13:06:36,690] xyCustomConstraintViolationExceptionMapper: The request entity had the following errors: field may not be empty ERROR [2016-07-05 13:19:41,326] xyCustomJsonProcessingExceptionMapper: Unrecognized field "UnknownField" (class xyzXyz), not marked as ignorable 

For more information on the subject, you can also follow these references:

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM