Let us imagine a large java system, composed of independently compiled modules and jars from multiple providers, without any universal dependency other than the standard API.
On top of this collection of runtime dependencies, you have built an interactive GUI framework. Whenever there is an error or a warning, you want to pop up an appropriate error dialog or update a message panel.
Many of the plugin packages may not be designed for a GUI.
Preferably, they report errors by throwing appropriate checked
exceptions. Sometimes, however, they could report some
additional details about exactly what went wrong. Even though
they fulfill most requests, they might still call attention
to some problems along the way. (E.g. Unable to load 2 of 100
files: file1, file2
.) Any number of useful messages could be
presented to a user with a "more details" button.
Saving information for an error dialog is really no different from logging in general. In fact, there are probably many useful error messages being saved to logs already, but invisible to users.
Logging for users requires a little more care, however. User messages belong in resource files, in a simple format that can be edited or translated by non-programmers. If this step has been taken, we can assume the message is appropriate for presentation to an end-user.
Even so, logging for a GUI requires no features on the client
side that are not already available in the standard Java
Logger
in java.util.logging
. Much third-party code is
likely to be using it already. All you need is some custom
filtering, and formatting, which the logging service
conveniently supports.
To see how powerful this simple API can be, first read https://blogs.oracle.com/corejavatechtips/logging-localized-message
Your usability experts and technical writers can edit and correct the messages in the resource files. A non-programmer can add new languages at any time.
To select and format messages appropriately for GUI dialogs,
the framework needs to add a custom
java.util.logging.Handler
to the standard logging system.
We can add as many custom Handlers as we want.
Each Handler can have a custom Formatter
or Filter
, to
decide what messages deserve to appear in an error dialog. A
Handler can filter by package or class names, by
java.util.logging.Level
, by message ID numbers, and more.
Before the GUI framework calls a service API from a plugin, it can first clear the custom Handler's cache of messages. After the service returns or throws an exception, the GUI framework can check the custom Handler to see if any SEVERE or WARNING messages were logged. If so, these could be included in an error or warning dialog. Preference could be given to error messages logged first, or logged with a ResourceBundle. If too many messages fell into these categories, we could get prepend a special tag to the logger name.
I strongly discourage any custom wrapping of the client API for Logger. There is nothing special about the way we need to log these messages -- only in the way we format and present them. Normal logging is still free to capture logging intended for error dialogs. The point of a standard Logging API is that it is standard, and is used by all code, including third-party code, without any compilation dependencies.
You might think using the standard Logger is too difficult for most clients. How difficult is this?
Logger.getLogger(Foo.class.getName()).severe("fileNotFoundMessage", filename); |
That one-liner identifies the package and class originating the
message, specifies an error level, specifies multilingual
resource files Foo.properties
(default) or
Foo_es.properties
(Spanish), and uses MessageFormat
to combine arguments like printf.
Of course a optional static convenience method could also be provided.
Logger was already designed for all the customization we need, with a simple API we would do well to study.
Message IDs should remain unique for support calls. These could appear as an alphanumeric code in each error message and would also serve as the logged message name.
Bill Harlan, June 2009
Return to parent directory.