PDGuide - Guide to Instrumenting Your Code: Difference between revisions
Line 305: | Line 305: | ||
'''Note:''' Some additional overhead exists when you use the TracecCreateEntry function without checking the state of the trace first. The trace service automatically time-stamps all trace entries that TraceCreateEntry creates. | '''Note:''' Some additional overhead exists when you use the TracecCreateEntry function without checking the state of the trace first. The trace service automatically time-stamps all trace entries that TraceCreateEntry creates. | ||
For more information about these and other trace related functions, refer to | For more information about these and other trace related functions, refer to ''Problem Determination APIs''. | ||
In the example that is described in [[#Examples of Code when Instrumenting for FFST and Trace]], the code calls the TraceCreateEntry function. This example logs two data variables for the trace point. The first variable is a 32-bit status code. The second variable is a 16-bit flag word: | In the example that is described in [[#Examples of Code when Instrumenting for FFST and Trace]], the code calls the TraceCreateEntry function. This example logs two data variables for the trace point. The first variable is a 32-bit status code. The second variable is a 16-bit flag word: | ||
An application program can add trace points to a program. The program adds trace points by using the TraceCreateEntry function. Refer to | An application program can add trace points to a program. The program adds trace points by using the TraceCreateEntry function. Refer to ''Problem Determination APIs'' for information about the TraceCreateEntry function. | ||
==Defining Trace Information Format== | ==Defining Trace Information Format== |
Revision as of 05:55, 19 January 2018
Reprint Courtesy of International Business Machines Corporation, © International Business Machines Corporation
Code instrumentation improves problem analysis. Instrumented components of OS/2 Warp Version 4 use First Failure Support Technology (FFST) and trace. This chapter defines the required steps for instrumentation, and things you should consider before you instrument your code. This chapter also tells you what to expect when you use the FFSTProbe API and trace utility.
Introduction to FFST Instrumentation
FFST is a programming concept that uses a set of software tools and services to capture error information at the time of a code failure. You view the error information using system error log or PM Dump Facility dump formatter to determine the cause of the problem. You capture error information by placing a call to the FFSTProbe API in your code. You instrument your code by calling FFSTProbe and specifying which data to collect.
When your properly instrumented code encounters an unsuspected or unrecoverable error, the code immediately calls the FFSTProbe API to capture failure related information. Your code specifies the parameters to capture data when calling the FFSTProbe function. The system creates an error log entry each time your code calls the FFSTProbe function. The log entry will contain the information your code specifies in the call to FFSTProbe. After the call, the system returns control to your code unless the system triggered a system dump. System dumps automatically restart the system. Additional error information can be collected by using a Probe Control Table (PCT) entry. System dumps are triggered by using PCT entries. The captured information that is contained in the error log entry can include event trace data, program error information, or user-defined data.
Therefore, FFST consists of a collection of functions, commands, and utilities within the Problem Determination Tools folder. Use the utilities to do the following:
- collect problem determination data
- define the types of data collected
- specify where to store the collected error data
- override parameters on calls to the FFSTProbe function.
Summary of Functions and Interfaces, provides an overview of the interfaces to FFST. Problem Determination APIs, provides descriptions of the API functions.
This chapter provides the information you need to instrument your code. It may be helpful to have the OS/2 Warp Version 4 Tools Reference document available for reference while using this book. The associated references are available on the Toolkit CD ROM.
Benefits of Instrumenting for FFST
Instrumentation is key to providing adequate code serviceability. If problems occur, instrumented code allows you or service personnel to take full advantage of the FFST technology in OS/2 Warp Version 4. The system records problem determination data with no user or additional programmer intervention. Instrumentation decreases the need for reproducing user failures. System dumps and process dumps however do require intervention and problem reproduction.
The captured information that is recorded in the error log is essential to problem solving. An error log entry contains information that indicates the failing product, and the time the error occurred. By analyzing the captured information, you can determine the failing components, diagnose the causes of the error, and correct the problems.
Overview of FFSTProbe API
The FFSTProbe API is the key to problem analysis by signalling that your code has encountered a problem. FFSTProbe captures the requested data, and stores the data in the error log for use in problem analysis.
FFSTProbe Parameters
The FFSTProbe API parameters identify the product that reported the problem. The parameters specify which data to collect for the problem. You can use the parameters to specify the following:
- the severity of the call
- the associated error message data
- the name of the formatting template that is used to display the error information
- any system process information
- any specific user data that you want collected.
The system stores module name and time stamp automatically. The FFSTProbe API can also initiate a system dump to capture data that resides in the main memory of the system. Refer to Problem Determination APIs for the FFSTProbe API and its parameters.
FFST Flow

The sequence of events that are shown in FFST Flow shows how FFST logs errors and captures data when your code calls FFSTProbe.
After you develop and install your code on the system, the application program box that is shown in the diagram above signifies your code. The FFSTProbe API is called when your code discovers a problem. If you specify to capture user data in the call to FFSTProbe, the system captures the data with the other error-related information.
Your code calls FFSTProbe to gather the following product information:
- dump information
- error message information
- other error-related data
The system records the data in the error log entry. If your code has entries in the Probe Control Table, FFST uses the entry values instead of the FFSTProbe parameters that are used in the calls. The system records the data in the error log entry. FFST uses the configuration values to create the error log entry.
After FFST gathers the error-related information, it stores the data as an error log entry. The system stores FFST dump information in a file named FFxxxxxx.DMP, where xxxxxx signifies a six-digit identifier. If a trace snapshot is requested, a file named FFxxxxxx.TRC will be created. If a process dump is requested, a file named FFxxxxxx.PRC will be created. The error log information contains the name of the FFST dump file along with the trace file if applicable.
Use the SYSLOG utility to view the error log information. SYSLOG uses message files and template files to format and display error log records. Use SYSLOG to control the following log functions:
- specify which error log file to use.
- suspend or resume error logging.
- change the size of the error log.
Steps for Instrumenting for FFST
The steps for instrumenting your code are as follows:
- Planning for Instrumenting Your Code
- Code the FFSTProbe API.
- Compile the code.
- Create the error record template file
- Create message files.
- Create DMI MIF files.
The remainder of the information in this chapter provides information about each step.
Planning for Instrumenting Your Code
There are several things to consider before you begin putting calls to the FFSTProbe API in your code. This section describes the following considerations and steps:
- Define and ensure existence of Vital Product Data (VPD). VPD is the description of your code to the system. The system uses VPD to identify the product that is reporting a problem.
- Decide how and where you should code your calls to the FFSTProbe function.
- Decide what data you want the function to collect for code failures.
Defining Vital Product Data (VPD)
The DMI facility provides a standard way to register the hardware and software on the system. This allows both system software and system-based software (for example, application programs or device drivers) to register with the system. This information is called Vital Product Data (VPD). The system uses VPD to identify the source of error log entries. Various system management applications require access to the VPD information. When a product component uses FFSTProbe to log an error, the error logging function automatically includes the VPD information in the error record.
The VPD information allows systems management applications to assume a base level of VPD for all conforming products on a system. The VPD information for software products differs from the VPD information for hardware products. You can define additional specialized VPD information for your product.
Both your component's install object (that the feature installer uses to install your product) and the FFSTProbe parameter information must have identical information. This enables DMI to provide the template file that is specified on the call to FFSTProbe. Recommendations for these values are:
- Vendor - a description of the organization or company that developed the product that is reporting an error (example: IBM).
- Tag - a unique description of the product that is reporting an error (example: FFSTProbe SAMPLE).
- Revision - optional description of the development organization's revision level, change level, or version of the product that is reporting an error. (example: 1.0.1c). If a component within a product is reporting the error, the revision may not correspond to the revision level of the entire product.
Programmers refer to the Vendor, Tag, and Revision values as the DMI triplet.
When your code calls FFSTProbe, the DMI triplet values you specified must match the DMI values stored in the DMI database for your product. If the values do not match, FFSTProbe cannot find the VPD for your product in the DMI database.
If the DMI triplet for your product matches the DMI triplet of a different product, the results are unpredictable.
Deciding How and Where to Place Calls to FFSTProbe API
Here are two common approaches to instrumentation. One way is to place numerous calls to FFSTProbe throughout your product to get broad coverage. This approach might contain only a minimum amount of error data since you know every error would be captured via a probe. The second approach is to use just a few strategically placed calls that capture greater amounts of error data to better isolate the the exact cause of the failure.
The advantage to the broad coverage approach is that errors are most likely to be identified because of the greater number of calls to FFSTProbe. The strategic approach usually involves instrumenting existing exception paths or thoroughly understanding the code to identify where to place the call to FFSTProbe.
You might consider combining both approaches in your code. The broad coverage aspect identifies exactly where the error occurred, and the strategic aspect identifies the cause.
You should use FFSTProbe only to detect problems that would require a program fix or a modification to user operation procedures.
Places to Instrument
The following list contains situations and places in your code you should consider for instrumentation:
- When your code generates an error return, create an error log entry for the error condition that caused the error.
- Some programmers use Print Debug and Print File for testing code. These instructions print certain variables and messages at various code failure points. Convert the Print Debug and Print File instructions to calls to the FFSTProbe API. The system disables the Print Debug and Print File functions after you install your code.
- When you expect return codes, create an error log entry when you receive unexpected return codes.
- In environment situations (circumstances that are not necessarily program errors but are worthy of creating an error log entry). For example, resource shortages, time-out conditions, system-hang conditions, or lost physical connections.
- In cleanup functions, your code may be tolerant of potential errors and may do some error recovery. The cleanup functions in your code are candidates for logging if the recovery signifies an important event.
Consider that the number of log entries and the size of entries you log could cause too much information to be logged. Creating excessive error log entries can cause the error log to wrap. This causes previously logged information to be overwritten. One of the most frequent questions that are asked about FFST is where and when to use it. When instrumenting your product, you should consider several places:
- Exception Paths
- Many programmers already take some actions in various exception conditions. These actions often include cleaning up execution environments, closing files, and ending the program. Your code should call the FFSTProbe API to create an error log entry that contains the following information:
- the program or module that failed
- why the failure occurred
- what corrective actions to take.
- Incorrect Conditionals (for example, switch case)
- As developers write programs, they make assumptions of what can or cannot happen, and add various conditionals and execution blocks to programs.
- Conditionals that are not valid are ideal candidates for a call to the FFSTProbe API to log these failures. By calling the FFSTProbe function at these points, you can quickly and accurately pinpoint the failure and capture the associated data at the time of failure.
- External Calls
- OS/2 Warp Version 4 does not expect calls to external programs to fail. However, unexpected return codes, when not handled, can result in program failure. Your code should call FFSTProbe after each external call that results in an unexpected return code.
- Some development groups use someone other than the developer instrument all calls. Other groups spend more time anticipating the potential problem areas and placing probes only in those areas. Your code should do what is achievable for the current circumstances. You should then evaluate how well your calls to FFSTProbe work before you begin the next development cycle.
For FFSTProbe API calls to be useful in debugging a problem, the calls must specify:
- A unique probe ID
- Descriptive text explaining the problem
- Data that is relevant to the failure
- Instructions on how to resolve the problem if appropriate.
With well-instrumented code, several benefits of using the FFSTProbe function are evident. You can use FFST to capture error information. You can also identify areas in your code that did not cause the problem. If instrumented code made no calls to FFSTProbe, you can focus on code without calls to FFSTProbe.
Your code should not call the FFSTProbe function inside a loop. Call FFSTProbe only once per error situation. Repeated calls may cause system performance problems and cause wrapping of FFST data by storing unnecessary data.
Problem-prone components in products are good candidates for the FFSTProbe function.
Your decision about using instrumentation depends on the possible errors and the cost of solving an error.
Deciding What Data You Want to Collect
After you decide where to call the FFSTProbe function, you need to decide what data to capture. The question to ask is, "What data would I need to see to have a good chance of determining the source of the error?" Consider capturing data items that are global variables and control blocks.
Other things to consider are:
- How much data you need to determine the cause of the problem?
- Has this problem been encountered before?
- How complex is the code?
- Are other components or products being called?
- Does the error message information point to the problem?
Make every effort to collect enough data to solve the problem without requiring the user to re-create the problem.
The amount of data collected could also be affected by the amount of system storage that is available or allocated to store error data.
Error Types to Consider
When an error occurs, call the FFSTProbe function to log the error. The following examples describe several error types you should consider when you instrument your code and the types of data to capture for the error:
- Error return
- Determine the severity of an error so that you call the FFSTProbe function only when the error return indicates a serious problem. When a calling program has a significant failure that causes an error return, the program calls FFSTProbe. Be careful not to cause a "cascade" of calls to FFSTProbe as the system passes error returns back up through a set of higher level function calls.
- Failure-related data may include:
- Return code
- Input parameters to the function
- Returned values from the function
- Any internal variables that determine or affect the erroneous results
- Damaged data structures
- Product data structures can become damaged with data that is not valid. To capture data for this type of error during normal processing, your code could have a method for periodically checking important internal data structures. Such logic is an important step toward improving the reliability and availability of the product.
- Failure-related data may include:
- Data structures
- Historical information that indicates when your code found the product data structure to be correct
- General system data showing other programs in use by the system when the error occurred.
- Time-outs and detected hangs
- To detect time-outs and hangs, design your code to sense how long a given request should take.
- Failure-related data may include:
- Current time-out values
- Any state information that describes what the timed-out function is currently doing
- States of resources that may relate to the time-out or hang
- Historical information that describes what the timed-out function had been doing before the error occurred.
- Slow performance of a service
- In order to detect a slow performance condition, design code to sense how long a given service should take before calling FFSTProbe.
- Failure-related data may include:
- Internal resource states that may relate to the slow performance of the service
- Historical information that indicates who has been using that service and what requests the user made of the service.
- Traps
- It is difficult to detect a failure within a product and determine its cause after an exception management routine has received control. Well-designed and instrumented code can detect a failure before exception management routines get control.
- Failure-related data may include:
- Exception blocks that contain the hardware state when the trap occurred
- Context data indicates what was being run when the trap occurred (for example, call stacks or internal state variables)
Ways to Collect Data
FFST takes care of storing the collected data in the error log and optional FFST dump. This information is available for viewing through use of the SYSLOG utility. For more information on error logs and the SYSLOG utility, see Viewing and Analyzing Error Log Entries.
User data could be data areas, control blocks, complete files, or any other form of data that could be used to determine the problem.
Two parameters on the FFST Probe function allow user-specified data to be collected:
- The pDmpUsrData parameter saves information in the FFST Dump. You can specify up to 30 items, each having a maximum size of 32 KB. For example, you use this parameter to save large control structures or buffers.
- The LogUsrData parameter save saves user data in the error log. The maximum amount of logged data is 2 KB. You need to determine what data you want as part of the 2 KB. For example, you use this parameter to save small items such as return codes, function names, or system names.
FFST Dump Data
The system creates FFST dumps when you use the pDumpUserData parameter with the FFSTProbe function. The Enable FFST Dump option on the FFST Probe Control Table Entry Summary window must be selected before the system will create a FFST dump (see Probe Control Table (PCT) Entry Add or Change Summary Window).
If you did not specify the parameter to collect the FFST dump in the original call to the FFSTProbe function, you can dynamically change the call. You use the Probe Control Table (PCT) to request the FFST dump the next time the specified call to FFSTProbe occurs. The system stores the FFST dump information in the file that is defined on the FFST Setup (FFSTCONF) window (see Using FFST Setup (FFSTCONF)). You can select the path but not the file name.
To delete FFST dumps, use the FFSTCONF command and select the Actions option. Then choose the Dumps option to display the FFST Dump File Summary window. Select the dump file to delete and click on the File menu bar option. Click on Delete to delete the dump file.
The FFST dump data can be of the various types. Some types may not be part of dump, depending on availability of data. The system displays the information when you format the dump. The various types are: process environment data, process status data, trace buffer data, user data, error log data, and process errors.
Process Environment Data
If you requested the process environment data, FFST collects and stores the data as part of the FFST dump. The system displays this information when you use the PM Dump Facility dump formatter.
You can specify to have the process environment data captured by selecting the Capture Process Environment checkbox on the FFST PCT Entry window (see Probe Control Table (PCT) Entry Add or Change Summary Window).
System Process Status Data
Process status data is a record of all processes and threads that are running on the system. This information is similar to information you get when you use the PSTAT command.
If you requested process status data, FFST collects and stores the data as part of the FFST dump. The system displays this information when you use the PM Dump Facility dump formatter.
You can specify to have the process status data captured by selecting the Capture System Processes checkbox on the FFST PCT Entry window (see Probe Control Table (PCT) Entry Add or Change Summary Window).
Trace Data
When you enable your code for trace, FFST collects and stores trace data. You can specify to have the trace snapshot captured by selecting the Capture Trace Snapshot checkbox on the FFST PCT Entry window (see Probe Control Table (PCT) Entry Add or Change Summary Window). The system stores trace information in a separate file.
You display trace information either by using the TRACEFMT command or by using the Display Trace File option in the SYSLOG Tools menu. For information about using the trace functions and formatter, see Analyzing Performance and Debugging Problems Using Trace.
User Storage Data
If you requested user storage data, FFST collects and stores the data as part of the dump. Using the function parameters, you can capture up to 30 data areas. The system displays this information when you use the PM Dump Facility dump formatter. For information about using the dump functions and formatter, see Capturing and Saving Failure-Related Information through Dumps.
Additional Error Log User Data
If you requested additional error log user data in the FFSTProbe call, FFST generates a FFST dump and stores the data as part of the dump. This information is identical to the error log entry that is stored in the error log. The system displays this information when you use the PM Dump Facility dump formatter. For information about using the error log functions and formatter, see Viewing and Analyzing Error Log Entries.
FFST Dump Process Errors
FFST collects and stores FFST dump-processing errors that occurred when the system creates the dump. The system includes error message identifiers in this information. The system displays this information when you use the PM Dump Facility dump formatter.
Process Dumps
FFST collects and stores a process dump only when the Capture process dump option is selected on the Probe Control Table (PCT) Entry Summary window. Refer to FFST Probe Control Table Entry Summary Window.
System Dumps
FFST collects and stores a system dump only when the Capture system dump is selected on the Probe Control Table (PCT) Entry Summary window. Refer to FFST Probe Control Table Entry Summary Window.
Coding the FFSTProbe Functions
You can code the FFSTProbe function to capture data in several ways:
- By direct call to the FFSTProbe function
- By coding a macro that uses FFSTProbe
- By creating a subroutine to call the FFSTProbe function if you specify certain parameter values.
The best way to call the FFSTProbe function is through the subroutine method.
Direct Calls
Your code calls the FFSTProbe function at each specific instrumentation point. All pertinent parameters need to be specified on each call to capture the required data.
As you can see, when you use several calls to the FFSTProbe function, you greatly increase your coding efforts. You need to specify every parameter for each call in order to capture the required error data for problem analysis. This method requires you to change each call to FFSTProbe in your code if you decide to change parameters and is difficult to maintain.
Using Macros to Call the FFSTProbe Function
You can also use a macro to call the FFSTProbe function; however, this is not recommended. When you use a macro, the macro gets expanded into working code when you compile your code. Using a macro causes your components to increase in size. Macros could have a dramatic effect on the size your product if your code has numerous calls to FFSTProbe.
Using Subroutines to Call the FFSTProbe Function
An effective way to instrument a call to FFSTProbe is to create a subroutine in your code components. Many FFSTProbe parameters for your code contain the same values for each call. Using the subroutine allows you to code these parameters once rather than requiring all parameter information for each individual call as in the direct call approach.
Using the subroutine provides common parameter information for all calls to FFSTProbe in your code. When you need to change parameter information, you only change the parameters in the FFST subroutine rather than the parameters on every call to FFSTProbe.
See #Example of an Application Program Using a Subroutine for an example of how you use the subroutine method to call the FFSTProbe function.
Creating Template Files
Use the MKTMPF (Make Template File) command to create template files with message IDs that refer to text information about the error. Use a text editor to create an input file for your template. Input files may have any file name that is valid for your file system.
SYSLOG uses template files to format and display error data and user data in the error log entry. There should be a unique template file entry for each template ID used by your code.
For information regarding the template files and MKTMPF command, see the documentation in the OS/2 Warp Version 4 Tools Reference located in the Toolkit.
Why Template Files Are Important
In the template file are the identification numbers of the error messages and possible recovery actions for the error messages. The template file also contains the formatting instructions for LogUsrData entries in the system error log. Each template in the file has a unique identifier that is specified in the parameters of the call to the FFSTProbe function.
The system creates an error log entry that contains the information that is specified on the call to FFSTProbe. The system also stores the VPD information that is related to the calling product in the error log entry.
When you instrument your code, ensure that an appropriate error record template entry exists in DMI for your product. The FFSTProbe function needs to point to a specific error record template entry within a the template file. Each product should maintain a separate error record template file.
See #Creating an Error Record Template Input File for an example of an error record template input file.
Creating Message Files
Message files contain the text of the error messages that error log entries use. The process of producing message files begins with creating an input file. The contents of the input file define the product the messages belong to, the message numbers, and text of the messages. The message text can include the substitution variables provided by FFSTProbe's MSGINSDATA parameter. After you complete the input file, use MKMSGF to compile the file. The output of the compiler is the message file.
A description of how you create an input file and use MKMSGF to create the message text file is in the Toolkit OS/2 Warp Version 4 Tools Reference.
See #Message Input File Example for an example of a message input file.
Setting Up (Instrumenting) for Trace
OS/2 Warp Version 4 applications can be instrumented for trace by adding calls to the TraceCreateEntry function to collect user-specified data. When running the program, the system collects specified data and stores the data in a trace file. Use the trace format (TRACEFMT) command discussed Analyzing Performance and Debugging Problems Using Trace to view and analyze the data stored in the trace file.
Using trace points is one of the best ways to collect serviceability information on a customer system. It allows service personnel and developers to follow the course of events that lead to the failure.
What Is Trace?
Trace is a tool that you use for performance analysis and service level debugging. Use the trace tool after you perform development and debugging at the individual module level or object level. Microkernel, operating system, and application programmers as well as service personnel can use the trace facilities to assist in tracking code problems. For more information about using trace, refer to Analyzing Performance and Debugging Problems Using Trace.
Creating a Trace File Entry Using the TraceCreateEntry Function
Use the TraceCreateEntry function to create an entry in a trace file when trace is being performed.
The TraceCreateEntry function uses a single parameter packet structure, TCEREQUEST, that is defined in the trace.h file that is part of the Toolkit. Use the packet to specify the following information:
- Major and minor codes
- An optional set of state-related data that is to be logged within the trace entry that the trace point creates
A parameter packet is a structure that contains values or parameters.
The TraceCreateEntry caller does not have to provide any logic to check whether you turned on the trace point. The TraceCreateEntry function performs all necessary checking.
Note: Some additional overhead exists when you use the TracecCreateEntry function without checking the state of the trace first. The trace service automatically time-stamps all trace entries that TraceCreateEntry creates.
For more information about these and other trace related functions, refer to Problem Determination APIs.
In the example that is described in #Examples of Code when Instrumenting for FFST and Trace, the code calls the TraceCreateEntry function. This example logs two data variables for the trace point. The first variable is a 32-bit status code. The second variable is a 16-bit flag word:
An application program can add trace points to a program. The program adds trace points by using the TraceCreateEntry function. Refer to Problem Determination APIs for information about the TraceCreateEntry function.
Defining Trace Information Format
You create the defined format for a major code by using TRCUST. The system formats trace entries to represent the actual major code by descriptive text instead of just numbers. In addition, the system can format data saved by the trace entries instead of being displaying the data as hexadecimal numbers. The use of TRCUST is completely optional.
The trace source file (.TSF) contains lines that describe the format of each major and minor code. TRCUST uses the .TSF file to generate .TFF files (trace format files). TRCUST generates one .TFF file for each major code. The trace formatter program uses the .TFF files to determine how to format the trace point entries being displayed.
Creating Trace Entry Formatting Directives
To define trace entry formatting directives, you should place entries in a Trace Source File (.TSF) file. The .TSF file is an ASCII text file that defines the trace points being traced in the program. The TRCUST Trace Point Definition tool uses the .TSF file. TRCUST converts the information in the .TSF file into Trace Format Files (.TFF) having the name of TRC00xxx.TFF, where xxx is the major code defined in the .TSF file. The trace formatter uses the TFF file to format and displays the trace information.
The following file TEST.TSF is an example of a simple .TSF file. You use the .TSF file to specify the formatting directives for a trace entry that TraceCreateEntry creates:
TEST.TSF Trace Source File Example MODNAME = probe.exe MAJOR = 220 TRACE MINOR=1, TP=@STATIC, DESC="Tracepoint example start", FMT ="Data %D String %S" TRACE MINOR=0x8001, TP=@STATIC, DESC="Tracepoint example end", FMT ="Data %D String %S"
For more information about the TRCUST command, the .TSF file and syntax used in the file, refer to the Trace Customizer User's Guide in the Toolkit.
Creating DMI MIF Files
The Desktop Management Interface (DMI) Management Interface Format (MIF) file is an ASCII text file that contains the attributes that describe manageable products. The MIF defines a standard way of providing the product information to be retrieved by product management applications.
A manageable product provides information about itself in the form of attributes in a MIF file that is stored in the MIF database. There is a MIF file for each manageable product on the system.
You use the attributes in the MIF file to describe components and characteristics of your product. Attributes can define the component version and revision date, the date you installed the product, or the hardware requirements that are needed to use your product. Group the specific attributes together. In this example, the component version and the revision date would be one group in the MIF file, and hardware requirements would be in a different group.
Management applications retrieve the information in your MIF file. You use the management applications to list information about your specific manageable product or all manageable products that are installed on a system.
The management applications, such as SystemView Agent or DMI Browser, contain functions that can change the DMI information for a specific manageable product. You can change the DMI information of a manageable product without reinstalling the product. The product monitors its own DMI information for any changes. When changes occur, the product updates the functions that it performs based on the new DMI information.
You can find the MIF file requirements in the SystemView Agent Programmer's Guide in the Toolkit in the Problem Determination Tools folder.
There is an example MIF file in the Toolkit that you can copy as a base for the MIF file for your product. The file name is PROBEMXP.MIF.
For an example of a MIF file, see #MIF File Example.
How to Install Your Software Product
You can use the software installer to install your product and the associated MIF file. The Software Install Reference documents the steps required to install your product and MIF file. This document is in the Software Install Package in the Software Developer Kit and is also available on The Developers Connection for OS/2 compact disk.
The Getting Started with Software Install in the Software Developer Kit explains how to install and use the Software Developer Kit tools.
For more information about DMI and MIF, refer to the #The Desktop Management Interface (DMI).
FFST-Related Functions
You can change the configuration information with a program by using the FFSTQueryConfiguration and FFSTSetConfiguration functions in your code.
When you call FFSTQueryConfiguration, the system returns the configuration information into a structure that you specify. Your code then compares the configuration information in the structure to the configuration values your code is expecting. If any of the values are different, your code can change them by calling the FFSTSetConfiguration function. You then specify the configuration information for the system to use.
Refer to Problem Determination APIs for more information about these functions.
Examples of Code when Instrumenting for FFST and Trace
This section contains the following examples:
- how you instrument a product by using subroutines to call FFSTProbe and TraceCreateEntry
- a template input file
- a message input file
- a MIF file
Example of an Application Program Using a Subroutine
This example shows the user application PROBE.C. The application uses the subroutine approach to call the FFSTProbe function. User Application using FFST and Trace Subroutines
/**************************************************************************/ /* probe.c: FFSTProbe sample */ /* */ /* This test program gives an example of using the FFSTProbe API and the */ /* TraceCreateEntry API by using 'wrapper' functions. The dummy API */ /* My_Dummy_Api returns a return code which is then used as the basis of */ /* firing a FFSTProbe via the wrapper function, callFFST. callFFST can */ /* be modified to include more or less data as needed. */ /* */ /**************************************************************************/ #define INCL_DOS #define INCL_DOSMEMMGR #define INCL_DOSPROCESS #define INCL_FFST #define NO_ERROR 0 #include <os2.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <FFST.h> #include <trace.h> /**************************************************************************/ /* Define probe ID for FFSTProbe called when dummy API fails. Probe ID */ /* is the unique identifier you use later to find the source of the */ /* failure. It should be unique within a DMI triplet (explained later) */ /* or within your product */ /**************************************************************************/ #define DUMMY_API_PROBE 22222 void callFFST ( ULONG input_version, /* FFST 'Wrapper' Function */ /* input version lets you change the wrapper */ /* without changing each call, just make sure */ /* the wrapper still treats the 'old' version */ /* the same and that any new code is */ /* conditioned on a new input_version # */ ULONG input_probe_flags, /* FFSTProbe probe flags */ ULONG input_severity, /* FFSTProbe severity */ ULONG input_probe_id, /* FFSTProbe ID */ CHAR* input_module_name, /* module name passed to probe */ ULONG input_log_data_length, /* log data length for the system error log */ PVOID input_pError_log_data, /* pointer to the data for system error log */ int argc); /*****************************************************/ /* This is for a common trace entry routine */ /*****************************************************/ #define HKWD_TEST 220 /* major code */ #define hkwd_test_entry 0x0001 /* minor code for entry */ #define hkwd_test_exit 0x8001 /* minor code for exit */ struct { int count; char text12Ù; } trace_capture_start, trace_capture_end; APIRET trace_out(ULONG major, ULONG minor, void *trace_data, ULONG data_len); /* trace wrapper function */ /**************************************/ /* End of trace declarations for Main */ /**************************************/ ULONG My_Dummy_API(ULONG Mydata); /**************************************************************************/ /* */ /* Main Application (this uses the callFFST wrapper function). */ /* */ /**************************************************************************/ int main ( int argc, char * argvÙ, char * envp ) { ULONG rc = 0; ULONG Mydata = 2; ULONG userDataLen = 0; PVOID pUserData = NULL; printf ( "Starting FFSTProbe Sample\n" ); /**************************************/ /* Do the trace entry point */ /**************************************/ trace_capture_start.count = 3; /* just a number */ strncpy(trace_capture_start.text, "Start main", 12); /******** CALL TraceCreateEntry function ****/ trace_out(HKWD_TEST, hkwd_test_entry, &trace_capture_start, sizeof(trace_capture_start)); /***********************************************************************/ /* call the 'dummy' API so it returns a non-zero rc */ /***********************************************************************/ rc = My_Dummy_API ( Mydata ); if ( rc != NO_ERROR ) { /********************************************************************/ /* The API has failed. Setup the userData to contain the failing rc */ /********************************************************************/ pUserData = calloc ( 2, sizeof ( ULONG ) ); memcpy ( pUserData, &rc, sizeof ( ULONG ) ); memcpy ( ( PBYTE ) pUserData + sizeof ( ULONG ) , &Mydata, sizeof ( ULONG ) ); /****************************************************************************/ /* Call the FFSTProbe wrapper function with a version of 1, */ /* Have FFST post the process status and environment variables in the */ /* syslog, a severity of 4, a probe id of DUMMY_API_PROBE which was */ /* previously defined as 22222, a module name of 'my_module_1', the length */ /* of logusrdta, the logUserData (equal to the failing rc (1) as */ /* setup above) and Argc is passed in to determine whether or not data */ /* should be retrieved from DMI. */ /****************************************************************************/ callFFST ( 1 , PSTAT_FLAG º PROC_ENV_FLAG , SEVERITY4 , DUMMY_API_PROBE , "my_module_1" , 2 * sizeof ( ULONG ) , pUserData , argc ); } if (pUserData != NULL) { free(pUserData); pUserData = NULL; } if (argc > 1) { printf("\nFFSTProbe sample ended not using DMI component:\n\n\n"); } else { printf("\nFFSTProbe sample ended using DMI component:\n\n\n"); } /**************************************/ /* Do the trace end point */ /**************************************/ trace_capture_end.count = 99; strncpy(trace_capture_end.text, "End main", 12); /******** CALL TraceCreateEntry function ****/ trace_out(HKWD_TEST, hkwd_test_entry, &trace_capture_end, sizeof(trace_capture_end)); return 0; } /**************************************************************************/ /* callFFST is the FFSTProbe wrapper function. It allows you to code the */ /* FFSTProbe API once with data that is static as far as your usage is */ /* concerned and allows you to pass in dynamic data. It also helps */ /* insulate your code if you decide to change your 'static' options */ /**************************************************************************/ void callFFST ( ULONG input_version, /* FFST 'Wrapper' Function */ ULONG input_probe_flags, /* FFSTProbe probe flags */ ULONG input_severity, /* FFSTProbe severity */ ULONG input_probe_id, /* FFSTProbe ID */ CHAR* input_module_name, /* module name passed to probe */ ULONG input_log_data_length, /* log data length for the system error log */ PVOID input_pError_log_data, /* pointer to the data for system error log */ int argc) { APIRET rc = 0; PVOID pvar_n0; ULONG pvar_n1; /***********************************************************************/ /* FFSTProbe API structures. Described in the API Guide */ /***********************************************************************/ FFSTPARMS FFSTParms; PRODUCTINFO productInfo; PRODUCTDATA productData; DMIDATA DMIData; DUMPUSERDATA dumpUserData; MSGINSDATA msgInsData; /***********************************************************************/ /* The PRODUCTDATA structure defines the DMI triplet which allows */ /* additional product information, including template repository */ /* filename, to be retrieved from DMI. DMI is a industry standard */ /* for desktop mgt */ /***********************************************************************/ productData.packet_size = sizeof ( productData ); productData.packet_revision_number = PRODUCTDATA_ASCII; /* data can be ASCII or UNI */ productData.DMI_tag = "FFSTProbe Sample"; /* Customize for your program */ productData.DMI_vendor_tag = "IBM"; /*Customize for your company */ productData.DMI_revision = "1.00"; /* Customize */ /***********************************************************************/ /* The DMIDATA structure below is the information which can either be */ /* retrieved by DMI or passed in by the FFSTProbe function. The */ /* preferred method is to use DMI. In the example below, you can see */ /* the use of either depending on whether or not a parm was passed on */ /* call to this program */ /***********************************************************************/ if ( !(argc > 1) ) { /********************************************************************/ /* Setting this structure to NULL indicates that the information is */ /* to be retrieved from DMI using the DMI triplet as defined in the */ /* productData structure. This is the preferred method. */ /* Other files in this example show how to build your own DMI */ /********************************************************************/ productInfo.pDMIData = NULL; /********************************************************************/ /* Note: This shows the usage of message insert text and is NOT part*/ /* of the information that could or could not be retrieved from DMI */ /* This is included as an example of MsgInsTxt and how it can be */ /* used to send probe specific data to the SYSLOG (System Error Log)*/ /********************************************************************/ msgInsData.MsgInsTxt0Ù.insert_number = 1; msgInsData.MsgInsTxt0Ù.insert_text = "We did use a DMI component"; } else { /********************************************************************/ /* fill the DMI data structure - useful only in test environments */ /********************************************************************/ DMIData.packet_size = sizeof ( DMIData ); DMIData.packet_revision_number = DMIDATA_ASCII; /* could be unicode instead */ DMIData.DMI_product_ID = "FFST_toolkt_sample"; /* note this is different than tag */ DMIData.DMI_modification_level = "000000"; DMIData.DMI_fix_level = "010101"; DMIData.template_filename = "PROBE.REP"; /* this file must be on the DPATH */ DMIData.template_filename_length = strlen (DMIData.template_filename) * sizeof ( char ); /* since ascii is being used */ productInfo.pDMIData = &DMIData; /********************************************************************/ /* Note: This shows the usage of message insert text and is NOT a */ /* of the information that could or could not be retrieved from DMI */ /********************************************************************/ msgInsData.MsgInsTxt0Ù.insert_number = 1; msgInsData.MsgInsTxt0Ù.insert_text = "We did not use a DMI component"; } /***********************************************************************/ /* set the pointers up for PRODUCTINFO */ /***********************************************************************/ productInfo.pProductData = &productData; /* This points to the DMI related data */ /***********************************************************************/ /* set up some DUMPUSERDATA items */ /***********************************************************************/ pvar_n0 = "Dump user data"; /* Anything can be dumped here up to 32 Kbytes */ pvar_n1 = 2; dumpUserData.no_of_variables = 2; dumpUserData.DumpDataVar0Ù.var_n_length = strlen(pvar_n0) + 1; dumpUserData.DumpDataVar0Ù.var_n = pvar_n0; dumpUserData.DumpDataVar1Ù.var_n_length = sizeof(ULONG); dumpUserData.DumpDataVar1Ù.var_n = (PVOID)(&pvar_n1); /***********************************************************************/ /* set up a couple of MSGINSDATA messages- just to show it can be done */ /***********************************************************************/ msgInsData.no_inserts = 2; msgInsData.MsgInsTxt1Ù.insert_number = 2; msgInsData.MsgInsTxt1Ù.insert_text = "Message insert variable 2"; /***********************************************************************/ /* set the FFSTPARMS structure, most values from DEFINEs above. */ /* See API GUIDE for details on each field and their possible values */ /***********************************************************************/ FFSTParms.packet_size = sizeof ( FFSTParms ); FFSTParms.packet_revision_number = FFSTPARMS_OS2_ASCII; /* ASCII vs UNICODE data */ FFSTParms.module_name = input_module_name; FFSTParms.probe_ID = input_probe_id; FFSTParms.severity = input_severity; FFSTParms.template_record_ID = input_probe_id; FFSTParms.pMsgInsData = &msgInsData; FFSTParms.probe_flags = input_probe_flags; FFSTParms.pDumpUserData = &dumpUserData; /* dump data is stored in .DMP files */ FFSTParms.log_user_data_length = input_log_data_length; FFSTParms.log_user_data = input_pError_log_data; /* log data is stored as part of the SYSLOG entry */ /***********************************************************************/ /* Call the FFSProbe API */ /***********************************************************************/ if ( input_version == 1) { rc = FFSTProbe ( &productInfo, &FFSTParms); } printf("\n----- Fired the FFSTProbe, rc=%d\n",rc); /* for example only, do not do this in customer level code */ } /**************************************************************************/ /* This is the dummy API for use in the example. It can easily set */ /* non-zero rc's */ /**************************************************************************/ ULONG My_Dummy_API ( ULONG Mydata ) { if ( Mydata != 123456 ) { return 1; } else { return 0; } } /**************************************************************************/ /* Trace events function */ /**************************************************************************/ APIRET trace_out(ULONG major, ULONG minor, void *trace_data, ULONG data_len) { TCEREQUEST packet; APIRET rc; packet.packet_size = sizeof packet; /* Size of packet in bytes */ packet.packet_revision_number = TRACE_RELEASE; /* Revision level of trace */ packet.major_event_code = major; /* Major code event to be logged */ packet.minor_event_code = minor; /* Minor code event to be logged */ packet.event_data_length = data_len; /* Length of callers event buffer*/ packet.event_data = trace_data; /* Pointer to callers buffer */ /* call the TraceCreateEntry function */ rc = TraceCreateEntry(&packet); return rc; }
Creating an Error Record Template Input File
You use a text editor to create an input file. MKTMPF uses this file to create error record template files. There should be one set of default path names and one or more sets of template entries for each use of MKTMPF.
The following example shows a template input text file to use with the MKTMPF command for the procedure in the PROBE.C example. Error Record Template Input File
Descriptive_Name = 'System Management Example Template file' * * 'File name only' can be specified as long as the message files are on the * system's DPATH otherwise full path must be specified. * NOTE: MESSAGE FILES WILL BE 6 CHAR file name with a .MSG Extension * Created by MKMSGF utility * * A single template file can contain entries for an entire product or a * single program *depending solely on the development teams preferences. * The only requirement is that all users of the template file use the *same DMI triplet or hardcode to the same path * Default_message_pathname = probe.msg Default_causes_pathname = probe.msg Default_actions_pathname = probe.msg Default_details_pathname = probe.msg * * Template number is associated with the FFSTProbe call * Template_number = 11111 * * Message_number is the message number you want displayed on the SYSLOG * summary screen * Message_number = 1 * * Log_class 1 is hardware, 2 is software * Log_class = 2 * * Default_xxxxx_pathname can be overridden on a template entry basis * like this: * Causes_pathname = c:\os2\system\othrCmsg.msg * Actions_pathname = c:\os2\system\othrAmsg.msg * Details_pathname = c:\os2\system\othrDmsg.msg * * On the right of the = sign you specify which message number you want * displayed in the relevant _causes _actions section of the SYSLOG * display. Here message 4 is displayed from PROBE.MSG in the * Fail_causes section of SYSLOG. * Fail_causes = 4,0,0,0 Fail_actions = 0,0,0,0 Install_causes = 0,0,0,0 Install_actions = 0,0,0,0 User_causes = 0,0,0,0 User_actions = 0,0,0,0 * Template_number = 22222 Message_number = 2 Log_class = 2 Fail_causes = 4,0,0,0 Fail_actions = 0,0,0,0 Install_causes = 0,0,0,0 Install_actions = 0,0,0,0 User_causes = 5,0,0,0 User_actions = 6,0,0,0 * * Detail data allows you to format the FFSTProbes log_user_data (if * used). You can use as many Detail data phrases as needed. The * format is: Detail_data = L,O,H,T where L is Length of data, O is the * Offset it starts at, T is the Type of data as it was sent and how you * want it formatted (e.g. binary show as hex) and H is the heading * message number you want to display with it. When your run the example * you will notice the difference in formatting. * Detail_data = 4,0,7,3 Detail_data = 4,4,9,2 *
Template File Tips
The following list contains other helpful tips about the error record templates:
Template files use message-file path names without drive letters. You must ensure the following:
- you place the message files in the proper directory
- you place the directory in the DPATH statement of CONFIG.SYS
- the template entries in the file point to the proper message file.
The message resource files (xxx.mes) that are specified in the templates are created by using MKMSGF. You install these files on the system during product installation.
The error logging facility directly accesses the error record template files to find error messages, causes of the error, and corresponding recovery actions in various message files. The system stores this information in a file in the form of message identifier numbers and message file path names.
Message Input File Example
You use a text editor to create an input file. MRES utility uses this file to create message files. The following example shows what you can entered in a message text file. You use the input file with MKMSGF to create messages. Message Input File
;Input file for MKMSGF the resulting .MSG file must be placed in the DPATH or ;the template file specification must specify the path on the boot drive. ; ;The 'number' component of the msg id must be 4 numeric chars. ;This 'number' is what is used in the template file _causes _actions phrases ;between the comma's. e.g. Fail Causes = 4,5,0,0 will cause SYSLOG to display ;message BNB0004I followed by BNB0005I in its fail causes section. ;Message text can continue across multiple lines if so desired. BNB BNB0001I: Message for probe 11111, with 2 substitution vars: %1 and %2 BNB0002I: Message for probe 22222, with 2 substitution vars: %1 and %2 BNB0003I: Hello World! BNB0004I: Hello World! My_Dummy_API returned a non-zero rc BNB0005I: A non-zero rc is the result of 123456 not being sent to My_Dummy_API BNB0006I: Call My_Dummy_API with 123456 passed as Mydata. BNB0007I: Is the Log User Data sent with this probe, formatted to hexidecimal BNB0008I: Is the Log User Data sent with this probe, formatted to ASCII BNB0009I: Is the Log User Data sent with this probe, formatted as decimal
MIF File Example
This is an example of the MIF file for the sample program. You can find this file in the Toolkit. The file name is PROBEXMP.MIF. MIF File Example
start component name = "FFST Example code" description = "This is the FFST Example code Component" // // // This is a particularly complicated file. Fortunately you only need // // to deal with the section at the very bottom, where you put in the // // information related to your DMI triplet (Vendor Tag, Tag, and // // Revision. The rest of this file defines itself to DMI and layouts // // the fields of information that DMI will manage // // // ////////////////////////////////////////////////////////////////////// // // // component id group // // // ////////////////////////////////////////////////////////////////////// // Component ID Group // // Enumerations for this group // Start Enum Name = "Verify_Type" Type = Integer 0x00 = "An error occurred; check status code" 0x01 = "This component does not exist" 0x02 = "The verify is not supported" 0x03 = "Reserved" 0x04 = "This component exists, but the functionality is untested" 0x05 = "This component exists, but the functionality is unknown" 0x06 = "This component exists, and is not functioning correctly" 0x07 = "This component exists, and is functioning correctly" End Enum start group name = "ComponentID" id = 1 class = "DMTFºComponentIDº1.0" description = "This group defines attributes common to all components. This group is required." start attribute name = "Manufacturer" id = 1 description = "The name of the manufacturer that produces this component." access = READ-ONLY storage = COMMON type = STRING(64) value = "IBM Corp." end attribute start attribute name = "Product" id = 2 description = "The name of the component." access = READ-ONLY storage = COMMON type = STRING(64) value = "FFST Example code" end attribute start attribute name = "Version" id = 3 description = "The version for the component." access = READ-ONLY storage = COMMON type = STRING(64) value = "" end attribute start attribute name = "Serial Number" id = 4 description = "The serial number for this instance of this component." access = READ-ONLY storage = SPECIFIC type = STRING(64) value = "" end attribute start attribute name = "Installation" id = 5 description = "The time and date of the last install of this component." access = READ-ONLY storage = SPECIFIC type = DATE value = "" end attribute Start Attribute Name = "Verify" Id = 6 Access = Read-Only Storage = Specific Type = "Verify_Type" Description = "A code that provides a level of verification " "that the component is still installed and working." Value = 0x07 End Attribute end group // // Software Product Group // // This is the group that contains the software Vital Product // Data attributes that identify the software product that is // represented by this DMI component // // This group is a template that defines the software product group // // This definition should not be modified the actual values are found in // the table which is after this template definition // // There are two sample rows defined for the table, however the table can // have one or more rows, what ever is correct for your component // start group name = "OS/2 Warp Software Product" class = "IBM_OS/2 WarpºSoftwareProductº1.0" description = "OS/2 Warp standard Software Product attributes" key=2,4,5 // The (Tag, VendorTag, Revision) triplet acts // as the key to this group start attribute name = "Title" id = 1 access = READ-ONLY type = STRING(256) value = " " description = "Long name for software product package unit" end attribute start attribute name = "Tag" id = 2 access = READ-ONLY type = STRING(256) value = " " description = "Short name for software product package unit" end attribute start attribute name = "VendorTitle" id = 3 access = READ-ONLY type = STRING(256) value = " " description = "Long name for manufacturer of software product package unit" end attribute start attribute name = "VendorTag" id = 4 access = READ-ONLY type = STRING(256) value = " " description = "Short name for manufacturer of software product package unit" end attribute start attribute name = "Revision" id = 5 access = READ-ONLY type = STRING(256) value = " " description = "Major, Minor and Modification levels for software product package unit" end attribute start attribute name = "ModificationLevel" id = 6 access = READ-ONLY type = STRING(256) value = " " description = "Current CSD level for software product package unit" end attribute start attribute name = "SelectiveFixLevel" id = 7 access = READ-ONLY type = STRING(256) value = " " description = "Selective Fix level for software product package unit" end attribute start attribute name = "Description" id = 8 access = READ-ONLY type = STRING(256) value = " " description = "String that describes the software product package unit" end attribute start attribute name = "ParentTag" id = 9 access = READ-ONLY type = STRING(256) value = " " description = "Short name for the parent package unit of this software product package unit" end attribute start attribute name = "ParentVendorTag" id = 10 access = READ-ONLY type = STRING(256) value = " " description = "Short manufacturer name for the parent package unit of this software product package unit" end attribute start attribute name = "ParentRevision" id = 11 access = READ-ONLY type = STRING(256) value = " " description = "Short revision string for the parent package unit of this software product package unit" end attribute start attribute name = "Error Record Template File" id = 12 access = READ-ONLY type = STRING(508) value = " " description = "Name of the Error Record Template file for this software product package unit" end attribute end group // // Software product group table with actual values // // This is the group that contains the software Vital Product // Data attributes that identify the software product that is // represented by this DMI component // // There are two sample rows defined for the table, however the table can // have one or more rows, what ever is correct for your component // // Note each of the fields assigned a position value below // are defined in the sections above. // // THIS IS THE ONLY SECTION YOU NEED TO DEAL WITH FOR THE PURPOSE OF // BUILDING YOUR OWN EXAMPLE // start table name = "Software components and their VPD" id = 2 class = "IBM_OS/2 WarpºSoftwareProductº1.0" {"", "FFSTProbe Sample", //Tag - Part of the triplet, // identifies your product "", "IBM", // Vendor Tag - Part of the triplet, // identifies your company "1.00", // Revision - Part of Triplet "000000", // Modification Level - Specified in your // code if not looked up "010101", // Selective Fix Level - Specified in your // code if not looked up "FFSTProbe Example Program", // Description "", "", "", "PROBE.REP"} // Repository (Template File) Name. // Should be on your DPATH // Otherwise full path would be specified. // This field is the prime // reason FFSTProbe uses DMI. The triplet // above forms the key // to retrieve the repository file // name so that the probe can be // formatted by SYSLOG end table end component