A previous article of mine explained the basics of log4j
. log4j
is an open source logging tool developed under the Jakarta Apache project. The previous article demonstrated how to use log4j
in a strictly JSP/servlet environment, which forms half of the whole J2EE world. The other half, EJBs, requires a subtler way of handling your log4j
code and configuration. This article will show you why this is the case and how to go about it.
log4j
is a popular logging tool, as it provides flexible control over logging and debugging requirements of a Java project. It is hierarchical in nature and provides runtime control over all aspects of logging without having to change the source code.
log4j
controls logging with three main properties: loggers, appenders, and layouts. A logger logs to an appender in a particular layout (style). These can be specified using an external configuration file, which is the best way of doing so. These configuration properties are loaded during your application startup and can be changed at runtime.
The steps involved in using log4j
are:
1. Write a configuration file. In this file:
2. In your code, acquire a logger by class or name. Typically, this should be the logger associated with the current class.
3. Start logging using any of the methods of the logger you acquired in step 2 (log.debug()
, log.info()
, log.warn()
, log.error()
, log.fatal()
).
Related Reading Weblogic Server 6.1 Workbook for Enterprise Java Beans
Table of Contents (PDF)
|
The examples in this article are tested on BEA WebLogic 7.0 SP2 demo version. The reason for using WebLogic instead of an open source equivalent like JBoss is because WebLogic provides the hardest challenge in terms of configuring log4j
. It is also the most prevalent application server and the one for which I received the most requests for help after my previous article.
This setup is by no means the recommended setup for WebLogic. It is only intended as a testing environment towards configuring log4j
in a J2EE environment for this article.
WebLogic 7.0 SP 2 can be downloaded from BEA's trial page. Select and download the installer with which you are most comfortable. Note that you will need to register with BEA and that the download size may be huge (approximately 150MB). Alternatively, you could ask for a free demo CD to be sent to you.
Once you get hold of the installer, installing WebLogic is a simple process of answering wizard-style questions. Choose the typical install for this testing environment. When you reach the end of the install, you will be asked if you want to configure a domain. Select "yes" to run the domain configuration wizard. The first screen will ask you to select the domain type and name. Select WLSDomain
as the domain type and leave the name as mydomain
. In the next screen, leave the server type as single server (standalone server). Use the default location in the next screen for the domain location. On clicking "next," you will be taken to the standalone server configuration. Leave all entries as they are and click "next." You will now need to select a username and password for this domain. I used admin
as the username and password
as the password (Highly original!). Select "No" on the next screen for registering the service as a Windows service (if you are running this on Windows). Finally, select "Yes" to placing a shortcut on the Windows Start Menu. The final screen lets you review everything that you have just done. Clicking the "create" button will create this domain for you.
To run WebLogic for this domain, go to Start->All Programs->BEA WebLogic Platform 7.0->User Projects->mydomain->Start Server. This simply launches a Windows command file located in your BEA home directory under user_projects/mydomain called startWebLogic.cmd. You will be asked for the username and password that you provided while running the domain configuration wizard. You will know the server is running successfully when you see the message "Server started in running mode." To exit the server, simply close this DOS window.
Once your server is running successfully, fire up a browser window and navigate to http://localhost:7001/console. This will bring up the console window from where you can install and configure the applications to run on this server. You will be asked for your username and password, as before. Once you are in, you will see various administrative tasks that you can perform.
log4j
SetupAs mentioned before, log4j
can be downloaded from the log4j
web site. Please refer to the previous article on how to download and install the log4j
binaries. We will leave the configuration of log4j
until later in this chapter.
Although a full and thorough discussion on classloaders is outside of the scope of this article, I will try and explain what classloaders are and how they impact our configuration of log4j
in an application server.
Classloaders, as the name suggests, are responsible for loading classes within the JVM. Before your class can be executed or accessed, it must become available via a classloader. Given a class name, a classloader locates the class and loads it into the JVM. Classloaders are Java classes themselves. This brings the question: if classloaders are Java classes themselves, who or what loads them?
When you execute a Java program (i.e., by typing java
at a command prompt), it executes and launches a native Java launcher. By native, I mean native to your current platform and environment. This native Java launcher contains a classloader called the bootstrap classloader. This bootstrap classloader is native to your environment and is not written in Java. The main function of the bootstrap classloader is to load the core Java classes.
Figure 1; Classloader delegation hierarchy
The JVM implements two other classloaders by default. The bootstrap classloader loads the extension and application classloaders into memory. Both are written in Java. As mentioned before, the bootstrap classloader loads the core Java classes (for example, classes from the java.util
package). The extension classloader loads classes that extend the core Java classes (e.g., classes from the javax
packages, or the classes under the ext
directory of your runtime). The application classloader loads the classes that make up your application.
All three default classloaders follow the delegation model. Before a child classloader tries to locate a class, it delegates that task to a parent. When your application requests a particular class, the application classloader delegates this request to the extension classloader, which in turn delegates it to the bootstrap classloader. If the class that you requested is a Java core class, the bootstrap classloader will make the class available to you. However, if it cannot find the class, the request returns to the extension classloader, and from there to the application classloader itself. The idea is that each classloader first looks up to its parent for a particular class. Only if the parent does not have the class does the child classloader try to look it up itself.
In application servers, each separately-deployed web application and EJB gets its own classloader (normally; this is certainly the case in WebLogic). This classloader is derived from the application classloader and is responsible for that particular EJB or web application. (Note that if an application is deployed as an EAR file--a combination of EJB and webapps--it gets one classloader, no more). This new classloader loads all classes that the webapp or EJB require that are not already part the Java core classes or the extension packages. It is also responsible for loading and unloading of classes, a feature missing from the default classloaders. This feature helps in hot deploy of applications.
When WebLogic starts up, it uses the Java-supplied application classloader to load the classes that make up its runtime. It then launches individual classloaders, derived from the Java application classloader, which load the classes for individual applications. The individual classloaders are invisible to the classloaders of the other applications; hence, classes loaded for one particular application will not be seen by another application.
Figure 2: Individual application classloaders
What if you want to make a single class available to all applications? Load it in a top-level classloader. This could be in the classpath of WebLogic. When WebLogic starts, it will automatically load this class in memory using the Java-supplied application classloader. All sub-application classloaders get access to it. However, the negatives of this approach are clear too. First, you lose the capability of hot deploy for this particular class in all individual applications. Second, any change in this class means that the server needs to be restarted, as there is no mechanism for a Java application classloader to reload classes. You will need to weigh in the pros and cons before you take this approach.
log4j
is an external library to your J2EE application. Where do you store this library? As mentioned in the previous paragraph, one option is in the WebLogic startup classpath. However, this seems to be an easy way out, and is not recommended for the reasons stated earlier. Configuration of log4j
in a J2EE environment is different because EJBs don't see the classes loaded by a relevant webapp--EJBs are loaded by a different classloader! This is the general case, unless you package your application to use the same classloader for loading your EJB as well as the webapp. I will illustrate this concept with some examples.
Source Code • Log4JDemo-EJB-src.zip |
We will start with deploying the original webapp from the previous article along with an EJB and a JSP that exercises this EJB in our newly-configured WebLogic server. The EJB is a very simple EJB, containing an even simpler method that returns "Hello World" when invoked.
Deploy the updated .war file and then the EJB .jar file for this example using the WebLogic console. When you try to install the EJB .jar file, you will get an error stating that the org.apache.log4j.Logger
classes cannot be found.
The EJB .jar file has no knowledge about the log4j
classes in the WEB-INF directory of the corresponding webapp, as the EJB and webapp use different classloaders. Even if you combine these two into an .ear file and try to deploy it, you will still get the same error message. Why? Even though there is only one classloader for the .ear file and it theoretically should be loaded when you deploy, we have not told our EJB where to access the log4j.jar files.
Here is an updated .ear file with a working example. Let me list the changes to make this example work:
Classpath
, pointing to log4j.jar. These changes are enough to make this .ear file deployable in WebLogic. When you deploy this application using the console, you will not get any errors, because our EJB now has access to the log4j
classes. There is only one classloader for the Log4JDemoEAR2 application. It is responsible for loading the libraries and classes for this application as a whole. The Classpath
entry for the EJB is used to resolve dependencies and load log4j.jar. The webapp still has access to this library, even after moving it out of lib, as we use the same classloader!
Depending on your requirements, I suggest the following strategy. You will realize that it is not just relevant for log4j
, but to any external utility classes that your application might require.
Classpath
entry. Keep this utility file either at the top level or under a top-level directory in your .ear file. This way, all of your EJBs and .war files will have visibility to this utility class without you needing to duplicate it. J2EE packaging can be quite tiresome if you are not clear on how classloading works. A good understanding of this "under the hood" mechanism is critical to deploying your J2EE applications successfully. It helps to have a deployment engineer specifically geared towards this task.
log4j
works seamlessly in both aspects of a J2EE application. It just has to be configured correctly. I hope this article has shown you the correct way.
log4j
and classloader issues can be found in the log4j
troubleshooting docs. Vikram Goyal is the author of Pro Java ME MMAPI.