The Raccoon Core Framework comes along with two Log Services:
You can jump directly to the sections in which you're interested by clicking on one of the links:
We understand that this document is rather, but that's because it's extensive ... using the logging component is as simple as this:
public void testGetLog() throws Exception { LogBase log = CoreHelper.getLog(this.getClass().getName()); if (log.isDebugEnabled()) { log.debug("Hello world with a debug String"); } else if (log.isErrorEnabled() { log.error("Hello world with an error String"); } else { System.out.println("ooops the logging component seems to be deactivated!"); }
The following paragraphe is extracted from the documentation Ceki Gülcü wrote
As Brian W. Kernigan and Rob Pike put it in their truly excellent book "The Practice of Programming"
As personal choice, we tend not to use debuggers beyond getting a stack trace or the value of a variable or two. One reason is that it is easy to get lost in details of complicated data structures and control flow; we find stepping through a program less productive than thinking harder and adding output statements and self-checking code at critical places. Clicking over statements takes longer than scanning the output of judiciously-placed displays. It takes less time to decide where to put print statements than to single-step to the critical section of code, even assuming we know where that is. More important, debugging statements stay with the program; debugging sessions are transient.
The aim of this chapter is to explain how to quickly setup the Log4j service and use it within the context of the Raccoon Core Framework or not.
In the first part the reader will learn how to use the Log4jProxy class, which is a wrapper around the Log4j logging utility, in a standalone mode. In the second part the reader will learn how to use the Log4jProxy through the Service Manager. Normaly, the Log4jProxy should be used in conjunction with the Service Manager but for clarities sake we thought it interesting to explain how the Log4jProxy class works. Our intention is to make sure that you the reader understands thouroughly how the Raccoon Core Framework works so as to use it in the best possible fashion.
Now it's time ... on with show ...
The Log4j component requires a property file in order for it to be configured correctly. The most complete sample that we have is the default property file that the Raccoon Core Framework uses, however in this tutorial we will use a very simple configuration file:
## # A simple configuration file that is to be put in the classpath. # In our tutorial this file is name log.properties and is located in the # raccoon.core.services.log package. # # The default logging level enabled is INFO, therefore all DEBUG messages won't be logged. However WARN and ERROR # will be logged. # # Order is DEBUG, INFO, WARN, ERROR ## log4j.appender.Raccoon = org.apache.log4j.RollingFileAppender log4j.appender.Raccoon.File = raccoon.log log4j.appender.Raccoon.Append = false log4j.appender.Raccoon.MaxFileSize = 5MB log4j.appender.Raccoon.MaxBackupIndex = 10 log4j.appender.Raccoon.layout = org.apache.log4j.PatternLayout log4j.appender.Raccoon.layout.ConversionPattern = %r [%t] %-5p %c{2} %x - %m %n log4j.rootCategory = debug, Raccoon
Put this file somewhere in your classpath, the easiest thing to do is to put it in the same package as the test class that we will develop in the following steps.
Let's create a TestClass that uses the Log4jProxy and tests it's behaviour ... The sample code for this
test case is located in the package raccoon.core.service.log
and is
called TestLog4jProxy
under the src/test directory of this project.
public class TestLog4jProxy extends TestCase { /** A simple message to log */ private static final String DEBUG_MESSAGE = "This is an debug message that you will see in the log file"; public TestLog4jProxy(String pTestCaseName) { ... } /** * Simple usage of the debug method. * * @throws Exception if something goes wrong. */ public void testLog4jProxyDebug() throws Exception { mLogProxy = new Log4jProxy(); mLogProxy.setPropertyFileName(LOG_CONFIGURATION); /** * This is an artifact when not using the ServiceManager. * It is an undocumented feature and shouldn't be normaly employed. */ int oldLevel = Log4jProxy.CALLING_CLASS_LEVEL; Log4jProxy.CALLING_CLASS_LEVEL = 1; /** Initialise the log proxy. */ mLogProxy.load(); /** End of artifact mode */ Log4jProxy.CALLING_CLASS_LEVEL = oldLevel; if (!mLogProxy.isDebugEnabled()) { System.out.println("Debugging level is disabled!"); mLogProxy.debug(NOT_LOGGED_MSG); } else { mLogProxy.debug(DEBUG_MESSAGE); Throwable th = new Throwable("Some error message"); mLogProxy.debug("Message with simple exception", th); String msg = "Hello {0}. How are you {1}?"; mLogProxy.debug(msg, new Object[] {"there", "today"}); mLogProxy.debug(msg, new Object[] {"exception", "today"}, th); } /** We've finished with this logging session (should be in the tear down normally though */ mLogProxy.unload(); } }
In my case the result of this test case is the following (i added the source code here and there in comments so that the reader may link the log with the code):
0 [TestRunner-Thread] DEBUG log.TestLog4jProxy - This is an debug message that you will see in the log file 30 [TestRunner-Thread] DEBUG log.TestLog4jProxy - Message with simple exception java.lang.Throwable: Some error message at raccoon.core.service.log.TestLog4jProxy.testLog4jProxyDebug(TestLog4jProxy.java:101) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:324) at junit.framework.TestCase.runTest(TestCase.java:166) at junit.framework.TestCase.runBare(TestCase.java:140) at junit.framework.TestResult$1.protect(TestResult.java:106) at junit.framework.TestResult.runProtected(TestResult.java:124) at junit.framework.TestResult.run(TestResult.java:109) at junit.framework.TestCase.run(TestCase.java:131) at junit.framework.TestSuite.runTest(TestSuite.java:173) at junit.framework.TestSuite.run(TestSuite.java:168) at junit.swingui.TestRunner$17.run(TestRunner.java:644) # mLogProxy.debug(msg, new Object[] {"there", "today"}); 30 [TestRunner-Thread] DEBUG log.TestLog4jProxy - Hello there. How are you today? # mLogProxy.debug(msg, new Object[] {"exception", "today"}, th); 30 [TestRunner-Thread] DEBUG log.TestLog4jProxy - Hello exception. How are you today? java.lang.Throwable: Some error message at raccoon.core.service.log.TestLog4jProxy.testLog4jProxyDebug(TestLog4jProxy.java:101) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:324) at junit.framework.TestCase.runTest(TestCase.java:166) at junit.framework.TestCase.runBare(TestCase.java:140) at junit.framework.TestResult$1.protect(TestResult.java:106) at junit.framework.TestResult.runProtected(TestResult.java:124) at junit.framework.TestResult.run(TestResult.java:109) at junit.framework.TestCase.run(TestCase.java:131) at junit.framework.TestSuite.runTest(TestSuite.java:173) at junit.framework.TestSuite.run(TestSuite.java:168) at junit.swingui.TestRunner$17.run(TestRunner.java:644)
A more interesting log statement (interesting because it shows how the RaccoonException dumps it's stack trace) can be obtained with the following source code:
[...] /** * A simple usage case of a RaccoonException with the logging component. * * @throws RaccoonException ... see AbsComponent.getLog() to understand why. */ public void tryLog() throws RaccoonException { getLog().debug("Hello world from Debug"); RaccoonException raccoonException = new RaccoonException(ComponentErrors.RESOURCE_INVALID, ComponentErrors.MSG_INVALID_RESOURCE); try { ResourceBundle.getBundle("someInvalidResourceBundle"); } catch (MissingResourceException e) { raccoonException.addContainedException(e); } String msg = null; try { msg.indexOf("bla"); } catch (NullPointerException npe) { raccoonException.addContainedException(npe); } getLog().error("Bad bad bad ...", raccoonException); } [...]
We'll see in the second step (using the ServiceManager) what the getLog() method does. For the time here is the log file that was generated by the previous code:
0 [TestRunner-Thread] DEBUG manager.ServiceManager - Hello world from Debug 20 [TestRunner-Thread] ERROR manager.ServiceManager - Bad bad bad ... Raccoon exception. Error code is 11. Error message is: "The resource appears to be invalid" Contained Exception { Message: Can't find bundle for base name someInvalidResourceBundle, locale fr_FR Exception is: java.util.MissingResourceException java.util.ResourceBundle.throwMissingResourceException(ResourceBundle.java:804) java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:773) java.util.ResourceBundle.getBundle(ResourceBundle.java:511) raccoon.core.SampleComponent.tryLog(SampleComponent.java:95) raccoon.core.manager.TestServiceManager.testLoadSampleComponent(TestServiceManager.java:181) } Contained Exception { Exception is: java.lang.NullPointerException raccoon.core.SampleComponent.tryLog(SampleComponent.java:103) raccoon.core.manager.TestServiceManager.testLoadSampleComponent(TestServiceManager.java:181) sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) } Stack trace is: raccoon.core.exception.RaccoonException: The resource appears to be invalid at raccoon.core.SampleComponent.tryLog(SampleComponent.java:91) at raccoon.core.manager.TestServiceManager.testLoadSampleComponent(TestServiceManager.java:181) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:324) at junit.framework.TestCase.runTest(TestCase.java:166) at junit.framework.TestCase.runBare(TestCase.java:140) at junit.framework.TestResult$1.protect(TestResult.java:106) at junit.framework.TestResult.runProtected(TestResult.java:124) at junit.framework.TestResult.run(TestResult.java:109) at junit.framework.TestCase.run(TestCase.java:131) at junit.framework.TestSuite.runTest(TestSuite.java:173) at junit.framework.TestSuite.run(TestSuite.java:168) at junit.swingui.TestRunner$17.run(TestRunner.java:644)
In fact, one should call this section "Using the Log4jProxy with the CoreHelper" ... none the less it's still the same thing.
The first thing to do is to create an entry in the configuration file used by the Service Manager if you're not using the default configuration file that comes with Raccoon. The following xml file contains a sample configuration for the Log4j implementation:
[ ...] <Component ComponentName="log" ComponentClass="raccoon.core.service.log.Log4jProxy"> <PropertyDefaultValues PropertyName="propertyFileName" PropertyType="string" PropertyValue="raccoon.core.service.log.log" /> </Component> [...]
However if you're using the Raccoon Core Framework as is then you don't have bother about all this, in fact you can directly go to this step.
Where the file log.properties
found under the package
raccoon.core.service.log
is currently:
# This is the default log file for Raccoon. log4j.appender.Raccoon = org.apache.log4j.RollingFileAppender log4j.appender.Raccoon.File = raccoon.log log4j.appender.Raccoon.Append = false log4j.appender.Raccoon.MaxFileSize = 5MB log4j.appender.Raccoon.MaxBackupIndex = 10 log4j.appender.Raccoon.layout = org.apache.log4j.PatternLayout log4j.appender.Raccoon.layout.ConversionPattern = %r [%t] %-5p %c{2} %x - %m %n log4j.rootCategory = debug, Raccoon # This is the core part of Raccoon log4j.appender.RaccoonCore = org.apache.log4j.RollingFileAppender log4j.appender.RaccoonCore.File = raccoon-core.log log4j.appender.RaccoonCore.Append = false log4j.appender.RaccoonCore.MaxFileSize = 5MB log4j.appender.RaccoonCore.MaxBackupIndex = 10 log4j.appender.RaccoonCore.layout = org.apache.log4j.PatternLayout log4j.appender.RaccoonCore.layout.ConversionPattern = %r [%t] %-5p %c{2} %x - %m %n log4j.category.raccoon.core = info, RaccoonCore log4j.additivity.raccoon.core = false
At this point everything should be fine to use the logging component. The following source code shows you how to do this:
public void testGetLog() throws Exception { LogBase log = CoreHelper.getLog(this.getClass().getName()); if (log.isDebugEnabled()) { log.debug("Hello world with a debug String"); } else if (log.isErrorEnabled() { log.error("Hello world with an error String"); } else { System.out.println("ooops the logging component seams to be deactivated!"); }
There we go ... easy isn't it?
...