How to use Commons Logging
I’ve spent the whole of today trying to find information on how to properly configure commons logging in my java classes, specifically with Jdk14Logger. It’s been a labourous task as a) there’s not much out there and b) Apache’s documentation isn’t brilliant. I finally found one page on Tigris.org explaining commons logging (from the view point of a change in their software), which helped me greatly.
Due to the lack of decent documentation out there, I’m writing this article to try and help others.
Logging messages in your code
In order to log messages in your java code, you will need to import two classes into your source code. These classes are from the Apache Commons Logging library which can be downloaded from here.
import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory;
Now, to create your log, create an attribute in your class in one of two ways:
private Log m_log = LogFactory.getLog(MyClass.class);
private Log m_log = LogFactory.getLog("MyClassLogger");
The first option is just creating a generic logger for your class, which will be controlled by the default logging options.
The second option is creating a specific logger which you have named ‘MyClassLogger’, that can be controlled individually to the defaults. You may want to do this if you use other third party source code that uses logging but you do not want to see the debugs or other information from that source code.
Using the logger is pretty straight forward. You can send log messages by calling a method corresponding to priority:
m_log.fatal(Object message); m_log.fatal(Object message, Throwable t); m_log.error(Object message); m_log.error(Object message, Throwable t); m_log.warn(Object message); m_log.warn(Object message, Throwable t); m_log.info(Object message); m_log.info(Object message, Throwable t); m_log.debug(Object message); m_log.debug(Object message, Throwable t); m_log.trace(Object message); m_log.trace(Object message, Throwable t);
These methods are listed in order of priority from highest to lowest. Commons logging, by default, is set to display all messages from INFO and higher. As you can see, each method is overloaded with a method where you can send a Throwable type, such as an Exception – very handy!
That’s all you have to do to log the messages, now comes the tricky part, getting to see your messages.
Configuring your logger.
There are a number of ways you can set the properties of your logger, either in the system, in a file, in your java source code or at run time. I prefer in a file so that you have a record of your settings and they can be changed easily without chaning your source code every time you change a setting.
In my example, I’ll have a file which sits in the same location as my jar file called commons-logging.properties.
The first setting tells the system what logger to use. To specify a specific logger be used, set:
org.apache.commons.logging.Log
org.apache.commons.logging.impl.Log4JLogger org.apache.commons.logging.impl.Jdk14Logger org.apache.commons.logging.impl.SimpleLog
Where Log4J is the Log4J Logging API, Jdk14Logger uses the Java 1.4+ java.util.logging classes and SimpleLog sends all messages to System.err
So, to use Jdk14Logger, it would look like this:
org.apache.commons.logging.Log=org.apache.commons.logging.impl.Jdk14Logger
If this is not set, then by default, the commons-logging framework will attempt to use loggers in this order:
1. Log4J
2. Jdk 1.4 logger
3. Simple log
So if the org.apache.commons.logging.Log property is not set and Log4J is found in the classpath, it will be used. Otherwise, if the JVM is version 1.4 or later, the java.util.logging classes will be used. Failing that, the built-in SimpleLog will be used.
To set up Log4JLogger:
To use Log4J, you need to configure a separate configuration file for it’s logging options. You will need to make sure that the Log4J binary (jar file) is in the classpath for the application.
To use Log4J, you need to tell java you want to use it in your properties file:
org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JLogger
In your commons-logging.properties set the following property:
log4j.configuration=log4j.properties
This is for the name of a property file containing the configuration settings for Log4J and it must be in your source code (usually under WEB-INF/classes or lib), see the log4j home pages for documentation on the specific configuration settings.
To set up Jdk14Logger:
This is the information I struggled to find.
To use the Jdk14Logger, set the Log property to:
org.apache.commons.logging.Log=org.apache.commons.logging.impl.Jdk14Logger
To configure the JDK14 logger, you will need to specify a property named “handler” to a white-space separated (or comma separated) list of java.util.logging Handler classes:
handler=java.util.logging.ConsoleHandler java.util.logging.FileHandler
The log level can be set per logger or for all loggers at once. To set them all in one go, use:
To set the log level of a specific logger, like one we created called ‘MyClassLogger’, use:
Where you use the name of the logger in the property.
Here’s an example commons-logging.properties file:
# commons-logging.properties # jdk handlers handlers=java.util.logging.FileHandler, java.util.logging.ConsoleHandler # default log level .level=INFO # Specific logger level MyClassLogger.level=FINE # FileHandler options - can also be set to the ConsoleHandler # FileHandler level can be set to override the global level: #java.util.logging.FileHandler.level=WARN # log file name for the File Handler java.util.logging.FileHandler.pattern=javalog%u.log # Specify the style of output (simple or xml) java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter # Optional - Limit the size of the file (in bytes) java.util.logging.FileHandler.limit=50000 # Optional - The number of files to cycle through, by # appending an integer to the base file name: java.util.logging.FileHandler.count=1
In the above properties file, we’ve set the global log level to INFO, and the specific class logger to FINE (which is debug). This means that you can print out debug log messages from your class but any third party code you might use (like apache commons XML etc) will be filtered out to INFO (global debug level might print out a lot more information than you really need!).
The commons logging log levels correspond to the java.util.logging.Level levels like this:
fatal = Level.SEVERE
error = Level.SEVERE
warn = Level.WARNING
info = Level.INFO
debug = Level.FINE
trace = Level.FINEST
So, if you want to set your class to log all debugs, you use LEVEL.FINE. These are also in order of priority, so, like in our example, if you set your class logger to FINE, then trace log messages will not be recorded.
One other very important point to remember is that the ConsoleHandler defaults to a level of INFO, so in order to display debugs to the console (even if your logger is set to debug), you must set the level for the ConsoleHandler to debug. For example:
java.util.logging.ConsoleHandler.level=FINE
If you want even more information on the FileHandler, check out it’s API documentation here. There is also other Handlers available, which you will find in that documentation.
To set up SimpleLog:
Finally, if there are no other options for commons logging to use, it defaults to the SimpleLog implementation. This is an extremely simple logging system.
To use it, use the property:
org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog
The simple implementation of commons logging sends all enabled log messages, for all defined loggers to System.err. You can configure it’s behaviour with these properties:
# Default logging level for all instances of SimpleLog. # Must be either trace, debug, info, warn, error or fatal. Defaults to info. org.apache.commons.logging.simplelog.defaultlog=warn # Logging detail level for a SimpleLog instance named MyClassLogger. # Must be either trace, debug, info, warn, error or fatal. Defaults to the # above default if not set. org.apache.commons.logging.simplelog.log.MyClassLogger=debug # Show the log name in every message. Defaults to false. org.apache.commons.logging.simplelog.showlogname=true # Show the last component of the name to be output with every message. Defaults to true. org.apache.commons.logging.simplelog.showShortLogname=true # Show the date and time in every message. Defaults to false org.apache.commons.logging.simplelog.showdatetime=true
In addition to looking for system properties, the current implementation checks for a class loader resource named ‘simplelog.properties’.
Running your program
In order to make sure your program uses the defined logger you’ve set up, run your java program like this:
java -Djava.util.logging.config.file=/absolute/path/to/your/config/file/commons-logging.properties MyClass
java -Djava.util.logging.config.file=/absolute/path/to/your/config/file/commons-logging.properties -jar /absolute/path/to/your/jar/file/MyClass.jar
So that java will load your config file and the logger you wish to use. If for some reason it does not want to pay attention to the Log property in your config file, add this line to your command:
-Dorg.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog
And replace SimpleLog with whichever log implementation you wish to use.
Thanks to the Tigris guys for writing their doco and helping me. 🙂
Логирование с Apache Commons Logging
В этой статье мы будем разбирать даже не фреймворк логирования, а API логирования, которое перенаправляет сообщения лога в другие фреймворки. Как и JUL, и log4j 1.2, и System.err его не стоит использовать в реальных проектах, так как у Apache Commons Logging (ранее Jakarta Commons Logging) слишком много проблем, о которых будет рассказано в конце статьи.
Зачем был нужен Apache Commons Logging? Почему нельзя просто использовать log4j 1,2, JUL, Avalon LogKit или любой другой? На самом деле проблема была очень масштабна. На момент создания Apache Commons Logging существовало огромнейшее количество библиотек логирования для Java, но при этом не было единого стандарта, они все были несовместимы друг с другом. Но ведь в лог писать нужно не только конечным приложениям, но и библиотекам. В какой логер писать библиотеке, если нет единого? И как быть с тем, что каждая библиотека использует свою систему логирования, которая может отличаться от используемой в вашем проекте? Apache Commons Logging должен был решить эту проблему.
Сам по себе Apache Commons Logging не предоставляет никакой реализации логирования. Он лишь определяет интерфейсы, то есть API. Внутри себя он определяет, какую реализацию библиотеки логирования использовать и направляет сообщения в неё.
Определение библиотеки логирования, которую будет использовать Apache Commons Logging происходит следующим образом:
- Смотрится org.apache.commons.logging.Log в файле конфигурации “commons-logging.properties”.
- Смотрится org.apache.commons.logging.Log в системных параметрах JVM.
- Если библиотека Log4j есть в classpath, то используется она.
- Если версия Java > 1.4, то используется java . util . logging .
- Если ничего из вышестоящего не помогло, то используется SimpleLogger, который просто пишет все сообщения в System.err.
Сам по себе Apache Commons Logging не содержит какой-бы то ни было конфигурации или реализации логирования, он просто перенаправляет логи в соответствующие библиотеки, а значит, нам нужно настраивать нужную библиотеку вручную в соответствии с её документацией.
С теми знаниями, что у нас есть, давайте создадим пример приложения с логированием. Создайте новый Maven проект и добавьте в него зависимости: