Logs are like onions

Or, What underlying implementation is clojure.tools.logging using?

Today I want to change the logging configuration of a Clojure program. Where is that configuration located? Changing the obvious resources/log4j.properties doesn’t seem to change the program’s behavior.

The program uses clojure.tools.logging, but that’s a wrapper around four different underlying implementations. Each of those implementations has its own ideas about configuration. How can I find out which one it uses?

Add a println to your program[1] to output this:

(.name clojure.tools.logging/*logger-factory*)         

In my case the output is:

org.slf4j

This is clojure logging’s first choice of factories. If it can instantiate this, it’ll use it. Now I can google slf4j and find that it… is also a facade on top of multiple logging implementations.
Digging into the slf4j source code reveals this trick:

(class (org.slf4j.LoggerFactory/getILoggerFactory)) 

which prints:

org.slf4j.impl.Log4jLoggerFactory

so hey! I am using log4j after all! Now why doesn’t it pick up resources/log4j.properties?
Crawling through the log4j 1.2 (slf4j seems to use this version) source code suggests this[2]:

(org.apache.log4j.helpers.Loader/getResource “log4j.properties”)

which gives me

#

So hey, I finally have a way to trace where logging configuration comes from! 
In the end, my guess of resources/log4j.properties was correct. I forgot to rebuild the uberjar that I was running. The uberjar found the properties file in itself:

jar:file:/Users/jessitron/…/target/program-0.1.0-SNAPSHOT-standalone.jar!/log4j.properties

Bet I’d have realized that a few hours earlier if I were pairing today. And then I wouldn’t have made this lovely post.

———-
[1] or run it in the cider REPL in emacs, in your namespace
[2] actually it checks for log4j.xml first; if that’s found it’ll choose the xml file over the .properties.