Using WebLogic Logging Services
When WebLogic Server message catalogs and the NonCatalogLogger
generate messages, they distribute their messages to a java.util.logging.Logger
object. The Logger
object allocates a WLLogRecord
object to describe the message and publishes the WLLogRecord
to any message handler that has subscribed to the Logger
.
WebLogic Server instantiates and subscribes a set of messages handlers that receive and print log messages. You can also create your own message handlers and subscribe them to the WebLogic Server Logger
objects (see Figure 5-1).
For example, if your application runs in a client JVM and you want the application to listen for the messages that your application generates, you can create a handler and subscribe it to the Logger
object in the client JVM. If your application receives a log message that signals the failure of a specific subsystem, it can perform actions such as:
The following sections describe creating and subscribing a message handler:
For more information about WebLogic Server loggers and handlers, refer to Overview of Distributing and Filtering Messages.
Figure 5-1 Subscribing a Handler
A handler that you create and subscribe to a Logger
object receives all messages that satisfy the level and filter criteria of the logger. Your handler can specify additional level and filter criteria so that it responds only to a specific set of messages that the logger publishes.
To create and subscribe a handler:
import java.util.logging.Handler;
import java.util.logging.LogRecord;
import java.util.logging.ErrorManager;
import weblogic.logging.WLLogRecord;
import weblogic.logging.WLLevel;
import weblogic.logging.WLErrorManager;
import weblogic.logging.LoggingHelper;
All handlers that work with resources should implement the flush
method so that it flushes any buffered output and the close
method so that it closes any open resources.
When the parent Logger
object shuts down, it calls the Handler.close
method on all of its handlers. The close method calls the flush
method and then executes its own logic.
Handler
object should receive. For more information, refer to Setting a Filter for Loggers and Handlers.Logger
object is running.getClientLogger
if the current context is a client JVM.getServerLogger
if the current context is a server JVM and you want to filter the Logger
object that a server uses to manage its local server log.getDomainLogger
if the current context is the Administration Server and you want to filter the Logger
object that manages the domain server log.
This example creates a handler that connects to a JDBC data source and issues SQL statements that insert messages into a database table. The example implements the following classes:
Handler
class. See Example: Implementing a Handler Class.Filter
class. See Setting a Filter for Loggers and Handlers.Logger
class. See Example: Subscribing to a Logger Class. The example Handler
class in Listing 5-1 writes messages to a database by doing the following:
javax.naming.InitialContext
object and invokes the Context.lookup
method to look up a data source named myPoolDataSource
.javax.sql.DataSource.getConnection
method to establish a connection with the data source.setErrorManager
method, which constructs a java.util.logging.ErrorManager
object for this handler. If this handler encounters any error, it invokes the error manager's error
method. The error
method in this example:
Note: Instead of defining the ErrorManager
class in a separate class file, the example includes the ErrorManager
as an anonymous inner class.
For more information about error managers, refer to the Sun API documentation for java.util.logging.ErrorManager
.
isLoggable
method to apply any filters that are set for the handler. The isLoggable
method is defined at the end of this handler class.For more information about WLLogRecord
methods, refer to the WLLogRecord
Javadoc.
Listing 5-1 Example: Implementing a Handler Class
import java.util.logging.Handler;
import java.util.logging.LogRecord;
import java.util.logging.Filter;
import java.util.logging.ErrorManager;
import weblogic.logging.WLLogRecord;
import weblogic.logging.WLLevel;
import weblogic.logging.WLErrorManager;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.PreparedStatement;
import weblogic.logging.LoggingHelper;
public class MyJDBCHandler extends Handler {
private Connection con = null;
public MyJDBCHandler() throws NamingException, SQLException {
InitialContext ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup("myPoolDataSource");
con = ds.getConnection();
setErrorManager(new ErrorManager() {
public void error(String msg, Exception ex, int code) {
System.err.println("Error reported by MyJDBCHandler "
+ msg + ex.getMessage());
//Removing any prior istantiation of this handler
LoggingHelper.getServerLogger().removeHandler(
MyJDBCHandler.this);
}
});
}
public void publish(LogRecord record) {
WLLogRecord rec = (WLLogRecord)record;
if (!isLoggable(rec)) return;
try {
PreparedStatement stmt = con.prepareStatement(
"INSERT INTO myserverLog VALUES (?, ?, ? ,?)");
stmt.setEscapeProcessing(true);
stmt.setString(1, rec.getId());
stmt.setString(2, rec.getLevel().getLocalizedName());
stmt.setString(3, rec.getLoggerName());
stmt.setString(4, rec.getMessage());
stmt.executeUpdate();
flush();
} catch(SQLException sqex) {
reportError("Error publihsing to SQL", sqex,
ErrorManager.WRITE_FAILURE);
}
}
public void flush() {
try {
con.commit();
} catch(SQLException sqex) {
reportError("Error flushing connection of MyJDBCHandler",
sqex, ErrorManager.FLUSH_FAILURE);
}
}
public boolean isLoggable(LogRecord record) {
Filter filter = getFilter();
if (filter != null) {
return filter.isLoggable(record);
} else {
return true;
}
}
public void close() {
try {
con.close();
} catch(SQLException sqex) {
reportError("Error closing connection of MyJDBCHandler",
sqex, ErrorManager.CLOSE_FAILURE);
}
}
}
The example class in Listing 5-2 does the following:
If you wanted your handler and filter to subscribe to the server's Logger
object each time the server starts, you could deploy this class as a WebLogic Server startup class. For information about startup classes, refer to "Startup and Shutdown Classes" in the Administration Console Online Help.
Listing 5-2 Example: Subscribing to a Logger Class
import java.util.logging.Logger;
import java.util.logging.Handler;
import java.util.logging.Filter;
import java.util.logging.LogRecord;
import weblogic.logging.LoggingHelper;
import weblogic.logging.FileStreamHandler;
import weblogic.logging.WLLogRecord;
import weblogic.logging.WLLevel;
import java.rmi.RemoteException;
import weblogic.jndi.Environment;
import javax.naming.Context;
public class LogConfigImpl {
public void configureLogger() throws RemoteException {
Logger logger = LoggingHelper.getServerLogger();
try {
Handler h = null;
h = new MyJDBCHandler();
logger.addHandler(h);
h.setFilter(new MyFilter());
} catch(Exception nmex) {
System.err.println("Error adding MyJDBCHandler to logger "
+ nmex.getMessage());
logger.removeHandler(h);
}
}
public static void main(String[] argv) throws Exception {
LogConfigImpl impl = new LogConfigImpl();
impl.configureLogger();
}
}
Prior to WebLogic Server 8.1, the only technique for receiving messages from the WebLogic logging services was to create a Java Management Extensions (JMX) listener and register it with a LogBroadcasterRuntimeMBean
. With the release of WebLogic Server 8.1, you can now use JDK 1.4 handlers to receive (subscribe to) log messages.
While both techniques—JDK 1.4 handlers and JMX listeners—provide similar results, the JDK 1.4 APIs include a Formatter
class that a Handler
object can use to format the messages that it receives. JMX does not offer similar APIs for formatting messages. For more information about formatters, refer to the Sun API documentation for Formatter
: http://java.sun.com/j2se/1.4/docs/api/java/util/logging/Formatter.html.
In addition, the JDK 1.4 Handler
APIs are easier to use and require fewer levels of indirection than JMX APIs. For example, the following lines of code retrieve a JDK 1.4 Logger
object and subscribe a handler to it:
Logger logger = LoggingHelper.getServerLogger();
Handler h = null;
h = new MyJDBCHandler();
logger.addHandler(h)
To achieve a similar result by registering a JMX listener, you must use lines of code similar to Listing 5-3. The code looks up the MBeanHome
interface, looks up the RemoteMBeanServer
interface, looks up the LogBroadcasterRuntimeMBean
, and then registers the listener.
For information on using JMX listeners, refer to "Using WebLogic Server MBean Notifications and Monitors" in Programming WebLogic Management Services with JMX.
Listing 5-3 Registering a JMX Listener
MBeanHome home = null;
RemoteMBeanServer rmbs = null;
//domain variables
String url = "t3://localhost:7001";
String serverName = "Server1";
String domainName= "mydomain"
String username = "weblogic";
String password = "weblogic";
//Using MBeanHome to get MBeanServer.
try {
Environment env = new Environment();
env.setProviderUrl(url);
env.setSecurityPrincipal(username);
env.setSecurityCredentials(password);
Context ctx = env.getInitialContext();
//Getting the Administration MBeanHome.
home = (MBeanHome) ctx.lookup(MBeanHome.ADMIN_JNDI_NAME);
System.out.println("Got the Admin MBeanHome: " + home );
rmbs = home.getMBeanServer();
} catch (Exception e) {
System.out.println("Caught exception: " + e);
}
try {
//Instantiating your listener class.
MyListener listener = new MyListener();
MyFilter filter = new MyFilter();
//Construct the WebLogicObjectName of the server's
//log broadcaster
WebLogicObjectName logBCOname = new
WebLogicObjectName("TheLogBroadcaster",
"LogBroadcasterRuntime", domainName, serverName);
//Passing the name of the MBean and your listener class to the
//addNotificationListener method of MBeanServer.
rmbs.addNotificationListener(logBCOname, listener, filter, null);
} catch(Exception e) {
System.out.println("Exception: " + e);
}
}