 | Configuring java.util.logging in Community Edition
In this section, we briefly describe the java.util.logging API and explain how it works in Community Edition. We do not elaborate on the various features of this API. However, we list the objects involved and show the different ways you can use this logging service in an applications.
Applications make logging calls on Logger objects. Logger objects are organized in a hierarchical namespace fashion, and child Loggers can inherit some logging properties from their parents in the hierarchy. The Logger objects allocate LogRecord objects when logging calls are made. They pass the LogRecord objects to Handler objects for publication to destinations. Both Loggers and Handlers may use logging levels, and optionally filters, to evaluate if they are interested in the LogRecord. If the LogRecord must be published, a Handler can optionally use a Formatter to localize and format the message before sending it to the destination. Figure 6 explains how all these objects relate:
Figure 6. java.util.logging object
relationships
The java.util.logging API provides the following handlers:
-
StreamHandler: A simple handler for writing formatted records to an OutputStream.
-
ConsoleHandler: A simple handler for writing formatted records to System.err
-
FileHandler: A handler that writes formatted log records either to a single file, or to a rotating set of log files.
-
SocketHandler: A handler that writes formatted log records to remote TCP ports.
-
MemoryHandler: A handler that buffers log records in memory.
In addition to the above handlers, the API also provides the following formatters:
-
SimpleFormatter : Writes brief human-readable summaries of log records.
-
XMLFormatter : Writes detailed XML-structured information
java.util.logging defines the following log levels:
-
SEVERE (highest)
-
WARNING
-
INFO
-
CONFIG
-
FINE
-
FINER
-
FINEST (lowest)
In this section, we show the following aspects of the java.util.logging, using the EMPDemo application to illustrate how java.util.logging works:
-
Using the default java.util.logging configuration
-
Customizing java.util.logging using a gbean
Using the default java.util.logging configuration
By default, java.util.logging uses the <JAVA_HOME>/jre/lib/logging.properties file to configure Loggers, Handlers and Formatters. However, you can programmatically add new Handlers and Formatters at runtime. The default configuration supplied is a very simple one that configures only a ConsoleHandler with the SimpleFormatter. The log level set for ConsoleHandler is INFO; that is, messages whose log level is INFO or above are logged by ConsoleHandler by default.
We can modify the logging.properties file to add new Handlers or Formatters. EMPDemo contains the com.ibm.sample.EMPDemo servlet that connects to the EMPLOYEE_DB database and retrieves the rows from the EMPLOYEE table. It also logs messages when it performs various database operations. Listing 3 shows the corresponding code, with the logging statements marked in bold:
Listing 3. Default java.util.logging
Logger logger = Logger.getLogger(EMPDemo.class.getName());
logger.setLevel(Level.FINEST);
Connection con = null;
Statement stmt = null;
PrintWriter out = response.getWriter();
logger.info("Created the PrintWriter on the Response object");
try {
Context initContext = new InitialContext();
Context envContext = Context)initContext.lookup("java:comp/env");
logger.info("Got Initial context: " +envContext);
DataSource ds = (DataSource)envContext.lookup("jdbc/DataSource");
logger.info("Got DataSource: " +ds.toString());
con = ds.getConnection();
logger.info("Got Connection: " +con.toString() +"\n");
stmt = con.createStatement();
logger.info("Got Statement : " +stmt);
ResultSet rs = stmt.executeQuery("SELECT * FROM EMPLOYEE");
logger.info("Table EMP after SELECT:");
out.println("Your EMP table contains the following entries:<BR>");
out.println("<table>");
out.println("<tr>");
out.println("<th>Empno</th>");
out.println("<th>Name</th>");
out.println("<th>Job</th>");
out.println("<th>Manager</th>");
out.println("<th>Salary</th>");
out.println("<th>Commission</th>");
out.println("<th>Deptno</th>");
out.println("</tr>");
while (rs.next()) {
String emp = rs.getString("EMPNO");
String name = rs.getString("ENAME");
String job = rs.getString("JOB");
String mgr = rs.getString("MGR");
String sal = rs.getString("SAL");
String comm = rs.getString("COMM");
String dept = rs.getString("DEPTNO");
out.println("<tr>");
out.println("<td>"+emp+"</td>");
out.println("<td>"+name+"</td>");
out.println("<td>"+job+"</td>");
out.println("<td>"+mgr+"</td>");
out.println("<td>"+sal+"</td>");
out.println("<td>"+comm+"</td>");
out.println("<td>"+dept+"</td>");
out.println("</tr>");
logger.info(emp + " " + name + " " + job);
logger.info(" " + mgr + " " + dept);
}
out.println("</table>");
rs.close();
stmt.close();
con.close();
logger.severe("my severe message");
logger.warning("my warning message");
logger.info("my info message");
logger.config("my config message");
logger.fine("my fine message");
logger.finer("my finer message");
logger.finest("my finest message");
}
catch(java.lang.Exception e) {
e.printStackTrace();
logger.severe(e.getClass().getName());
logger.severe(e.getMessage());
}
}
|
The servlet gets the Logger and overrides the default log level (which is INFO in the <JAVA_HOME>/jre/lib/logging.properties file) to FINEST. It starts logging the messages at the INFO level using the logger.info() method at several places during the execution. To illustrate logging at different levels, it also logs sample messages at all levels after displaying the EMPLOYEE table rows. Finally, in the catch block, it logs the exception at SEVERE level. Follow these steps to deploy and run the EMPDemo application:
-
Download the EMPDemo application. The WAR file is
EMPdemo-UtilLogging.war.
-
Deploy the war file using this deploy command:
<wasce_home>/bin>deploy --user system --password manager deploy EMPdemo-UtilLogging.war
-
Access the EMPDemo servlet in a browser at this URL:
http://localhost:8080/EMPdemo-UtilLogging/EMPDemo.
You can see on the server console all INFO, WARNING and SEVERE messages logged by the application. The console does not show the messages logged with the other log levels even though the log level is overridden in the servlet to be FINEST. This is because; by default, the ConsoleHandler logs the messages with an INFO or above log level only as configured in the <JAVA_HOME>/jre/lib/logging.properties file. Listing 4 shows the output:
Listing 4. Messages logged on the console
Jan 2, 2009 10:49:14 AM com.ibm.sample.EMPDemo doPost INFO:
Created the PrintWriter on the Response object
Jan 2, 2009 10:49:14 AM com.ibm.sample.EMPDemo doPost INFO:
Got Initial context:
org.apache.xbean.naming.context.ImmutableContext$NestedImmutableContext@16801680
Jan 2, 2009 10:49:14 AM com.ibm.sample.EMPDemo doPost INFO:
Got DataSource: org.tranql.connector.jdbc.DataSource@55425542
Jan 2, 2009 10:49:14 AM com.ibm.sample.EMPDemo doPost INFO:
Got Connection: org.tranql.connector.jdbc.ConnectionHandle@30363036
Jan 2, 2009 10:49:14 AM com.ibm.sample.EMPDemo doPost INFO:
Got Statement : org.tranql.connector.jdbc.StatementHandle@43aa43aa
Jan 2, 2009 10:49:14 AM com.ibm.sample.EMPDemo doPost INFO: Table EMP after SELECT:
Jan 2, 2009 10:49:14 AM com.ibm.sample.EMPDemo doPost INFO: 1 PHANI SSE
Jan 2, 2009 10:49:14 AM com.ibm.sample.EMPDemo doPost INFO: NIKHIL 100
Jan 2, 2009 10:49:14 AM com.ibm.sample.EMPDemo doPost INFO: 2 JOE SSE
Jan 2, 2009 10:49:14 AM com.ibm.sample.EMPDemo doPost INFO: NIKHIL 100
Jan 2, 2009 10:49:14 AM com.ibm.sample.EMPDemo doPost INFO: 3 JOHN SSE
Jan 2, 2009 10:49:14 AM com.ibm.sample.EMPDemo doPost INFO: BOB 200
Jan 2, 2009 10:49:14 AM com.ibm.sample.EMPDemo doPost SEVERE: my severe message
Jan 2, 2009 10:49:14 AM com.ibm.sample.EMPDemo doPost WARNING: my warning message
Jan 2, 2009 10:49:14 AM com.ibm.sample.EMPDemo doPost INFO: my info message
|
You can modify the logging.properties file to add a FileHandler to log the message to a file. You can also use XMLFormatter instead of SimpleFormatter. For example, set the ConsoleHandler’s log level to FINEST to observe that all the log messages logged at all levels in the servlet are logged on the console. The line to modify is as follows.
java.util.logging.ConsoleHandler.level = FINEST.
If you have a different configuration file from the default <JAVA_HOME>/jre/lib/logging.properties file, you can supply the file as a JVM argument during server start-up as in Listing 5 (which is for Windows.)
Listing 5. Starting a Windows server with a properties file parameter
C:\>set -Djava.util.logging.config.file=<new_configuration.properties>
C:\>startup.bat
|
Customizing java.util.logging using a gbean
Sometimes you may want to tweak the logging configuration programmatically using the java.util.logging API. That is, add a new handler dynamically and adjust logging levels etc. Since, java.util.logging is configured per JVM instance; programmatic configuration is best done in a separate module rather than in any applications. That way, you can easily make any changes required to the logging configuration in this separate module. The Community Edition provides the gbean mechanism for developing and deploying custom services. This section explains the gbean service.
Listing 6 show UtilLogPropGBean.java, which implements a
gbean service, with the relevant portion marked in bold:
Listing 6. UtilLogPropGBean.java
package com.ibm.sample;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.logging.LogManager;
import org.apache.geronimo.gbean.GBeanInfo;
import org.apache.geronimo.gbean.GBeanInfoBuilder;
import org.apache.geronimo.gbean.GBeanLifecycle;
public class UtilLogPropGBean implements GBeanLifecycle{
private static final GBeanInfo GBEAN_INFO;
private final String objectName;
private String utilPropFile;
static {
GBeanInfoBuilder infoFactory =
new GBeanInfoBuilder(UtilLogPropGBean.class.getName(),
UtilLogPropGBean.class);
infoFactory.addAttribute("objectName", String.class, false);
infoFactory.addAttribute("utilPropFile", String.class, true);
infoFactory.setConstructor(
new String[]{"objectName","utilPropFile"});
GBEAN_INFO = infoFactory.getBeanInfo();
}
public UtilLogPropGBean(String objectName, String utilPropFile) {
this.objectName = objectName;
this.utilPropFile = utilPropFile;
}
public UtilLogPropGBean() {
objectName = null;
utilPropFile = null;
}
public void doFail() {
System.out.println("UtilLogPropGBean has failed");
}
public void doStart(){
LogManager logManager;
try{
System.out.println("[UtilLogPropGBean] GBean " + objectName + " Started");
InputStream in = new FileInputStream(utilPropFile);
logManager = LogManager.getLogManager();
logManager.reset();
logManager.readConfiguration(in);
System.out.println("Properties file successfully read!!");
}catch(IOException exp){
exp.printStackTrace();
logManager = LogManager.getLogManager();
}catch(Exception exp){
exp.printStackTrace();
}
}
public void doStop(){
System.out.println("GBean " + objectName + " Stoped");
}
public static GBeanInfo getGBeanInfo() {
return GBEAN_INFO;
}
}
|
When you deploy the gbean, the GBean kernel in Community Edition calls the doStart() method on the gbean. This method opens the FileInputStream on utilPropFile, injected to the gbean specified in the gbean deployment plan as an attribute. Then the LogManager reads the configuration from the input stream and configures java.util.logging.
Listing 7 shows the deployment plan of the gbean.
Listing 7. The gbean deployment plan
<module xmlns="http://geronimo.apache.org/xml/ns/deployment-1.2">
<environment>
<moduleId>
<groupId>UtilLogPropGBean</groupId>
<artifactId>UtilLogPropGBean-app</artifactId>
<version>1.0</version>
<type>car</type>
</moduleId>
<dependencies>
<dependency>
<groupId>GBeans</groupId>
<artifactId>UtilLoggingCustom</artifactId>
<version>1.0</version>
<type>jar</type>
</dependency>
</dependencies>
</environment>
<gbean name="UtilLogPropGBean"
class="com.ibm.sample.UtilLogPropGBean" xsi:type="dep:gbeanType"
xmlns:dep="http://geronimo.apache.org/xml/ns/deployment-1.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<attribute name="utilPropFile">
C:/temp/applevellogging/UtilLogging/UtilLogging.properties
</attribute>
</gbean>
</module>
|
In Listing 6, the java.util.logging configuration properties file, C:/temp/applevellogging/UtilLogging/UtilLogging.properties, is injected as a string to the utilPropFile attribute of UtilLogPropGBean.
In this section, we will deploy our gbean in Community Edition. When this gbean is deployed, all the applications that use java.util.logging API will use this configuration. Follow these steps to deploy the gbean:
-
Download the zip file and unzip the gbean (
UtilLogPropGBean.jar), the deployment plan (UtilLogPropGBean.xml) and the sample java.util.logging configuration properties file (UtilLogging.properties.
-
This jar file contains
UtilLogPropGBean.java. The UtilLogging.properties file defines a ConsoleHandler and a FileHandler. The FileHandler logs the messages to the C:/temp/applevellogging/UtilLogging/java.log file. The log levels of FileHandler and ConsoleHandler are FINER and CONFIG respectively. The log level for com.ibm.sample.EMPDemo is set to SEVERE at the bottom of the file. Of course, this value is overridden in the EMPDemo servlet. You can modify these values including the location of the log file according to your needs.
-
Upload the
UtilLogPropGBean.jar to the Community Edition server repository with the moduleid configuration as GBeans/UtilLoggingCustom/1.0/jar. This link explains how to upload the Java libraries into the repository.
-
Open a command prompt and change the directory to
<wasce_home>/bin. Deploy the GBean using the deploy command.
<wasce_home>/bin>deploy –user system –password manager deploy UtilLogPropGBean.xml
-
The gbean reads the
UtilLogging.properties file and configures the java.util.logging system. Access the EMPDemo servlet by pointing your browser to this URL http://localhost:8080/EMPdemo-UtilLogging/EMPDemo (deployed in the previous section).
Listing 8 shows the messages from the server console:
Listing 8. Server console messages
Jan 2, 2009 11:11:46 AM com.ibm.sample.EMPDemo doPost INFO:
Created the PrintWriter on the Response object
Jan 2, 2009 11:11:46 AM com.ibm.sample.EMPDemo doPost INFO:
Got Initial context:
org.apache.xbean.naming.context.ImmutableContext$NestedImmutableContext@16801680
Jan 2, 2009 11:11:46 AM com.ibm.sample.EMPDemo doPost INFO:
Got DataSource: org.tranql.connector.jdbc.DataSource@a000a00
Jan 2, 2009 11:11:46 AM com.ibm.sample.EMPDemo doPost INFO:
Got Connection: org.tranql.connector.jdbc.ConnectionHandle@1b3a1b3a
Jan 2, 2009 11:11:46 AM com.ibm.sample.EMPDemo doPost INFO:
Got Statement : org.tranql.connector.jdbc.StatementHandle@3b6e3b6e
Jan 2, 2009 11:11:46 AM com.ibm.sample.EMPDemo doPost INFO: Table EMP after SELECT:
Jan 2, 2009 11:11:46 AM com.ibm.sample.EMPDemo doPost INFO: 1 PHANI SSE
Jan 2, 2009 11:11:46 AM com.ibm.sample.EMPDemo doPost INFO: NIKHIL 100
Jan 2, 2009 11:11:46 AM com.ibm.sample.EMPDemo doPost INFO: 2 JOE SSE
Jan 2, 2009 11:11:46 AM com.ibm.sample.EMPDemo doPost INFO: NIKHIL 100
Jan 2, 2009 11:11:46 AM com.ibm.sample.EMPDemo doPost INFO: 3 JOHN SSE
Jan 2, 2009 11:11:46 AM com.ibm.sample.EMPDemo doPost INFO: BOB 200
Jan 2, 2009 11:11:46 AM com.ibm.sample.EMPDemo doPost SEVERE: my severe message
Jan 2, 2009 11:11:46 AM com.ibm.sample.EMPDemo doPost WARNING: my warning message
Jan 2, 2009 11:11:46 AM com.ibm.sample.EMPDemo doPost INFO: my info message
Jan 2, 2009 11:11:46 AM com.ibm.sample.EMPDemo doPost CONFIG: my config message
|
The ConsoleHandler’s log level has been set to CONFIG in the UtilLogging.properties file. Hence, we see all the messages logged at log level CONFIG or above (CONFIG, INFO, WARNING and SEVERE).
In addition to the output in Listing 5, the log file, Community Edition also creates C:/temp/applevellogging/UtilLogging/java.log. Because we have configured XMLFormatter for FileHandler, this file has the messages logged in XML format. Also, the log level has been set to FINER for FileHandler. Hence, in the file we see all the messages logged at FINER or above, except for FINEST.
|  |