Unfortunately, It is not obvious how to use tools.logging in such a scenario. tools.logging will pick up the bridge version of commons logging, think it has the real commons logging, and configure itself to use the bridge. This is undesirable from a performance perspective.
Is there are reason that commons comes first? Would it be better to provide a path for consumers to be explicit about which lib they want?
Stu
Commons-logging can itself be configured, and for that reason it needed to take precedence over the concrete logging library it might be wrapping. Checking now though, the current docs don't mention it anymore.
SLF4J was included later by request from someone using logback. Since SLF4J does not have its own configuration it really should go after the known, concrete logging libraries to avoid the unnecessary wrapping.It was not foreseen that someone would use tools.logging, and SLF4J, and commons-logging, all at the same time.I suspect that the commons-logging configuration was rarely used (it's not mentioned in the current docs), so in order to avoid minimize wrapping I am inclined to change the order to the following:log4jSLF4Jcommons-loggingjava.util.logging
Does the above look reasonable?To answer your second question, you can alter/bind the value of *logger-factory* to something else that satisfies the LoggerFactory protocol, e.g., the instance returned from (log4j/load-factory), and that will be the system that gets invoked.Note that the generated docs do not reflect the latest code.
--To view this discussion on the web visit https://groups.google.com/d/msg/clojure-dev/-/QQ9u4nd8vwcJ.
You received this message because you are subscribed to the Google Groups "Clojure Dev" group.
To post to this group, send email to cloju...@googlegroups.com.
To unsubscribe from this group, send email to clojure-dev...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/clojure-dev?hl=en.
Really, only slf4j is doing things right, by separating in different jars the client API and the implementation.
1. slf4j
2. commons-logging
3. java.util.logging
4. log4j
(or switch 3 <-> 4)
In mixed Java lib/app + Clojure envs, using slf4j is the least worst
choice (which is truly the best we can hope for these days). In a
pure Clojure env, pick what you like.
> --
> You received this message because you are subscribed to the Google Groups
> "Clojure Dev" group.
> To view this discussion on the web visit
> https://groups.google.com/d/msg/clojure-dev/-/vna9Dz9DQEUJ.
Like most people in a large Java project, I don't have any choice. My set of dependencies forces every single one of the Java logging choices on me, simultaneously.
SLF4J helps by pretending to be all of them.
tools.logging is fooled by SLF4J into thinking I am using commons.logging, and then binds to the commons logging bridge.
Stu
I finally got around to trying tools.logging 0.2.3 with this change
and ran into a problem. We're using a container that has its own
variant of SLF4J and tools.logging selects that and reports it's using
LOG4J (which is what we really want) but the variant SLF4J throws NPE
trying to get the stack trace from the non-existent exception we're
passing in (nil). Clearly it's a bug in the SLF4J variant (which we
have no control over right now) but I wanted to report it as a data
point.
Luckily we have our own wrapper around tools.logging so I added this:
(alter-var-root (var log/*logger-factory*) (constantly (impl/log4j-factory)))
;; log = clojure.tools.logging, impl = clojure.tools.logging.impl
That seems to work but I wondered how "kosher" it is to do that and
whether there is a better / safer way?
--
Sean A Corfield -- (904) 302-SEAN
An Architect's View -- http://corfield.org/
World Singles, LLC. -- http://worldsingles.com/
Railo Technologies, Inc. -- http://www.getrailo.com/
"Perfection is the enemy of the good."
-- Gustave Flaubert, French realist novelist (1821-1880)
LOG4J (which is what we really want) but the variant SLF4J throws NPE
trying to get the stack trace from the non-existent exception we're
passing in (nil).
That seems to work but I wondered how "kosher" it is to do that and
whether there is a better / safer way?
Thanx. I'll keep an eye out for 0.2.4 and see if that allows me to
remove the alter-root-var call (I didn't want to add binding to each
of my wrapper functions).
That fixes the NPE I was seeing. Thanx.
It still selects the container's variant SLF4J which doesn't pick up
my LOG4J configuration (and custom appender) so I still need the
alter-var-root to force the real LOG4J configuration. That feels
pretty ugly, especially since I have to reach into the impl ns for the
log4j factory. It would be nicer if there was a simple way to tell
tools.logging "Hey, just use this logger instead of trying to deduce
one for me!" so I could just tell it :log4j or "log4j" or something...
OK, then alter-var-root is the right (but ugly) solution to my problem, yes?
If so, that should be clearly documented for this library.
An instance satisfying the impl/LoggerFactory protocol. Used internally to obtain an impl/Logger. Defaults to the value returned from impl/find-factory.
The protocol through which the core api will obtain an instance satisfying Logger as well as providing information about the particular implementation being used. Implementations should be bound to *logger-factory* in order to be picked up by this library.
I meant more that it's a ugly way to tell tools.logging you want to
override the default algorithm for finding a logger, esp. since it
means knowledge of clojure.tools.logging.impl which ought to be an
implementation detail...
How about a function, say (set-logger! logger-name), that takes a
keyword (:auto - default, :log4j, :slf4j, :commons, :jul) and then
have the default factory implementation do its current behavior if
:auto is selected but otherwise have it directly select the
appropriate logger factory.
That would allow for the simple case to be nice and clean - folks who
need to override the default lookup could just call (set-logger!
:log4j) - for example - before they log anything; folks who need to
provide their own logger factory based on the (implementation
detail's) protocol and can alter/re-def *logger-factory*.
Regards,
Sean