Eclipse Tip: Don't Let Bugs Get Lost Without Trace
The ability to trace your program's execution may prove invaluable when you are trying to hunt down an elusive problem. Although the Eclipse Java Debugger is a powerful tool, there are situations when it just cannot be used effectively. Even during regular program execution, various error conditions can occur, and not necessarily due to bugs in your code. Systematically logging these errors aids in diagnosing the conditions under which a particular error occurred.
Eclipse Error Log
The Eclipse runtime makes a standard logging facility available to all plug-ins. However, those familiar with logging frameworks commonly used in enterprise applications, such as Log4J, might be disappointed—Eclipse logging is far less powerful at the first glance. For instance, it uses its own flat-text format, provides rather limited API, and generally lacks configurability (for example, you can only log to the console, or a rolling file located at a fixed path under your instance area). That said, it is fit for its purpose, and if all else fails, you can always implement an alternative solution (see the Resources section for some pointers).
The easiest way to view your IDE's error log is to open the Error Log view. It is not all too apparent where to find it, unless you're in the PDE perspective—it is tucked away under the PDE Runtime category (also try pressing Alt+Shift+Q, L). Once you open it, you'll see a table of log entries showing the status message (typically an error, but there are also warnings and information entries), the identifier of the plug-in that logged the entry, and the timestamp. Some entries may have "child" entries—this happens when multiple errors were grouped and logged together under one entry. Double-clicking an entry brings up the Event Details dialog, which also displays any attached exception stack trace, as well as your workbench session data.
You can also import and export a log to and from the view, respectively. If you're curious what its actual file contents look like, you can open the log in a text editor by clicking Open Log from the view's toolbar. In the filesystem, the log file is located in your workspace directory under .metadata/.log (note the leading dots).
Logging And Reporting Exceptions
To write to the Eclipse log, one must first obtain an instance of ILog. Each plug-in is provisioned with one for its own internal use. It can be obtained by calling Plugin.getLog(). All logging then is performed by calling log(IStatus). The argument is an instance of IStatus, which is used to represent the outcome of operations in Eclipse. As such, it is also used to carry detailed error information in CoreException, which is the standard checked exception used throughout Eclipse.
In most cases, you can use the Status class whenever you need to provide an IStatus (for instance, when throwing a CoreException). You also can subclass it to add application-specific data. If multiple status objects need to be aggregated and reported as one "super-status," you can use the MultiStatus and add child status objects to it. When a MultiStatus is logged, its children are properly expanded.
Note that it also is possible to listen to an individual plug-in's logging requests. To do that, one would first obtain the plug-in's log by calling Platform.getLog(Bundle), and then registering an ILogListener, which is notified every time an entry is logged. For notification of all logging requests regardless of the origin, register your listener by calling Platform.addLogListener(ILogListener).
In a typical usage scenario, a plug-in would catch an exception generated elsewhere. As part of processing the exception, it would create a Status object describing the outcome of the operation (its own, not the one that threw the exception) and attach the caught exception to it. Finally, it would log the status to its log. If the attached exception is a CoreException, the logger detects it and expands the resulting status hierarchy (in other words, it retrieves the exception's status, and so on). Because the generated CoreException contains a status object created by the originating plug-in, it is not recommended (though quite tempting) to simply log the attached status to the receiver's log. Doing so results in a loss of context—you know that a basic operation failed, but you don't know where it was called and why. The attached example project illustrates the logging of various types of exceptions.
Optionally, the status object may be reused to report the error to the user by calling one of the ErrorDialog.openError(...) methods, which will pop up a standard error dialog capable of displaying status information. Note that as of version 3.3, a new service—StatusManager—is recommended for handling (that is, logging as well as reporting) exceptions. This service supports pluggable status handlers that can control the manner in which errors are logged and reported across the application.
Tracing Code Execution
In many logging frameworks, tracing is not much different from other kinds of logging. Typically, the same logging facilities also are used to capture the program's execution trace. Tracing, however, often generates a large amount of detailed information and thus it is not normally enabled in production other than for debugging. In Eclipse, tracing is a rather specific activity. In fact, it doesn't have all that much to do with logging. Rather, it has a lot to do with debugging.
Although there are no special facilities for logging trace messages (in fact, as horrible as it may sound, System.out.println() will often suffice), there is a special "debug mode" in which the platform can be launched. Plug-ins that support tracing must detect whether they are running in this debug mode (which, for good measure, has nothing to do with Java debugging) and only then generate trace messages. This is to avoid likely performance penalties, which are often incurred when tracing is enabled. Plug-ins may also query for "debug options," which is a simple property-based mechanism for configuring tracing.