users@glassfish.java.net

Re: Logging to multiple files using JDK logging?

From: <glassfish_at_javadesktop.org>
Date: Wed, 05 Sep 2007 18:25:58 PDT

> I know enough that we can code a customer log handler
> to log to something other than server.log. But in GF
> Admin, there's only one field for a custom Log
> Handler, which kinda implies that you can customize
> it to output to another file and that's about it.

No, the LogHandler that you can put in essentially replaces (or supplements as the case may be) the ROOT Handler, which all of the children Loggers would route through.

The way the system works is that you have named Loggers. Those Loggers placed in an implicit hierarchy in a Java package naming style (a.b is a parent of a.b.c.d, for example).

Each Logger in the system can have 0, 1 or more Handlers through which their LogRecords are passed through. After routing through their local Handlers, they continue up the parent chain, and the LogRecord is routed through any Handlers tied to the parents.

The last part is optional (it can be disabled on a Logger by Logger basis), but is the default behavior.

So, GF gives you the opportunity replace the root handler.

Now, as mentioned, Handlers are tied to Loggers, and have historically been the mechanism for routing messages to different destinations.

But there's no reason why a Handler need to so limited.

The key to the entire mechanism is the information passed in my the core LogRecord. It has a bunch of different fields. Notably, one of the fields is loggerName.

With loggerName available, your custom Handler has a lot of capability to route things where you want. For example, you could name your loggers in an app specific way:

Logger log = Logger.getLogger(APPNAME + "." + this.getClass().getName());

You can configure you custom Handler however you want, after all you're writing it.

As long as you get every Log message routed through your handler, you can route it as you like.

The only thing to note is that the JDK Loggers are all in a single, global namespace in the current implementation. You don't get a seperate logger for each WAR or EAR, for example. You get one for the entire server. So, if you want to log common code in an application specific way, you'll need to somehow discern and attach to the log record what that application is so your handler can route it properly.

This kind of thing is probably best done through a wrapper class around the JDK Logging, or you can implement a LogManager that gives custom Logger subclasses, or you can use the simple mechanism I suggested earlier using the Logger name.

Finally, you may not need to implement a custom handler at all. Rather you can simply implement a JDK logging configuration class that creates and binds the appropriate handlers to the appropriate loggers at boot time.

So, going with the prefixing class names with your application meme i used earlier, you can have a simple start up class:
[code]
public class ConfigLoggers() {
    public ConfigLoggers() {
        Logger l = Logger.getLogger("AppA");
        l.addHandler(new FileHandler("AppA.log"));
        l = Logger.getLogger("AppB");
        l.addHandler(new FileHandler("AppB.log"));
    }
}
[/code]

Then you can stick:
config=com.example.ConfigLoggers

in the logging.properties file (at the JVM, or specified on startup command line as a property)

After that, all of the AppA prefixed loggers will go to the AppA log file, and AppB to the AppB log file.

The primary weakness of JDK Logging over Log4J is that the JDKs configuration file isn't as robust, but it does provide a mechanism to punt down in to classes to do arbitrary work rather than having a more rich configuration file format.

Anyway, the point is that you have a lot of flexibility in what you can do. Your custom Handler can do a bunch of stuff, or you can just write a simple configuration class to set things up how you like without going the Handler route.
[Message sent by forum member 'whartung' (whartung)]

http://forums.java.net/jive/thread.jspa?messageID=234132