-
Notifications
You must be signed in to change notification settings - Fork 4
Home
Nearly every application needs to be able to log messages that pertain to their operation. It is an essential, and expected feature of almost all applications. Standard logging frameworks have existed for some time, such as log4j and slf4j, and they work well as far as they go. As globalization of applications has gained momentum, we have found these logging frameworks to be insufficient. The logging frameworks do not have support for I18N, and push that requirement back to the application. This means that every application has to solve this problem for themselves. Additionally, users are less tolerant of lack of documentation, especially any parts of the application that are customer facing. This is especially true for messages issued by the application. Users want a place where they can find information pertaining to a message, such as “what does it mean” and “how do I recover from this”.
Event and Error Logging Framework aka EELF, builds on top of existing logging frameworks, adding the I18N support in a standard way, and also provides the ability to generate wiki documentation from the message definitions. The framework includes classes with numerous convenience methods to perform logging operations with ease. EELF API and Features
- Pluggable Logging framework built on SLF4j
- Message Logging with error codes
- Resource Management of resource bundles
-
Load Resource Bundles
- Format Message Resources
- Exception Formatting
- Wiki Content generation from the message definitions
- Ability to capture exception hierarchy
- Internationalization/Localization support
EELF provides a mechanism to load and format internationalized messages from multiple resource bundles, thus allowing for multiple language support as well as generalized message formatting. The formatting allows for the insertion of string values into the message text by using the position of the argument in the argument list. The formatting of the insertion can be controlled from the message resource and does not require any code changes. Since the mechanism used to format the messages is the standard java class java.text.MessageFormat, the user should be familiar with its capabilities.
Formatting of messages is performed by scanning the message skeleton for data insertion points, each identified by a number that corresponds to the variable argument list. For example, {0} represents the first data argument to the method call (the variable arguments array is zero-based). The reason the inserts are identified by the position of the argument in the method call is because some languages may need to format the message with the inserts in different locations in the message. This allows the code to remain unchanged, even though the message may be formatted in a completely different order for different languages.
An example message skeleton may look something like: Unexpected exception attempting to detach device {0}, volume definition {1}, from server {2} in stack {3}
The message skeletons are loaded from property files which constitute the resource bundle that has been loaded. Each bundle is identified by a base name. Different locale-specific resource files use the same base name plus a language and optional country code as part of the file name. This allows the appropriate resource file to be searched based on the locale used when the message is requested.
For example, assume the base name was "Messages" and there is support for US English, UK English, and German, with the default language being US English. To set that up, you would create three property files, each containing the message text appropriate to the specific language. This would result in three files, something like:
- Messages.properties
This is the "default" resource file searched if none exist that match the requested locale
- Messages_en-UK
This message resource file is searched when the locale is Great Britain.
- Messages_de
This message resource is used if the current locale specifies German as the language. Since no country code is present, this resource file would be used for ANY country locale that specifies the German language.
When a message is requested, the locale is examined to determine which resource file to use to obtain the message skeleton. If no resource file exists that matches the provided locale, then the default resource file (the one without any language or country code suffix) is used. All of the messages are present in each of the resource files, translated to the appropriate text for that specific language and/or country. It also means that any specific message identity be the same for the same message in all of the files.
To make the use of EELF easier, the message identifiers (keys) are defined using a simple enumeration. The application would create their own enumeration and create message identifiers within it. These identifiers are then used as the key of the message skeleton in each resource file that makes up the resource bundle.
EELF also allows for the creation of any logger that you want, and it is possible to use the fully qualified class name as the logger (as per many log4j examples). However, in an application where it may be necessary to isolate different logging events because of security, audit, or other concerns, this is not a good approach to use. The reason is that a specific class may emit both a security message and a
performance related message (for example). If the "class" logger example is used, both messages would go to the same logger and could not be individually managed.
Another approach often used in COTS applications is to assign loggers to "functionality". For example, there may be an application, security, audit, and performance logger. There could be others as well, or fewer depending on the applications actual needs. The EELF framework also supports the use of functional logging.
To use EELF, an application would perform the following basic operations:
- Create the message enumeration which must extend EELFResolvableErrorEnum. The application enumerated values are also the keys into the resource bundle(s) that get loaded.
- Create a resource bundle or bundles per language that needs to be supported. It is better to have one resource file in the bundle that uses only the base name to identify it, as this will be the default bundle if a resource in a language that has not been provided is requested. Usually, the default resource file will be English.
- Add a static initializer in the enumeration created above to call the EELFResourceManager to load the bundle(s) that were created.
The EELF framework allows the application to obtain not only the formatted message from the resource bundle(s), but also the description and suggested recovery action(s). This allows the application to provide this information to the user if desired. For example, when a request fails, the application could format the message as usual and log that message. It could also return to the user a detailed analysis of the error including the formatted message, the description, and suggested action(s). A maven plugin, eelf-maven-plugin is provided that constructs wiki documentation. It does this by reading the same resource bundles that the application uses to generate the messages. This ensures that the generation of documentation can be done during the application build process and that it is synchronized with the actual application. The resource definition includes the message id (key), the message skeleton, a description, and the suggested recovery action(s). It uses this information to create message descriptions in a format that can be directly inserted into a wiki. It also provides the feature of uploading to the wiki site as part of the plugin process.