6.2. JBoss Logging Tools
6.2.1. Overview
6.2.1.1. JBoss Logging Tools Internationalization and Localization
org.jboss.logging
annotations. It is not necessary to implement the interfaces, JBoss Logging Tools does this at compile time. Once defined you can use these methods to log messages or obtain exception objects in your code.
6.2.1.2. JBoss Logging Tools Quickstart
logging-tools
, contains a simple Maven project that demonstrates the features of JBoss Logging Tools. It has been used extensively in this documentation for code samples.
6.2.1.3. Message Logger
@org.jboss.logging.MessageLogger
.
6.2.1.4. Message Bundle
@org.jboss.logging.MessageBundle
.
6.2.1.5. Internationalized Log Messages
@LogMessage
and @Message
annotations and specify the log message using the value attribute of @Message
. Internationalized log messages are localized by providing translations in a properties file.
6.2.1.6. Internationalized Exceptions
6.2.1.7. Internationalized Messages
6.2.1.8. Translation Properties Files
6.2.1.9. JBoss Logging Tools Project Codes
projectCode
attribute of the @MessageLogger
annotation.
6.2.1.10. JBoss Logging Tools Message IDs
id
attribute of the @Message
annotation.
6.2.2. Creating Internationalized Loggers, Messages and Exceptions
6.2.2.1. Create Internationalized Log Messages
logging-tools
quick start for a complete example.
Prerequisites:
- You must already have a working Maven project. Refer to Section 6.2.6.1, “JBoss Logging Tools Maven Configuration”.
- The project must have the required Maven configuration for JBoss Logging Tools.
Procedure 6.1. Create an Internationalized Log Message Bundle
Create an Message Logger interface
Add a Java interface to your project to contain the log message definitions. Name the interface descriptively for the log messages that will be defined in it.The log message interface has the following requirements:- It must be annotated with
@org.jboss.logging.MessageLogger
. - It must extend
org.jboss.logging.BasicLogger
. - The interface must define a field of that is a typed logger that implements this interface. Do this with the
getMessageLogger()
method oforg.jboss.logging.Logger
.
package com.company.accounts.loggers; import org.jboss.logging.BasicLogger; import org.jboss.logging.Logger; import org.jboss.logging.MessageLogger; @MessageLogger(projectCode="") interface AccountsLogger extends BasicLogger { AccountsLogger LOGGER = Logger.getMessageLogger( AccountsLogger.class, AccountsLogger.class.getPackage().getName() ); }
Add method definitions
Add a method definition to the interface for each log message. Name each method descriptively for the log message that it represents.Each method has the following requirements:- The method must return
void
. - It must be annotated with the
@org.jboss.logging.LogMessage
annotation. - It must be annotated with the
@org.jboss.logging.Message
annotation. - The value attribute of
@org.jboss.logging.Message
contains the default log message. This is the message that is used if no translation is available.
@LogMessage @Message(value = "Customer query failed, Database not available.") void customerQueryFailDBClosed();
The default log level isINFO
.Invoke the methods
Add the calls to the interface methods in your code where the messages must be logged from. It is not necessary to create implementations of the interfaces, the annotation processor does this for you when the project is compiled.AccountsLogger.LOGGER.customerQueryFailDBClosed();
The custom loggers are sub-classed from BasicLogger so the logging methods ofBasicLogger
(debug()
,error()
etc) can also be used. It is not necessary to create other loggers to log non-internationalized messages.AccountsLogger.LOGGER.error("Invalid query syntax.");
The project now supports one or more internationalized loggers that can be localized.
6.2.2.2. Create and Use Internationalized Messages
logging-tools
quickstart for a complete example.
Prerequisites
- You have a working Maven project using the JBoss EAP 6 repository. Refer to Section 2.3.2, “Configure the JBoss EAP 6 Maven Repository Using the Maven Settings”.
- The required Maven configuration for JBoss Logging Tools has been added. Refer to Section 6.2.6.1, “JBoss Logging Tools Maven Configuration”.
Procedure 6.2. Create and Use Internationalized Messages
Create an interface for the exceptions
JBoss Logging Tools defines internationalized messages in interfaces. Name each interface descriptively for the messages that will be defined in it.The interface has the following requirements:- It must be declared as public
- It must be annotated with
@org.jboss.logging.MessageBundle
. - The interface must define a field that is a message bundle of the same type as the interface.
@MessageBundle(projectCode="") public interface GreetingMessageBundle { GreetingMessageBundle MESSAGES = Messages.getBundle(GreetingMessageBundle.class); }
Add method definitions
Add a method definition to the interface for each message. Name each method descriptively for the message that it represents.Each method has the following requirements:- It must return an object of type
String
. - It must be annotated with the
@org.jboss.logging.Message
annotation. - The value attribute of
@org.jboss.logging.Message
must be set to the default message. This is the message that is used if no translation is available.
@Message(value = "Hello world.") String helloworldString();
Invoke methods
Invoke the interface methods in your application where you need to obtain the message.System.console.out.println(helloworldString());
6.2.2.3. Create Internationalized Exceptions
logging-tools
quick start for a complete example.
Procedure 6.3. Create and use Internationalized Exceptions
Add JBoss Logging Tools configuration
Add the required project configuration to support JBoss Logging Tools. Refer to Section 6.2.6.1, “JBoss Logging Tools Maven Configuration”Create an interface for the exceptions
JBoss Logging Tools defines internationalized exceptions in interfaces. Name each interface descriptively for the exceptions that will be defined in it.The interface has the following requirements:- It must be declared as
public
. - It must be annotated with
@org.jboss.logging.MessageBundle
. - The interface must define a field that is a message bundle of the same type as the interface.
@MessageBundle(projectCode="") public interface ExceptionBundle { ExceptionBundle EXCEPTIONS = Messages.getBundle(ExceptionBundle.class); }
Add method definitions
Add a method definition to the interface for each exception. Name each method descriptively for the exception that it represents.Each method has the following requirements:- It must return an object of type
Exception
or a sub-type ofException
. - It must be annotated with the
@org.jboss.logging.Message
annotation. - The value attribute of
@org.jboss.logging.Message
must be set to the default exception message. This is the message that is used if no translation is available. - If the exception being returned has a constructor that requires parameters in addition to a message string, then those parameters must be supplied in the method definition using the
@Param
annotation. The parameters must be the same type and order as the constructor.
@Message(value = "The config file could not be opened.") IOException configFileAccessError(); @Message(id = 13230, value = "Date string '%s' was invalid.") ParseException dateWasInvalid(String dateString, @Param int errorOffset);
Invoke methods
Invoke the interface methods in your code where you need to obtain one of the exceptions. The methods do not throw the exceptions, they return the exception object which you can then throw.try { propsInFile=new File(configname); props.load(new FileInputStream(propsInFile)); } catch(IOException ioex) //in case props file does not exist { throw ExceptionBundle.EXCEPTIONS.configFileAccessError(); }
6.2.3. Localizing Internationalized Loggers, Messages and Exceptions
6.2.3.1. Generate New Translation Properties Files with Maven
logging-tools
quick start for a complete example.
Prerequisites:
- You must already have a working Maven project.
- The project must already be configured for JBoss Logging Tools.
- The project must contain one or more interfaces that define internationalized log messages or exceptions.
Procedure 6.4. Generate New Translation Properties Files with Maven
Add Maven configuration
Add the-AgenereatedTranslationFilePath
compiler argument to the Maven compiler plug-in configuration and assign it the path where the new files will be created.<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <configuration> <source>1.6</source> <target>1.6</target> <compilerArgument> -AgeneratedTranslationFilesPath=${project.basedir}/target/generated-translation-files </compilerArgument> <showDeprecation>true</showDeprecation> </configuration> </plugin>
The above configuration will create the new files in thetarget/generated-translation-files
directory of your Maven project.Build the project
Build the project using Maven.[Localhost]$ mvn compile
@MessageBundle
or @MessageLogger
. The new files are created in a subdirectory corresponding to the Java package that each interface is declared in.
InterfaceName
is the name of the interface that this file was generated for: InterfaceName.i18n_locale_COUNTRY_VARIANT.properties
.
6.2.3.2. Translate an Internationalized Logger, Exception or Message
logging-tools
quick start for a complete example.
Prerequisites
- You must already have a working Maven project.
- The project must already be configured for JBoss Logging Tools.
- The project must contain one or interfaces that define internationalized log messages or exceptions.
- The project must be configured to generate template translation property files.
Procedure 6.5. Translate an internationalized logger, exception or message
Generate the template properties files
Run themvn compile
command to create the template translation properties files.Add the template file to your project
Copy the template for the interfaces that you want to translate from the directory where they were created into thesrc/main/resources
directory of your project. The properties files must be in the same package as the interfaces they are translating.Rename the copied template file
Rename the copy of the template file according to the translation it will contain. E.g.GreeterLogger.i18n_fr_FR.properties
.Translate the contents of the template.
Edit the new translation properties file to contain the appropriate translation.# Level: Logger.Level.INFO # Message: Hello message sent. logHelloMessageSent=Bonjour message envoyé.
Repeat steps two, three, and four for each translation of each bundle being performed.
target/generated-sources/annotations/
.
6.2.4. Customizing Internationalized Log Messages
6.2.4.1. Add Message IDs and Project Codes to Log Messages
logging-tools
quick start for a complete example.
Prerequisites
- You must already have a project with internationalized log messages. Refer to Section 6.2.2.1, “Create Internationalized Log Messages”.
- You need to know the project code you will be using. You can use a single project code, or define different ones for each interface.
Procedure 6.6. Add message IDs and Project Codes to Log Messages
Specify the project code for the interface.
Specify the project code using the projectCode attribute of the@MessageLogger
annotation attached to a custom logger interface. All messages that are defined in the interface will use that project code.@MessageLogger(projectCode="ACCNTS") interface AccountsLogger extends BasicLogger { }
Specify Message IDs
Specify a message ID for each message using theid
attribute of the@Message
annotation attached to the method that defines the message.@LogMessage @Message(id=43, value = "Customer query failed, Database not available.") void customerQueryFailDBClosed();
10:55:50,638 INFO [com.company.accounts.ejb] (MSC service thread 1-4) ACCNTS000043: Customer query failed, Database not available.
6.2.4.2. Specify the Log Level for a Message
INFO
. A different log level can be specified with the level
attribute of the @LogMessage
annotation attached to the logging method.
Procedure 6.7. Specify the log level for a message
Specify level attribute
Add thelevel
attribute to the@LogMessage
annotation of the log message method definition.Assign log level
Assign thelevel
attribute the value of the log level for this message. The valid values forlevel
are the six enumerated constants defined inorg.jboss.logging.Logger.Level
:DEBUG
,ERROR
,FATAL
,INFO
,TRACE
, andWARN
.Import org.jboss.logging.Logger.Level; @LogMessage(level=Level.ERROR) @Message(value = "Customer query failed, Database not available.") void customerQueryFailDBClosed();
ERROR
.
10:55:50,638 ERROR [com.company.app.Main] (MSC service thread 1-4) Customer query failed, Database not available.
6.2.4.3. Customize Log Messages with Parameters
Procedure 6.8. Customize log messages with parameters
Add parameters to method definition
Parameters of any type can be added to the method definition. Regardless of type, the String representation of the parameter is what is displayed in the message.Add parameter references to the log message
References can use explicit or ordinary indexes.- To use ordinary indexes, insert the characters
%s
in the message string where you want each parameter to appear. The first instance of%s
will insert the first parameter, the second instance will insert the second parameter, and so on. - To use explicit indexes, insert the characters
%{#$}s
in the message, where # indicates the number of the parameter you wish to appear.
Important
@Cause
annotation is not included in the number of parameters.
Example 6.1. Message parameters using ordinary indexes
@LogMessage(level=Logger.Level.DEBUG) @Message(id=2, value="Customer query failed, customerid:%s, user:%s") void customerLookupFailed(Long customerid, String username);
Example 6.2. Message parameters using explicit indexes
@LogMessage(level=Logger.Level.DEBUG) @Message(id=2, value="Customer query failed, user:%2$s, customerid:%1$s") void customerLookupFailed(Long customerid, String username);
6.2.4.4. Specify an Exception as the Cause of a Log Message
Throwable
or any of its sub-classes and is marked with the @Cause
annotation. This parameter cannot be referenced in the log message like other parameters and is displayed after the log message.
@Cause
parameter to indicate the "causing" exception. It is assumed that you have already created internationalized logging messages to which you want to add this functionality.
Procedure 6.9. Specify an exception as the cause of a log message
Add the parameter
Add a parameter of the typeThrowable
or a sub-class to the method.@LogMessage @Message(id=404, value="Loading configuration failed. Config file:%s") void loadConfigFailed(Exception ex, File file);
Add the annotation
Add the@Cause
annotation to the parameter.import org.jboss.logging.Cause @LogMessage @Message(value = "Loading configuration failed. Config file: %s") void loadConfigFailed(@Cause Exception ex, File file);
Invoke the method
When the method is invoked in your code, an object of the correct type must be passed and will be displayed after the log message.try { confFile=new File(filename); props.load(new FileInputStream(confFile)); } catch(Exception ex) //in case properties file cannot be read { ConfigLogger.LOGGER.loadConfigFailed(ex, filename); }
Below is the output of the above code samples if the code threw an exception of typeFileNotFoundException
.10:50:14,675 INFO [com.company.app.Main] (MSC service thread 1-3) Loading configuration failed. Config file: customised.properties java.io.FileNotFoundException: customised.properties (No such file or directory) at java.io.FileInputStream.open(Native Method) at java.io.FileInputStream.<init>(FileInputStream.java:120) at com.company.app.demo.Main.openCustomProperties(Main.java:70) at com.company.app.Main.go(Main.java:53) at com.company.app.Main.main(Main.java:43)
6.2.5. Customizing Internationalized Exceptions
6.2.5.1. Add Message IDs and Project Codes to Exception Messages
Prerequisites
- You must already have a project with internationalized exceptions. Refer to Section 6.2.2.3, “Create Internationalized Exceptions”.
- You need to know the project code you will be using. You can use a single project code, or define different ones for each interface.
Procedure 6.10. Add Message IDs and Project Codes to Exception Messages
Specify a project code
Specify the project code using theprojectCode
attribute of the@MessageBundle
annotation attached to a exception bundle interface. All messages that are defined in the interface will use that project code.@MessageBundle(projectCode="ACCTS") interface ExceptionBundle { ExceptionBundle EXCEPTIONS = Messages.getBundle(ExceptionBundle.class); }
Specify message IDs
Specify a message ID for each exception using theid
attribute of the@Message
annotation attached to the method that defines the exception.@Message(id=143, value = "The config file could not be opened.") IOException configFileAccessError();
Important
Example 6.3. Creating internationalized exceptions
@MessageBundle(projectCode="ACCTS") interface ExceptionBundle { ExceptionBundle EXCEPTIONS = Messages.getBundle(ExceptionBundle.class); @Message(id=143, value = "The config file could not be opened.") IOException configFileAccessError(); }
throw ExceptionBundle.EXCEPTIONS.configFileAccessError();
Exception in thread "main" java.io.IOException: ACCTS000143: The config file could not be opened. at com.company.accounts.Main.openCustomProperties(Main.java:78) at com.company.accounts.Main.go(Main.java:53) at com.company.accounts.Main.main(Main.java:43)
6.2.5.2. Customize Exception Messages with Parameters
Procedure 6.11. Customize an exception message with parameters
Add parameters to method definition
Parameters of any type can be added to the method definition. Regardless of type, theString
representation of the parameter is what is displayed in the message.Add parameter references to the exception message
References can use explicit or ordinary indexes.- To use ordinary indexes, insert the characters
%s
in the message string where you want each parameter to appear. The first instance of%s
will insert the first parameter, the second instance will insert the second parameter, and so on. - To use explicit indexes, insert the characters
%{#$}s
in the message where#
indicates the number of the parameter which you wish to appear.
Using explicit indexes allows the parameter references in the message to be in a different order than they are defined in the method. This is important for translated messages which may require different ordering of parameters.
Important
@Cause
annotation is not included in the number of parameters.
Example 6.4. Using ordinary indexes
@Message(id=2, value="Customer query failed, customerid:%s, user:%s") void customerLookupFailed(Long customerid, String username);
Example 6.5. Using explicit indexes
@Message(id=2, value="Customer query failed, user:%2$s, customerid:%1$s") void customerLookupFailed(Long customerid, String username);
6.2.5.3. Specify One Exception as the Cause of Another Exception
@Cause
. This parameter is used to pass the causing exception. This parameter cannot be referenced in the exception message.
@Cause
parameter to indicate the causing exception. It is assumed that you have already created an exception bundle to which you want to add this functionality.
Procedure 6.12. Specify one exception as the cause of another exception
Add the parameter
Add the a parameter of the typeThrowable
or a sub-class to the method.@Message(id=328, value = "Error calculating: %s.") ArithmeticException calculationError(Throwable cause, String msg);
Add the annotation
Add the@Cause
annotation to the parameter.import org.jboss.logging.Cause @Message(id=328, value = "Error calculating: %s.") ArithmeticException calculationError(@Cause Throwable cause, String msg);
Invoke the method
Invoke the interface method to obtain an exception object. The most common use case is to throw a new exception from a catch block using the caught exception as the cause.try { ... } catch(Exception ex) { throw ExceptionBundle.EXCEPTIONS.calculationError( ex, "calculating payment due per day"); }
Example 6.6. Specify one exception as the cause of another exception
@MessageBundle(projectCode = "TPS") interface CalcExceptionBundle { CalcExceptionBundle EXCEPTIONS = Messages.getBundle(CalcExceptionBundle.class); @Message(id=328, value = "Error calculating: %s.") ArithmeticException calcError(@Cause Throwable cause, String value); }
int totalDue = 5; int daysToPay = 0; int amountPerDay; try { amountPerDay = totalDue/daysToPay; } catch (Exception ex) { throw CalcExceptionBundle.EXCEPTIONS.calcError(ex, "payments per day"); }
Exception in thread "main" java.lang.ArithmeticException: TPS000328: Error calculating: payments per day. at com.company.accounts.Main.go(Main.java:58) at com.company.accounts.Main.main(Main.java:43) Caused by: java.lang.ArithmeticException: / by zero at com.company.accounts.Main.go(Main.java:54) ... 1 more
6.2.6. Reference
6.2.6.1. JBoss Logging Tools Maven Configuration
pom.xml
file.
logging-tools
quick start for an example of a complete working pom.xml
file.
- JBoss Maven Repository must be enabled for the project. Refer to Section 2.3.2, “Configure the JBoss EAP 6 Maven Repository Using the Maven Settings”.
- The Maven dependencies for
jboss-logging
andjboss-logging-processor
must be added. Both of dependencies are available in JBoss EAP 6 so the scope element of each can be set toprovided
as shown.<dependency> <groupId>org.jboss.logging</groupId> <artifactId>jboss-logging-processor</artifactId> <version>1.0.0.Final</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.jboss.logging</groupId> <artifactId>jboss-logging</artifactId> <version>3.1.0.GA</version> <scope>provided</scope> </dependency>
- The
maven-compiler-plugin
must be at least version2.2
and be configured for target and generated sources of1.6
.<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <configuration> <source>1.6</source> <target>1.6</target> </configuration> </plugin>
6.2.6.2. Translation Property File Format
key=value
pair format described in the documentation for the java.util.Properties
class, http://docs.oracle.com/javase/6/docs/api/java/util/Properties.html.
InterfaceName.i18n_locale_COUNTRY_VARIANT.properties
InterfaceName
is the name of the interface that the translations apply to.locale
,COUNTRY
, andVARIANT
identify the regional settings that the translation applies to.locale
andCOUNTRY
specify the language and country using the ISO-639 and ISO-3166 Language and Country codes respectively.COUNTRY
is optional.VARIANT
is an optional identifier that can be used to identify translations that only apply to a specific operating system or browser.
Example 6.7. Sample Translation Properties File
GreeterService.i18n_fr_FR_POSIX.properties
.
# Level: Logger.Level.INFO # Message: Hello message sent. logHelloMessageSent=Bonjour message envoyé.
6.2.6.3. JBoss Logging Tools Annotations Reference
Annotation | Target | Description | Attributes |
---|---|---|---|
@MessageBundle | Interface |
Defines the interface as a Message Bundle.
| projectCode |
@MessageLogger | Interface |
Defines the interface as a Message Logger.
| projectCode |
@Message | Method |
Can be used in Message Bundles and Message Loggers. In a Message Logger it defines a method as being a localized logger. In a Message Bundle it defines the method as being one that returns a localized String or Exception object.
| value , id |
@LogMessage | Method |
Defines a method in a Message Logger as being a logging method.
| level (default INFO ) |
@Cause | Parameter |
Defines a parameter as being one that passes an Exception as the cause of either a Log message or another Exception.
| - |
@Param | Parameter |
Defines a parameter as being one that is passed to the constructor of the Exception.
| - |