Logging is an obvious requirement when it comes to being able to debug non-trivial systems. We’ve been thinking a lot about logging, thanks to the large-scale, distributed nature of the Zolodeck architecture. Unfortunately, when logging larger Clojure data-structures, I often find some kinds of log statements a bit hard to decipher. For instance, consider a map m that looked like this:
When you log things like m (shown here with println for simplicity), you may end up needing to understand this:
Aaugh, look at that second line! Where does the data-structure begin and end? What is nested, and what’s top-level? And this problem gets progressively worse as the size and nested-ness of such data-structures grow. I wrote this following function to help alleviate some of the pain:
Remember to include clojure.pprint. And here’s how you use it:
That’s it, really. Not a big deal, not a particularly clever function. But it’s much better to see this structured and formatted log statement when you’re poring over log files in the middle of the night.
Just note that you want to use this sparingly. I first modified things to make ALL log statements automatically wrap everything being logged with pp-str: it immediately halved the performance of everything. pp-str isn’t cheap (actually, pprint isn’t cheap). So use with caution, where you really need it!
Now go sign-up for Zolodeck!
Cool!
Did you consider using (clojure.pprint/write things :stream nil)?
Not sure if that is basically identical, or worse in some way…
OK, upon further reflection, I have a few more comments:
1) When I first saw the sequence of string manipulation calls, I thought WTF?, but armed with the REPL and the java.lang.String docs, I quickly figured out what you were doing….
2) String munging would not be first thought about how to accomplish this, so I started re-writing it, but quickly found I was calling map, apply, etc., so that can’t be faster, so for now I think your string munging approach is probably best.
3) That being said, are you sure about: (.replace “(” ” “) ?
, then hack off the leading open paren with another call to substring…
Seems like if one of the “things” I am formatting includes a list, then the replace above will do something bad! If you are just trying to get rid of the leading ( in the resulting string, and you are full-fledged member of the positional-string-munging club
Enough for now, I have other yaks to shave
Yea – all good points.
The problem with calling substring to get rid of the leading “(” is that it shifts the first line to the left by 1 character, and so the pretty-printed string ends up being slightly less pretty.
Try it at the REPL and you’ll see what I mean.
Understood. I guess I would take the final (str :\n”) out of the threading operator, and wrap the result of the threading operator with
(str ” ” result-of-threading “\n”)
Yea fair enough, that is nice too.