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 LogManager supports the following APIs:

  • JBoss Logging
  • commons-logging
  • SLF4J
  • Log4j
  • Log4j2
  • java.util.logging

JBoss LogManager also supports the following SPIs:

  • java.util.logging Handler
  • Log4j Appender
Note

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.

Important

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.

  1. The JBoss Logging JAR files must be in the build path for your application.

    • If you build using Red Hat CodeReady Studio, select Properties from the Project menu, then select Targeted Runtimes and ensure the runtime for JBoss EAP is checked.

      Note

      If you set the Target runtime to 7.4 or a later runtime version in Red Hat CodeReady Studio, your project is compatible with the Jakarta EE 8 specification.

    • If you use Maven to build your project, make sure you add the jboss-logging dependency to your project’s pom.xml file for access to the 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-eap-jakartaee8 BOM manages the version of jboss-logging. For more details, see Manage Project Dependencies. See the logging quickstart that ships with JBoss EAP 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.

  2. For each class to which you want to add logging:

    1. 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;
    2. Create an instance of org.jboss.logging.Logger and initialize it by calling the static method Logger.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);
  3. 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 the message 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.2.3. Adding the Apache Log4j2 API to your application

You can use an Apache Log4j2 API instead of an Apache Log4j API to send application logging messages to your JBoss LogManager implementation.

Important

The JBoss EAP 7.4 release supports the Log4J2 API, but not the Apache Log4j2 Core implementation, org.apache.logging.log4j:log4j-core, or its configuration files.

Procedure

  1. Add the org.apache.logging.log4j:log4j-api as a dependency to your project pom.xml file.

    Example of adding org.apache.logging.log4j:log4j-api to a pom.xml file.

    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-api</artifactId>
        <version>${version.org.apache.logging.log4j}</version>
        <scope>provided</scope>
    </dependency>

    Note

    The log4j-api Maven dependency refers to the Apache Log4j2 API. The log4j Maven dependency refers to the Apache Log4j API.

    When you log an application message, you send that message to your JBoss Log Manager implementation.

  2. Optional: To exclude the org.apache.logging.log4j.api module, you must either exclude the module from the jboss-deployment-structure.xml file or set the add-logging-api-dependencies attribute to false.

4.2.4. Creating a Log4j2 LogManager implementation

You can use your Log4j2 LogManager in your application by including the Log4j2 API in your project’s pom.xml file. Additionally, you must include the corresponding Log4j2 LogManager version in your project’s pom.xml file.

Procedure

  1. Disable the Log4j logging dependencies by excluding the org.apache.logging.log4j.api module dependency in the jboss-deployment-structure.xml file.
  2. Add the log4j-api dependency and the log4j2 dependency to your project pom.xml file.

    Example of adding a log4j-api dependency and the log4j2 dependency to a pom.xml file.

    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-api</artifactId>
        <version>${version.org.apache.logging.log4j}</version>
    </dependency>
    
    <dependency>
        <groupId>org.apache.logging.log4j2</groupId>
        <artifactId>log4j2-core</artifactId>
        <version>${version.org.apache.logging.log4j}</version>
    </dependency>

    Note

    The log4j-api Maven dependency refers to the Apache Log4j2 API. The log4j Maven dependency refers to the Apache Log4j API.

    When you log an application message, you send that message to your Log4j2 LogManager implementation.

  3. Optional: To exclude the org.apache.logging.log4j.api module, you must exclude the module from the jboss-deployment-structure.xml file or set the add-logging-api-dependencies attribute to false. You must then add the log4j2-api and log4j2-core to your project pom.xml file.

    Note

    If you make changes to the jboss-deployment-structure.xml file, you apply the changes to your deployment. If you make changes to the add-logging-api-dependencies attribute, you apply the changes to all deployed applications.

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.

Note

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 for 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.
Note

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 is true.

Handler options

  • handler.<name>=<className> - Specify the class name of the handler to instantiate. This option is mandatory.

    Note

    Table 4.1. Possible Class Names:

    NameAssociated Class

    Console

    org.jboss.logmanager.handlers.ConsoleHandler

    File

    org.jboss.logmanager.handlers.FileHandler

    Periodic

    org.jboss.logmanager.handlers.PeriodicRotatingFileHandler

    Size

    org.jboss.logmanager.handlers.SizeRotatingFileHandler

    Periodic Size

    org.jboss.logmanager.handlers.PeriodicSizeRotatingFileHandler

    Syslog

    org.jboss.logmanager.handlers.SyslogHandler

    Async

    org.jboss.logmanager.handlers.AsyncHandler

    The Custom handler can have any associated class or module. It is available in the logging subsystem for users to define their own log handlers.

    For further information, see Log Handlers in the JBoss EAP Configuration Guide.

  • 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.

    In case of all file handlers in JBoss Log Manager, append needs to be set before the fileName. The order in which the properties appear in handler.<name>.properties, is the order in which the properties will be set.

  • 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.
  • handler.<name>.module=<name> - Specify the name of the module the handler resides in.

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.

