|
What appears below are my personal notes I wish were part of my long-term memory but don't always seem to fit. I strive for accuracy and clarity and appreciate feedback. If applying any of this information anywhere, confirm for youself the correctness of your work as what you see below might very well be, albeit unintentionally, incorrect or misleading. These notes are here as an easy reference for myself.
Information worthy of a more formal presentation will appear elsewhere than this "Scratch" area. - ksb
Table of Contents |
References |
From what I understand: Log4j was the de facto standard logging system for Java, then Sun added it into the JDK as java.util.logging and 'got it wrong'. Commons-Logging came into existance as a compromise as a general logging API under which your logging engine of choice could be used. The de facto standard now appears to be to use the commons-logging API with log4j underneath as the implementation.
What follows is my brief example-driven introduction to using the commons-logging API with (the default) log4j underneath. Read the two (short) user guides for Commons Logging and Log4j for a real introduction.
Compile and run the the following code:
import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; public class KSBLogTest { // Get a log object named after this class private static Log log = LogFactory.getLog(KSBLogTest.class); public static void main(String[] args) { System.out.println("Sysout: main: in"); log.info("log: hello"); log.info("log: goodbye"); System.out.println("Sysout: main: out"); } } |
and here is what you get:
$ javac -classpath /usr/local/share/java/classes/commons-logging.jar KSBLogTest.java $ java -cp /usr/local/share/java/classes/commons-logging.jar:. KSBLogTest Sysout: main: in log4j:WARN No appenders could be found for logger (KSBLogTest). log4j:WARN Please initialize the log4j system properly. Sysout: main: out |
Probably not what you expected but it points out that log4j is the default implementation and it needs something more to initialize it properly - namely a configuration file.
By default a log4j.properties file will be looked for to configure log4j. Drop this into the current dir (or anywhere in the CLASSPATH):
# Set the root logger to the DEBUG level and CA to be it's appender log4j.rootLogger=DEBUG, CA # Set CA to be a ConsoleAppender. log4j.appender.CA=org.apache.log4j.ConsoleAppender # Set CA to use the SimpleLayout log4j.appender.CA.layout=org.apache.log4j.SimpleLayout |
and now you get:
$ java -cp /usr/local/share/java/classes/commons-logging.jar:. KSBLogTest Sysout: main: in INFO - log: hello INFO - log: goodbye Sysout: main: out |
So if we want to format that output a little better use a different layout, like this:
# Set the root logger to the DEBUG level and CA to be it's appender log4j.rootLogger=DEBUG, CA # Set CA to be a ConsoleAppender. log4j.appender.CA=org.apache.log4j.ConsoleAppender # Set CA to use a PatternLayout log4j.appender.CA.layout=org.apache.log4j.PatternLayout log4j.appender.CA.layout.ConversionPattern=%-4r [%t] (%F:%L) %-5p %c %x - %m%n |
Now we get:
$ java -cp /usr/local/share/java/classes/commons-logging.jar:. KSBLogTest Sysout: main: in 1 [main] (KSBLogTest.java:13) INFO KSBLogTest - log: hello 9 [main] (KSBLogTest.java:16) INFO KSBLogTest - log: goodbye Sysout: main: out |
Log4j can also be configured using a log4j.xml XML file rather than the log4j.properties file. Here is the equivalent of the first .properties file (which can also be anywhere on the CLASSPATH):
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"> <appender name="CA" class="org.apache.log4j.ConsoleAppender"> <layout class="org.apache.log4j.SimpleLayout"/> </appender> <root> <priority value ="debug" /> <appender-ref ref="CA"/> </root> </log4j:configuration> |
Here is the logj4.xml file that uses the PatternLayout as the second log4j.properties file does.
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"> <appender name="CA" class="org.apache.log4j.ConsoleAppender"> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%-4r [%t] (%F:%L) %-5p %c %x - %m%n"/> </layout> </appender> <root> <priority value ="debug" /> <appender-ref ref="CA"/> </root> </log4j:configuration> |
When writing log4j config files, use the log4j javadoc as your guide. It appears that they follow the class and member structure in a pretty straightforward way.
A helpful trick is to turn on debugging for logj4 itself by setting log4j.debug property in the VM:
$ java -Dlog4j.debug -cp /usr/local/share/java/classes/commons-logging.jar:. KSBLogTest log4j: Trying to find [log4j.xml] using context classloader sun.misc.Launcher$AppClassLoader@53c015. log4j: Trying to find [log4j.xml] using sun.misc.Launcher$AppClassLoader@53c015 class loader. log4j: Trying to find [log4j.xml] using ClassLoader.getSystemResource(). log4j: Trying to find [log4j.properties] using context classloader sun.misc.Launcher$AppClassLoader@53c015. log4j: Using URL [file:/home/ksb/Scratch/log4j.properties] for automatic log4j configuration. log4j: Reading configuration from URL file:/home/ksb/Scratch/log4j.properties log4j: Parsing for [root] with value=[DEBUG, CA]. log4j: Level token is [DEBUG]. log4j: Category root set to DEBUG log4j: Parsing appender named "CA". log4j: Parsing layout options for "CA". log4j: Setting property [conversionPattern] to [%-4r [%t] (%F:%L) %-5p %c %x - %m%n]. log4j: End of parsing for "CA". log4j: Parsed "CA" options. log4j: Finished configuring. Sysout: main: in 1 [main] (KSBLogTest.java:13) INFO KSBLogTest - log: hello 24 [main] (KSBLogTest.java:16) INFO KSBLogTest - log: goodbye Sysout: main: out |
So the log4j.xml file takes precedence over the logj4.properties file, as that is searched for, and used, first.
Another possibility is to set the name (and location) of the config file with the log4j.configuration property. As in:
$ java -Dlog4j.configuration=file:///tmp/log4j.xml -cp /usr/local/share/java/classes/commons-logging.jar:. KSBLogTest Sysout: main: in 0 [main] (KSBLogTest.java:13) INFO KSBLogTest - log: hello 10 [main] (KSBLogTest.java:16) INFO KSBLogTest - log: goodbye Sysout: main: out |
Yes, that's a URL so it could be http:// something and therefore remote.
Here is a pair of config files using a FileAppender to log to a file.
# Set the root logger to the DEBUG level and FA as a FileAppender log4j.rootLogger=DEBUG, FA # Set FA to be a FileAppender. log4j.appender.FA=org.apache.log4j.FileAppender # Set the filename and layout for FA to use log4j.appender.FA.file=KSBTest.log log4j.appender.FA.layout=org.apache.log4j.SimpleLayout |
and the equivalent log4j.xml file:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"> <appender name="FA" class="org.apache.log4j.FileAppender"> <param name="file" value="KSBTest.log"/> <layout class="org.apache.log4j.SimpleLayout"/> </appender> <root> <priority value ="debug" /> <appender-ref ref="FA"/> </root> </log4j:configuration> |
I figured this out by looking at the javadoc for FileAppender and using the file property. Log4j will print out helpfull information if doesn't understand what you've got.