8.1 Messages, Warnings, and Errors
A ROSE application may generate Part 21 syntax error or warning messages when reading a file, as well as other useful status messages. By default, these are printed to the console via stdout or stderr , but Windows programs can easily send them to a window as described in ST-Developer Message Window.
Internally, ROSE handles all messages through a special reporter object. This object has many configuration options, and applications can replace it with a subclass of RoseErrorReporter for completely customized message handling.
Errors and warnings from ROSE are prefixed by a tag indicating the severity, and then followed by a brief explanation of the error, as shown below:
ROSE: warning: $ROSE not set. System schemas may not be found.
Informational messages do not have any prefix, such as the banner, shown below, that prints out whenever ROSE is initialized:
ST-DEVELOPER
System Release v12
Copyright (c) 1991-2007 by
STEP Tools Inc., Troy, New York
All Rights Reserved
It is possible to turn off the printing of informational messages. This might be desirable when preparing an application for production release. The RoseInterface::quiet() function turns off printing of all informational messages.
ROSE.quiet (TRUE); /* turn off informational messages */
. . .
ROSE.quiet (FALSE); /* turn messages back on */
The RoseErrorReporter ranks messages by severity. The least severe is message, then warning, error, and fatal. The quiet() function works by setting the error reporter's print threshold so that informational messages are not reported. This threshold can be set to other levels so that, for example, only error and fatal severity messages are printed. The severity levels are given by the RoseSeverity as shown below:
ROSE_SEV_FATAL = 4 /* Fatal error, no recovery possible */
ROSE_SEV_ERROR = 3 /* Problem, unable to complete function */
ROSE_SEV_WARNING = 2 /* Problem, may still complete function */
ROSE_SEV_MESSAGE = 1 /* Application status messages */
ROSE_SEV_NULL = 0 /* severity unset */
The RoseErrorReporter::report_threshold() function sets the minimum severity at which messages will be printed. The default threshold is ROSE_SEV_MESSAGE . The following example has the same effect as the quiet() function. The RoseInterface::error_reporter() function returns the error reporter object from the RoseInterface object.
ROSE.error_reporter()-> report_threshold (ROSE_SEV_WARNING);
A version of the report_threshold() function that takes no parameters returns the current threshold value, so it is possible to bump up the threshold temporarily and then reset it to the previous value:
RoseSeverity sev;
sev = ROSE.error_reporter()-> report_threshold();
ROSE.error_reporter()-> report_threshold (ROSE_SEV_ERROR);
/* some code that would generate unwanted warnings */
ROSE.error_reporter()-> report_threshold (sev);
Similarly, there is a threshold that controls whether the reporter will continue or exit after receiving an error. The default exit threshold is ROSE_SEV_ERROR . The reporter continues execution after informational and warning messages, but will exit after error and fatal messages. The RoseErrorReporter::exit_threshold() function can be used to change this behavior. The following example shows how to set the exit threshold so that an application keeps executing after an error:
/* not recommended*/
ROSE.error_reporter()-> exit_threshold (ROSE_SEV_FATAL);
Some functions may not be able to recover from conditions more severe than ROSE_SEV_WARNING and so the use of this function is not recommended. It may keep your application running, but you may see inconsistent or inexplicable results later on in execution.
8.2 Logging and Debugging
The ROSE error reporter can log error messages to a file. This is useful for debugging applications that has turned off message printing or on systems that do not have a proper stdout , such as Windows. Logging can be controlled from within the application or from the environment. Within an application, logging can be activated by using the RoseErrorReporter::log() and RoseErrorReporter::log_filename() functions:
ROSE.error_reporter()-> log_filename ("logfile");
ROSE.error_reporter()-> log(); /* turn it on */
. . .
ROSE.error_reporter()-> log (FALSE); /* turn it off */
This fine-grained control may be useful in some situations, but the most common use of logging is to record an entire application run. The $ROSE_LOG environment variable controls logging from the command line. Set $ROSE_LOG to the name of a log file to turn on logging. The file will be opened in "append" mode and all messages will be added to it. If you have several ROSE applications running at the same time, they will all write to the file.
% setenv ROSE_LOG logfile -- Turns on logging
% unsetenv ROSE_LOG -- Turns off logging
Any message that is reported will be logged. By default, this threshold is set to ROSE_SEV_MESSAGE , and this is the threshold used when logging with the $ROSE_LOG mechanism. Setting the report threshold is only possible from within the application, but setting the $ROSE_DEBUG environment variable will override any threshold settings and print all messages.
% setenv ROSE_DEBUG foo -- Force reporting of all messages
% unsetenv ROSE_DEBUG -- Back to normal reporting
This feature is useful for tracking down problems in an execution that does not print many messages.
8.3 Error Reporting
The RoseErrorReporter can report predefined as well as ad-hoc errors. Predefined errors are RoseError objects associated with a RoseErrorContext object. These RoseError objects define a numeric code, severity, and printf-style message for each error. They may be reported by passing the numeric code to the RoseInterface::report() or the RoseErrorContext::report() functions. The error contexts group errors and provide additional control over reporting parameters. For example, the ROSE library defines contexts for general system errors and STEP Part 21 file errors, returned by the rose_ec() and rose_io_ec() functions, respectively. The context for the Part 21 files sets separate thresholds to make sure that file error messages are always seen.
The predefined system errors used by the ROSE library are listed in Section 8.4. In addition to the predefined errors, ad-hoc errors can be reported with the RoseInterface::error() , RoseInterface::warning() , and RoseInterface::message() functions, or the corresponding messages on the RoseErrorContext class. The report() , error() , warning() , and message() functions on RoseInterface are the same as the equivalent function on the rose_ec() error context. Note in the following examples that a trailing newline " \n " is omitted. The report routines add one automatically.
ROSE.warning ("Could not open file %s.", filename);
rose_ec()-> warning ("Could not open file %s.", filename);
ROSE.error ("Out of memory!");
rose_ec()-> error ("Out of memory!");
ROSE.report (ROSE_EC_NO_DESIGN, designname);
rose_ec()-> report (ROSE_EC_NO_DESIGN, designname);
When an error of ROSE_SEV_ERROR severity is reported, the code and matching context are saved and can be queried with RoseInterface::errcode() and RoseInterface::errcontext() . Warnings and messages do not set errcode() . These can be cleared with the RoseInterface::error_reset() function.
The errcode() method returns the numeric code for the last error seen, or zero ( ROSE_OK ) if there was no error. If the error was a general one reported through the error() member function, the code returned is ROSE_GENERAL . The errcontext() function returns the context object that defines the error. The error_reset() function can be used to clear the error status.
Trace Information
When an error message is printed, the RoseErrorReporter can prepend some trace information to the message. The reporter keeps a stack of special traceobjects that provide this information. When printing a message, the reporter will get a trace string from the top object. If the top object is null, no trace string is added.
The trace objects are derived from the RoseErrorTrace class. The location() virtual function provides trace information that is used as a prefix for error messages. Use these to indicate a location in a file, an application name, or whatever. There are subclasses for files and other named locations.
class RoseErrorTrace /* base class */
class RoseErrorNamedTrace /* prepends: name: */
class RoseErrorFileTrace /* prepends: "filename":<line>: */
To use the trace objects, create them and then push them on the reporter stack using the push_trace() function. Any message that is printed will use the location information from the top object. When done, pop it off using the pop_trace() function. The following example shows how to prepend the application name to every message using the RoseErrorNamedTrace class:
RoseErrorNamedTrace trace;
trace.name (argv[0]);
ROSE.error_reporter()-> push_trace (&trace);
[ . . .]
ROSE.error_reporter()-> pop_trace();
The following example shows how to prepend a file name and line number to every message using the RoseErrorFileTrace class:
RoseErrorFileTrace trace;
trace.file ("filename");
trace.line (0);
ROSE.error_reporter()-> push_trace (&trace);
[ . . .]
trace-> increment_line();
[ . . .]
ROSE.error_reporter()-> pop_trace();
The following example shows how to temporarily remove all trace information from the messages by pushing a null trace object on the stack:
ROSE.error_reporter()-> push_trace (0);
[ . . .]
ROSE.error_reporter()-> pop_trace();
8.4 ROSE Library Predefined Errors
These are the predefined errors, warnings and messages that may appear while processing any of the core system functions. The errors and warnings are prefixed with ROSE_EC while the messages are prefixed by ROSE_MSG . These errors are defined in rose_errors.h .
|
Error Code |
Severity |
Error Message |
|---|---|---|
ROSE_EC_BAD_ATT
|
WARNING
|
"Attribute %s.%s not found."
|
ROSE_EC_BAD_BINCHAR
|
WARNING
|
"Bad hex character '%c' for binary value. Using '0'."
|
ROSE_EC_BAD_BINSTART
|
WARNING
|
"Bad first character '%c' for binary value. Expecting 0, 1, 2, or 3."
|
ROSE_EC_BAD_CLASS
|
WARNING
|
"Class %s not found."
|
ROSE_EC_BAD_DOMAIN
|
WARNING
|
"Domain %s not found."
|
ROSE_EC_BAD_HASH
|
ERROR
|
"Could not find hash insertion point."
|
ROSE_EC_BAD_NODETYPE
|
ERROR
|
"Unknown RoseNodeType %d found."
|
ROSE_EC_BAD_SCHEMA
|
WARNING
|
"Schema %s not found."
|
ROSE_EC_EXTRA_OBJECTS
|
WARNING
|
"Design contains extra '%s' objects."
|
ROSE_EC_FREAKY_ENUM
|
ERROR
|
"Found enum of size (%d).Expected: %d %d or %d"
|
ROSE_EC_FREAKY_PRIM
|
ERROR
|
"Found primitive value of size (%d).Expected: %d %d or %d"
|
ROSE_EC_GEN_DOMAIN
|
WARNING
|
"Generating domain%s - %s."
|
ROSE_EC_GEN_DUP_SCHEMA
|
WARNING
|
"Generating schema - schema '%s' is in search path, generating from scratch."
|
ROSE_EC_GEN_NULL_SCHEMA
|
WARNING
|
"Generating schema - schema name cannot be null."
|
ROSE_EC_GEN_SCHEMA
|
WARNING
|
"Generating schema - creating schema '%s'."
|
ROSE_EC_INVALID_CHANGE
|
ERROR
|
"Change value not allowed on '%s' object"
|
ROSE_EC_INVALID_INSERT
|
ERROR
|
"Insert not allowed on '%s' object"
|
ROSE_EC_INVALID_REMOVE
|
ERROR
|
"Remove not allowed on '%s' object"
|
ROSE_EC_LOCKED_DESIGN
|
WARNING
|
"Attempt to modify read-only design '%s'."
|
ROSE_EC_MUST_OVERRIDE
|
ERROR
|
"%s::%s: Method must be overridden."
|
ROSE_EC_NESTED_TRAVERSAL
|
ERROR
|
"Traversal already in progress, nested traversals not allowed."
|
ROSE_EC_NOT_IMPLEMENTED
|
ERROR
|
"%s::%s: Sorry, method not yet implemented."
|
ROSE_EC_NO_ATT
|
WARNING
|
"No attribute specified."
|
ROSE_EC_NO_COPY_CTOR
|
WARNING
|
"No copy ctors for 'best-fit' classes. '%s' copied as a '%s'."
|
ROSE_EC_NO_CTOR
|
ERROR
|
"Class '%s' has no creator function."
|
ROSE_EC_NO_DESIGN
|
WARNING
|
"Problems reading design '%s'"
|
ROSE_EC_NO_FORMAT
|
WARNING
|
"Format '%s' not available, no such repository present."
|
ROSE_EC_NO_KEYSTONE_OID
|
WARNING
|
"No OID for built-in type '%s'"
|
ROSE_EC_NO_MEMORY
|
FATAL
|
"Out of memory, can not continue."
|
ROSE_EC_NO_PROTO
|
ERROR
|
"Class '%s' has no prototype."
|
ROSE_EC_NO_REPO
|
WARNING
|
"Repository '%s' not found."
|
ROSE_EC_OID_BOOT
|
ERROR
|
"Problems creating ROSE oid index."
|
ROSE_EC_OID_EXISTS
|
ERROR
|
"Object with the requested OID already exists in design '%s'."
|
ROSE_EC_OID_FAILED
|
ERROR
|
"Could not generate unique OID."
|
ROSE_EC_RTP_AFTER_BOOT
|
ERROR
|
"RoseTypePtrs cannot be created after ROSE is initialized."
|
ROSE_EC_RTP_ON_HEAP
|
FATAL
|
"RoseTypePtrs must be statically created."
|
ROSE_EC_UNREGISTERED_REPO
|
WARNING
|
"Repository of type '%s' was not registered."
|
ROSE_MSG_READING_FORMAT
|
MESSAGE
|
"Reading in %s format"
|
ROSE_MSG_WRITING_FORMAT
|
MESSAGE
|
"Writing in %s format"
|