For more information, see Configure a Logging Profile in the JBoss EAP Configuration Guide.

Each logging profile can have:

  • A unique name. This value is 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.

Note

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
Note

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.

Note

For a complete list of the new log message project code prefixes, see the Project Codes used in JBoss EAP 7.4.

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.

Note

This section does not cover all optional features or the localization of the log messages.

  1. 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.

  2. Configure the project’s pom.xml file to use JBoss Logging Tools.

    For details, see JBoss Logging Tools Maven Configuration.

  3. 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() );
      }

  4. 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();
  5. 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 of BasicLogger can also be used. It is not necessary to create other loggers to log non-internationalized messages.

    AccountsLogger.LOGGER.error("Invalid query syntax.");
  6. The project now supports one or more internationalized loggers that can be localized.
Note

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.

Note

This section does not cover all optional features or the process of localizing those messages.

  1. 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.
  2. Configure the project’s pom.xml file to use JBoss Logging Tools. For details, see JBoss Logging Tools Maven Configuration.
  3. 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);
      }

      Note

      Calling Messages.getBundle(GreetingMessagesBundle.class) is equivalent to calling Messages.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 the setDefault method.

      See Set the Default Locale of the Server in the JBoss EAP Configuration Guide for more information.

  4. 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();
  5. 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.

Note

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 CodeReady Studio or Maven.

Note

This section does not cover all optional features or the process of localization of those exceptions.

  1. Configure the project’s pom.xml file to use JBoss Logging Tools. For details, see JBoss Logging Tools Maven Configuration.
  2. Create an interface for the exceptions. JBoss Logging Tools defines internationalized exceptions in interfaces. Name each interface descriptively for the exceptions that it defines. 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);
      }

  3. 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 of Exception.
    • 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);
  4. 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.

Note

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

  1. 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>

  2. 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.

Note

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

  1. Run the following command to create the template translation properties files:

    $ mvn compile
  2. 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.
  3. Rename the copied template file to indicate the language it will contain. For example: GreeterLogger.i18n_fr_FR.properties.
  4. 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é.
  5. 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

  1. You must already have a project with internationalized log messages. For details, see Create Internationalized Log Messages.
  2. 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

  1. 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 {
    
    }
  2. 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();
  3. 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.

  1. Add the level attribute to the @LogMessage annotation of the log message method definition.
  2. Assign the log level for this message using the level attribute. The valid values for level are the six enumerated constants defined in org.jboss.logging.Logger.Level: DEBUG, ERROR, FATAL, INFO, TRACE, and WARN.

    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 example 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

  1. 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.
  2. 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.

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 might require different ordering of parameters.

Important

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

  1. 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);
  2. 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);
  3. 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 example if the code throws 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

  1. You must already have a project with internationalized exceptions. For details, see Create Internationalized Exceptions.
  2. 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

  1. 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);
    }
  2. 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();
Important

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

  1. 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.
  2. 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.

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 might require different ordering of parameters.

Important

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.

  1. 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);
  2. 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);
  3. Invoke the interface method to obtain an exception object. The most common use case is to throw a new exception from a catch block, specifying 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);
}

The following example demonstrates 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 the exception message generated from the previous example:

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. JBoss Logging Tools 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.

  1. 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-jakartaee8 BOM in the <dependencyManagement> section of the project’s pom.xml file.

    <dependencyManagement>
      <dependencies>
        <!-- JBoss distributes a complete set of Jakarta 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 Jakarta EE APIs). You can actually
          use this stack with any version of JBoss EAP that implements Jakarta EE. -->
        <dependency>
          <groupId>org.jboss.bom</groupId>
           <artifactId>jboss-eap-jakartaee8</artifactId>
           <version>7.4.0.GA</version>
           <type>pom</type>
           <scope>import</scope>
        </dependency>
      <dependencies>
    <dependencyManagement>
  2. Add the Maven dependencies to the project’s pom.xml file:

    1. Add the jboss-logging dependency for access to JBoss Logging framework.
    2. 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>
  3. The maven-compiler-plugin must be at least version 3.1 and configured for target and generated sources of 1.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>
Note

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, and VARIANT identify the regional settings that the translation applies to.
  • locale and COUNTRY 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.

Example: Translation Properties File

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.

Table 4.2. JBoss Logging Tools Annotations

AnnotationTargetDescriptionAttributes

@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 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.

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.

-

4.5.7.4. Project Codes Used in JBoss EAP

The following table lists all the project codes used in JBoss EAP 7.4, along with the Maven modules they belong to.

Table 4.3. Project Codes Used in JBoss EAP

Maven ModuleProject 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/jacorb

WFLYORB

legacy/messaging

WFLYMSG

legacy/web

WFLYWEB

logging

WFLYLOG

mail

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