Run-time Debug Messages

Brief

Supply a straight-forward means of tracing program flow through the APS library for debugging and logging purposes.  In particular, to support the selective display of helpful information as supplied by compiled macros in library functions, and to categorise and group this information according to message class (type/meaning) and channel (unit representing a functional block).  The contents of these messages are entirely at the discretion of the programming team.

Needs

This component must be able to...

Background

Existing Support in APS

APS currently defines a TRACE pre-processor macro in apsinternal.h to output freeform printf-formatted text via stdout.  The mechanism does not attempt to format the text or to supply additional information (such as function and line location), nor does it distinguish between different classes of messages.  It is also not possible to selectively choose which messages are to be displayed.

WINE (WINE Is Not an Emulator)

WINE provides a simple interface for debugging the source on a per-module basis.   While most source files designate which channel is to be used by default, it is also possible for one to direct messages to multiple different channels.  Clearly this greatly simplifies the task of breaking up the code into manageable debugging segments.

Message Classes

WINE subdivides each channel into four independently-controlled message classes:

Message Channels

WINE defines a plurality of independent message channels.  While the channels do not represent different output pathways, they do provide independent controls over which messages are to be output and which are to be ignored.  The set of selected channels and classes is generally represented by the key [class]{+-}channel[,...] which must be passed to the -debug-msg argument at run-time.  For instance, all Postscript printer driver related messages are grouped under the heading of psdrv.  This allows a user to monitor that channel without being bombarded by literally millions of other unrelated messages.  Moreover, it is possible to monitor only particular classes of messages such as "err" or "fixme" using the special "all" meta-channel.

e.g. +all,trace-somemodule : enable all messages, except trace class in somemodule

Output Formatting

Output is preformatted by the interface such that each message contains:

Compiler Support

Remarks

Although not perfect, the WINE idea appears to be a good starting point for our new design.  It main flaw is that the messages which are produced are difficult to read at a glance.  They also fail to provide sufficient context information in many cases thereby requiring the user to "grep" and examine the source code in order to further diagnose the problem.

New design

Pursuant to discussions among the APS Development Team with the original design criteria, the following design is proposed as being adequate.  It is designed to be both flexible and extensible while remaining lightweight.

Message Classes

Five classes of message have been defined.  It is not permitted to use a class for other than it was intended.

Message Channels

The following channels are defined for the moment following the same design concept as in WINE.  This list should be updated as new ones are added or old ones are split.   Each channel name is followed by a list of default source file associations:

Output Formatting

The output format will be managed exclusively by the library to ensure clarity and conformance to the following guidelines.

All messages will be formatted such that...

In addition, user messages should follow the following style guide...

e.g.:

123456789012345678901234567890234567890123456789012345678901234567890123456789
====== LPR      ERROR = LprSetConfigFlags (lprtransport.c:729) ===============
  Could not make necessary changes to filter configurations due to
  filesystem error.  Returning APS_ACCESS_DENIED.
====== LPR      TRACE = ReallyReallyReallyReallyLongNam(lprtransport.c:729) ==
  This message will contain a hard linebreak as its author did not take term
  inal with into account and the code does not (presently) bother to word-wr
  ap in a pretty fashion.
====== PRINTCAP MSG   = doSomeThing (readwriteprintcap.c:1234) ===============
  Was unable to create "/etc/printcap" file, returning an error.

Compile-time Specification of Default Active Channels

Default active channels may be specified when configuring and affect all subsequent compilations. The --enable-debug-trace parameter consists of two parts separated by a colon. If not specified, the default is: msg,warn,error,fixme:all+error+fixme.

The first part of the --enable-debug-trace parameter (before the colon) specifies message classes which are to be enabled. All others will be compiled out. This may be useful for improving performance or before release to market. Classes must be specified using the key [all|default][class[,...]].

The second part specifies which channels are to be enabled by default at run-time. The specification of channels is similar to that of WINE, but reversed: their order matches that of the tokens in debug messages that are produced.  Channel specification key: [default][channel{+-}[class][{+-}[class][...]][,...]].  Channels and classes may also be identified here using the "all" keyword.

e.g.:

./configure --enable-debug-trace=msg,warn,error,fixme:all+error+fixme
./configure --enable-debug-trace=default:default
    default settings

./configure --enable-debug-trace=all:lpr+all-fixme
    enables all lpr messages except those which are fixme's
    enables all classes

./configure --enable-debug-trace=default:all+error+fixme,attr-all,lpr+trace fixme,error,warn,trace
    enables all errors and fixme's, except those in attr, and enables lpr trace messages [and errors and fixme's]
    enables classes fixme, error, warn, msg

Run-time Specification of Active Channels

It is possible to override the default set of enabled channels by defining the environment variable "APSTRACE" in the application's context.  The contents of this variable override those of the --default-trace parameter.  The variable may be empty, but if it does not exist the configured defaults are preserved.

It is not possible, without recompilation, to enable classes which have been disabled by the --enable-debug-trace configuration parameter.

e.g.:

$ echo "Enabling all debug message channels for lprtransport and related components"
$ export APSTRACE="lpr+all,transport+all,utils+all"
$ myApplication

$ echo "Disabling all debug message channels"
$ export APSTRACE=""
$ myApplication

Interface

The supplied interface is heavily inspired from the WINE sources.  The macros have been renamed to avoid name clashing and confusion between the APS and WINE teams due to the apparent functional similarities.

Definitions:
    channel : unquoted literal all-lowercase channel identifier
    fmt : printf-style format string
    ... : variable arguments for printf formatting

These macros select and declare channels...
N.B All channels must be declared in a source file before they can be used.

These macros operate on the default channel...

These macros operate on the specified channel (unquoted literal)... Specifying "default" (w/o quotes) causes the action to occur on the default channel.

e.g.:

#include <stdlib.h>
#include "apsinternal.h"
#include "aps.h"

DEBUG_CHANNEL_DEFAULT(attrprov)
DEBUG_CHANNEL(attr)

int myFunction(const char *name, int value)
{
    TRACE("got name=\"%s\", value=%d", name, value);
    if (MSG_ON) {
        /* do some extra work to put out a nice-looking message */
        MSG("Object \"%s\" will be removed in %d seconds",
            getExpiryTimeRemaining(name));
    }
    TRACE("returning TRUE");
    return TRUE;
}

int mySpecialFunction(int foobar)
{
    TRACE_ON_(attr)("got foobar=%d", foobar);
    FIXME_ON_(attr)("unimplemented");
    return 0;
}

Future Directions

Corel Corporation
Linux Printing (APS) Development Team
April 2000.