Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Error/Diagnostics and Tracing/Logging for Daffodil

Design notes and Requirements Analysis

Compilation

Sometimes we return

  1. a value
  2. a set of errors/diagnostics/warnings
  3. both

This suggests that Scala's convention of using an Either object is no good for us, because its very name implies one or the other, not both.  Both will certainly happen if there are only compile-time warnings.

A functional-programming approach to errors/diagnostics, that also is consistent with Daffodil's DSOM model and the OOLAG (object oriented lazy attribute grammar) approach works like this: You call a function or evaluate an expression to create a value. The returned object is always of the correct type, but the returned object represents either a value, a set of errors/diagnostics/warnings, or both. Attributes of the returned object will include the set of errors/diagnostics/warnings, a status of whether the value is ok, or there was an error severe enough to prevent creation of a value.

Example: an xpath expression is compiled into a CompiledExpression type object. This object type should contain a boolean member named hasValue or isRunnable (or perhaps wasCompilationSuccessful()?) which is true of compilation of the xpath succeeded. A member errorSet will be Nil if there are no errors/diagnostics/warnings, otherwise will contain a Set of error/diagnostic/warning objects. If hasValue is true, then any error/diagnostic/warning objects are not ones that prevent the CompiledExpression from being used (i.e., probably all warnings)

In general, this is the idiom for any sort of compilation step. So instead of a compilation action returning an Option[T] where None indicates failure, we get type T, and isRunnable will be true or false.

(TBD: use unapply in Scala to make it possible to use Scala match-case and destructuring to determine the status.)

Runtime

...

  • we will want to do lazy message construction.

...

Error Types

...

  • Schema Definition Error - detected at compile time
  • Schema Definition Error - detected at run time
  • Schema Definition Warning - detected at compile time - not called out explicitly in the spec, though there are many places it says implementations may want to warn....
  • Schema Definition Warning - detected at run time
  • Processing Error - always a run-time thing - causes backtracking when the schema expresses alternatives
  • Recoverable Error - always a run-time thing - never causes backtracking, really this is just a run-time "warning".  We may want to have a threshold that determines how many of these are allowed before it escalates it to either a Processing error (which can cause backtracking), or a fatal error.

...

  • SchemaComponent(s) will contain their schema location.
  • Every sub-structure within a schema component will contain its schema location.
  • At runtime, a data location is either
    • an offset (in bits, bytes, characters, or combination thereof) from the beginning of the data stream
    • a relative offset from another data location (recursively, this bottoms out at the beginning of the data stream)
  • Any data location can always be converted into an absolute location in the data stream, but relative offsets to other locations in the data (e.g., the beginning of the current record) are often more useful for diagnostics.

Continuing Execution After Fatal Error

...

Recovery from a runtime error involves a point of uncertainty expressed in the schema. Consider:  the root element for the parse could be placed as an element reference inside a choice as the first alternative. The second alternative could be one hexBinary type element extending with lengthKind='endOfParent', meaning to the end of the data stream in this case. This second alternative will always succeed to parse, so provides a natural way to move forward if parsing based on the schema and its root element ultimately fails.

However, this is not quite enough, as the user is likely to want to route this hexBinary data blob somewhere, and capture the diagnostic information from the parse failure to keep with it. The normal behavior of a choice where a second alternative succeeds would be to discard error/diagnostic information from any prior failing alternative. Hence, a top-level API is needed which provides access to the failure diagnostic information for the overall parse.

Gathering Multiple Compile-Time Errors

At compile time, we want to gather a set of SDEs to issue to the user. So compilation wants to continue to process more of the schema where possible, gather together the results, and then return that full set of diagnostics from all the compilation results. Given a schema with many top-level elements, we can easily just compile each of the top-level elements regardless of any errors on the other top-level elements, and then present the complete set of errors to the user.  However, it may not be desirable to treat every top-level element as a potential root; this may simply produce many irrelevant errors. A large schema with many top level element declarations may still have only one that is intended to be the document root.

It is harder to gather a set of diagnostics from the compilation of a single root element, rather than stop on the first such issue.The thing to depend on is this:

  • Compilation of each of the children of a sequence or choice can be isolated, and the errors from those compilations concatenated (in schema order) to form the set for the whole compilation.

Tracing/Logging

Purposes of tracing and logging include:

  1. helping Daffodil developers find and isolate bugs in the Daffodil code base.
  2. helping DFDL schema authors write correct schemas by tracing/logging compiler behavior. These traces/logs can be about identifying problems, or simply building confidence that a schema is correct. In the latter case, the trace/log is effectively useful redundant information.
  3. helping DFDL schema authors write correct schemas by tracing/logging runtime behavior.
  4. helping DFDL processor users (who are running applications that embed Daffodil) identify problems in either the data or schemas that purport to describe that data.

...

  • turn on/off this tracing, without having to restart, and similarly control the verbosity of detail in the traces/log, and control any selectivity features of the tracing.
  • supply the streams to which the trace/logs are written. These may or may not be streams leading to a file system.
  • avoid full-disk situations by being notified about the volume of data written to the streams and being able to change the streams without loss of any traces/log records.
  • run forever with tracing/logging turned on, albeit with some performance degradation proportional to the amount of trace/log information being generated.

Coding Style Requirements

...

this page has moved to https://cwiki.apache.org/confluence/display/DAFFODIL/Error%2C+Diagnostics%2C+Tracing%2C+Logging