Imagine you're writing a small test case to check out some
new library or version or cool new technology.
You're eager to try out that stuff, learn how it works and how to use it.
But, unfortunately,
something goes wrong and you see the following:
Exactly,
you see nothing.
You didn't quite read the quick start tutorial carefully and you must have missed something at the configuration file or at the code. You're not sure - all you get is a mysterious exception or the code just doesn't do anything visible, as it does here. At this point,
you just want it to print out what's going on, anything - you would like to have some fine-grained logging output on your console.
You know it's a pain to set up all that logging facility stuff correctly and your loved pre-configured
log4j.xml with all the handy shortcuts is on the other machine. Okay, all you needed was just the whole debug output of that library to get it to know better and see what's going wrong.
The project already has commons-logging on it's classpath, but gladly no implementation, so it's using JDK Logging as a backend. Commons-logging should die anyway. Really. I mean it.. You can see that it's using JDK Logging since the console output is two-line formatted like the following snippet. The name of the logger is the adapter used to bridge between Commons-Logging and JDK Logging, and in this case it's iBatis 3 JakartaCommonsLoggingImpl.
16.01.2010 16:20:27 org.apache.ibatis.logging.commons.JakartaCommonsLoggingImpl debug
FEIN: PooledDataSource forcefully closed/removed all connections.
16.01.2010 16:20:27 org.apache.ibatis.logging.commons.JakartaCommonsLoggingImpl debug
FEIN: PooledDataSource forcefully closed/removed all connections.
Now, back to the example which is currently not printing out anything. To get decent logging output to your console with standard JDK logging, you either have to create a
logging.properties and fill it with some obscure properties like
.handlers and anyway you don't know how to configure that correctly.
Isn't there anywhere a good and quick to find example for that?
I started using this code, which seems to be the simplest possible way of getting something to the console quickly.
Logger rootLogger = LogManager.getLogManager().getLogger("");
Handler handler = new ConsoleHandler();
handler.setLevel(Level.ALL);
rootLogger.addHandler(handler);
rootLogger.setLevel(Level.ALL);
As you can see,
there's some output now.
But it's red (System.err stream) and there are too many newlines for my taste.
It uses the root logger, identified by the empty string (""), adds a Handler, which is responsible for printing the log messages to the console. Other Handlers write the log messages to the file system or send it over the wire. The Level is the log level, which determines which log messages are being sent to the Handler and which are ignored. For example, you can set it to INFO, so only Info, Warning, Error-level log messages are being printed. Log messages of level Debug and Trace are being ignored.
Since
I don't like the output being spread over two lines (it makes it reading much harder, especially if your output is tabular like like the iBatis output for
java.sql statements. So I ended up with something like this, to format the lines into a single line and get it to print out on System output console instead of System error:
Logger logger = LogManager.getLogManager().getLogger("");
class RedirectingConsoleHandler extends ConsoleHandler {
public RedirectingConsoleHandler(OutputStream target) {
super();
setOutputStream(target);
}
}
;
Handler handler = new RedirectingConsoleHandler(System.out);
handler.setLevel(Level.ALL);
// handler.setFormatter(new XMLFormatter());
Formatter newFormatter = new Formatter() {
@Override
public String format(LogRecord record) {
return String.format("%tT %-40.40s %-8.8s %s\n", new Date(),
record.getLoggerName(), record.getLevel().getLocalizedName(),
formatMessage(record));
}
};
handler.setFormatter(newFormatter);
logger.addHandler(handler);
logger.setLevel(Level.ALL);
This code will
redirect the output of the Logging facility to a configure stream, in this case the
System.out stream. That's the
RedirectingConsoleHandler class is for. The anonymous
Formatter class will format the log message, e.g. add a timestamp, the name of the logger, on which level it was logged and the actual log message of the log record and
only use one single line. The output looks much more how I like it:
(Yeah, i know the SQL statements are truncated at the example screenshot. But in modern times, with larger screens, it's no problem since the consoles are much broader than the space available on my blog)
Note: this is only used for testing, not for production, not for performance measurements, not for audit logging. This kind of logging is only meant for technical debug tracing. Logging is among the Top10 unknown performance killers in enterprise applications.