Configuring application logging

We will be illustrating how applications can log messages in Geronimo by using two logging frameworks, namely, log4j and JUL. We will also illustrate how you can use the slf4j wrapper to log messages with the above two underlying implementations. We will be using a sample application, namely, the HelloWorld web application to illustrate this.

Using log4j

We can use log4j for logging the application log to either a separate logfile or to the geronimo.log file. We will also illustrate how the logs can be written to a separate file in the <GERONIMO_HOME>/var/log directory, by using a GBean.

Logging to the geronimo.log file and the command console

Logging to the geronimo.log file and the command console is the simplest way to do application logging in Geronimo. For enabling this in your application, you only need to add logging statements to your application code. The HelloWorld sample application has a servlet called HelloWorldServlet, which has the following statements for enabling logging. The servlet is shown below.

package com.packtpub.hello;
import java.io.*;
import javax.servlet.ServletException;
import javax.servlet.http.*;
import org.apache.log4j.Logger;
public class HelloWorldServlet extends HttpServlet
{
Logger logger = Logger.getLogger(HelloWorldServlet.class.getName());
protected void service(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
res.setContentType("text/html");
PrintWriter out = res.getWriter();
out.print("<html>");
logger.info("Printing out <html>");
out.print("<head><title>Hello World Application</title></head>");
logger.info("Printing out <head><title>Hello World Application</title></head>");
out.print("<body>");
logger.info("Printing out <body>");
out.print("<b>Hello World</b><br>");
logger.info("Printing out <b>Hello World</b><br>");
out.print("</body>");
logger.info("Printing out </body>");
out.print("</html>");
logger.info("Printing out </html>");
logger.warn("Sample Warning message");
logger.error("Sample error message");
}
}

Deploy the sample HelloWorld-1.0.war file, and then access http://localhost:8080/HelloWorld/. This servlet will log the following messages in the command console, as shown in the image below:

The geronimo.log file will have the following entries:

2009-02-02 20:01:38,906 INFO [HelloWorldServlet] Printing out <html>

2009-02-02 20:01:38,906 INFO [HelloWorldServlet] Printing out <head><title>Hello World Application</title></head>

2009-02-02 20:01:38,906 INFO [HelloWorldServlet] Printing out <body>

2009-02-02 20:01:38,906 INFO [HelloWorldServlet] Printing out <b>Hello World </b><br>

2009-02-02 20:01:38,906 INFO [HelloWorldServlet] Printing out </body>

2009-02-02 20:01:38,906 INFO [HelloWorldServlet] Printing out </html>

2009-02-02 20:01:38,906 WARN [HelloWorldServlet] Sample Warning message

2009-02-02 20:01:38,906 ERROR [HelloWorldServlet] Sample error message

Notice that only the messages with a logging level of greater than or equal to WARN are being logged to the command console, while all the INFO, ERROR, and WARN messages are logged to the geronimo.log file. This is because in server-log4j.properties the CONSOLE appender's threshold is set to the value of the system property, org.apache.geronimo.log.ConsoleLogLevel, as shown below:

log4j.appender.CONSOLE.Threshold=${org.apache.geronimo.log.ConsoleLogLevel}

The value of this property is, by default, WARN. All of the INFO messages are logged to the logfile because the FILE appender has a lower threshold, of TRACE, as shown below:

log4j.appender.FILE.Threshold=TRACE

Using this method, you can log messages of different severity to the console and logfile to which the server messages are logged. This is done for operator convenience, that is, only high severity log messages, such as warnings and errors, are logged to the console, and they need the operator's attention. The other messages are logged only to a file.

Logging to a separate log file

In case you want your application to log to a separate logfile so that there is a separation of the log messages from the server and your application, you can follow the method described next. You can also follow this method in case your application bundles a version of log4j. In both of these cases, we use the hidden-classes feature of Geronimo to hide the log4j implementation that is bundled along with the server. This causes the application class loader to load the log4j JAR that is bundled along with your application or is given as a dependency to your application. The freshly-loaded log4j classes will again cause a new logger hierarchy, starting with a new root logger, for the application that is not aware of the log4j configurations at the server level. This application-level root logger and its descendants can be configured through a log4j.properties file in the classpath of the application. We will illustrate this by using the previous application, but this time adding the hidden-classes element to the deployment plan geronimo-web.xml.

Do not forget to hide the log4j.properties file in the parent class loaders that are also using the hidden-classes element. Otherwise, your log4j implementation may get configured by any other log4j.properties file that is present in your parent class loaders. This is because resources are loaded by class loaders through a parent-first policy. You can hide the resources in the parent class loaders by using the hidden-classes element.


Add the following lines to the Geronimo deployment plan of the HelloWorld sample:

<hidden-classes>
<filter>org.apache.log4j</filter>
<filter>log4j</filter>
</hidden-classes>

The first entry is to hide the log4j classes that are packaged with Apache Geronimo, while the second entry is to hide the log4j.properties files that may be present in parent class loaders of the application.

You will also need to add a dependency on the log4j JAR in the server repository, or add the log4j JAR to your application's lib directory.

Now you will need to configure this new instance of log4j. For this, you either need to write code to programmatically configure the loggers (for example, you want to configure your application's logging levels only through your application's user interface) in order to load custom log4j configuration files, or you need to have a log4j configuration file in your application's classpath, with a name of log4j. Log4j automatically recognizes and loads files called log4j.properties or log4j.xml, and uses the entries in these files to configure itself. In the sample, we have a log4j.properties present in the classes directory, and this will be used to configure the log4j instance in case the log4j implementations used by the parent class loaders are hidden.

The contents of this file are shown below:

log4j.rootLogger=INFO, CONSOLE, FILE
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.Threshold=TRACE
log4j.appender.CONSOLE.Target=System.out
log4j.appender.CONSOLE.layout=org.apache.log4j.SimpleLayout
log4j.appender.FILE=org.apache.log4j.RollingFileAppender
log4j.appender.FILE.Threshold=TRACE
log4j.appender.FILE.layout=org.apache.log4j.SimpleLayout
log4j.appender.FILE.append=true
log4j.appender.FILE.file=${org.apache.geronimo.server.dir} /var/log/helloworldapp.log
log4j.appender.FILE.bufferedIO=false
log4j.appender.FILE.maxBackupIndex=3
log4j.appender.FILE.maxFileSize=10MB

The output will be logged to the file <GERONIMO_HOME>/var/log/helloworldapp.log, as the property log4j.appender.FILE.file is configured and the value of the property org.apache.geronimo.server.dir maps to the <GERONIMO_HOME> directory. It will also be logged to the console. Because both the appenders have the same logging threshold, the same log messages will be output to both the log file and the console. Deploy the sample application HelloWorld-SLF4J-1.0.war, and then access http://localhost:8080/HelloWorldSLF4J/. The output in this case will look as shown in the image below:

This is different from the previous output, as this time we are using a different layout, namely, org.apache.log4j.SimpleLayout for the log messages.

Logging using the ApplicationLog4jConfigurationGBean

