Chapter 4. Logging
4.1. About Logging
Logging is the practice of recording a series of messages from an application that provides a record (or log) of the application’s activities.
Log messages provide important information for developers when debugging an application and for system administrators maintaining applications in production.
Most modern Java logging frameworks also include details such as the exact time and the origin of the message.
4.1.1. Supported Application Logging Frameworks
JBoss LogManager supports the following logging frameworks:
- JBoss Logging (included with JBoss EAP)
- Apache Commons Logging
- Simple Logging Facade for Java (SLF4J)
- Apache log4j
- Java SE Logging (java.util.logging)
JBoss LogManager supports the following APIs:
- JBoss Logging
- commons-logging
- SLF4J
- Log4j
- java.util.logging
JBoss LogManager also supports the following SPIs:
- java.util.logging Handler
- Log4j Appender
If you are using the Log4j API
and a Log4J Appender
, then Objects will be converted to string
before being passed.
4.2. Logging with the JBoss Logging Framework
4.2.1. About JBoss Logging
JBoss Logging is the application logging framework that is included in JBoss EAP. It provides an easy way to add logging to an application. You add code to your application that uses the framework to send log messages in a defined format. When the application is deployed to an application server, these messages can be captured by the server and displayed or written to file according to the server’s configuration.
JBoss Logging provides the following features:
-
An innovative, easy-to-use typed logger. A typed logger is a logger interface annotated with
org.jboss.logging.annotations.MessageLogger
. For examples, see Creating Internationalized Loggers, Messages and Exceptions. - Full support for internationalization and localization. Translators work with message bundles in properties files while developers work with interfaces and annotations. For details, see Internationalization and Localization.
- Build-time tooling to generate typed loggers for production and runtime generation of typed loggers for development.
4.2.2. Add Logging to an Application with JBoss Logging
This procedure demonstrates how to add logging to an application using JBoss Logging.
If you use Maven to build your project, you must configure Maven to use the JBoss EAP Maven repository. For more information, see Configure the JBoss EAP Maven Repository.
The JBoss Logging JAR files must be in the build path for your application.
-
If you build using Red Hat JBoss Developer Studio, select
Properties
from theProject
menu, then selectTargeted Runtimes
and ensure the runtime for JBoss EAP is checked. If you use Maven to build your project, make sure you add the
jboss-logging
dependency to your project’spom.xml
file for access to JBoss Logging framework:<dependency> <groupId>org.jboss.logging</groupId> <artifactId>jboss-logging</artifactId> <version>3.3.0.Final-redhat-1</version> <scope>provided</scope> </dependency>
The jboss-javaee-7.0 BOM manages the version of
jboss-logging
. For more details, see Manage Project Dependencies. See thelogging
quickstart for a working example of logging in an application.
You do not need to include the JARs in your built application because JBoss EAP provides them to deployed applications.
-
If you build using Red Hat JBoss Developer Studio, select
For each class to which you want to add logging:
Add the import statements for the JBoss Logging class namespaces that you will be using. At a minimum you will need the following import:
import org.jboss.logging.Logger;
Create an instance of
org.jboss.logging.Logger
and initialize it by calling the static methodLogger.getLogger(Class)
. It is recommended to create this as a single instance variable for each class.private static final Logger LOGGER = Logger.getLogger(HelloWorld.class);
Call the
Logger
object methods in your code where you want to send log messages.The
Logger
has many different methods with different parameters for different types of messages. Use the following methods to send a log message with the corresponding log level and themessage
parameter as a string:LOGGER.debug("This is a debugging message."); LOGGER.info("This is an informational message."); LOGGER.error("Configuration file not found."); LOGGER.trace("This is a trace message."); LOGGER.fatal("A fatal error occurred.");
For the complete list of JBoss Logging methods, see the Logging API documentation.
The following example loads customized configuration for an application from a properties file. If the specified file is not found, an ERROR level log message is recorded.
Example: Application Logging with JBoss Logging
import org.jboss.logging.Logger; public class LocalSystemConfig { private static final Logger LOGGER = Logger.getLogger(LocalSystemConfig.class); public Properties openCustomProperties(String configname) throws CustomConfigFileNotFoundException { Properties props = new Properties(); try { LOGGER.info("Loading custom configuration from "+configname); props.load(new FileInputStream(configname)); } catch(IOException e) //catch exception in case properties file does not exist { LOGGER.error("Custom configuration file ("+configname+") not found. Using defaults."); throw new CustomConfigFileNotFoundException(configname); } return props; } }
4.3. Per-deployment Logging
Per-deployment logging allows a developer to configure the logging configuration for their application in advance. When the application is deployed, logging begins according to the defined configuration. The log files created through this configuration contain information only about the behavior of the application.
If the per-deployment logging configuration is not done, the configuration from logging
subsystem is used for all the applications as well as the server.
This approach has advantages and disadvantages over using system-wide logging. An advantage is that the administrator of the JBoss EAP instance does not need to configure any other logging than the server logging. A disadvantage is that the per-deployment logging configuration is read only on server startup, and so cannot be changed at runtime.
4.3.1. Add Per-deployment Logging to an Application
To configure per-deployment logging to an application, add the logging.properties
configuration file to your deployment. This configuration file is recommended because it can be used with any logging facade where JBoss Log Manager is the underlying log manager.
The directory into which the configuration file is added depends on the deployment method:
-
For EAR deployments, copy the logging configuration file to the
META-INF
directory. -
For WAR or JAR deployments, copy the logging configuration file to the
WEB-INF/classes
directory.
If you are using Simple Logging Facade for Java (SLF4J)
or Apache log4j
, the logging.properties
configuration file is suitable. If you are using Apache log4j appenders then the configuration file log4j.properties
is required. The configuration file jboss-logging.properties
is supported only for legacy deployments.
Configuring logging.properties
The logging.properties
file is used when the server boots, until the logging
subsystem is started. If the logging
subsystem is not included in your configuration, then the server uses the configuration in this file as the logging configuration for the entire server.
JBoss Log Manager Configuration Options
Logger options
-
loggers=<category>[,<category>,…]
- Specify a comma-separated list of logger categories to be configured. Any categories not listed here will not be configured from the following properties. -
logger.<category>.level=<level>
- Specify the level for a category. The level can be one of the valid levels. If unspecified, the level of the nearest parent will be inherited. -
logger.<category>.handlers=<handler>[,<handler>,…]
- Specify a comma-separated list of the handler names to be attached to this logger. The handlers must be configured in the same properties file. -
logger.<category>.filter=<filter>
- Specify a filter for a category. -
logger.<category>.useParentHandlers=(true|false)
- Specify whether log messages should cascade up to parent handlers. The default value istrue
.
Handler options
-
handler.<name>=<className>
- Specify the class name of the handler to instantiate. This option is mandatory. -
handler.<name>.level=<level>
- Restrict the level of this handler. If unspecified, the default value of ALL is retained. -
handler.<name>.encoding=<encoding>
- Specify the character encoding, if it is supported by this handler type. If not specified, a handler-specific default is used. -
handler.<name>.errorManager=<name>
- Specify the name of the error manager to use. The error manager must be configured in the same properties file. If unspecified, no error manager is configured. -
handler.<name>.filter=<name>
- Specify a filter for a category. See the filter expressions for details on defining a filter. -
handler.<name>.formatter=<name>
- Specify the name of the formatter to use, if it is supported by this handler type. The formatter must be configured in the same properties file. If not specified, messages will not be logged for most handler types. -
handler.<name>.properties=<property>[,<property>,…]
- Specify a list of JavaBean-style properties to additionally configure. A rudimentary type introspection is done to ascertain the appropriate conversion for the given property. -
handler.<name>.constructorProperties=<property>[,<property>,…]
- Specify a list of properties that should be used as construction parameters. A rudimentary type introspection is done to ascertain the appropriate conversion for the given property. -
handler.<name>.<property>=<value>
- Set the value of the named property.
For further information, see Log Handler Attributes in the JBoss EAP Configuration Guide.
Error manager options
-
errorManager.<name>=<className>
- Specify the class name of the error manager to instantiate. This option is mandatory. -
errorManager.<name>.properties=<property>[,<property>,…]
- Specify a list of JavaBean-style properties to additionally configure. A rudimentary type introspection is done to ascertain the appropriate conversion for the given property. -
errorManager.<name>.<property>=<value>
- Set the value of the named property.
Formatter options
-
formatter.<name>=<className>
- Specify the class name of the formatter to instantiate. This option is mandatory. -
formatter.<name>.properties=<property>[,<property>,…]
- Specify a list of JavaBean-style properties to additionally configure. A rudimentary type introspection is done to ascertain the appropriate conversion for the given property. -
formatter.<name>.constructorProperties=<property>[,<property>,…]
- Specify a list of properties that should be used as construction parameters. A rudimentary type introspection is done to ascertain the appropriate conversion for the given property. -
formatter.<name>.<property>=<value>
- Set the value of the named property.
The following example shows the minimal configuration for logging.properties
file that will log to the console.
Example: Minimal logging.properties
Configuration
# Additional logger names to configure (root logger is always configured) # loggers= # Root logger level logger.level=INFO # Root logger handlers logger.handlers=CONSOLE # Console handler configuration handler.CONSOLE=org.jboss.logmanager.handlers.ConsoleHandler handler.CONSOLE.properties=autoFlush handler.CONSOLE.autoFlush=true handler.CONSOLE.formatter=PATTERN # Formatter pattern configuration formatter.PATTERN=org.jboss.logmanager.formatters.PatternFormatter formatter.PATTERN.properties=pattern formatter.PATTERN.pattern=%K{level}%d{HH:mm:ss,SSS} %-5p %C.%M(%L) [%c] %s%e%n
4.4. Logging Profiles
Logging profiles are independent sets of logging configurations that can be assigned to deployed applications. As with the regular logging
subsystem, a logging profile can define handlers, categories, and a root logger, but it cannot refer to configurations in other profiles or the main logging
subsystem. The design of logging profiles mimics the logging
subsystem for ease of configuration.
Logging profiles allow administrators to create logging configurations that are specific to one or more applications without affecting any other logging configurations. Because each profile is defined in the server configuration, the logging configuration can be changed without requiring that the affected applications be redeployed. However, logging profiles cannot be configured using the management console. For more information, see Configure a Logging Profile in the JBoss EAP Configuration Guide.
Each logging profile can have:
- A unique name (required)
- Any number of log handlers
- Any number of log categories
- Up to one root logger
An application can specify a logging profile to use in its MANIFEST.MF
file, using the Logging-Profile
attribute.
4.4.1. Specify a Logging Profile in an Application
An application specifies the logging profile to use in its MANIFEST.MF
file.
You must know the name of the logging profile that has been set up on the server for this application to use.
To add a logging profile configuration to an application, edit the MANIFEST.MF
file.
If your application does not have a
MANIFEST.MF
file, create one with the following content to specify the logging profile name.Manifest-Version: 1.0 Logging-Profile: LOGGING_PROFILE_NAME
If your application already has a
MANIFEST.MF
file, add the following line to specify the logging profile name.Logging-Profile: LOGGING_PROFILE_NAME
If you are using Maven and the maven-war-plugin
, put your MANIFEST.MF
file in src/main/resources/META-INF/
and add the following configuration to your pom.xml
file:
<plugin> <artifactId>maven-war-plugin</artifactId> <configuration> <archive> <manifestFile>src/main/resources/META-INF/MANIFEST.MF</manifestFile> </archive> </configuration> </plugin>
When the application is deployed, it will use the configuration in the specified logging profile for its log messages.
For an example of how to configure a logging profile and the application using it, see Example Logging Profile Configuration in the JBoss EAP Configuration Guide.
4.5. Internationalization and Localization
4.5.1. Introduction
4.5.1.1. About Internationalization
Internationalization is the process of designing software so that it can be adapted to different languages and regions without engineering changes.
4.5.1.2. About Localization
Localization is the process of adapting internationalized software for a specific region or language by adding locale-specific components and translations of text.
4.5.2. JBoss Logging Tools Internationalization and Localization
JBoss Logging Tools is a Java API that provides support for the internationalization and localization of log messages, exception messages, and generic strings. In addition to providing a mechanism for translation, JBoss Logging Tools also provides support for unique identifiers for each log message.
Internationalized messages and exceptions are created as method definitions inside of interfaces annotated using org.jboss.logging.annotations
annotations. Implementing the interfaces is not necessary; 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.
Internationalized logging and exception interfaces created with JBoss Logging Tools can be localized by creating a properties file for each bundle containing the translations for a specific language and region. JBoss Logging Tools can generate template property files for each bundle that can then be edited by a translator.
JBoss Logging Tools creates an implementation of each bundle for each corresponding translations property file in your project. All you have to do is use the methods defined in the bundles and JBoss Logging Tools ensures that the correct implementation is invoked for your current regional settings.
Message IDs and project codes are unique identifiers that are prepended to each log message. These unique identifiers can be used in documentation to make it easy to find information about log messages. With adequate documentation, the meaning of a log message can be determined from the identifiers regardless of the language that the message was written in.
The JBoss Logging Tools includes support for the following features:
- MessageLogger
-
This interface in the
org.jboss.logging.annotations
package is used to define internationalized log messages. A message logger interface is annotated with@MessageLogger
. - MessageBundle
-
This interface can be used to define generic translatable messages and Exception objects with internationalized messages. A message bundle is not used for creating log messages. A message bundle interface is annotated with
@MessageBundle
. - Internationalized Log Messages
These log messages are created by defining a method in a
MessageLogger
. The method must be annotated with the@LogMessage
and@Message
annotations and must specify the log message using the value attribute of@Message
. Internationalized log messages are localized by providing translations in a properties file.JBoss Logging Tools generates the required logging classes for each translation at compile time and invokes the correct methods for the current locale at runtime.
- Internationalized Exceptions
- An internationalized exception is an exception object returned from a method defined in a MessageBundle. These message bundles can be annotated to define a default exception message. The default message is replaced with a translation if one is found in a matching properties file for the current locale. Internationalized exceptions can also have project codes and message IDs assigned to them.
- Internationalized Messages
-
An internationalized message is a string returned from a method defined in a
MessageBundle
. Message bundle methods that return Java String objects can be annotated to define the default content of that string, known as the message. The default message is replaced with a translation if one is found in a matching properties file for the current locale. - Translation Properties Files
- Translation properties files are Java properties files that contain the translations of messages from one interface for one locale, country, and variant. Translation properties files are used by the JBoss Logging Tools to generate the classes that return the messages.
- JBoss Logging Tools Project Codes
Project codes are strings of characters that identify groups of messages. They are displayed at the beginning of each log message, prepended to the message ID. Project codes are defined with the projectCode attribute of the
@MessageLogger
annotation.NoteFor a complete list of the new log message project code prefixes, see the Project Codes used in JBoss EAP 7.0.
- JBoss Logging Tools Message IDs
-
Message IDs are numbers that uniquely identify a log message when combined with a project code. Message IDs are displayed at the beginning of each log message, appended to the project code for the message. Message IDs are defined with the ID attribute of the
@Message
annotation.
The logging-tools
quickstart that ships with JBoss EAP is a simple Maven project that provides a working example of many of the features of JBoss Logging Tools. The code examples that follow are taken from the logging-tools
quickstart.
4.5.3. Creating Internationalized Loggers, Messages and Exceptions
4.5.3.1. Create Internationalized Log Messages
You can use JBoss Logging Tools to create internationalized log messages by creating MessageLogger
interfaces.
This topic does not cover all optional features or the localization of the log messages.
If you have not yet done so, configure your Maven settings to use the JBoss EAP Maven repository.
For more information, see Configure the JBoss EAP Maven Repository Using the Maven Settings.
Configure the project’s
pom.xml
file to use JBoss Logging Tools.For details, see JBoss Logging Tools Maven Configuration.
Create a message logger interface by adding a Java interface to your project to contain the log message definitions.
Name the interface to describe the log messages it will define. The log message interface has the following requirements:
-
It must be annotated with
@org.jboss.logging.annotations.MessageLogger
. -
Optionally, it can extend
org.jboss.logging.BasicLogger
. The interface must define a field that is a message logger of the same type as the interface. Do this with the
getMessageLogger()
method of@org.jboss.logging.Logger
.Example: Creating a Message Logger
package com.company.accounts.loggers; import org.jboss.logging.BasicLogger; import org.jboss.logging.Logger; import org.jboss.logging.annotations.MessageLogger; @MessageLogger(projectCode="") interface AccountsLogger extends BasicLogger { AccountsLogger LOGGER = Logger.getMessageLogger( AccountsLogger.class, AccountsLogger.class.getPackage().getName() ); }
-
It must be annotated with
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.annotation.LogMessage
annotation. -
It must be annotated with the
@org.jboss.logging.annotations.Message
annotation. -
The default log level is
INFO
. The value attribute of
@org.jboss.logging.annotations.Message
contains the default log message, which is used if no translation is available.@LogMessage @Message(value = "Customer query failed, Database not available.") void customerQueryFailDBClosed();
-
The method must return
Invoke the methods by adding the calls to the interface methods in your code where the messages must be logged from.
Creating implementations of the interfaces is not necessary, the annotation processor does this for you when the project is compiled.
AccountsLogger.LOGGER.customerQueryFailDBClosed();
The custom loggers are subclassed from
BasicLogger
, so the logging methods ofBasicLogger
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.
The logging-tools
quickstart that ships with JBoss EAP is a simple Maven project that provides a working example of how to use JBoss Logging Tools.
4.5.3.2. Create and Use Internationalized Messages
This procedure demonstrates how to create and use internationalized messages.
This section does not cover all optional features or the process of localizing those messages.
- If you have not yet done so, configure your Maven settings to use the JBoss EAP Maven repository. For more information, see Configure the JBoss EAP Maven Repository Using the Maven Settings.
-
Configure the project’s
pom.xml
file to use JBoss Logging Tools. For details, see JBoss Logging Tools Maven Configuration. Create an interface for the exceptions. JBoss Logging Tools defines internationalized messages in interfaces. Name each interface descriptively for the messages that it contains. The interface has the following requirements:
-
It must be declared as
public
. -
It must be annotated with
@org.jboss.logging.annotations.MessageBundle
. The interface must define a field that is a message bundle of the same type as the interface.
Example: Create a
MessageBundle
Interface@MessageBundle(projectCode="") public interface GreetingMessageBundle { GreetingMessageBundle MESSAGES = Messages.getBundle(GreetingMessageBundle.class); }
NoteCalling
Messages.getBundle(GreetingMessagesBundle.class)
is equivalent to callingMessages.getBundle(GreetingMessagesBundle.class, Locale.getDefault())
.Locale.getDefault()
gets the current value of the default locale for this instance of the Java Virtual Machine. The Java Virtual Machine sets the default locale during startup, based on the host environment. It is used by many locale-sensitive methods if no locale is explicitly specified. It can be changed using thesetDefault
method.See Set the Default Locale of the Server in the JBoss EAP Configuration Guide for more information.
-
It must be declared as
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.annotations.Message
annotation. The value attribute of
@org.jboss.logging.annotations.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();
-
It must return an object of type
Invoke the interface methods in your application where you need to obtain the message:
System.out.println(helloworldString());
The project now supports internationalized message strings that can be localized.
See the logging-tools
quickstart that ships with JBoss EAP for a complete working example.
4.5.3.3. Create Internationalized Exceptions
You can use JBoss Logging Tools to create and use internationalized exceptions.
The following instructions assume that you want to add internationalized exceptions to an existing software project that is built using either Red Hat JBoss Developer Studio or Maven.
This topic does not cover all optional features or the process of localization of those exceptions.
-
Configure the project’s
pom.xml
file to use JBoss Logging Tools. For details, see 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
@MessageBundle
. The interface must define a field that is a message bundle of the same type as the interface.
Example: Create an
ExceptionBundle
Interface@MessageBundle(projectCode="") public interface ExceptionBundle { ExceptionBundle EXCEPTIONS = Messages.getBundle(ExceptionBundle.class); }
-
It must be declared as
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
Exception
object, or a sub-type ofException
. -
It must be annotated with the
@org.jboss.logging.annotations.Message
annotation. -
The value attribute of
@org.jboss.logging.annotations.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 they are in the constructor of the exception.@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);
-
It must return an
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(); }
The project now supports internationalized exceptions that can be localized.
See the logging-tools
quickstart that ships with JBoss EAP for a complete working example.
4.5.4. Localizing Internationalized Loggers, Messages and Exceptions
4.5.4.1. Generate New Translation Properties Files with Maven
Projects that are built using Maven can generate empty translation property files for each MessageLogger
and MessageBundle
it contains. These files can then be used as new translation property files.
The following procedure demonstrates how to configure a Maven project to generate new translation property files.
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.
Generate the Translation Properties Files
Add the Maven configuration by adding the
-AgenereatedTranslationFilePath
compiler argument to the Maven compiler plug-in configuration, and assign it the path where the new files will be created.This configuration creates the new files in the
target/generated-translation-files
directory of your Maven project.Example: Define the Translation File Path
<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>
Build the project using Maven:
$ mvn compile
One properties file is created for each interface annotated with
@MessageBundle
or@MessageLogger
.- The new files are created in a subdirectory corresponding to the Java package in which each interface is declared.
Each new file is named using the following pattern where
INTERFACE_NAME
is the name of the interface used to generated the file.INTERFACE_NAME.i18n_locale_COUNTRY_VARIANT.properties
The resulting files can now be copied into your project as the basis for new translations.
See the logging-tools
quickstart that ships with JBoss EAP for a complete working example.
4.5.4.2. Translate an Internationalized Logger, Exception, or Message
Properties files can be used to provide translations for logging and exception messages defined in interfaces using JBoss Logging Tools.
The following procedure shows how to create and use a translation properties file, and assumes that you already have a project with one or more interfaces defined for internationalized exceptions or log messages.
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.
- The project must be configured to generate template translation property files.
Translate an Internationalized Logger, Exception, or Message
Run the following command to create the template translation properties files:
$ mvn compile
-
Copy the template for the interfaces that you want to translate from the directory where they were created into the
src/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 to indicate the language it will contain. For example:
GreeterLogger.i18n_fr_FR.properties
. Edit the contents of the new translation properties file to contain the appropriate translation:
# Level: Logger.Level.INFO # Message: Hello message sent. logHelloMessageSent=Bonjour message envoyé.
- Repeat the process of copying the template and modifying it for each translation in the bundle.
The project now contains translations for one or more message or logger bundles. Building the project generates the appropriate classes to log messages with the supplied translations. It is not necessary to explicitly invoke methods or supply parameters for specific languages, JBoss Logging Tools automatically uses the correct class for the current locale of the application server.
The source code of the generated classes can be viewed under target/generated-sources/annotations/
.
4.5.5. Customizing Internationalized Log Messages
4.5.5.1. Add Message IDs and Project Codes to Log Messages
This procedure demonstrates how to add message IDs and project codes to internationalized log messages created using JBoss Logging Tools. A log message must have both a project code and message ID to be displayed in the log. If a message does not have both a project code and a message ID, then neither is displayed.
Prerequisites
- You must already have a project with internationalized log messages. For details, see 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.
Add Message IDs and Project Codes to Log Messages
Specify the project code for the interface by 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 a message ID for each message using the
id
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();
The log messages that have both a message ID and project code associated with them will prepend these to the logged message.
10:55:50,638 INFO [com.company.accounts.ejb] (MSC service thread 1-4) ACCNTS000043: Customer query failed, Database not available.
4.5.5.2. Specify the Log Level for a Message
The default log level of a message defined by an interface by JBoss Logging Tools is INFO
. A different log level can be specified with the level
attribute of the @LogMessage
annotation attached to the logging method. Use the following procedure to specify a different log level.
-
Add the
level
attribute to the@LogMessage
annotation of the log message method definition. Assign the log level for this message using the
level
attribute. 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();
Invoking the logging method in the above sample will produce a log message at the level of ERROR
.
10:55:50,638 ERROR [com.company.app.Main] (MSC service thread 1-4) Customer query failed, Database not available.
4.5.5.3. Customize Log Messages with Parameters
Custom logging methods can define parameters. These parameters are used to pass additional information to be displayed in the log message. Where the parameters appear in the log message is specified in the message itself using either explicit or ordinary indexing.
Customize Log Messages with Parameters
- Add parameters of any type 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
%s
characters 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
%#$s
characters in the message, where # indicates the number of the parameter that you wish to appear.
-
To use ordinary indexes, insert
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 that may require different ordering of parameters.
The number of parameters must match the number of references to the parameters in the specified message or the code will not compile. A parameter marked with the @Cause
annotation is not included in the number of parameters.
The following is an example of 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);
The following is an example of 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);
4.5.5.4. Specify an Exception as the Cause of a Log Message
JBoss Logging Tools allows one parameter of a custom logging method to be defined as the cause of the message. This parameter must be the Throwable
type 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.
The following procedure shows how to update a logging method using the @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.
Specify an Exception as the Cause of a Log Message
Add a parameter of the type
Throwable
or its subclass to the method.@LogMessage @Message(id=404, value="Loading configuration failed. Config file:%s") void loadConfigFailed(Exception ex, File file);
Add the
@Cause
annotation to the parameter.import org.jboss.logging.annotations.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); }
The following is the output of the above code samples if the code threw an exception of type FileNotFoundException
:
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)
4.5.6. Customizing Internationalized Exceptions
4.5.6.1. Add Message IDs and Project Codes to Exception Messages
Message IDs and project codes are unique identifiers that are prepended to each message displayed by internationalized exceptions. These identifying codes make it possible to create a reference for all the exception messages in an application. This allows someone to look up the meaning of an exception message written in language that they do not understand.
The following procedure demonstrates how to add message IDs and project codes to internationalized exception messages created using JBoss Logging Tools.
Prerequisites
- You must already have a project with internationalized exceptions. For details, see 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.
Add Message IDs and Project Codes to Exception Messages
Specify the project code using the
projectCode
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 for each exception using the
id
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();
A message that has both a project code and message ID displays them prepended to the message. If a message does not have both a project code and a message ID, neither is displayed.
Example: Internationalized Exception
This exception bundle interface example uses the project code of "ACCTS". It contains a single exception method with the ID of "143".
@MessageBundle(projectCode="ACCTS") interface ExceptionBundle { ExceptionBundle EXCEPTIONS = Messages.getBundle(ExceptionBundle.class); @Message(id=143, value = "The config file could not be opened.") IOException configFileAccessError(); }
The exception object can be obtained and thrown using the following code:
throw ExceptionBundle.EXCEPTIONS.configFileAccessError();
This would display an exception message like the following:
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)
4.5.6.2. Customize Exception Messages with Parameters
Exception bundle methods that define exceptions can specify parameters to pass additional information to be displayed in the exception message. The exact position of the parameters in the exception message is specified in the message itself using either explicit or ordinary indexing.
Customize Exception Messages with Parameters
- Add parameters of any type 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 exception message. References can use explicit or ordinary indexes.
-
To use ordinary indexes, insert
%s
characters 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
%#$s
characters in the message, where # indicates the number of the parameter that you wish to appear.
-
To use ordinary indexes, insert
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 that may require different ordering of parameters.
The number of parameters must match the number of references to the parameters in the specified message, or the code will not compile. A parameter marked with the @Cause
annotation is not included in the number of parameters.
Example: Using Ordinary Indexes
@Message(id=2, value="Customer query failed, customerid:%s, user:%s") void customerLookupFailed(Long customerid, String username);
Example: Using Explicit Indexes
@Message(id=2, value="Customer query failed, user:%2$s, customerid:%1$s") void customerLookupFailed(Long customerid, String username);
4.5.6.3. Specify One Exception as the Cause of Another Exception
Exceptions returned by exception bundle methods can have another exception specified as the underlying cause. This is done by adding a parameter to the method and annotating the parameter with @Cause
. This parameter is used to pass the causing exception, and cannot be referenced in the exception message.
The following procedure shows how to update a method from an exception bundle using the @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.
Add a parameter of the type
Throwable
or its subclass to the method.@Message(id=328, value = "Error calculating: %s.") ArithmeticException calculationError(Throwable cause, String msg);
Add the
@Cause
annotation to the parameter.import org.jboss.logging.annotations.Cause @Message(id=328, value = "Error calculating: %s.") ArithmeticException calculationError(@Cause Throwable cause, String msg);
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"); }
The following is an example of specifying an exception as the cause of another exception. This exception bundle defines a single method that returns an exception of type ArithmeticException
.
@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); }
This code snippet performs an operation that throws an exception, because it attempts to divide an integer by zero. The exception is caught, and a new exception is created using the first one as the cause.
int totalDue = 5; int daysToPay = 0; int amountPerDay; try { amountPerDay = totalDue/daysToPay; } catch (Exception ex) { throw CalcExceptionBundle.EXCEPTIONS.calcError(ex, "payments per day"); }
The following is an example of the exception message:
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
4.5.7. References
4.5.7.1. JBoss Logging Tools Maven Configuration
The following procedure configures a Maven project to use JBoss Logging and JBoss Logging Tools for internationalization.
If you have not yet done so, configure your Maven settings to use the JBoss EAP repository. For more information, see Configure the JBoss EAP Maven Repository Using the Maven Settings.
Include the
jboss-eap-javaee7
BOM in the<dependencyManagement>
section of the project’spom.xml
file.<dependencyManagement> <dependencies> <!-- JBoss distributes a complete set of Java EE APIs including a Bill of Materials (BOM). A BOM specifies the versions of a "stack" (or a collection) of artifacts. We use this here so that we always get the correct versions of artifacts. Here we use the jboss-javaee-7.0 stack (you can read this as the JBoss stack of the Java EE APIs). You can actually use this stack with any version of JBoss EAP that implements Java EE. --> <dependency> <groupId>org.jboss.bom</groupId> <artifactId>jboss-eap-javaee7</artifactId> <version>${version.jboss.bom.eap}</version> <type>pom</type> <scope>import</scope> </dependency> <dependencies> <dependencyManagement>
Add the Maven dependencies to the project’s
pom.xml
file:-
Add the
jboss-logging
dependency for access to JBoss Logging framework. If you plan to use the JBoss Logging Tools, also add the
jboss-logging-processor
dependency.Both of these dependencies are available in JBoss EAP BOM that was added in the previous step, so the scope element of each can be set to
provided
as shown.<!-- Add the JBoss Logging Tools dependencies --> <!-- The jboss-logging API --> <dependency> <groupId>org.jboss.logging</groupId> <artifactId>jboss-logging</artifactId> <scope>provided</scope> </dependency> <!-- Add the jboss-logging-tools processor if you are using JBoss Tools --> <dependency> <groupId>org.jboss.logging</groupId> <artifactId>jboss-logging-processor</artifactId> <scope>provided</scope> </dependency>
-
Add the
The maven-compiler-plugin must be at least version
3.1
and configured for target and generated sources of1.8
.<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin>
For a complete working example of a pom.xml
file that is configured to use JBoss Logging Tools, see the logging-tools
quickstart that ships with JBoss EAP.
4.5.7.2. Translation Property File Format
The property files used for the translation of messages in JBoss Logging Tools are standard Java property files. The format of the file is the simple line-oriented, key=value
pair format described in the java.util.Properties
class documentation.
The file name format has the following format:
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.
The properties contained in the translation file are the names of the methods from the interface being translated. The assigned value of the property is the translation. If a method is overloaded, then this is indicated by appending a dot and then the number of parameters to the name. Methods for translation can only be overloaded by supplying a different number of parameters.
Translation Properties File Example
File name: GreeterService.i18n_fr_FR_POSIX.properties
.
# Level: Logger.Level.INFO # Message: Hello message sent. logHelloMessageSent=Bonjour message envoyé.
4.5.7.3. JBoss Logging Tools Annotations Reference
The following annotations are defined in JBoss Logging for use with internationalization and localization of log messages, strings, and exceptions.
Annotation | Target | Description | Attributes |
---|---|---|---|
| Interface | Defines the interface as a message bundle. |
|
| Interface | Defines the interface as a message logger. |
|
| Method | Can be used in message bundles and message loggers. In a message bundle it defines the method as being one that returns a localized String or Exception object. In a message logger it defines a method as being a localized logger. |
|
| Method | Defines a method in a message logger as being a logging method. |
|
| Parameter | Defines a parameter as being one that passes an Exception as the cause of either a Log message or another Exception. | - |
| Parameter | Defines a parameter as being one that is passed to the constructor of the Exception. | - |
4.5.7.4. Project Codes Used in JBoss EAP
The following table lists all the project codes used in JBoss EAP 7.0, along with the Maven modules they belong to.
Maven Module | Project Code |
---|---|
appclient | WFLYAC |
batch/extension-jberet | WFLYBATCH |
batch/extension | WFLYBATCH-DEPRECATED |
batch/jberet | WFLYBAT |
bean-validation | WFLYBV |
controller-client | WFLYCC |
controller | WFLYCTL |
clustering/common | WFLYCLCOM |
clustering/ejb/infinispan | WFLYCLEJBINF |
clustering/infinispan/extension | WFLYCLINF |
clustering/jgroups/extension | WFLYCLJG |
clustering/server | WFLYCLSV |
clustering/web/infinispan | WFLYCLWEBINF |
connector | WFLYJCA |
deployment-repository | WFLYDR |
deployment-scanner | WFLYDS |
domain-http | WFLYDMHTTP |
domain-management | WFLYDM |
ee | WFLYEE |
ejb3 | WFLYEJB |
embedded | WFLYEMB |
host-controller | WFLYDC |
host-controller | WFLYHC |
iiop-openjdk | WFLYIIOP |
io/subsystem | WFLYIO |
jaxrs | WFLYRS |
jdr | WFLYJDR |
jmx | WFLYJMX |
jpa/hibernate5 | JIPI |
jpa/spi/src/main/java/org/jipijapa/JipiLogger.java | JIPI |
jpa/subsystem | WFLYJPA |
jsf/subsystem | WFLYJSF |
jsr77 | WFLYEEMGMT |
launcher | WFLYLNCHR |
legacy | WFLYORB |
legacy | WFLYMSG |
legacy | WFLYWEB |
logging | WFLYLOG |
| WFLYMAIL |
management-client-content | WFLYCNT |
messaging-activemq | WFLYMSGAMQ |
mod_cluster/extension | WFLYMODCLS |
naming | WFLYNAM |
network | WFLYNET |
patching | WFLYPAT |
picketlink | WFLYPL |
platform-mbean | WFLYPMB |
pojo | WFLYPOJO |
process-controller | WFLYPC |
protocol | WFLYPRT |
remoting | WFLYRMT |
request-controller | WFLYREQCON |
rts | WFLYRTS |
sar | WFLYSAR |
security-manager | WFLYSM |
security | WFLYSEC |
server | WFLYSRV |
system-jmx | WFLYSYSJMX |
threads | WFLYTHR |
transactions | WFLYTX |
undertow | WFLYUT |
webservices/server-integration | WFLYWS |
weld | WFLYWELD |
xts | WFLYXTS |