Logging functions delegated to java logging systems

39 views
Skip to first unread message

ataggart

unread,
Jul 22, 2009, 1:13:55 AM7/22/09
to Clojure
I've written up a small set of logging functions to output from
clojure what I'm already doing from my production java code.

Currently it checks for the presence of commons-logging, log4j, and
finally java.util.logging. The clojure code doesn't actually do any
logging itself; instead everything is delegated to whatever you've
been using all along.

I've stuck the code at http://paste.lisp.org/display/83982


I'd welcome any thoughts, particularly if this merits going into
clojure-contrib.

Timothy Pratley

unread,
Jul 22, 2009, 3:04:44 AM7/22/09
to Clojure
Hi Alex,

You've got my vote - logging is essential for non-trivial programs.

Your implementation is superior to mine, but maybe you would like to
include some sub-parts:
http://github.com/timothypratley/strive/blob/baf83e2bb26662f5f5049d165dec31e47b91e171/clj/timothypratley/logging.clj

log-capture -> grabs normal prints if any are left in the code
log-format -> better output for java.logging
logged-future -> I find handy for long running threads
debug -> its nice to be able to log an expression and what
its evaluated to while leaving it in place (+ (debug (+ 1 2)) 3)
current-function-name (Stephen C. Gilardi posted) -> optionally
including the function and thread id


Regards,
Tim.


On Jul 22, 3:13 pm, ataggart <alex.tagg...@gmail.com> wrote:
> I've written up a small set of logging functions to output from
> clojure what I'm already doing from my production java code.
>
> Currently it checks for the presence of commons-logging, log4j, and
> finally java.util.logging.  The clojure code doesn't actually do any
> logging itself; instead everything is delegated to whatever you've
> been using all along.
>
> I've stuck the code athttp://paste.lisp.org/display/83982

Tom Faulhaber

unread,
Jul 22, 2009, 12:57:57 PM7/22/09
to Clojure
Yeah, I'd like to see something like this in clojure-contrib. One of
the problems that java systems routinely have is mismatches between
the assumed logging system. This is a real pain when it comes up and
it would be nice to have that taken care of by an abstraction layer.

Tom

On Jul 21, 10:13 pm, ataggart <alex.tagg...@gmail.com> wrote:
> I've written up a small set of logging functions to output from
> clojure what I'm already doing from my production java code.
>
> Currently it checks for the presence of commons-logging, log4j, and
> finally java.util.logging.  The clojure code doesn't actually do any
> logging itself; instead everything is delegated to whatever you've
> been using all along.
>
> I've stuck the code athttp://paste.lisp.org/display/83982

ataggart

unread,
Jul 22, 2009, 2:53:24 PM7/22/09
to Clojure
Tim, you're too modest. I'm incorporating some of your stuff now.
I'll update once it's done.



On Jul 22, 12:04 am, Timothy Pratley <timothyprat...@gmail.com> wrote:
> Hi Alex,
>
> You've got my vote - logging is essential for non-trivial programs.
>
> Your implementation is superior to mine, but maybe you would like to
> include some sub-parts:http://github.com/timothypratley/strive/blob/baf83e2bb26662f5f5049d16...

ataggart

unread,
Jul 23, 2009, 5:12:09 AM7/23/09
to Clojure
Ok, I've updated the code with some of Tim's code:
http://paste.lisp.org/display/84053

The "public" functions/macros are:

enabled? [level] [level log-name]
true/false whether that level is enabled for the current namespace
or log-name

log [level message ...]
logs the message either directly or via an agent. The selection
logic defaults to agent, unless the *allow-direct-logging* flag is set
to true and the log is not being called from within a running
transaction.

debug [expr]
Evaluates and returns the expr. If debug is enabled logs the form
and its result.

log-capture! [log-name]
Redirects writes of System.out and System.err to the logs

log-uncapture!
Restores the System.out and System.err to their defaults.

with-logs [log-name & body]
Evaluates the body with *out* and *err* redirected to the logs

Laurent PETIT

unread,
Jul 23, 2009, 5:27:45 AM7/23/09
to clo...@googlegroups.com
Hello,

2009/7/23 ataggart <alex.t...@gmail.com>


Ok, I've updated the code with some of Tim's code:
http://paste.lisp.org/display/84053

