When I started using Spring, I need to include some logging and basic configuration. This page gives the details for the entire setup I’m using.
Log 4j
- Download log4j from here (in my case, I downloaded the Spring jar with dependencies from here, which includes Log4j).
- Extract the jar somewhere
- Add the jar to your Eclipse project
- Create a simple configurator, see LogginConfiguration.java, and a simple configuration file, see log4j.properties.
LoggingConfiguration.java
Interesting Lines
Line | Description |
11 - 13 | I’m using Checkstyle and PMD. One of them has a rule that suggests classes with all static methods should have a private constructor to disallow instantiation. |
15 - 24 | When loading this class, perform basic Log4j configuration, line 17. In addition, Spring, by default, produces quite a bit of output. The output is useful but I generally don’t want it unless I’m debugging a problem. So I load a simple properties file that sets the default logging for Spring to WARN. If I need to switch to DEBUG, I simply edit log4j.properties. |
17 | Generate a URL for the resource named LOG4J_PROPS. I use the same classloader used for this class, and ask it to find the named resource. This returns either a URL to the location of the file or null. |
18 - 21 | If the resource is not found (null returned), log a fatal error to the console and do nothing else. Hopefully someone will notice it. I don’t want this class’ static initializer to fail because if it does it will cause classes that use it to fail since the class will not be loaded. This is an important point to make, generally you should not allow a static initializer to fail because what you’ll see is an error about the class not being found but the actual error was lost when the static initialzier failed. |
19 - 20 | If I’m unable to locate the URL, get a logger and log a fatal message. |
20 | Use the new method, String.format, to format a string using old C-Style format strings. |
22 | I did find the URL, go ahead a process the contents of this property file. |
26 - 28 | Just in case I want to get a logger, I have a simple method that will give me an ILogger for a given class. Notice that I’m not using Sun’s or Lor4J’s Logger. Why? I change the interface to support both a variable number of parameters and automatic log level checking. So no place in my code beyond this configuration utility is aware of Log4J. I know I’m going to use Log4J so is there any value in wrapping it? In this case I am not simply wrapping it by actually adapting its interface. |
30 - 34 | The comment says it all. If you want to look like you are initializing the logging infrastructure, call initialize. It’s an empty method, but by referencing it, the class will get loaded and the logger will get initialized because of the static initializer on lines 12 - 15. |
log4j.properties
This file resides in the same directory as the source file for LogginConfiguration.java.
Interesting Lines
Line | Description |
01 | This sets the logging level from its default, DEBUG, to WARN. I did this to reduce the output produced by Spring. I’ve occasionally turned it back on to DEBUG to trace through things. However, I generally prefer my console to have little if any output so that what’s there is something I know I need to pay attention to. |
ILogger.java
Yes this is yet another logger wrapper, or is it? I use Log4J. Unfortunately it does not have an interface that uses the features offered by Java 5 so instead of using Lof4J directly, I have returned this interface that publishes what I think is a better interface.
Interesting Lines
There are not really any specifically interesting lines. Notice that every method’s last parameter is a variable number of parameters. Take a look below at the implementation of this class.
Logger.java
Interesting Lines
Line | Description |
6 | This class holds a reference to a Log4J logger instance. It publishes a different interface and adapts the new interface on to the Log4J interface. |
12 - 17 | A typical problem with logging is that of string concatenation. A way to avoid this is to check the logging level performing any string concatenation. That makes for ugly code. With variable arguments to methods, we can pass in a format string and the parameters to be sent into the format string, check the logging level and only actually perform the string formatting if the logging level is enabled. Each of these methods does exactly that. |
12 | Take in a format string and a variable number of arguments. |
13 | Is debug output enables for my contained logger? |
14 | Degugging is enabled, use the static method String.format passing in the variables arguments received by this method into the format method. The result of that is sent to the underlying Log4J logger. |
16 | Return myself to allow for method chaining. |
19 | Notice that Throwable is the first parameter. In the Log4J methods, the Throwable parameter is last. Since we are using variable arguments, we cannot put the Throwable parameter last so we instead make it the first one. |
All of the methods follow the same pattern. Rather that writing the following code, which I’ve seen:
Of course, you might want to simplify this code to the following, and I’ve seen this even more often:
The problem with this is that we perform the work of concatenating three strings even if the logger does not have debug level messages enabled. So the first form is ugly but better. The second form looks better, but performs potentially unnecessary work.
This adapted interface gives us the following:
This looks like the cleaner second version but it performs like the better first version.
This example is not complete. It does not publish the logging levels, which really is still necessary. Consider the following example that is NOT fixed by this interface:
Let’s say that the method getUserNameFromJndi() takes a long time. In this example, we called the method before calling the debug() method, so we did this extra work potentially unnecessarily.
Comments