alexander-yakushev/neko — pull request #13 by AdamClements (2013-10-17 10:16:27+00:00)
Title: Logging proposal

Example:
```
(ns my.app)
(log-d "Hello, here is a map coll: " coll " and x: " x :exception err)
```
gives:
```
D/my.app (1234): Hello, here is a map coll: {:thing :other} and x: 45
D/my.app (1234): ... Exception stacktrace
```
Other examples:
```
(log-d "This is tagged HELLO" :tag "HELLO")
(log-e :exception err)
(log-d "-- mark --")
```

The current logging setup really bothers me, this is my proposed alternative. Issues I have with the current implementation are:

* the logging methods as they stand are awkward to use - most common log commands need to wrap in a str or pr-str and it would be more idiomatic clojure to have a varargs function which can take any number of things that can be cast to a string and concatenate them.

* in a varargs function, it is highly *un* idiomatic to have the exception last in the list, most logging libraries I have seen put the optional exception first, but I've decided on end of list keyword arguments as you'll see

* I don't like (deflogfn "blah") - it tends to result in random naming, and generates a lot of functions that might not be required at all (all the different log levels). What about simply setting the tag to *ns* by default and exposing the version with tag if a different tag is required? Clojure namespaces tend to be a lot more concise than java package names anyway, so this seems reasonable to me. I have made it so that you can optionally pass in a :tag keyword argument if you want to set it explicitly for any reason.

* deflog pollutes the current namespace, my proposed solution doesn't. Plus macros that def things are generally a bad code smell.

I have left deflog for back compatibility and the two solutions work fine alongside one another (well, unless you try and use both in a namespace - due to the original issue of deflog polluting the namespace!), depending on the current back compatibility policy/upcoming version numbers though it might be best to remove it entirely if this solution does turn out to be preferable.

Potential future improvements:
* Debug logs should probably be compiled out of release builds completely - this means not doing any processing required to build the strings passed to the log function e.g. (log-d (generate-expensive-logging-info x)) shouldn't run the function. This means that the logging function itself should be a macro which checks *release-build*, however the *release-build* seems to be unbound in my debug builds, which is evaluating as truthy (???) and so my conditions weren't working. I don't know how this is handled in other places in the code? It might be that the variable just isn't bound in all the threads? Either way I have left this functionality out for now.