The "public" functions/macros are:

enabled? [level] [level log-name]
 true/false whether that level is enabled for the current namespace
or log-name

log [level message ...]
 logs the message either directly or via an agent.  The selection
logic defaults to agent, unless the *allow-direct-logging* flag is set
to true and the log is not being called from within a running
transaction.

debug [expr]
 Evaluates and returns the expr.  If debug is enabled logs the form
and its result.

One of the problems with logging in traditional java is that you have to encapsulate your call to debug with an isDebugEnabled (for example) call before doing a potentially heavy computation for expr :

if (log.isDebugEnabled()) {
  String message = <potentially heavy computation>;
  log.debug(message);
}

In clojure, with macros, it is easy to get rid of this verbose pattern:
(debug <potentially heavy computation>) => the macro can generate the boilerplate for us.

But I see your debug function/macro always returns the result, so the problem we had in java remains intact ?
What about just making debug return nil (so that it's clear that its primary use implies a side effect) and generate the code to only evaluate the expression generating the message if necessary ?

I know that it would make you change a lot of your library, but I think this functionality is important.

Regards,

--
Laurent



Timothy Pratley

unread,
Jul 23, 2009, 5:56:26 AM7/23/09
to Clojure
Hi Laurent,

I believe using
(log :fine (expensive-calc))
will do precisely what you describe (not do anything unless
level :fine is enabled, and return nil)

(debug (some-expr)) is intended when you want to leave the logic
precisely as is but display part of the calculation;
(+ a b (- c d))
; I can easily examine part of the equation that I think might be
wrong:
(+ a b (debug (- c d)))

This produces the same output and logic as the original statement, but
if the logging level is :fine then it will additionally log the
intermediate part. I find both forms useful. Unfortunately the naming
gives no clue as to the differences between them.


Regards,
Tim.


On Jul 23, 7:27 pm, Laurent PETIT <laurent.pe...@gmail.com> wrote:
> Hello,
>
> 2009/7/23 ataggart <alex.tagg...@gmail.com>

Laurent PETIT

unread,
Jul 23, 2009, 7:19:09 AM7/23/09
to clo...@googlegroups.com
Thanks for the explanation, that makes sense.


2009/7/23 Timothy Pratley <timothy...@gmail.com>

ataggart

unread,
Jul 23, 2009, 1:52:43 PM7/23/09
to Clojure
Tim is correct. The log macro is what you want to use when you're
really just wanting to log something; in that case the message
expression won't get evaluated unless the particular logging level is
enabled.

The debug function is for when you want to execute an expression
regardless, but would also like to have the expression and its result
logged. In this way it is analogous to the time function.

I agree the naming isn't very self-descriptive (trying to keep things
short), but I welcome any suggestions.

Also note that the log levels are like commons-logging/log4j: trace,
debug, info, warn, error, fatal. I've submitted the code to assembla,
but once it's up in git, I plan on adding support for levels that
correspond to java.util.logging.



On Jul 23, 4:19 am, Laurent PETIT <laurent.pe...@gmail.com> wrote:
> Thanks for the explanation, that makes sense.
>
> 2009/7/23 Timothy Pratley <timothyprat...@gmail.com>

Laurent PETIT

unread,
Jul 23, 2009, 2:01:01 PM7/23/09
to clo...@googlegroups.com
What about 'spy instead of 'debug ? Or 'trace ?

2009/7/23 ataggart <alex.t...@gmail.com>

ataggart

unread,
Jul 23, 2009, 2:20:17 PM7/23/09
to Clojure
Hmm, I like "spy" since it doesn't mimic a logging level like "debug"
and "trace" do. Making the change now, thanks.



On Jul 23, 11:01 am, Laurent PETIT <laurent.pe...@gmail.com> wrote:
> What about 'spy instead of 'debug ? Or 'trace ?
>
> 2009/7/23 ataggart <alex.tagg...@gmail.com>

ataggart

unread,
Jul 27, 2009, 11:09:11 PM7/27/09
to Clojure
Ok the patch file has been languishing on assembla for a few days, so
I've uploaded it to the files section here if anyone wants to use the
latest version.

logging.clj at http://groups.google.com/group/clojure/files


http://groups.google.com/group/clojure/files
Reply all
Reply to author
Forward
0 new messages