[slf4j-user] Fail Silently on NOP implementation

Joachim Durchholz jo at durchholz.org
Fri Apr 29 05:58:42 UTC 2016


 >> Now if you're writing a library you should never bother with logging
 >> configuration. Maybe make sure it doesn't clutter your unit-testing
 >> output, but that's more cosmetic than anything. If, on the other hand,
 >> you're writing an application, you definitely need to configure
 >> logging.
 >
 > As I have said, this distinction is artificial.

Decisions like detail level and where to finally write the logs are made 
on a per-application basis, so if libraries start to assume or decide 
things in this area it's going to be a source of eternal conflict.
Ceki has another argument:
http://www.slf4j.org/faq.html#configure_logging
Essentially, both arguments hinge on the fact that libraries are reused 
in different contexts with different logging targets, and that they need 
to adapt which they can't if they make global logging decisions; an 
application, on the other hand, needs to make a logging decision or give 
the administrator a way to decide about logging.
So I strongly disagree that the distinction is artificial; in fact it's 
unavoidable. If you insist on declaring a dependency on a specific 
logger you still burden your library consumers with excluding that 
dependency - that's exactly what you hated about having to bother about 
indirect dependencies.

Now you have a case where your library can also stand as an application.
The best advice is to pull the application part out into a separate 
artifact. Let the application have a hard dependency on whatever backend 
you prefer.
You mentioned that you have a REPL; it should actually go into the 
library, too. The main program just configures logging and starts the 
REPL. That way, people who write something more elaborate (say, a GUI 
around your REPL) can easily call the REPL without having to worry about 
the logging decisions that were right for your application.

 >> The good news is that the NOP logger message you are seeing is just a
 >> misconfiguration.
 >
 > No, the logger message is coming directly from slf4j-api. The code
 > is here, in LoggerFactory.java.
 >
 >        if (messageContainsOrgSlf4jImplStaticLoggerBinder(msg)) {
 >          INITIALIZATION_STATE = NOP_FALLBACK_INITIALIZATION;
 >          Util.report("Failed to load class 
\"org.slf4j.impl.StaticLoggerBinder\".");
 >          Util.report("Defaulting to no-operation (NOP) logger 
implementation");
 >          Util.report("See " + NO_STATICLOGGERBINDER_URL + " for 
further details.");
 >        }

All SLF4J backend jars contain an implementation of 
org.slf4j.impl.StaticLoggerBinder.
Just include one in your build and the message should go away; you can 
start with slf4j-nop.jar which is an extremely thin thing (I guess it 
just provides a StaticLoggerBinder class to make the message go away and 
otherwise makes SLF4J fall back to its builting NOP logging). Or you 
might want to use SimpleLogger because occasionally log messages are 
indeed interesting, at least for your debugging configurations.

 >> many libraries are misguided in that they declare a dependency on a
 >> logging backend, and you need to exclude that
 >
 > I think including an explict dependency on the slf4j-nop backend is the
 > correct thing to do. Otherwise, slf4j-api prints an error message.

Actually it's already the case.
You're getting the message as a hint that tells you that you should 
really have made an explicit decision about the logging backend. That's 
because for the vast majority of cases, NOP logging is not what you want 
but SLF4J can't reasonably tell which backend is the right one to use.

 >>> Yes, although these do not equate to the artifacts. slf4j-api is
 >>> actually the API and the NOP logger.
 >>
 >> Last time I looked these were different libraries.
 >
 > I'm sorry to contradict you again, but I'm afraid you are wrong. The
 > NOPLogger is in org.slf4j.helpers.NOPLogger, and it's packaged as part
 > of slf4j-api. It would have to be, else how could slf4j-api fallback to
 > it?
 >
 > slf4j-nop simply provides the StaticLoggerBinder which, erm, binds the
 > logger statically. Having done so, slf4j-api finds
 > org.slf4j.helpers.NOPLoggerFactory through reflection at runtime, rather
 > than at compile time, and in the process supresses the warning.

Well, as I said above, then that's exactly what it's supposed to do: 
slf4j-nop essentially just records the fact that the main application 
consciously decided to ignore all log messages.

 >> I dimly recall that slf4j-api didn't even pull in any logger as a
 >> dependency
 >
 > It doesn't. It just includes the NOPLogger directly.

Good to hear that my memory served me right.

 >>> If not, I will just include slf4j-nop directly and leave it at that.
 >>
 >>  From the keywords I have seen, you're getting messages because you 
have more
 >> than one logging backend in your classpath, slf4j-nop and something 
else.
 >> Including slf4j-nop will not change anything about that.
 >
 > I'm getting error messages because there is no binding. I want to stop
 > this.

Yes, I saw that.

 > The simple way to do this with slf4j is to include slf4j-nop.

That's the simple way for you.
It's making things more complicated for everybody who does not use nop 
logging. And there's another simple way for you: include slf4j-nop.

 > The only other solutions that I can see are:
 >
 > 1) Ask the slf4j developers to not print an error message.

The message is to remind application developers that they did not yet 
decide what logging backend to use.

 > 2) Replacing System.err with a PrintStream that looks for the error
 >     messages from slf4j and filters them.
 > 3) Creating a slf4j binding which looks for other bindings in the same
 >     way as StaticLoggerBinder, automatically defers to one if it finds it
 >     (and without complaining to System.err), falls back to nop otherwise.
 > 4) Forking slf4j and removing the error message there.
 >
 > This is in approximately decreasing order of sanity.

Heh. Indeed.
I'd like to add this:

0) Include slf4j-nop in the class path of the main application.

No insanity at all here.


More information about the slf4j-user mailing list