Skip to content

EVF Tutorial Errors

Paul Rogers edited this page May 18, 2019 · 2 revisions

Better Error Reporting

One of the typical user complaints about Drill (or really any Java-based service) is that errors often include a wonderfully robust set of stack traces, but no actual information about what went wrong in a form that helps the user. You can help your user by providing good error messages. We'll discus two techniques for doing so.

UserException

Drill, as a Java application is a bit odd: it does not use the Java checked exception feature. If it did, you'd know what kind of exception to throw when things go wrong. Instead, Drill uses unchecked exceptions. But, which one should you use?

You can actually use any kind you like (IllegalArgumentException, IllegalStateException and so on.) EVF will catch such exceptions and translate them to Drill's UserException class. (The name means, "exception to be sent to the user", not "exception caused by the user.")

UserException provides context information to help the user understand where things went off the rails. While EVF will try to guess if you use your own exceptions, you can do a better job by throwing UserException directly.

The log reader we looked at earlier has some nice examples:

        throw UserException
            .validationError()
            .message("Undefined column types")
            .addContext("Position", patternIndex)
            .addContext("Field name", name)
            .addContext("Type", typeName)
            .build(logger);

UserException works by creating a builder for the type of error you want to throw. For a reader, validationError() or dataReadError() are the most common. Use validation error if something in the setup fails. Use the read error for problems with external data sources or files. You can also use systemError if you detect an internal error, such as a violation of an invariant, that indicates a bug in Drill rather than a problem that the user can fix.

The addContext() methods are key: they allow you to fill in additional information to tell the user what went wrong.

Adding EVF Context

EVF maintains additional context, such as the name of the plugin and the name of the table. You can use that context as follows. (This feature is currently in a pull request, you can use it once the code finds its way into master.) First, in the open() method, obtain the error context:

RowSetContext errorContext;

  @Override
  public boolean open(FileSchemaNegotiator negotiator) {
    errorContext = negotiator.parentErrorContext();

This is the parentErrorContext because it knows about the scan operator and plugin.

Then, use the error context to add more context to your UserException objects:

        UserException.Builder ueb = UserException
          .validationError()
          .message("`columns`[%d] index out of bounds, max supported size is %d",
              maxIndex, TextReader.MAXIMUM_NUMBER_COLUMNS)
          .addContext("Column:", inCol.name())
          .addContext("Maximum index:", TextReader.MAXIMUM_NUMBER_COLUMNS)
          .addContext("Actual index:", maxIndex);
        errorContext.addContext(ueb);
        throw ueb.build(logger);

You can customize the context with more information about your plugin or reader. This is a bit of an advanced topic; ask on the dev list if you want the details.


Next: Support an External Schema

Clone this wiki locally