Geronimo provides a GBean for configuring logging. You can use this in case you want to use the log4j implementation that is loaded and used by Apache Geronimo, but want to log your output to a different file. We will discuss the steps to do this below:

  • You will need to add an instance of the ApplicationLog4jConfigurationGBean to the application's Apache Geronimo-specific deployment plan. This is shown below:

    <gbean name="HelloWorldLog4jConfiguration" class="org.apache.geronimo.system.logging.log4j.ApplicationLog4jConfigurationGBean">
    <attribute name="log4jFile">var/HelloWorld/HelloWorld-log4j.properties</attribute>
    <reference name="ServerInfo"><name>ServerInfo</name> </reference>
    </gbean>
    
  • The entry shown above will configure the ApplicationLog4jConfigurationGBean so that it makes log4j load the configuration file that is specified through the attribute log4jFile, and then use it to add additional configurations to the server implementation of log4j. You can also specify this GBean, as shown below, in case the log4j properties file is in your application's classpath.

    <gbean name="HelloWorldLog4jConfiguration" class="org.apache.geronimo.system.logging.log4j.ApplicationLog4jConfigurationGBean">
    <attribute name="log4jResource">log4j.properties </attribute>
    </gbean>
    
  • You should now configure application-specific logging in your log4j.properties file. This GBean prevents you from overriding global logging settings, but you can configure appenders for your application-specific loggers, as shown in the example below:

    #Add an appender to the HelloWorld App package logger:
    log4j.logger.com.packtpub.hello=INFO, helloworld
    #Do not add the logs to geronimo.log:
    log4j.additivity.com.packtpub.hello=false
    #Configure appenders for the helloworld app loggers:
    log4j.appender.helloworld=org.apache.log4j.DailyRollingFileAppender
    log4j.appender.helloworld.File=${org.apache.geronimo.server.dir}/var/log/HelloWorldApp.log
    log4j.appender.helloworld.layout=org.apache.log4j.SimpleLayout
    

Using the Java Logging API

The Java logging API, by default, uses the <JAVA_HOME>/jre/lib/logging.properties file for configuring Loggers, Handlers, and Formatters. You can change the default logging configuration for all programs using that JRE and the Java logging API, by editing this file. You can also specify two system properties to change the logging configuration for each run of the JRE. These properties are:

  • java.util.logging.config.file: The value of this property should be the path of a file in the properties file format that contains the initial logging configuration.

  • java.util.logging.config.class: The value of this property should be the fully-qualified name of the class whose constructor is responsible for reading in the initial configuration.

If you need to set these at startup for Apache Geronimo, then you can use the GERONIMO_OPTS or the JAVA_OPTS environment variable, as shown below:

set GERONIMO_OPTS=-Djava.util.logging.config.file=C:xyzlogging.properties

The default configuration configures a ConsoleHandler with a SimpleFormatter and the log level set to INFO. You can programmatically configure the Java Logging API to accept different log files. You can do this either in a custom GBean or in the code that is executed during the startup of your application, for example ServletContextListener.

Using the SLF4j logging adapter

Apache Geronimo uses slf4j over log4j for logging purposes. Geronimo ships with the following slf4j modules included in the repository:

  • slf4j-api

  • slf4j-log4j12

  • jcl-over-slf4j

  • jul-to-slf4j

Getting your application to use slf4j for logging is a very simple process. We will demonstrate this by converting the application that we have been using up to now, that is, the HelloWorld application, to use slf4j for logging.

The first step in this is to add dependencies to the slf4j-api and slf4j-log4j12 JARs. We will then need to import the slf4j classes that we are going to use for logging in our class. These import statements are shown below:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

In the next step, remove the previous import of the log4j logger and then replace the log4j API for getting the logger:

Logger logger = Logger.getLogger(HelloWorldServlet.class.getName());

with the slf4j API:

Logger logger = LoggerFactory.getLogger(HelloWorldServlet.class);

You will now be able to use slf4j for logging to the geronimo.log file.

If you want to log to a separate file, then you can either use the hidden-classes element or the ApplicationLog4jConfigurationGBean. The log4j configurations remain the same. The only additional thing that you should remember if you are using hidden-classes is that you should also hide the slf4j implementation that is shipped with Geronimo, that is, the org.slf4j package. The converted application is provided in the samples directory, and is called HelloWorld-SLF4J.

Thus, we can see that, at deployment time, we can deploy a static JAR—configured to work with either JUL or log4j —so that a developer can use JUL/slf4j, but the application can be deployed with log4j/slf4j without changing even a single line of code. This is the advantage that using a logging facade provides.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset