![]() |
![]() HP OpenVMS Systems Documentation |
![]() |
OpenVMS Programming Concepts Manual
9.11.2 Logging Error Messages to a FileYou can write a condition handler to obtain a copy of a system error message text and write the message into an auxiliary file, such as a listing file. In this way, you can receive identical messages at the terminal (or batch log file) and in the auxiliary file. To log messages, you must write a condition handler and an action subroutine. Your handler calls the Put Message (SYS$PUTMSG) system service explicitly. The operation of SYS$PUTMSG is described in Section 9.11. The handler passes to SYS$PUTMSG the signal argument vector and the address of the action subroutine. SYS$PUTMSG passes to the action subroutine the address of a string descriptor that contains the length and address of the formatted message. The action subroutine can scan the message or copy it into a log file, or both. It is important to keep the display messages centralized and consistent. Thus, you should use only SYS$PUTMSG to display or log system error messages. Further, because the system default handlers call SYS$PUTMSG to display error messages, your handlers should avoid displaying the error messages. You can do this in two ways:
Figure 9-15 shows the sequence of events involved in calling SYS$PUTMSG to log an error message to a file. Figure 9-15 Using a Condition Handler to Log an Error Message ![]() 9.11.2.1 Creating a Running Log of Messages Using SYS$PUTMSG
To keep a running log (that is, a log that is resumed each time your
program is invoked) of the messages displayed by your program, use
SYS$PUTMSG. Create a condition handler that invokes SYS$PUTMSG
regardless of the signaled condition code. When you invoke SYS$PUTMSG,
specify a function that writes the formatted message to your log file
and then returns with a function value of 0. Have the condition handler
resignal the condition code. One of the arguments of SYS$PUTMSG allows
you to specify a user-defined function that SYS$PUTMSG invokes after
formatting the message and before displaying the message. SYS$PUTMSG
passes the formatted message to the specified function. If the function
returns with a function value of 0, SYS$PUTMSG does not display the
message; if the function returns with a value of 1, SYS$PUTMSG displays
the message. The OpenVMS System Services Reference Manual contains complete specifications for
SYS$PUTMSG.
To keep a running log of messages, you might have your main program open a file for the error log, write the date, and then establish a condition handler to write all signaled messages to the error log. Each time a condition is signaled, a condition handler like the one in the following example invokes SYS$PUTMSG and specifies a function that writes the message to the log file and returns with a function value of 0. SYS$PUTMSG writes the message to the log file but does not display the message. After SYS$PUTMSG writes the message to the log file, the condition handler resignals to continue program execution. (The condition handler uses LIB$GET_COMMON to read the unit number of the file from the per-process common block.)
9.11.3 Using the Message Utility to Signal and Display User-Defined MessagesSection 9.11 explains how the OpenVMS Condition Handling facility displays messages. The signal argument list passed to LIB$SIGNAL or LIB$STOP can be seen as one or more message sequences. Each message sequence consists of a condition value, an FAO count, which specifies the number of FAO arguments to come, and the FAO arguments themselves. (The FAO count is omitted in the case of system and RMS messages.) The message text definition itself is actually a SYS$FAO control string, which may contain embedded $FAO directives. The OpenVMS System Services Reference Manual describes the Formatted ASCII Output (SYS$FAO) system service in detail. The Message utility is provided for compiling message sequences specific to your application. When you have defined an exception condition and used the Message utility to associate a message with that exception condition, your program can call LIB$SIGNAL or LIB$STOP to signal the exception condition. You signal a message that is defined in a message source file by calling LIB$SIGNAL or LIB$STOP, as for any software-detected exception condition. Then the system default condition handlers display your error message in the standard operating system format. To use the Message utility, follow these steps:
See also the description of the Message utility in the OpenVMS Command Definition, Librarian, and Message Utilities Manual.
A message source file contains definition statements and directives. The following message source file defines the error messages generated by the sample INCOME program:
The default file type of a message source file is .MSG. For a complete
description of the Message utility, see the OpenVMS Command Definition, Librarian, and Message Utilities Manual.
To specify the name and number of the facility for which you are defining the error messages, use the .FACILITY directive. For instance, the following .FACILITY directive specifies the facility (program) INCOME and a facility number of 1:
In addition to identifying the program associated with the error messages, the .FACILITY directive specifies the facility prefix that is added to each condition name to create the symbolic name used to reference the message. By default, the prefix is the facility name followed by an underscore. For example, a condition name BADFIXVAL defined following the previous .FACILITY directive is referenced as INCOME_BADFIXVAL. You can specify a prefix other than the specified program name by specifying the /PREFIX qualifier of the .FACILITY directive. By convention, system-defined condition values are identified by the facility name, followed by a dollar sign ($), an underscore (_), and the condition name. User-defined condition values are identified by the facility name, followed by two underscores (_ _), and the condition name. To include two underscores in the symbolic name, use the /PREFIX qualifier to specify the prefix:
A condition name BADFIXVAL defined following this .FACILITY directive is referenced as INCOME__BADFIXVAL. The facility number, which must be between 1 and 2047, is part of the condition code that identifies the error message. To prevent different programs from generating the same condition values, the facility number must be unique. A good way to ensure uniqueness is to have the system manager keep a list of programs and their facility numbers in a file.
All messages defined after a .FACILITY directive are associated with
the specified program. Specify either an .END directive or another
.FACILITY directive to end the list of messages for that program.
Compaq recommends that you have one .FACILITY directive per message
file.
Use the .SEVERITY directive and one of the following keywords to specify the severity of one or more condition values: Success All condition values defined after a .SEVERITY directive have the specified severity (unless you use the /SEVERITY qualifier with the message definition statement to change the severity of one particular condition code). Specify an .END directive or another .SEVERITY directive to end the group of errors with the specified severity. Note that when the .END directive is used to end the list of messages for a .SEVERITY directive, it also ends the list of messages for the previous .FACILITY directive. The following example defines one condition code with a severity of warning and two condition values with a severity of severe. The optional spacing between the lines and at the beginning of the lines is used for clarity.
9.11.3.1.3 Specifying Condition Names and MessagesTo define a condition code and message, specify the condition name and the message text. The condition name, when combined with the facility prefix, can contain up to 31 characters. The message text can be up to 255 characters but only one line long. Use quotation marks (" ") or angle brackets (<>) to enclose the text of the message. For example, the following line from INCMSG.MSG defines the condition code INCOME__BADFIXVAL:
9.11.3.1.4 Specifying Variables in the Message TextTo include variables in the message text, specify formatted ASCII output (FAO) directives. For details, see the description of the Message utility in the OpenVMS Command Definition, Librarian, and Message Utilities Manual. Specify the /FAO_COUNT qualifier after either the condition name or the message text to indicate the number of FAO directives that you used. The following example includes an integer variable in the message text:
The FAO directive !UL converts a longword to decimal notation. To include a character string variable in the message, you could use the FAO directive !AS, as shown in the following example:
If the message text contains FAO directives, you must specify the
appropriate variables when you signal the condition code (see
Section 9.11.4).
Use the DCL command MESSAGE to compile a message source file into an object module. The following command compiles the message source file INCMSG.MSG into an object module named INCMSG in the file INCMSG.OBJ:
To specify an object file name that is different from the source file
name, use the /OBJECT qualifier of the MESSAGE command. To specify an
object module name that is different from the source file name, use the
.TITLE directive in the message source file.
The message object module must be linked with your program so the system can reference the messages. To simplify linking a program with the message object module, include the message object module in the program's object library. For example, to include the message module in INCOME's object library, enter the following:
9.11.3.1.7 Accessing the Message Object Module from Multiple ProgramsIncluding the message module in the program's object library does not allow other programs-access to the module's condition values and messages. To allow several programs access to a message module, create a default message library as follows:
The following example creates the message library MESSAGLIB.OLB, enters the message object module INCMSG.OBJ into it, and makes MESSAGLIB.OLB a default library:
9.11.3.1.8 Modifying a Message Source ModuleTo modify a message in the message library, modify and recompile the message source file, and then replace the module in the object module library. To access the modified messages, a program must relink against the object module library (or the message object module). The following command enters the module INCMSG into the message library MESSAGLIB; if MESSAGLIB already contains an INCMSG module, it is replaced:
9.11.3.1.9 Accessing Modified Messages Without Relinking
To allow a program to access modified messages without relinking,
create a message pointer file. Message pointer files are useful if you
need either to provide messages in more than one language or frequently
change the text of existing messages. See the description of the
Message utility in the OpenVMS Command Definition, Librarian, and Message Utilities Manual.
To signal a user-defined condition value, you use the symbol formed by
the facility prefix and the condition name (for example,
INCOME__BADFIXVAL). Typically, you reference a condition value as a
global symbol; however, you can create an include file (similar to the
modules in the system library SYS$LIBRARY:FORSTSDEF.TLB) to define the
condition values as local symbols. If the message text contains FAO
arguments, you must specify parameters for those arguments when you
signal the condition value.
To signal a user-defined condition value using a global symbol, declare the appropriate condition value in the appropriate section of the program unit, and then invoke the RTL routine LIB$SIGNAL to signal the condition value. The following statements signal the condition value INCOME__NOHOUSE when the value of FIX_HOUSE_NO is less than 1 or greater than the value of TOTAL_HOUSES:
9.11.4.2 Signaling with Local SymbolsTo signal a user-defined condition value using a local symbol, you must first create a file containing PARAMETER statements that equate each condition value with its user-defined condition value. To create such a file, do the following:
In the definition section of your program unit, declare the local symbol definitions by naming your edited listing file in an INCLUDE statement. (You must still link the message object file with your program.) Invoke the RTL routine LIB$SIGNAL to signal the condition code. The following statements signal the condition code INCOME__NOHOUSE when the value of FIX_HOUSE_NO is less than 1 or greater than the value of TOTAL_HOUSES:
9.11.4.3 Specifying FAO ParametersIf the message contains FAO arguments, you must specify the number of FAO arguments as the second argument of LIB$SIGNAL, the first FAO argument as the third argument, the second FAO argument as the fourth argument, and so on. Pass string FAO arguments by descriptor (the default). For example, to signal the condition code INCOME__NONUMBER, where FIX_HOUSE_NO contains the erroneous house number, specify the following:
To signal the condition code NOFILE, where FILE_NAME contains the invalid file specification, specify the following:
Both of the previous examples use global symbols for the condition
values. Alternatively, you could use local symbols, as described in
Section 9.11.4.2.
When you write a condition handler into your program, the process involves one or more of the following actions:
You can write a condition handler to take action when an exception condition is signaled. When the exception condition occurs, the OpenVMS Condition Handling facility sets up the signal argument vector and mechanism argument vector and begins the search for a condition handler. Therefore, your condition-handling routine must declare variables to contain the two argument vectors. Further, the handler must indicate the action to be taken when it returns to the OpenVMS Condition Handling facility. The handler uses its function value to do this. Thus, the calling sequence for your condition handler has the following format:
Handlers can modify the contents of either the signal-args vector or the mechanism-args vector. In order to protect compiler optimization, a condition handler and any routines that it calls can reference only arguments that are explicitly passed to handlers. They cannot reference COMMON or other external storage, and they cannot reference local storage in the routine that established the handler unless the compiler considers the storage to be volatile. Compilers that do not adhere to this rule must ensure that any variables referenced by the handler are always kept in memory, not in a register. As mentioned previously, a condition handler can take one of three actions:
The sections that follow describe how to write condition handlers to perform these three operations.
|