
Objective:
Be able to see things in the stdout/stderr during development in house
    For this we create a RI4Logger singleton. This logger DOES NOT
    extend the Java logger. It owns one of its copies. This logger
    will call the system logger and optionally put the same information
    on stdout/stderr


Be able to easily see what is going on given an xml MPLAB X log file. Be able to isolate operations at the following levels:
    + at the OperationInfo level
    + at the Programmer/Debugger level
    + at the runScript level
    + at the USB level (see the raw data)
    + at the exception level

To achieve this last object, we follow the following rules

1) Classes in MainController and those implementing
any of the com.microchip.mplab.libs.RI4ToolsController.interfaces (except
for the implementor of RI4ToolCommUsbInterface) log to INFO.
2) calls in Programmer/Debugger classes and their children are logged as CONFIG
3) calls in Command are logged as FINE (this are the runScript* methods)
4) calls in ToolCommsUsb log to FINER
5) calls to the actual read and send functions in the RI4ToolCommUsbInterface
(which happens only in ToolCommsUsb) log to FINEST. This is the actual
data being sent on the wire.

So we do NOT use the traditional implementations of log.entering/log.exiting.
Our RI4Logger has entering and exiting but they take as argument the Level


Additional some common sense rules

a) If parameters are passed, log them
b) If method is non-void, log result
c) if this is a pass through method (say MainController.getFirmwareInfo()) that calls something else to do the actual job (say com.getFirmwareInfo) do
not follow a, and b. Let the lowest level that gets the actual informatino log it.

The concept is that by looking at a single Level we can see the same problem
through different 'lenses'.

On entering a method that is worth logggin:

    public DeviceFile createDeviceFile(String processor, File f) throws RI4ControllerException {
        logger.entering(Level.FINE, "Commands", String.format("createDeviceFile, processor=%s, file=%s", processor, f.getAbsolutePath()));

"Commands" is the class, and the first keyword on the next string is the
function name "createDeviceFile", followed by space or ,. Then log
args if you want to.
On exit:
        logger.exiting(Level.FINER, "Commands", String.format("createDeviceFile, found %d scripts for processor %s", scripts.size(), processor));
Same, as in enter (class + first keyword being the method), them optionally show the return value.

In order to manage perusing logs, we will use the xmllint utility. This
utility allows you to use an xpath expression to filter data. Since we have
RI4Logger calling the system logger, it turns out that all entries related
to the controller have this entry:

   <class>com.microchip.mplab.libs.RI4ToolsController.RI4Logger</class>

So, we can ask xmllinst for all records with a class value of that, and
with a specific level. For example, if we want to see all FINE and FINER
methods from a log:

$ xmllint --xpath '//record[(level="FINE" and ./class/text()="com.microchip.mplab.libs.RI4ToolsController.RI4Logger") or (level="FINER" and ./class/text()="com.microchip.mplab.libs.RI4ToolsController.RI4Logger")]' MPLABX.xml

