The Waveset trace facility enables you to instrument code with trace points in the adapters component (resource adapters). This section contains some guidelines to help you to consistently use trace points to assess and resolve adapter problems.
Some guiding principles for instrumenting code with trace points are as follows:
Make trace points as useful as possible for troubleshooting in both production and development environments by displaying relevant information.
Create one entry point and one exit or exception trace point for every significant method.
Use trace points as efficiently as possible during normal operations and when tracing is enabled by
Minimizing the number of trace level checks
Minimizing object creation when tracing is enabled
You can specify a trace level for a trace point to control how much information displays. The following table describes each of the trace levels that are defined in the com.sun.idm.logging.TraceManager interface.
Table 5–2 Defined Trace Levels
Trace Level |
Trace Variable |
Usage |
---|---|---|
1 |
Trace.LEVEL1 |
Entry and exit points of public methods of the resource adapter interface |
2 |
Trace.LEVEL2 |
Entry and exit points of non-public methods or methods not included in the Waveset component external interface |
3 |
Trace.LEVEL3 |
Decision points or significant variables |
4 |
Trace.LEVEL4 |
Very detailed information, such as significant variables within a loop |
n/a |
Trace.ALWAYS |
Do not perform a trace-level check Note: Use this option if you have already specified the trace level in a condition. |
Use the com.sun.idm.logging.Trace class to prevent circular dependencies on the com.sun.idm.logging package that implements the com.sun.idm.logging.TraceManager interface.
When adding trace points to code, be aware of the following information:
Trace arguments to the method and return values from the method.
If the arguments “print large,” where the text representation is not brief, specify whether the Object is null or not. If the argument or return value is an array or a list, and the value could print large, showing the array size or list size is sufficient. You can use the com.waveset.util.Util.length() utility method to guard against null values.
To format trace information or to create objects that present trace information in a meaningful way, put an if statement around the trace statements, using the Trace.getLevel method and the isLogging(level) method, so that Waveset does not marshal the trace point data unless the specified trace level is enabled.
When using this construct, specify the Trace.ALWAYS trace level for trace points inside the condition. This trace level prevents an unnecessary check for the trace level when that check has already been performed in the condition.
If you are tracing an object value that requires a method call to get a printable representation of the object, such as obj.getName(), guard against a null object to prevent a NullPointerException occurring if trace becomes enabled.
In general, do not use trace points for simple getter and setter methods or for any other trivial methods.
When tracing a WSUser object, use the toString() method instead of the getName() method to present the value of the object. The toString()) method is more robust and prints more useful information than the getName() method. Instead of tracing user.getName(), trace user, which calls toString() implicitly.
If a method or constructor is just a wrapper, where that method or constructor does nothing significant except call another method or constructor with the same name but a different signature, just put trace points into the destination method or constructor.
If performance is critical and the method is called many times, use information trace points to indicate errors. Do not add entry or exit trace points to the method. Use this option carefully.
Before adding a trace point, ask yourself if that trace point will provide useful information when determining problems in the field.
The following sections describe specific trace levels in greater detail and provide examples showing how to use trace points in code.
Consider these guidelines before adding entry and exit trace points to your code:
Use Trace.Level1 entry or exit trace points for all Waveset component external interface methods, which are the public methods declared in the resource adapter interface.
Use Trace.Level2 entry or exit trace points for significant non-public methods including constructors and static methods or methods not included in the Waveset component external interface.
Specify arguments in the trace points.
If the argument is not a primitive type or java.lang.String, and the argument requires any kind of object creation or method calls, conditionalize the entry trace point so that the formatting work is only done when tracing is enabled.
When specifying an exit trace point, show the return value if the method is a primitive type or java.lang.String. If the return value requires some sort of formatting, conditionalize the object formatting as specified in these guidelines. Use the following:
int getLevel() int getLevel (Method) boolean isLogging(level,method) boolean level1 (method) boolean level2 (method) boolean level31 (method) boolean level4 (method) |
If you are tracing information that requires appending several java.lang.Strings together, use java.lang.StringBuffer instead of java.lang.String. Appends are faster using java.lang.StringBuffer. Also, conditionalize as in the preceding bullet item.
When adding entry or exit trace points for significant constructors, remember that you cannot place a trace point before a this() or super() method call within a constructor. Put the entry trace point immediately after the this() or super() method call.
Do not use an exit trace point to trace an exception condition. If the method throws an exception, use an exception trace point at the same trace level as the entry or exit trace point just before the exception is thrown. See Using Exception Trace Pointsfor more information.
If a method contains an entry trace point, that method also must contain a code path that executes either a throwing method, a caught method, or an exit.
Following are some simple entry and exit trace statements. For these examples, assume the following CLASS variables are declared for each statement.
private static final String CLASS = "com.waveset.adapter.MyResourceAdapter"; protected static Trace _trace = Trace.getTrace();
final String METHOD = methodName; _trace.entry(_trace.LEVEL1, CLASS, METHOD); _trace.entry(_trace.LEVEL1, CLASS, METHOD, user); if (_trace.level1(CLASS, METHOD)) { _trace.entry(_trace.ALWAYS, CLASS, METHOD, user= + user); } // Show the size of an array argument // ASSUME: password is an argument to the method // Note the use of the Util.length() method. It is // a convenience method that guards against null. if (_trace.level1(CLASS, METHOD)) { StringBuffer sb = new StringBuffer(32); sb.append(password length=); ab.append(Util.length(password)); _trace.entry(_trace.ALWAYS, CLASS, METHOD, sb.toString()); }
_trace.exit(_trace.LEVEL1, CLASS, METHOD); _trace.exit(_trace.LEVEL1, CLASS, METHOD, returnValue); if (_trace.level1(CLASS, METHOD)) { _trace.exit(_trace.ALWAYS, CLASS, METHOD, returnValue != null ? returnValue.getName() : returnValue); } // Show the size of an array String[] accounts = ... if (_trace.level1(CLASS, METHOD)) { StringBuffer sb = new StringBuffer(32) sb.append(accounts length=); ab.append(accounts.length); _trace.exit(_trace.ALWAYS, CLASS, METHOD, sb.toString()); }
Consider these guidelines before adding information trace points to your code:
Generally, use Trace.Level3 or Trace.Level4 for information, variable and data trace points. The trace level depends upon the significance, expense, and the verbosity of the information presented.
Use Trace.Level3 and Trace.Level4 information and variable trace points to trace significant conditions, branches, and other information as they occur in the code path.
A variable trace point is a convenience method that is the same as an information trace point, except that a variable trace point prints out variable=<variable> instead of just printing the argument value. In addition, this method does not format the information unless the trace level specified in the argument is matched.
Do not use an information trace point if the method contains an exception condition but does not rethrow the exception. Use the caught method. For an example, see Using Exception Trace Points.
Use Trace.Level3 and Trace.Level4 data trace points to show information in byte arrays. You can use a lower trace level if the information is appropriate for that trace level and the information presented is brief.
You can use Trace.Level1 and Trace.Level2 information, variable, and data trace points to trace significant, but brief, information. However, you should rarely use these trace points at these levels.
Following is an example of a simple information trace statement. For this example, assume the following CLASS variables are declared.
private static final String CLASS = "com.waveset.adapter.MyResourceAdapter"; protected static Trace _trace = Trace.getTrace();
_trace.info(_trace.LEVEL3, CLASS, METHOD, Some Message); WavesetResult result = new WavesetResult(); try { someMethod(); } catch(Exception e) { String msg = Some Error Message; WavesetException we = new Waveset(msg, e); _trace.caught(_trace.LEVEL3, CLASS, METHOD, e); result.addException(we); }
Consider these guidelines before adding exception trace points to your code:
Use exception trace points in all methods where entry or exit trace points are specified, and in methods that catch and rethrow exceptions. Waveset sometimes throws exceptions in which a new exception wraps the original exception. Use the same trace level being used by the entry and exit trace points.
Use an exception trace point if an exception is created and thrown from the current method.
Use an exception trace point caught method if an exception is caught and handled. For example, when the exception is not thrown from the current method. This situation typically occurs when Waveset catches and handles the exception by placing it in a container, such as a WavesetResult, to be examined later.
If the exception thrown from the current method is not a checked exception, which is an exception that extends java.lang.RuntimeException or java.lang.Error, the method exit point will not be traced unless other measures are taken. One way to set an exception trace point in this situation is to use a try/catch block around the critical section of the method and rethrow the exceptions that occur. In general, this means that you should use Trace.Level3 and higher when it is critical to know whether a method has succeeded or failed.
Following is an example of a simple exception trace statement. For this example, assume the following CLASS variables are declared:
private static final String CLASS = "com.waveset.adapter.MyResourceAdapter"; protected static Trace _trace = Trace.getTrace();
try { someMethod(); } catch(Exception e) { _trace.throwing(_trace.ALWAYS, CLASS, METHOD, e); throw e; } try { someMethod(); } catch(Exception e) { _trace.throwing(_trace.ALWAYS, CLASS, METHOD, e); WavesetException we = new WavesetException(Some Message, e); throw we; } if (error) { WavesetException e = new WavesetException(Some Error Message.; _trace.throwing(_trace.LEVEL3, CLASS, METHOD, e); throw e; } try { someMethod(); } catch(Exception e) { _trace.caught(_trace.LEVEL1, CLASS, METHOD, e); } // execution continues. someOtherMethod();
Using trace point templates can help you provide consistent and useful trace points in Waveset resource adapters. Waveset provides Eclipse templates in the following location:
src/wps/doc/eclipse-trace-templates.xml
To import these templates into Eclipse, select Window -> Preferences -> Java -> Editor -> Templates.
You can create similar templates if you are using Emacs or IDEA.