The Execution Tracing package groups traceable functions into trace event sets, which provide precise control of trace output. Once the sets have been defined, trace output can be toggled on or off at the package, class, or function level, simply by defining the appropriate environment variables.
To determine if a function should generate a trace event, the Execution Tracing package uses a hierarchical lookup through the sets, as shown in Figure 30. For example, if the environment variable mapping to a particular function is set to ON, the event is generated. If the environment variable is set to OFF, the event is not generated. If the environment variable is undefined (or defined to something else), the environment variable mapping to the class, if any, is checked. If the class environment variable is undefined, the package environment variable is checked. If it is OFF or undefined, no event is generated. Thus, coarse-grained control of trace output can be achieved by setting only the package or class environment variables to ON. Classes and global functions marked with the RW_USER macros default to the predefined rw_user package, as in the example on Example 52. See Section 6.4.4. for information on setting environment variables.
The set declaration macros implement the run-time lookup of environment variables that determine whether a function will generate a trace event. Trace does not work correctly if the set declaration macros are not used or are used improperly. Set declaration macro names all include the word TRACEABLE, to distinguish them from event generation macros. Set declaration macros come in three varieties: package declaration macros, class declaration macros, and function declaration macros.
The package declaration macros are optional. You use them only when your application is split into packages, and you want to control tracing separately for each package. For information on how you can create your own packages and package tracing macros, see Section 6.9, "Using Package-level Tracing."
NOTE: A predefined package set named rw_user acts as a default super set for your classes and functions. If this single package set is sufficient for your purposes, you can skip this section.
The package declaration macros are used in the implementation of the Execution Tracing package itself. To get a feel for what these macros do, you can check the userdefs.h and userdefs.cpp files in the trace source directories.
The macros take one parameter, packageName, to specify the name of the package to be traced. The packageName must be a valid C++ identifier. The DECLARE and DEFINE macros must be used in pairs, and the packageName of the DECLARE and DEFINE macros must match.
RW_TRACE_DECLARE_TRACEABLE_PACKAGE(packageName)
Declares a traceable package. This macro is normally placed at the end of the header file that defines the trace macros for that package. For an example, see the trace header file userdefs.h or the pkgdefs.h file for any other package in Threads.h++.
RW_TRACE_DEFINE_TRACEABLE_PACKAGE(packageName)
Provides a definition for a static variable defined by the matching DECLARE macro (above). This macro must be placed in some implementation file (.cpp) for your application. For an example, see the trace source file userdefs.cpp or the pkgdefs.cpp file in any of the other packages in Threads.h++.
The class declaration macros declare classes to be traceable, with the rw_user package as the super set. If you intend to trace any of a class' functions (member or static member), you must use these macros. Friend functions can either be traced with these macros or traced as global functions.
If you have used the package declaration macros to define other packages, you need to create your own class declaration macros. See Section 6.9, "Using Package-level Tracing."
The macros take one parameter, className, to specify the name of the class to be traced. The className must be a valid C++ identifier. The DECLARE and DEFINE macros must be used in pairs, and the className of the DECLARE and DEFINE macros must match.
RW_USER_DECLARE_TRACEABLE_CLASS(className)
Declares a non-template class as traceable. This macro must be placed in the header file for a class before the class declaration. Otherwise, it generates an undefined symbols compile error.
RW_USER_DEFINE_TRACEABLE_CLASS(className)
Provides a definition for a static variable defined by the matching DECLARE macro (above). This macro must be placed in the implementation (.cpp) file for the class.
RW_USER_DECLARE_TRACEABLE_TEMPLATE_CLASS(className)
Declares a template class as traceable. Do not include the template parameters in the className. This macro must be placed in the header file for a class before the class declaration. Otherwise, it generates an undefined symbols compile error.
RW_USER_DEFINE_TRACEABLE_TEMPLATE_CLASS(className)
Provides a definition for a static variable defined by the matching DECLARE macro (above). Do not include the template parameters in the className. This macro must be placed in the implementation file (typically a .cc file) for the template class.
Because you can place only one class declaration macro in each template class, you get only one environment variable, which controls the trace output from every instantiation of that particular template. You can't tell which instantiation of a template function produced a particular trace message. This is a known limitation of the Execution Tracing package.
The function declaration macros declare functions to be traceable. In addition, the macros automatically generate ENTRY and EXIT trace events upon entry and exit of the function. Every function that requires tracing must have one of these macros, normally as the first line of the function. Attempting to use more than one function declaration macro in a function results in compile or link errors.
The macro families come in sets of four macros, including an INLINE version for inline functions, a TEMPLATE version for template functions, a INLINE_TEMPLATE version for inline template functions, and a basic version for all other functions. Using the incorrect version results in compile and link errors.
Function declaration macros can take these parameters:
functionTag is used as the environment variable to control trace event generation for this function. It also appears in the trace output. The functionTag parameter must be a valid C++ identifier, and it must be enclosed in quotation marks, as a string. The functionTag is usually the name of the function (for a global function) or a string of the form "ClassName_functionName"(for a member function). See Section 6.4.3.6 for more on assigning tag names.
className specifies the name of the class to which the member or friend function belongs. It must match the className used in the RW_USER_DECLARE_TRACEABLE_CLASS macro for the class.
RW_USER_TRACEABLE_FUNCTION("functionTag")
RW_USER_TRACEABLE_INLINE_FUNCTION("functionTag")
RW_USER_TRACEABLE_TEMPLATE_FUNCTION("functionTag")
RW_USER_TRACEABLE_INLINE_TEMPLATE_FUNCTION("functionTag")
This macro family is used in global (non-member) functions. The functionTag is usually the name of the function.
RW_USER_TRACEABLE_MEMBER("functionTag", className)
RW_USER_TRACEABLE_INLINE_MEMBER("functionTag", className)
RW_USER_TRACEABLE_TEMPLATE_MEMBER("functionTag", className)
RW_USER_TRACEABLE_INLINE_TEMPLATE_MEMBER("functionTag", className)
This macro family is used in member functions. The functionTag is usually the string "ClassName_functionName".
RW_USER_TRACEABLE_STATIC_MEMBER("functionTag", className)
RW_USER_TRACEABLE_INLINE_STATIC_MEMBER("functionTag", className)
RW_USER_TRACEABLE_TEMPLATE_STATIC_MEMBER("functionTag", className)
RW_USER_TRACEABLE_INLINE_TEMPLATE_STATIC_MEMBER
("functionTag", className)
This macro family is used in static member functions. The functionTag is usually the string "ClassName_functionName".
RW_USER_TRACEABLE_FRIEND("functionTag", className)
RW_USER_TRACEABLE_INLINE_FRIEND("functionTag", className)
RW_USER_TRACEABLE_TEMPLATE_FRIEND("functionTag", className)
RW_USER_TRACEABLE_INLINE_TEMPLATE_FRIEND("functionTag", className)
This macro family is used in friend functions. The functionTag is usually the function name.
NOTE: Each function in an application may be traceable as a friend to only one class. Friend functions can also be traced as global functions.
Because you can place only one function declaration macro in each template function, you get only one environment variable, which controls the trace output from every instantiation of that particular template function. It is not trivial to determine which instantiation of a template function produced a particular trace message. If this information is required, you need to get it yourself, using a mechanism such as RTTI, and include it in the trace macro call. This is a known limitation of the Execution Tracing package.
The function declaration macros take a functionTag parameter (in quotes) to uniquely identify every traceable function. The tag appears in the trace output, so you can quickly find the function that generated a particular message.
Function names with special characters. The functionTag parameter must be a valid C++ identifier, so you need some convention to handle functions with characters that are invalid in C++ identifiers. Table shows the convention used throughout Threads.h++. You are not required to follow this convention in your code.
Function Name | Suggested Trace functionTag |
ClassName::ClassName() (constructors) |
"ClassName_ctor" |
ClassName::~ClassName() (destructor) |
"ClassName_dtor" |
ClassName::operator==() |
"ClassName_opEQ" |
ClassName::operator!=() |
"ClassName_opNE" |
ClassName::operator<() |
"ClassName_opLT" |
ClassName::operator<=() |
"ClassName_opLE" |
ClassName::operator>() |
"ClassName_opGT" |
ClassName::operator>=() |
"ClassName_opGE" |
ClassName::operator=() |
"ClassName_opAssign" |
ClassName::operator>>() |
"ClassName_opExtract" |
ClassName::operator<<() |
"ClassName_opInsert" |
ClassName::operator()() |
"ClassName_opFunctionCall" |
ClassName::operator Type() |
"ClassName_opType" |
The limitation of functionTags to be valid C++ identifiers stems from the fact that some shells (ksh in particular) do not permit the creation of environment variables that do not follow C++ identifier conventions.
Overloaded functions. This functionTag convention overloads tags. For example, all constructors for a class have the same functionTag. If multiple functions have the same functionTag, the single environment variable controls every version of the function. For distinguishing among overloaded functions, extra characters indicating the signature of the function can be included in the tag name. For example, "ClassName_ctor_ic" could be used for ClassName::ClassName(int, char). Because Trace outputs the filename and line number of the location of each trace event, the function that generated a trace event can be determined.
Before you run your program, you need some system-level environment variables to control the trace event sets (as explained in Section 6.4). Use variable names identical to the functionTags, classNames, and packageNames in your set declaration macros. You do not have to define a variable for every set you declared. If you don't need to control every function separately, you can define variables for just the classNames. You can define variables for a few interesting functions and throw away the output from everything else. In fact, you can generate trace output from an entire program by setting just the rw_user environment variable to ON (assuming that you have not used package declaration macros).
See your operating system documentation for instructions on setting environment variables on your system.
NOTE: To display the value of your environment variables on DOS, use "set myVariable" instead of the echo command. If the variable is turned off, "echo %myVariable%" turns echo itself off.
©Copyright 2000, Rogue Wave Software, Inc.
Contact Rogue Wave about documentation or support issues.