This post has a follow-up.
“I object to doing things that computers can do” — Olin Shivers
We are all familiar with the following scenario – You write some code. Everything is working. You change your code just a little bit…
Incidental logging and step-by-step debugging are basically the same thing. You make your way through your code in a divide-and-conquer search for the cause of an unexpected result. You add a log here, you debug a function there, you step-into-outta-over-and-out. And then you finally find it – the function that returns the wrong value. And then, hopefully, the line that messes everything up. It took you almost forever and you know that with the next bug everything will happen all over again. But you always have a feeling that there is some reason guiding you through this weird process. And it’s true – Logging is clearly a job for a computer. So we asked ourselves – why not automatically log all arguments and return-values for any function call?
If you were to try implementing this in other languages you would find out you need to pursue one of two approaches, both fundamentally flawed. One would be to preprocess your code and inject logs. Another approach would be to implement some hideous reflection mechanism to inject the logs in the right places. The first approach would require heavy coding and either text-parsing or some use of a code analysis library, the second approach would require compiling code at runtime. Luckily for us, a preprocessed code-walking in Lisp is as simple as writing a function that iterates a list. Well, It is iterating a list!. Moreover, what would be the right places to inject logs at? Well, if you write in functional style, you really know for certain that you only need to log the arguments and return value of every function (or a sub-special-form of a function). In a non-functional programming language (any language that allows modifying variables) this certainty doesn’t exist. Therefore, any attempt to automatically generate all needed logs would require the logging of all variables after each and every single line of code.
In Lisp, a code-walker macro can be written that will iterate a function’s s-expression and “inject” log calls before every sub-expression call. We had some issues with handling Clojure’s special forms like “let” and “for”, but victory was eventually ours. It ended up looking like this.
The question still arises: How will we view such a monstrous amount of logs? We would really want to be able to view it as if its a simulation of the actual run of the program. So we wrote a small Javascript application to display the results of the logging in such a way. And that looks something like this:

With that said, we are aware that as our project will grow in complexity it may not be feasible to continue with this paradigm. However, thanks to Clojure, we believe that we will be able to find ways to maintain some parts of it by improving the logging mechanism to be less verbose and more precise.
[...] This post was mentioned on Twitter by theWE.net, theWE.net. theWE.net said: logging and debugging in clojure: http://blog.thewe.net/2009/11/22/logging-and-debugging-in-clojure/ [...]
yeah, as a long time code maintainer, i’ve always thought that should be doable and useful. thanks for telling me i’m not insane, or at least that i’m not the only one.
You might not need to walk the code, if you can rebind the vars (the “function names”) to logged versions of themselves at the top level.
This is awesome. Seriously, thank you! Coming from amazing Smalltalk debuggers not having a good debugger is my biggest annoyance with Clojure.
I thought about writing an emacs function that would look at the function at point and you could select which variables you wanted printed and it would add print statements before them in the code, and then with an arg this function would remove all print statements from the current function.
Anyway, awesome contribution!
Hi Ayal,
isn’t that a bit similar to Common Lisp trace facility (http://www.lispworks.com/documentation/HyperSpec/Body/m_tracec.htm)? Doesn’t Clojure sports its own (it seams to http://clojure.org/libraries#toc29)?
I understand that logging for admin purposes may require something different from trace, something that may be persisted and probably that is your goal, but, in principle you could do that on top of trace, couldn’t you?
[...] some interesting comments on our previous blog post we thought it would be appropriate to emphasize the added value of our logging approach (which [...]