Well, my last post may have been a bit of a rant, but it did
spur my creativity. The more I thought about automatically replacing
logging statements with System.out.println()
, the more the idea
appealed to me. A couple of days later I had a day off with beautiful
weather and nothing to do, and I spent it out on the balcony, hacking
frantically. In the end I had a rough proof of concept that I’ve now
refined to the point that I’m not embarrased to show it to people.
Ladies and gentlemen, I give you WoodChipper. It is a command line utility that will automatically remove all Log4j and Commons Logging statements from a given .jar file or a classpath directory. This happens through bytecode manipulation, so the dependencies are removed completely. There is no classpath trickery like with Slf4j (which supplies its own replacement jars for the underlying logging system), no fiddling with your library path, no more need to write exclusion filters in maven. You can run it on your own code, but it’s really designed to work on 3rd party .jar files where you can’t influence the choice of logging framework.
Depending on your opinion on the state of Java logging frameworks, this is either wonderful or a terrible idea. Anyway, let me know what you think.
Demo
You need to have git and maven installed. Now get a bash prompt and download and install WoodChipper:
> git clone http://github.com/fred-o/woodchipper
> cd woodchipper
> mvn package
[lots and lots of maven output]
This builds woodchipper
and woodchipper-test-jar
. The latter is a
small project with trivial classes you can use for testing. Let’s
start by trying to run one of the classes directly:
> java -cp woodchipper-test-jar/target/woodchipper-test-jar-1.0-SNAPSHOT.jar woodchipper.TestClass
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/log4j/Priority
Caused by: java.lang.ClassNotFoundException: org.apache.log4j.Priority
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
Ok, so we get NoClassDefFoundError
. That’s actually expected, as I
didn’t include any log4j .jar file on the classpath. Anyway, let’s run
woodchipper on the sucker:
> java -jar woodchipper/target/woodchipper.jar -i \
woodchipper-test-jar/target/woodchipper-test-jar-1.0-SNAPSHOT.jar
Removing Log4J references from woodchipper/TestClass.class
Removing Commons Logging references from woodchipper/TestClass4.class
Looks like it’s working. Let’s try running it again:
> java -cp woodchipper-test-jar/target/woodchipper-test-jar-1.0-SNAPSHOT.jar woodchipper.TestClass
first message!
second message!
third message!
fourth message!
fifth message (with exception!)
java.lang.IllegalArgumentException
at woodchipper.TestClass.main(TestClass.java:29)
Yay! No log4j dependency anymore! (Note that the exception at the end isn’t acutally an error with WoodChipper, just a logged exception).