Single line Java Logging
Before Java Logging API became part of the JDK (1.4) the de facto standard was the Log4J logging library. It was customizable, easy to setup and configure.
Along came Java 1.4 and the new Java Logging API. Somewhat clumsy and much harder to configure or customize, it has not changed over the course of the subsequent releases.
One of the most annoying things about it was that out of the box it would write out the log message on two lines:
Jun 11, 2009 9:11:21 PM com.letor.example.logging.StandardTest INFO: Line 1 Jun 11, 2009 9:11:21 PM com.letor.example.logging.StandardTest INFO: Line 2 Jun 11, 2009 9:11:21 PM com.letor.example.logging.StandardTest INFO: Line 3
Now, I don't know about you, but I find this very hard on my eyes. It is much harder to get a feel for how many messages were printed, what is the difference between them and is significantly harder to spot what you are looking for.
To rectify this, we can use the following simple, single-line formatter.
You will need to create two files - a configuration file:
# log everything to the console
handlers = java.util.logging.ConsoleHandler
# set the default logging level for the root logger
.level = FINE
# set the default logging level for new ConsoleHandler instances
java.util.logging.ConsoleHandler.level = ALL
java.util.logging.ConsoleHandler.formatter = com.letor.util.SingleLineFormatter
# set the default logging level for the logger named com.mycompany
com.letor.level = INFO
And the Formatter class used for formatting the log record
package com.letor.util;
import java.text.SimpleDateFormat;
import java.util.logging.Formatter;
import java.util.logging.LogRecord;
public class SingleLineFormatter extends Formatter
{
private static SimpleDateFormat FRMT_DATE;
public SingleLineFormatter()
{
// check if the date format was specified
// by default this is used for quick and dirty runs, don't care about the year date
String dateFormat = System.getProperty("java.util.logging.dateFormat", "HH:mm:ss");
FRMT_DATE = new SimpleDateFormat(dateFormat);
}
public String format(LogRecord record)
{
// use the buffer for optimal string construction
StringBuffer sb = new StringBuffer();
// level
sb.append(record.getLevel().toString().toLowerCase());
sb.append(": ");
// format time
sb.append(FRMT_DATE.format(record.getMillis())).append(" ");
// thread
sb.append("[").append(Thread.currentThread().getName()).append("] ");
// package/class name, logging name
String name = record.getLoggerName();
if (name.startsWith("com.letor.")) // truncate the logging name, reduce the clutter
name = name.substring("com.letor.".length());
sb.append(name);
sb.append(" ");
sb.append(record.getMessage());
// if there was an exception thrown, log it as well
if (record.getThrown() != null)
{
sb.append("\n").append(printThrown(record.getThrown()));
}
sb.append("\n");
return sb.toString();
}
private String printThrown(Throwable thrown)
{
StringBuffer sb = new StringBuffer();
sb.append("").append(thrown.getClass().getName());
sb.append(" - ").append(thrown.getMessage());
sb.append("\n");
for (StackTraceElement trace : thrown.getStackTrace())
sb.append("\tat ").append(trace).append("\n");
Throwable cause = thrown.getCause();
if (cause != null)
sb.append("\n").append(printThrown(cause));
return sb.toString();
}
}
You will need to pass the configuration file location as a VM argument to your application.
java -Djava.util.logging.config.file=src/logging.properties your.package.YourApplication
Running this will result in the following output
info: 21:25:00 [main] example.logging.StandardTest Line 1 info: 21:25:00 [main] example.logging.StandardTest Line 2 info: 21:25:00 [main] example.logging.StandardTest Line 3
Now that's much nicer! Feel free to modify the Java file to your preferred format.
The SingleLineFormatter is also capable of logging thrown exceptions and nested exceptions. Here is an example output:
info: 11 Jun 21:29:03 [main] example.logging.Test Nice, clean single line output severe: 11 Jun 21:29:03 [main] example.logging.Test Divided by zero java.lang.ArithmeticException - / by zero at com.letor.example.logging.Test.(Test.java:21) at com.letor.example.logging.Test.main(Test.java:37) severe: 11 Jun 21:29:03 [main] example.logging.Test Nested operation threw an exception java.lang.RuntimeException - Parent exception at com.letor.example.logging.Test.(Test.java:26) at com.letor.example.logging.Test.main(Test.java:37) java.lang.ArithmeticException - / by zero at com.letor.example.logging.Test.(Test.java:21) at com.letor.example.logging.Test.main(Test.java:37)
Hopefully this will your Java Logging experience.
